Bug Summary

File:home/maarten/src/libreoffice/core/sw/source/core/text/itrform2.cxx
Warning:line 799, column 30
Called C++ object pointer is null

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name itrform2.cxx -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=all -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -isystem /usr/include/libxml2 -D BOOST_ERROR_CODE_HEADER_ONLY -D BOOST_SYSTEM_NO_DEPRECATED -D CPPU_ENV=gcc3 -D LINUX -D OSL_DEBUG_LEVEL=1 -D SAL_LOG_INFO -D SAL_LOG_WARN -D UNIX -D UNX -D X86_64 -D _PTHREADS -D _REENTRANT -D SW_DLLIMPLEMENTATION -D SWUI_DLL_NAME="libswuilo.so" -D SYSTEM_LIBXML -D EXCEPTIONS_ON -D LIBO_INTERNAL_ONLY -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source/i18n -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source/common -I /home/maarten/src/libreoffice/core/external/boost/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/boost -I /home/maarten/src/libreoffice/core/sw/source/core/inc -I /home/maarten/src/libreoffice/core/sw/source/filter/inc -I /home/maarten/src/libreoffice/core/sw/source/uibase/inc -I /home/maarten/src/libreoffice/core/sw/inc -I /home/maarten/src/libreoffice/core/workdir/SdiTarget/sw/sdi -I /home/maarten/src/libreoffice/core/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include/linux -I /home/maarten/src/libreoffice/core/config_host -I /home/maarten/src/libreoffice/core/workdir/CustomTarget/officecfg/registry -I /home/maarten/src/libreoffice/core/workdir/CustomTarget/sw/generated -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/udkapi/normal -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/offapi/normal -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/oovbaapi/normal -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10 -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/x86_64-redhat-linux -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/backward -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O0 -Wno-missing-braces -std=c++17 -fdeprecated-macro -fdebug-compilation-dir /home/maarten/src/libreoffice/core -ferror-limit 19 -fvisibility hidden -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcxx-exceptions -fexceptions -debug-info-kind=constructor -analyzer-output=html -faddrsig -o /home/maarten/tmp/wis/scan-build-libreoffice/output/report/2020-10-07-141433-9725-1 -x c++ /home/maarten/src/libreoffice/core/sw/source/core/text/itrform2.cxx

/home/maarten/src/libreoffice/core/sw/source/core/text/itrform2.cxx

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 <hintids.hxx>
21
22#include <memory>
23#include <com/sun/star/i18n/ScriptType.hpp>
24#include <editeng/lspcitem.hxx>
25#include <txtflcnt.hxx>
26#include <txtftn.hxx>
27#include <flyfrms.hxx>
28#include <fmtflcnt.hxx>
29#include <fmtftn.hxx>
30#include <ftninfo.hxx>
31#include <charfmt.hxx>
32#include <editeng/charrotateitem.hxx>
33#include <layfrm.hxx>
34#include <viewsh.hxx>
35#include <viewopt.hxx>
36#include <paratr.hxx>
37#include "itrform2.hxx"
38#include "porrst.hxx"
39#include "portab.hxx"
40#include "porfly.hxx"
41#include "portox.hxx"
42#include "porref.hxx"
43#include "porfld.hxx"
44#include "porftn.hxx"
45#include "porhyph.hxx"
46#include "pordrop.hxx"
47#include "redlnitr.hxx"
48#include <pagefrm.hxx>
49#include <tgrditem.hxx>
50#include <doc.hxx>
51#include "pormulti.hxx"
52#include <unotools/charclass.hxx>
53#include <xmloff/odffields.hxx>
54#include <IDocumentSettingAccess.hxx>
55#include <IMark.hxx>
56#include <IDocumentMarkAccess.hxx>
57
58#include <vector>
59
60using namespace ::com::sun::star;
61
62namespace {
63 //! Calculates and sets optimal repaint offset for the current line
64 long lcl_CalcOptRepaint( SwTextFormatter &rThis,
65 SwLineLayout const &rCurr,
66 TextFrameIndex nOldLineEnd,
67 const std::vector<long> &rFlyStarts );
68 //! Determine if we need to build hidden portions
69 bool lcl_BuildHiddenPortion(const SwTextSizeInfo& rInf, TextFrameIndex &rPos);
70
71 // Check whether the two font has the same border
72 bool lcl_HasSameBorder(const SwFont& rFirst, const SwFont& rSecond);
73}
74
75static void ClearFly( SwTextFormatInfo &rInf )
76{
77 delete rInf.GetFly();
78 rInf.SetFly(nullptr);
79}
80
81void SwTextFormatter::CtorInitTextFormatter( SwTextFrame *pNewFrame, SwTextFormatInfo *pNewInf )
82{
83 CtorInitTextPainter( pNewFrame, pNewInf );
84 m_pInf = pNewInf;
85 m_pDropFormat = GetInfo().GetDropFormat();
86 m_pMulti = nullptr;
87
88 m_bOnceMore = false;
89 m_bFlyInContentBase = false;
90 m_bTruncLines = false;
91 m_nContentEndHyph = 0;
92 m_nContentMidHyph = 0;
93 m_nLeftScanIdx = TextFrameIndex(COMPLETE_STRING);
94 m_nRightScanIdx = TextFrameIndex(0);
95 m_pByEndIter.reset();
96 m_pFirstOfBorderMerge = nullptr;
97
98 if (m_nStart > TextFrameIndex(GetInfo().GetText().getLength()))
99 {
100 OSL_ENSURE( false, "+SwTextFormatter::CTOR: bad offset" )do { if (true && (!(false))) { sal_detail_logFormat((
SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/text/itrform2.cxx"
":" "100" ": "), "%s", "+SwTextFormatter::CTOR: bad offset")
; } } while (false)
;
101 m_nStart = TextFrameIndex(GetInfo().GetText().getLength());
102 }
103
104}
105
106SwTextFormatter::~SwTextFormatter()
107{
108 // Extremely unlikely, but still possible
109 // e.g.: field splits up, widows start to matter
110 if( GetInfo().GetRest() )
111 {
112 delete GetInfo().GetRest();
113 GetInfo().SetRest(nullptr);
114 }
115}
116
117void SwTextFormatter::Insert( SwLineLayout *pLay )
118{
119 // Insert BEHIND the current element
120 if ( m_pCurr )
121 {
122 pLay->SetNext( m_pCurr->GetNext() );
123 m_pCurr->SetNext( pLay );
124 }
125 else
126 m_pCurr = pLay;
127}
128
129sal_uInt16 SwTextFormatter::GetFrameRstHeight() const
130{
131 // We want the rest height relative to the page.
132 // If we're in a table, then pFrame->GetUpper() is not the page.
133
134 // GetFrameRstHeight() is being called with Footnote.
135 // Wrong: const SwFrame *pUpper = pFrame->GetUpper();
136 const SwFrame *pPage = m_pFrame->FindPageFrame();
137 const SwTwips nHeight = pPage->getFrameArea().Top()
138 + pPage->getFramePrintArea().Top()
139 + pPage->getFramePrintArea().Height() - Y();
140 if( 0 > nHeight )
141 return m_pCurr->Height();
142 else
143 return sal_uInt16( nHeight );
144}
145
146SwLinePortion *SwTextFormatter::Underflow( SwTextFormatInfo &rInf )
147{
148 // Save values and initialize rInf
149 SwLinePortion *pUnderflow = rInf.GetUnderflow();
150 if( !pUnderflow )
151 return nullptr;
152
153 // We format backwards, i.e. attribute changes can happen the next
154 // line again.
155 // Can be seen in 8081.sdw, if you enter text in the first line
156
157 TextFrameIndex const nSoftHyphPos = rInf.GetSoftHyphPos();
158 TextFrameIndex const nUnderScorePos = rInf.GetUnderScorePos();
159
160 // Save flys and set to 0, or else segmentation fault
161 // Not ClearFly(rInf) !
162 SwFlyPortion *pFly = rInf.GetFly();
163 rInf.SetFly( nullptr );
164
165 FeedInf( rInf );
166 rInf.SetLast( m_pCurr );
167 // pUnderflow does not need to be deleted, because it will drown in the following
168 // Truncate()
169 rInf.SetUnderflow(nullptr);
170 rInf.SetSoftHyphPos( nSoftHyphPos );
171 rInf.SetUnderScorePos( nUnderScorePos );
172 rInf.SetPaintOfst( GetLeftMargin() );
173
174 // We look for the portion with the under-flow position
175 SwLinePortion *pPor = m_pCurr->GetFirstPortion();
176 if( pPor != pUnderflow )
177 {
178 // pPrev will be the last portion before pUnderflow,
179 // which still has a real width.
180 // Exception: SoftHyphPortion must not be forgotten, of course!
181 // Although they don't have a width.
182 SwLinePortion *pTmpPrev = pPor;
183 while( pPor && pPor != pUnderflow )
184 {
185 if( !pPor->IsKernPortion() &&
186 ( pPor->Width() || pPor->IsSoftHyphPortion() ) )
187 {
188 while( pTmpPrev != pPor )
189 {
190 pTmpPrev->Move( rInf );
191 rInf.SetLast( pTmpPrev );
192 pTmpPrev = pTmpPrev->GetNextPortion();
193 OSL_ENSURE( pTmpPrev, "Underflow: losing control!" )do { if (true && (!(pTmpPrev))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/text/itrform2.cxx"
":" "193" ": "), "%s", "Underflow: losing control!"); } } while
(false)
;
194 };
195 }
196 pPor = pPor->GetNextPortion();
197 }
198 pPor = pTmpPrev;
199 if( pPor && // Skip flys and initials when underflow.
200 ( pPor->IsFlyPortion() || pPor->IsDropPortion() ||
201 pPor->IsFlyCntPortion() ) )
202 {
203 pPor->Move( rInf );
204 rInf.SetLast( pPor );
205 rInf.SetStopUnderflow( true );
206 pPor = pUnderflow;
207 }
208 }
209
210 // What? The under-flow portion is not in the portion chain?
211 OSL_ENSURE( pPor, "SwTextFormatter::Underflow: overflow but underflow" )do { if (true && (!(pPor))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/text/itrform2.cxx"
":" "211" ": "), "%s", "SwTextFormatter::Underflow: overflow but underflow"
); } } while (false)
;
212
213 // Snapshot
214 if ( pPor==rInf.GetLast() )
215 {
216 // We end up here, if the portion triggering the under-flow
217 // spans over the whole line. E.g. if a word spans across
218 // multiple lines and flows into a fly in the second line.
219 rInf.SetFly( pFly );
220 pPor->Truncate();
221 return pPor; // Is that enough?
222 }
223 // End the snapshot
224
225 // X + Width == 0 with SoftHyph > Line?!
226 if( !pPor || !(rInf.X() + pPor->Width()) )
227 {
228 delete pFly;
229 return nullptr;
230 }
231
232 // Preparing for Format()
233 // We need to chip off the chain behind pLast, because we Insert after the Format()
234 SeekAndChg( rInf );
235
236 // line width is adjusted, so that pPor does not fit to current
237 // line anymore
238 rInf.Width( static_cast<sal_uInt16>(rInf.X() + (pPor->Width() ? pPor->Width() - 1 : 0)) );
239 rInf.SetLen( pPor->GetLen() );
240 rInf.SetFull( false );
241 if( pFly )
242 {
243 // We need to recalculate the FlyPortion due to the following reason:
244 // If the base line is lowered by a big font in the middle of the line,
245 // causing overlapping with a fly, the FlyPortion has a wrong size/fixed
246 // size.
247 rInf.SetFly( pFly );
248 CalcFlyWidth( rInf );
249 }
250 rInf.GetLast()->SetNextPortion(nullptr);
251
252 // The SwLineLayout is an exception to this, which splits at the first
253 // portion change.
254 // Here only the other way around:
255 if( rInf.GetLast() == m_pCurr )
256 {
257 if( pPor->InTextGrp() && !pPor->InExpGrp() )
258 {
259 const PortionType nOldWhich = m_pCurr->GetWhichPor();
260 *static_cast<SwLinePortion*>(m_pCurr) = *pPor;
261 m_pCurr->SetNextPortion( pPor->GetNextPortion() );
262 m_pCurr->SetWhichPor( nOldWhich );
263 pPor->SetNextPortion( nullptr );
264 delete pPor;
265 pPor = m_pCurr;
266 }
267 }
268
269 // Make sure that m_pFirstOfBorderMerge does not point to a portion which
270 // will be deleted by Truncate() below.
271 SwLinePortion* pNext = pPor->GetNextPortion();
272 while (pNext)
273 {
274 if (pNext == m_pFirstOfBorderMerge)
275 {
276 m_pFirstOfBorderMerge = nullptr;
277 break;
278 }
279 pNext = pNext->GetNextPortion();
280 }
281 pPor->Truncate();
282 SwLinePortion *const pRest( rInf.GetRest() );
283 if (pRest && pRest->InFieldGrp() &&
284 static_cast<SwFieldPortion*>(pRest)->IsNoLength())
285 {
286 // HACK: decrement again, so we pick up the suffix in next line!
287 m_pByEndIter->PrevAttr();
288 }
289 delete pRest;
290 rInf.SetRest(nullptr);
291 return pPor;
292}
293
294void SwTextFormatter::InsertPortion( SwTextFormatInfo &rInf,
295 SwLinePortion *pPor )
296{
297 SwLinePortion *pLast = nullptr;
298 // The new portion is inserted, but everything's different for
299 // LineLayout...
300 if( pPor == m_pCurr )
301 {
302 if ( m_pCurr->GetNextPortion() )
303 {
304 pLast = pPor;
305 pPor = m_pCurr->GetNextPortion();
306 }
307
308 // i#112181 - Prevent footnote anchor being wrapped to next line
309 // without preceding word
310 rInf.SetOtherThanFootnoteInside( rInf.IsOtherThanFootnoteInside() || !pPor->IsFootnotePortion() );
311 }
312 else
313 {
314 pLast = rInf.GetLast();
315 if( pLast->GetNextPortion() )
316 {
317 while( pLast->GetNextPortion() )
318 pLast = pLast->GetNextPortion();
319 rInf.SetLast( pLast );
320 }
321 pLast->Insert( pPor );
322
323 rInf.SetOtherThanFootnoteInside( rInf.IsOtherThanFootnoteInside() || !pPor->IsFootnotePortion() );
324
325 // Adjust maxima
326 if( m_pCurr->Height() < pPor->Height() )
327 m_pCurr->Height( pPor->Height(), pPor->IsTextPortion() );
328 if( m_pCurr->GetAscent() < pPor->GetAscent() )
329 m_pCurr->SetAscent( pPor->GetAscent() );
330
331 if (GetTextFrame()->GetDoc().getIDocumentSettingAccess().get(DocumentSettingId::MS_WORD_COMP_MIN_LINE_HEIGHT_BY_FLY))
332 {
333 // For DOCX with compat=14 the only shape in line defines height of the line in spite of used font
334 if (pLast->IsFlyCntPortion() && pPor->IsTextPortion() && pPor->GetLen() == TextFrameIndex(0))
335 {
336 m_pCurr->SetAscent(pLast->GetAscent());
337 m_pCurr->Height(pLast->Height());
338 }
339 }
340 }
341
342 // Sometimes chains are constructed (e.g. by hyphenate)
343 rInf.SetLast( pPor );
344 while( pPor )
345 {
346 if (!pPor->IsDropPortion())
347 MergeCharacterBorder(*pPor, pLast, rInf);
348
349 pPor->Move( rInf );
350 rInf.SetLast( pPor );
351 pLast = pPor;
352 pPor = pPor->GetNextPortion();
353 }
354}
355
356void SwTextFormatter::BuildPortions( SwTextFormatInfo &rInf )
357{
358 OSL_ENSURE( rInf.GetText().getLength() < COMPLETE_STRING,do { if (true && (!(rInf.GetText().getLength() < COMPLETE_STRING
))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/sw/source/core/text/itrform2.cxx"
":" "359" ": "), "%s", "SwTextFormatter::BuildPortions: bad text length in info"
); } } while (false)
1
Assuming the condition is false
2
Taking true branch
3
Loop condition is false. Exiting loop
359 "SwTextFormatter::BuildPortions: bad text length in info" )do { if (true && (!(rInf.GetText().getLength() < COMPLETE_STRING
))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/sw/source/core/text/itrform2.cxx"
":" "359" ": "), "%s", "SwTextFormatter::BuildPortions: bad text length in info"
); } } while (false)
;
360
361 rInf.ChkNoHyph( CntEndHyph(), CntMidHyph() );
362
363 // First NewTextPortion() decides whether pCurr ends up in pPor.
364 // We need to make sure that the font is being set in any case.
365 // This is done automatically in CalcAscent.
366 rInf.SetLast( m_pCurr );
367 rInf.ForcedLeftMargin( 0 );
368
369 OSL_ENSURE( m_pCurr->FindLastPortion() == m_pCurr, "pLast supposed to equal pCurr" )do { if (true && (!(m_pCurr->FindLastPortion() == m_pCurr
))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/sw/source/core/text/itrform2.cxx"
":" "369" ": "), "%s", "pLast supposed to equal pCurr"); } }
while (false)
;
4
Assuming the condition is true
5
Taking false branch
6
Loop condition is false. Exiting loop
370
371 if( !m_pCurr->GetAscent() && !m_pCurr->Height() )
7
Assuming the condition is false
372 CalcAscent( rInf, m_pCurr );
373
374 SeekAndChg( rInf );
375
376 // Width() is shortened in CalcFlyWidth if we have a FlyPortion
377 OSL_ENSURE( !rInf.X() || m_pMulti, "SwTextFormatter::BuildPortion X=0?" )do { if (true && (!(!rInf.X() || m_pMulti))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/text/itrform2.cxx"
":" "377" ": "), "%s", "SwTextFormatter::BuildPortion X=0?")
; } } while (false)
;
8
Assuming the condition is false
9
Assuming the condition is false
10
Taking false branch
11
Loop condition is false. Exiting loop
378 CalcFlyWidth( rInf );
379 SwFlyPortion *pFly = rInf.GetFly();
380 if( pFly )
12
Assuming 'pFly' is null
13
Taking false branch
381 {
382 if ( 0 < pFly->GetFix() )
383 ClearFly( rInf );
384 else
385 rInf.SetFull(true);
386 }
387
388 SwLinePortion *pPor = NewPortion( rInf );
14
Value assigned to field 'm_pCurr'
389
390 // Asian grid stuff
391 SwTextGridItem const*const pGrid(GetGridItem(m_pFrame->FindPageFrame()));
392 const bool bHasGrid = pGrid && rInf.SnapToGrid() &&
15
Assuming 'pGrid' is null
393 GRID_LINES_CHARS == pGrid->GetGridType();
394
395
396 const SwDoc & rDoc = rInf.GetTextFrame()->GetDoc();
397 const sal_uInt16 nGridWidth = bHasGrid
15.1
'bHasGrid' is false
15.1
'bHasGrid' is false
15.1
'bHasGrid' is false
15.1
'bHasGrid' is false
? GetGridWidth(*pGrid, rDoc) : 0;
16
'?' condition is false
398
399 // used for grid mode only:
400 // the pointer is stored, because after formatting of non-asian text,
401 // the width of the kerning portion has to be adjusted
402 // Inserting a SwKernPortion before a SwTabPortion isn't necessary
403 // and will break the SwTabPortion.
404 SwKernPortion* pGridKernPortion = nullptr;
405
406 bool bFull = false;
407 SwTwips nUnderLineStart = 0;
408 rInf.Y( Y() );
409
410 while( pPor && !rInf.IsStop() )
17
Assuming 'pPor' is non-null
18
Assuming the condition is true
19
Loop condition is true. Entering loop body
411 {
412 OSL_ENSURE(rInf.GetLen() < TextFrameIndex(COMPLETE_STRING) &&do { if (true && (!(rInf.GetLen() < TextFrameIndex
(COMPLETE_STRING) && rInf.GetIdx() <= TextFrameIndex
(rInf.GetText().getLength())))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/text/itrform2.cxx"
":" "414" ": "), "%s", "SwTextFormatter::BuildPortions: bad length in info"
); } } while (false)
20
Taking true branch
21
Loop condition is false. Exiting loop
413 rInf.GetIdx() <= TextFrameIndex(rInf.GetText().getLength()),do { if (true && (!(rInf.GetLen() < TextFrameIndex
(COMPLETE_STRING) && rInf.GetIdx() <= TextFrameIndex
(rInf.GetText().getLength())))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/text/itrform2.cxx"
":" "414" ": "), "%s", "SwTextFormatter::BuildPortions: bad length in info"
); } } while (false)
414 "SwTextFormatter::BuildPortions: bad length in info" )do { if (true && (!(rInf.GetLen() < TextFrameIndex
(COMPLETE_STRING) && rInf.GetIdx() <= TextFrameIndex
(rInf.GetText().getLength())))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/text/itrform2.cxx"
":" "414" ": "), "%s", "SwTextFormatter::BuildPortions: bad length in info"
); } } while (false)
;
415
416 // We have to check the script for fields in order to set the
417 // correct nActual value for the font.
418 if( pPor->InFieldGrp() )
22
Taking false branch
419 static_cast<SwFieldPortion*>(pPor)->CheckScript( rInf );
420
421 if( ! bHasGrid
22.1
'bHasGrid' is false
22.1
'bHasGrid' is false
22.1
'bHasGrid' is false
22.1
'bHasGrid' is false
&& rInf.HasScriptSpace() &&
23
Assuming the condition is false
422 rInf.GetLast() && rInf.GetLast()->InTextGrp() &&
423 rInf.GetLast()->Width() && !rInf.GetLast()->InNumberGrp() )
424 {
425 SwFontScript nNxtActual = rInf.GetFont()->GetActual();
426 SwFontScript nLstActual = nNxtActual;
427 sal_uInt16 nLstHeight = static_cast<sal_uInt16>(rInf.GetFont()->GetHeight());
428 bool bAllowBehind = false;
429 const CharClass& rCC = GetAppCharClass();
430
431 // are there any punctuation characters on both sides
432 // of the kerning portion?
433 if ( pPor->InFieldGrp() )
434 {
435 OUString aAltText;
436 if ( static_cast<SwFieldPortion*>(pPor)->GetExpText( rInf, aAltText ) &&
437 !aAltText.isEmpty() )
438 {
439 bAllowBehind = rCC.isLetterNumeric( aAltText, 0 );
440
441 const SwFont* pTmpFnt = static_cast<SwFieldPortion*>(pPor)->GetFont();
442 if ( pTmpFnt )
443 nNxtActual = pTmpFnt->GetActual();
444 }
445 }
446 else
447 {
448 const OUString& rText = rInf.GetText();
449 sal_Int32 nIdx = sal_Int32(rInf.GetIdx());
450 bAllowBehind = nIdx < rText.getLength() && rCC.isLetterNumeric(rText, nIdx);
451 }
452
453 const SwLinePortion* pLast = rInf.GetLast();
454 if ( bAllowBehind && pLast )
455 {
456 bool bAllowBefore = false;
457
458 if ( pLast->InFieldGrp() )
459 {
460 OUString aAltText;
461 if ( static_cast<const SwFieldPortion*>(pLast)->GetExpText( rInf, aAltText ) &&
462 !aAltText.isEmpty() )
463 {
464 bAllowBefore = rCC.isLetterNumeric( aAltText, aAltText.getLength() - 1 );
465
466 const SwFont* pTmpFnt = static_cast<const SwFieldPortion*>(pLast)->GetFont();
467 if ( pTmpFnt )
468 {
469 nLstActual = pTmpFnt->GetActual();
470 nLstHeight = static_cast<sal_uInt16>(pTmpFnt->GetHeight());
471 }
472 }
473 }
474 else if ( rInf.GetIdx() )
475 {
476 bAllowBefore = rCC.isLetterNumeric(rInf.GetText(), sal_Int32(rInf.GetIdx()) - 1);
477 // Note: ScriptType returns values in [1,4]
478 if ( bAllowBefore )
479 nLstActual = SwFontScript(m_pScriptInfo->ScriptType(rInf.GetIdx() - TextFrameIndex(1)) - 1);
480 }
481
482 nLstHeight /= 5;
483 // does the kerning portion still fit into the line?
484 if( bAllowBefore && ( nLstActual != nNxtActual ) &&
485 nLstHeight && rInf.X() + nLstHeight <= rInf.Width() &&
486 ! pPor->InTabGrp() )
487 {
488 SwKernPortion* pKrn =
489 new SwKernPortion( *rInf.GetLast(), nLstHeight,
490 pLast->InFieldGrp() && pPor->InFieldGrp() );
491 rInf.GetLast()->SetNextPortion( nullptr );
492 InsertPortion( rInf, pKrn );
493 }
494 }
495 }
496 else if ( bHasGrid
23.1
'bHasGrid' is false
23.1
'bHasGrid' is false
23.1
'bHasGrid' is false
23.1
'bHasGrid' is false
&& pGrid->IsSnapToChars() && ! pGridKernPortion && ! m_pMulti && ! pPor->InTabGrp() )
497 {
498 // insert a grid kerning portion
499 pGridKernPortion = pPor->IsKernPortion() ?
500 static_cast<SwKernPortion*>(pPor) :
501 new SwKernPortion( *m_pCurr );
502
503 // if we have a new GridKernPortion, we initially calculate
504 // its size so that its ends on the grid
505 const SwPageFrame* pPageFrame = m_pFrame->FindPageFrame();
506 const SwLayoutFrame* pBody = pPageFrame->FindBodyCont();
507 SwRectFnSet aRectFnSet(pPageFrame);
508
509 const long nGridOrigin = pBody ?
510 aRectFnSet.GetPrtLeft(*pBody) :
511 aRectFnSet.GetPrtLeft(*pPageFrame);
512
513 SwTwips nStartX = rInf.X() + GetLeftMargin();
514 if ( aRectFnSet.IsVert() )
515 {
516 Point aPoint( nStartX, 0 );
517 m_pFrame->SwitchHorizontalToVertical( aPoint );
518 nStartX = aPoint.Y();
519 }
520
521 const SwTwips nOfst = nStartX - nGridOrigin;
522 if ( nOfst )
523 {
524 const sal_uLong i = ( nOfst > 0 ) ?
525 ( ( nOfst - 1 ) / nGridWidth + 1 ) :
526 0;
527 const SwTwips nKernWidth = i * nGridWidth - nOfst;
528 const SwTwips nRestWidth = rInf.Width() - rInf.X();
529
530 if ( nKernWidth <= nRestWidth )
531 pGridKernPortion->Width( static_cast<sal_uInt16>(nKernWidth) );
532 }
533
534 if ( pGridKernPortion != pPor )
535 InsertPortion( rInf, pGridKernPortion );
536 }
537
538 if( pPor->IsDropPortion() )
24
Taking false branch
539 MergeCharacterBorder(*static_cast<SwDropPortion*>(pPor));
540
541 // the multi-portion has its own format function
542 if( pPor->IsMultiPortion() && ( !m_pMulti || m_pMulti->IsBidi() ) )
543 bFull = BuildMultiPortion( rInf, *static_cast<SwMultiPortion*>(pPor) );
544 else
545 bFull = pPor->Format( rInf );
546
547 if( rInf.IsRuby() && !rInf.GetRest() )
25
Assuming the condition is false
548 bFull = true;
549
550 // if we are underlined, we store the beginning of this underlined
551 // segment for repaint optimization
552 if ( LINESTYLE_NONE != m_pFont->GetUnderline() && ! nUnderLineStart )
26
Assuming the condition is false
553 nUnderLineStart = GetLeftMargin() + rInf.X();
554
555 if ( pPor->IsFlyPortion() )
27
Taking false branch
556 m_pCurr->SetFly( true );
557 // some special cases, where we have to take care for the repaint
558 // offset:
559 // 1. Underlined portions due to special underline feature
560 // 2. Right Tab
561 // 3. BidiPortions
562 // 4. other Multiportions
563 // 5. DropCaps
564 // 6. Grid Mode
565 else if ( ( ! rInf.GetPaintOfst() || nUnderLineStart < rInf.GetPaintOfst() ) &&
28
Assuming the condition is false
29
Assuming the condition is false
30
Taking false branch
566 // 1. Underlined portions
567 nUnderLineStart &&
568 // reformat is at end of an underlined portion and next portion
569 // is not underlined
570 ( ( rInf.GetReformatStart() == rInf.GetIdx() &&
571 LINESTYLE_NONE == m_pFont->GetUnderline()
572 ) ||
573 // reformat is inside portion and portion is underlined
574 ( rInf.GetReformatStart() >= rInf.GetIdx() &&
575 rInf.GetReformatStart() <= rInf.GetIdx() + pPor->GetLen() &&
576 LINESTYLE_NONE != m_pFont->GetUnderline() ) ) )
577 rInf.SetPaintOfst( nUnderLineStart );
578 else if ( ! rInf.GetPaintOfst() &&
31
Taking false branch
579 // 2. Right Tab
580 ( ( pPor->InTabGrp() && !pPor->IsTabLeftPortion() ) ||
581 // 3. BidiPortions
582 ( pPor->IsMultiPortion() && static_cast<SwMultiPortion*>(pPor)->IsBidi() ) ||
583 // 4. Multi Portion and 5. Drop Caps
584 ( ( pPor->IsDropPortion() || pPor->IsMultiPortion() ) &&
585 rInf.GetReformatStart() >= rInf.GetIdx() &&
586 rInf.GetReformatStart() <= rInf.GetIdx() + pPor->GetLen() )
587 // 6. Grid Mode
588 || ( bHasGrid && SwFontScript::CJK != m_pFont->GetActual() )
589 )
590 )
591 // we store the beginning of the critical portion as our
592 // paint offset
593 rInf.SetPaintOfst( GetLeftMargin() + rInf.X() );
594
595 // under one of these conditions we are allowed to delete the
596 // start of the underline portion
597 if ( IsUnderlineBreak( *pPor, *m_pFont ) )
32
Assuming the condition is false
33
Taking false branch
598 nUnderLineStart = 0;
599
600 if( pPor->IsFlyCntPortion() || ( pPor->IsMultiPortion() &&
601 static_cast<SwMultiPortion*>(pPor)->HasFlyInContent() ) )
602 SetFlyInCntBase();
603 // bUnderflow needs to be reset or we wrap again at the next softhyphen
604 if ( !bFull )
34
Assuming 'bFull' is true
35
Taking false branch
605 {
606 rInf.ClrUnderflow();
607 if( ! bHasGrid && rInf.HasScriptSpace() && pPor->InTextGrp() &&
608 pPor->GetLen() && !pPor->InFieldGrp() )
609 {
610 // The distance between two different scripts is set
611 // to 20% of the fontheight.
612 TextFrameIndex const nTmp = rInf.GetIdx() + pPor->GetLen();
613 if (nTmp == m_pScriptInfo->NextScriptChg(nTmp - TextFrameIndex(1)) &&
614 nTmp != TextFrameIndex(rInf.GetText().getLength()) &&
615 (m_pScriptInfo->ScriptType(nTmp - TextFrameIndex(1)) == css::i18n::ScriptType::ASIAN ||
616 m_pScriptInfo->ScriptType(nTmp) == css::i18n::ScriptType::ASIAN) )
617 {
618 const sal_uInt16 nDist = static_cast<sal_uInt16>(rInf.GetFont()->GetHeight()/5);
619
620 if( nDist )
621 {
622 // we do not want a kerning portion if any end
623 // would be a punctuation character
624 const CharClass& rCC = GetAppCharClass();
625 if (rCC.isLetterNumeric(rInf.GetText(), sal_Int32(nTmp) - 1)
626 && rCC.isLetterNumeric(rInf.GetText(), sal_Int32(nTmp)))
627 {
628 // does the kerning portion still fit into the line?
629 if ( rInf.X() + pPor->Width() + nDist <= rInf.Width() )
630 new SwKernPortion( *pPor, nDist );
631 else
632 bFull = true;
633 }
634 }
635 }
636 }
637 }
638
639 if ( bHasGrid
35.1
'bHasGrid' is false
35.1
'bHasGrid' is false
35.1
'bHasGrid' is false
35.1
'bHasGrid' is false
&& pGrid->IsSnapToChars() && pPor != pGridKernPortion && ! m_pMulti && ! pPor->InTabGrp() )
640 {
641 TextFrameIndex const nTmp = rInf.GetIdx() + pPor->GetLen();
642 const SwTwips nRestWidth = rInf.Width() - rInf.X() - pPor->Width();
643
644 const SwFontScript nCurrScript = m_pFont->GetActual(); // pScriptInfo->ScriptType( rInf.GetIdx() );
645 const SwFontScript nNextScript =
646 nTmp >= TextFrameIndex(rInf.GetText().getLength())
647 ? SwFontScript::CJK
648 : m_pScriptInfo->WhichFont(nTmp);
649
650 // snap non-asian text to grid if next portion is ASIAN or
651 // there are no more portions in this line
652 // be careful when handling an underflow event: the gridkernportion
653 // could have been deleted
654 if ( nRestWidth > 0 && SwFontScript::CJK != nCurrScript &&
655 ! rInf.IsUnderflow() && ( bFull || SwFontScript::CJK == nNextScript ) )
656 {
657 OSL_ENSURE( pGridKernPortion, "No GridKernPortion available" )do { if (true && (!(pGridKernPortion))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/text/itrform2.cxx"
":" "657" ": "), "%s", "No GridKernPortion available"); } } while
(false)
;
658
659 // calculate size
660 SwLinePortion* pTmpPor = pGridKernPortion->GetNextPortion();
661 sal_uInt16 nSumWidth = pPor->Width();
662 while ( pTmpPor )
663 {
664 nSumWidth = nSumWidth + pTmpPor->Width();
665 pTmpPor = pTmpPor->GetNextPortion();
666 }
667
668 const SwTwips i = nSumWidth ?
669 ( nSumWidth - 1 ) / nGridWidth + 1 :
670 0;
671 const SwTwips nTmpWidth = i * nGridWidth;
672 const SwTwips nKernWidth = std::min(nTmpWidth - nSumWidth, nRestWidth);
673 const sal_uInt16 nKernWidth_1 = static_cast<sal_uInt16>(nKernWidth / 2);
674
675 OSL_ENSURE( nKernWidth <= nRestWidth,do { if (true && (!(nKernWidth <= nRestWidth))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/text/itrform2.cxx"
":" "676" ": "), "%s", "Not enough space left for adjusting non-asian text in grid mode"
); } } while (false)
676 "Not enough space left for adjusting non-asian text in grid mode" )do { if (true && (!(nKernWidth <= nRestWidth))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/text/itrform2.cxx"
":" "676" ": "), "%s", "Not enough space left for adjusting non-asian text in grid mode"
); } } while (false)
;
677
678 pGridKernPortion->Width( pGridKernPortion->Width() + nKernWidth_1 );
679 rInf.X( rInf.X() + nKernWidth_1 );
680
681 if ( ! bFull )
682 new SwKernPortion( *pPor, static_cast<short>(nKernWidth - nKernWidth_1),
683 false, true );
684
685 pGridKernPortion = nullptr;
686 }
687 else if ( pPor->IsMultiPortion() || pPor->InFixMargGrp() ||
688 pPor->IsFlyCntPortion() || pPor->InNumberGrp() ||
689 pPor->InFieldGrp() || nCurrScript != nNextScript )
690 // next portion should snap to grid
691 pGridKernPortion = nullptr;
692 }
693
694 rInf.SetFull( bFull );
695
696 // Restportions from fields with multiple lines don't yet have the right ascent
697 if ( !pPor->GetLen() && !pPor->IsFlyPortion()
36
Taking true branch
698 && !pPor->IsGrfNumPortion() && ! pPor->InNumberGrp()
699 && !pPor->IsMultiPortion() )
700 CalcAscent( rInf, pPor );
37
Calling 'SwTextFormatter::CalcAscent'
701
702 InsertPortion( rInf, pPor );
703 if (pPor->IsMultiPortion() && (!m_pMulti || m_pMulti->IsBidi()))
704 {
705 (void) rInf.CheckCurrentPosBookmark(); // bookmark was already created inside MultiPortion!
706 }
707 pPor = NewPortion( rInf );
708 }
709
710 if( !rInf.IsStop() )
711 {
712 // The last right centered, decimal tab
713 SwTabPortion *pLastTab = rInf.GetLastTab();
714 if( pLastTab )
715 pLastTab->FormatEOL( rInf );
716 else if( rInf.GetLast() && rInf.LastKernPortion() )
717 rInf.GetLast()->FormatEOL( rInf );
718 }
719 if( m_pCurr->GetNextPortion() && m_pCurr->GetNextPortion()->InNumberGrp()
720 && static_cast<SwNumberPortion*>(m_pCurr->GetNextPortion())->IsHide() )
721 rInf.SetNumDone( false );
722
723 // Delete fly in any case
724 ClearFly( rInf );
725
726 // Reinit the tab overflow flag after the line
727 rInf.SetTabOverflow( false );
728}
729
730void SwTextFormatter::CalcAdjustLine( SwLineLayout *pCurrent )
731{
732 if( SvxAdjust::Left != GetAdjust() && !m_pMulti)
733 {
734 pCurrent->SetFormatAdj(true);
735 if( IsFlyInCntBase() )
736 {
737 CalcAdjLine( pCurrent );
738 // For e.g. centered fly we need to switch the RefPoint
739 // That's why bAlways = true
740 UpdatePos( pCurrent, GetTopLeft(), GetStart(), true );
741 }
742 }
743}
744
745void SwTextFormatter::CalcAscent( SwTextFormatInfo &rInf, SwLinePortion *pPor )
746{
747 bool bCalc = false;
748 if ( pPor->InFieldGrp() && static_cast<SwFieldPortion*>(pPor)->GetFont() )
38
Calling 'SwLinePortion::InFieldGrp'
41
Returning from 'SwLinePortion::InFieldGrp'
749 {
750 // Numbering + InterNetFields can keep an own font, then their size is
751 // independent from hard attribute values
752 SwFont* pFieldFnt = static_cast<SwFieldPortion*>(pPor)->m_pFont.get();
753 SwFontSave aSave( rInf, pFieldFnt );
754 pPor->Height( rInf.GetTextHeight() );
755 pPor->SetAscent( rInf.GetAscent() );
756 bCalc = true;
757 }
758 // i#89179
759 // tab portion representing the list tab of a list label gets the
760 // same height and ascent as the corresponding number portion
761 else if ( pPor->InTabGrp() && pPor->GetLen() == TextFrameIndex(0) &&
43
Taking false branch
762 rInf.GetLast() && rInf.GetLast()->InNumberGrp() &&
42
Assuming the condition is false
763 static_cast<const SwNumberPortion*>(rInf.GetLast())->HasFont() )
764 {
765 const SwLinePortion* pLast = rInf.GetLast();
766 pPor->Height( pLast->Height() );
767 pPor->SetAscent( pLast->GetAscent() );
768 }
769 else if (pPor->GetWhichPor() == PortionType::Bookmark
44
Assuming the condition is false
45
Taking false branch
770 && rInf.GetIdx() == TextFrameIndex(rInf.GetText().getLength()))
771 {
772 // bookmark at end of paragraph: *don't* advance iterator, use the
773 // current font instead; it's possible that there's a font size on the
774 // paragraph and it's overridden on the last line of the paragraph and
775 // we don't want to apply it via SwBookmarkPortion and grow the line
776 // height (example: n758883.docx)
777 SwLinePortion const*const pLast = rInf.GetLast();
778 assert(pLast)(static_cast <bool> (pLast) ? void (0) : __assert_fail (
"pLast", "/home/maarten/src/libreoffice/core/sw/source/core/text/itrform2.cxx"
, 778, __extension__ __PRETTY_FUNCTION__))
;
779 pPor->Height( pLast->Height(), false );
780 pPor->SetAscent( pLast->GetAscent() );
781 }
782 else
783 {
784 const SwLinePortion *pLast = rInf.GetLast();
785 bool bChg = false;
786
787 // In empty lines the attributes are switched on via SeekStart
788 const bool bFirstPor = rInf.GetLineStart() == rInf.GetIdx();
46
Calling 'strong_int::operator=='
49
Returning from 'strong_int::operator=='
789 if ( pPor->IsQuoVadisPortion() )
50
Calling 'SwLinePortion::IsQuoVadisPortion'
53
Returning from 'SwLinePortion::IsQuoVadisPortion'
54
Taking false branch
790 bChg = SeekStartAndChg( rInf, true );
791 else
792 {
793 if( bFirstPor
54.1
'bFirstPor' is true
54.1
'bFirstPor' is true
54.1
'bFirstPor' is true
54.1
'bFirstPor' is true
)
55
Taking true branch
794 {
795 if( !rInf.GetText().isEmpty() )
56
Calling 'OUString::isEmpty'
59
Returning from 'OUString::isEmpty'
60
Taking true branch
796 {
797 if ( pPor->GetLen() || !rInf.GetIdx()
61
Calling 'strong_int::operator bool'
63
Returning from 'strong_int::operator bool'
64
Calling 'strong_int::operator bool'
67
Returning from 'strong_int::operator bool'
798 || ( m_pCurr != pLast && !pLast->IsFlyPortion() )
68
Assuming 'pLast' is equal to field 'm_pCurr'
799 || !m_pCurr->IsRest() ) // instead of !rInf.GetRest()
69
Called C++ object pointer is null
800 bChg = SeekAndChg( rInf );
801 else
802 bChg = SeekAndChgBefore( rInf );
803 }
804 else if ( m_pMulti )
805 // do not open attributes starting at 0 in empty multi
806 // portions (rotated numbering followed by a footnote
807 // can cause trouble, because the footnote attribute
808 // starts at 0, but if we open it, the attribute handler
809 // cannot handle it.
810 bChg = false;
811 else
812 bChg = SeekStartAndChg( rInf );
813 }
814 else
815 bChg = SeekAndChg( rInf );
816 }
817 if( bChg || bFirstPor || !pPor->GetAscent()
818 || !rInf.GetLast()->InTextGrp() )
819 {
820 pPor->SetAscent( rInf.GetAscent() );
821 pPor->Height( rInf.GetTextHeight() );
822 bCalc = true;
823 }
824 else
825 {
826 pPor->Height( pLast->Height() );
827 pPor->SetAscent( pLast->GetAscent() );
828 }
829 }
830
831 if( pPor->InTextGrp() && bCalc )
832 {
833 pPor->SetAscent(pPor->GetAscent() +
834 rInf.GetFont()->GetTopBorderSpace());
835 pPor->Height(pPor->Height() +
836 rInf.GetFont()->GetTopBorderSpace() +
837 rInf.GetFont()->GetBottomBorderSpace() );
838 }
839}
840
841namespace {
842
843class SwMetaPortion : public SwTextPortion
844{
845public:
846 SwMetaPortion() { SetWhichPor( PortionType::Meta ); }
847 virtual void Paint( const SwTextPaintInfo &rInf ) const override;
848};
849
850}
851
852void SwMetaPortion::Paint( const SwTextPaintInfo &rInf ) const
853{
854 if ( Width() )
855 {
856 rInf.DrawViewOpt( *this, PortionType::Meta );
857 SwTextPortion::Paint( rInf );
858 }
859}
860
861namespace sw::mark {
862 OUString ExpandFieldmark(IFieldmark* pBM)
863 {
864 const IFieldmark::parameter_map_t* const pParameters = pBM->GetParameters();
865 sal_Int32 nCurrentIdx = 0;
866 const IFieldmark::parameter_map_t::const_iterator pResult = pParameters->find(OUString(ODF_FORMDROPDOWN_RESULT"Dropdown_Selected"));
867 if(pResult != pParameters->end())
868 pResult->second >>= nCurrentIdx;
869
870 const IFieldmark::parameter_map_t::const_iterator pListEntries = pParameters->find(OUString(ODF_FORMDROPDOWN_LISTENTRY"Dropdown_ListEntry"));
871 if (pListEntries != pParameters->end())
872 {
873 uno::Sequence< OUString > vListEntries;
874 pListEntries->second >>= vListEntries;
875 if (nCurrentIdx < vListEntries.getLength())
876 return vListEntries[nCurrentIdx];
877 }
878
879 static const sal_Unicode vEnSpaces[ODF_FORMFIELD_DEFAULT_LENGTH5] = {8194, 8194, 8194, 8194, 8194};
880 return OUString(vEnSpaces, ODF_FORMFIELD_DEFAULT_LENGTH5);
881 }
882}
883
884SwTextPortion *SwTextFormatter::WhichTextPor( SwTextFormatInfo &rInf ) const
885{
886 SwTextPortion *pPor = nullptr;
887 if( GetFnt()->IsTox() )
888 {
889 pPor = new SwToxPortion;
890 }
891 else if ( GetFnt()->IsInputField() )
892 {
893 if (rInf.GetOpt().IsFieldName())
894 {
895 OUString aFieldName = SwFieldType::GetTypeStr(SwFieldTypesEnum::Input);
896 // assume this is only the *first* portion and follows will be created elsewhere => input field must start at Idx
897 assert(rInf.GetText()[sal_Int32(rInf.GetIdx())] == CH_TXT_ATR_INPUTFIELDSTART)(static_cast <bool> (rInf.GetText()[sal_Int32(rInf.GetIdx
())] == u'\x0004') ? void (0) : __assert_fail ("rInf.GetText()[sal_Int32(rInf.GetIdx())] == CH_TXT_ATR_INPUTFIELDSTART"
, "/home/maarten/src/libreoffice/core/sw/source/core/text/itrform2.cxx"
, 897, __extension__ __PRETTY_FUNCTION__))
;
898 TextFrameIndex nFieldLen(-1);
899 for (TextFrameIndex i = rInf.GetIdx() + TextFrameIndex(1); ; ++i)
900 {
901 assert(rInf.GetText()[sal_Int32(i)] != CH_TXT_ATR_INPUTFIELDSTART)(static_cast <bool> (rInf.GetText()[sal_Int32(i)] != u'\x0004'
) ? void (0) : __assert_fail ("rInf.GetText()[sal_Int32(i)] != CH_TXT_ATR_INPUTFIELDSTART"
, "/home/maarten/src/libreoffice/core/sw/source/core/text/itrform2.cxx"
, 901, __extension__ __PRETTY_FUNCTION__))
; // can't nest
902 if (rInf.GetText()[sal_Int32(i)] == CH_TXT_ATR_INPUTFIELDENDu'\x0005')
903 {
904 nFieldLen = i + TextFrameIndex(1) - rInf.GetIdx();
905 break;
906 }
907 }
908 assert(2 <= sal_Int32(nFieldLen))(static_cast <bool> (2 <= sal_Int32(nFieldLen)) ? void
(0) : __assert_fail ("2 <= sal_Int32(nFieldLen)", "/home/maarten/src/libreoffice/core/sw/source/core/text/itrform2.cxx"
, 908, __extension__ __PRETTY_FUNCTION__))
;
909 pPor = new SwFieldPortion(aFieldName, nullptr, false, nFieldLen);
910 }
911 else
912 {
913 pPor = new SwTextInputFieldPortion();
914 }
915 }
916 else
917 {
918 if( GetFnt()->IsRef() )
919 pPor = new SwRefPortion;
920 else if (GetFnt()->IsMeta())
921 {
922 pPor = new SwMetaPortion;
923 }
924 else
925 {
926 // Only at the End!
927 // If pCurr does not have a width, it can however already have content.
928 // E.g. for non-displayable characters
929
930 auto const ch(rInf.GetText()[sal_Int32(rInf.GetIdx())]);
931 SwTextFrame const*const pFrame(rInf.GetTextFrame());
932 SwPosition aPosition(pFrame->MapViewToModelPos(rInf.GetIdx()));
933 sw::mark::IFieldmark *pBM = pFrame->GetDoc().getIDocumentMarkAccess()->getFieldmarkFor(aPosition);
934 if(pBM != nullptr && pBM->GetFieldname( ) == ODF_FORMDATE"vnd.oasis.opendocument.field.FORMDATE")
935 {
936 if (ch == CH_TXT_ATR_FIELDSTARTu'\x0007')
937 pPor = new SwFieldFormDatePortion(pBM, true);
938 else if (ch == CH_TXT_ATR_FIELDSEPu'\x0003')
939 pPor = new SwFieldMarkPortion(); // it's added in DateFieldmark?
940 else if (ch == CH_TXT_ATR_FIELDENDu'\x0008')
941 pPor = new SwFieldFormDatePortion(pBM, false);
942 }
943 else if (ch == CH_TXT_ATR_FIELDSTARTu'\x0007')
944 pPor = new SwFieldMarkPortion();
945 else if (ch == CH_TXT_ATR_FIELDSEPu'\x0003')
946 pPor = new SwFieldMarkPortion();
947 else if (ch == CH_TXT_ATR_FIELDENDu'\x0008')
948 pPor = new SwFieldMarkPortion();
949 else if (ch == CH_TXT_ATR_FORMELEMENTu'\x0006')
950 {
951 OSL_ENSURE(pBM != nullptr, "Where is my form field bookmark???")do { if (true && (!(pBM != nullptr))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/text/itrform2.cxx"
":" "951" ": "), "%s", "Where is my form field bookmark???")
; } } while (false)
;
952 if (pBM != nullptr)
953 {
954 if (pBM->GetFieldname( ) == ODF_FORMCHECKBOX"vnd.oasis.opendocument.field.FORMCHECKBOX")
955 {
956 pPor = new SwFieldFormCheckboxPortion();
957 }
958 else if (pBM->GetFieldname( ) == ODF_FORMDROPDOWN"vnd.oasis.opendocument.field.FORMDROPDOWN")
959 {
960 pPor = new SwFieldFormDropDownPortion(pBM, sw::mark::ExpandFieldmark(pBM));
961 }
962 /* we need to check for ODF_FORMTEXT for scenario having FormFields inside FORMTEXT.
963 * Otherwise file will crash on open.
964 */
965 else if (pBM->GetFieldname( ) == ODF_FORMTEXT"vnd.oasis.opendocument.field.FORMTEXT")
966 {
967 pPor = new SwFieldMarkPortion();
968 }
969 }
970 }
971 if( !pPor )
972 {
973 if( !rInf.X() && !m_pCurr->GetNextPortion() && !m_pCurr->GetLen() )
974 pPor = m_pCurr;
975 else
976 pPor = new SwTextPortion;
977 }
978 }
979 }
980 return pPor;
981}
982
983// We calculate the length, the following portion limits are defined:
984// 1) Tabs
985// 2) Linebreaks
986// 3) CH_TXTATR_BREAKWORD / CH_TXTATR_INWORD
987// 4) next attribute change
988
989SwTextPortion *SwTextFormatter::NewTextPortion( SwTextFormatInfo &rInf )
990{
991 // If we're at the line's beginning, we take pCurr
992 // If pCurr is not derived from SwTextPortion, we need to duplicate
993 Seek( rInf.GetIdx() );
994 SwTextPortion *pPor = WhichTextPor( rInf );
995
996 // until next attribute change:
997 const TextFrameIndex nNextAttr = GetNextAttr();
998 TextFrameIndex nNextChg = std::min(nNextAttr, TextFrameIndex(rInf.GetText().getLength()));
999
1000 // end of script type:
1001 const TextFrameIndex nNextScript = m_pScriptInfo->NextScriptChg(rInf.GetIdx());
1002 nNextChg = std::min( nNextChg, nNextScript );
1003
1004 // end of direction:
1005 const TextFrameIndex nNextDir = m_pScriptInfo->NextDirChg(rInf.GetIdx());
1006 nNextChg = std::min( nNextChg, nNextDir );
1007
1008 // hidden change (potentially via bookmark):
1009 const TextFrameIndex nNextHidden = m_pScriptInfo->NextHiddenChg(rInf.GetIdx());
1010 nNextChg = std::min( nNextChg, nNextHidden );
1011
1012 // bookmarks
1013 const TextFrameIndex nNextBookmark = m_pScriptInfo->NextBookmark(rInf.GetIdx());
1014 nNextChg = std::min(nNextChg, nNextBookmark);
1015
1016 // Turbo boost:
1017 // We assume that font characters are not larger than twice
1018 // as wide as height.
1019 // Very crazy: we need to take the ascent into account.
1020
1021 // Mind the trap! GetSize() contains the wished-for height, the real height
1022 // is only known in CalcAscent!
1023
1024 // The ratio is even crazier: a blank in Times New Roman has an ascent of
1025 // 182, a height of 200 and a width of 53!
1026 // It follows that a line with a lot of blanks is processed incorrectly.
1027 // Therefore we increase from factor 2 to 8 (due to negative kerning).
1028
1029 pPor->SetLen(TextFrameIndex(1));
1030 CalcAscent( rInf, pPor );
1031
1032 const SwFont* pTmpFnt = rInf.GetFont();
1033 sal_Int32 nExpect = std::min( sal_Int32( pTmpFnt->GetHeight() ),
1034 sal_Int32( pPor->GetAscent() ) ) / 8;
1035 if ( !nExpect )
1036 nExpect = 1;
1037 nExpect = sal_Int32(rInf.GetIdx()) + (rInf.GetLineWidth() / nExpect);
1038 if (TextFrameIndex(nExpect) > rInf.GetIdx() && nNextChg > TextFrameIndex(nExpect))
1039 nNextChg = TextFrameIndex(std::min(nExpect, rInf.GetText().getLength()));
1040
1041 // we keep an invariant during method calls:
1042 // there are no portion ending characters like hard spaces
1043 // or tabs in [ nLeftScanIdx, nRightScanIdx ]
1044 if ( m_nLeftScanIdx <= rInf.GetIdx() && rInf.GetIdx() <= m_nRightScanIdx )
1045 {
1046 if ( nNextChg > m_nRightScanIdx )
1047 nNextChg = m_nRightScanIdx =
1048 rInf.ScanPortionEnd( m_nRightScanIdx, nNextChg );
1049 }
1050 else
1051 {
1052 m_nLeftScanIdx = rInf.GetIdx();
1053 nNextChg = m_nRightScanIdx =
1054 rInf.ScanPortionEnd( rInf.GetIdx(), nNextChg );
1055 }
1056
1057 pPor->SetLen( nNextChg - rInf.GetIdx() );
1058 rInf.SetLen( pPor->GetLen() );
1059 return pPor;
1060}
1061
1062// first portions have no length
1063SwLinePortion *SwTextFormatter::WhichFirstPortion(SwTextFormatInfo &rInf)
1064{
1065 SwLinePortion *pPor = nullptr;
1066
1067 if( rInf.GetRest() )
1068 {
1069 // Tabs and fields
1070 if( '\0' != rInf.GetHookChar() )
1071 return nullptr;
1072
1073 pPor = rInf.GetRest();
1074 if( pPor->IsErgoSumPortion() )
1075 rInf.SetErgoDone(true);
1076 else
1077 if( pPor->IsFootnoteNumPortion() )
1078 rInf.SetFootnoteDone(true);
1079 else
1080 if( pPor->InNumberGrp() )
1081 rInf.SetNumDone(true);
1082
1083 rInf.SetRest(nullptr);
1084 m_pCurr->SetRest( true );
1085 return pPor;
1086 }
1087
1088 // We can stand in the follow, it's crucial that
1089 // pFrame->GetOffset() == 0!
1090 if( rInf.GetIdx() )
1091 {
1092 // We now too can elongate FootnotePortions and ErgoSumPortions
1093
1094 // 1. The ErgoSumTexts
1095 if( !rInf.IsErgoDone() )
1096 {
1097 if( m_pFrame->IsInFootnote() && !m_pFrame->GetIndPrev() )
1098 pPor = NewErgoSumPortion( rInf );
1099 rInf.SetErgoDone( true );
1100 }
1101
1102 // 2. Arrow portions
1103 if( !pPor && !rInf.IsArrowDone() )
1104 {
1105 if( m_pFrame->GetOffset() && !m_pFrame->IsFollow() &&
1106 rInf.GetIdx() == m_pFrame->GetOffset() )
1107 pPor = new SwArrowPortion( *m_pCurr );
1108 rInf.SetArrowDone( true );
1109 }
1110
1111 // 3. Kerning portions at beginning of line in grid mode
1112 if ( ! pPor && ! m_pCurr->GetNextPortion() )
1113 {
1114 SwTextGridItem const*const pGrid(
1115 GetGridItem(GetTextFrame()->FindPageFrame()));
1116 if ( pGrid )
1117 pPor = new SwKernPortion( *m_pCurr );
1118 }
1119
1120 // 4. The line rests (multiline fields)
1121 if( !pPor )
1122 {
1123 pPor = rInf.GetRest();
1124 // Only for pPor of course
1125 if( pPor )
1126 {
1127 m_pCurr->SetRest( true );
1128 rInf.SetRest(nullptr);
1129 }
1130 }
1131 }
1132 else
1133 {
1134 // 5. The foot note count
1135 if( !rInf.IsFootnoteDone() )
1136 {
1137 OSL_ENSURE( ( ! rInf.IsMulti() && ! m_pMulti ) || m_pMulti->HasRotation(),do { if (true && (!(( ! rInf.IsMulti() && ! m_pMulti
) || m_pMulti->HasRotation()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/text/itrform2.cxx"
":" "1138" ": "), "%s", "Rotated number portion trouble"); }
} while (false)
1138 "Rotated number portion trouble" )do { if (true && (!(( ! rInf.IsMulti() && ! m_pMulti
) || m_pMulti->HasRotation()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/text/itrform2.cxx"
":" "1138" ": "), "%s", "Rotated number portion trouble"); }
} while (false)
;
1139
1140 const bool bFootnoteNum = m_pFrame->IsFootnoteNumFrame();
1141 rInf.GetParaPortion()->SetFootnoteNum( bFootnoteNum );
1142 if( bFootnoteNum )
1143 pPor = NewFootnoteNumPortion( rInf );
1144 rInf.SetFootnoteDone( true );
1145 }
1146
1147 // 6. The ErgoSumTexts of course also exist in the TextMaster,
1148 // it's crucial whether the SwFootnoteFrame is aFollow
1149 if( !rInf.IsErgoDone() && !pPor && ! rInf.IsMulti() )
1150 {
1151 if( m_pFrame->IsInFootnote() && !m_pFrame->GetIndPrev() )
1152 pPor = NewErgoSumPortion( rInf );
1153 rInf.SetErgoDone( true );
1154 }
1155
1156 // 7. The numbering
1157 if( !rInf.IsNumDone() && !pPor )
1158 {
1159 OSL_ENSURE( ( ! rInf.IsMulti() && ! m_pMulti ) || m_pMulti->HasRotation(),do { if (true && (!(( ! rInf.IsMulti() && ! m_pMulti
) || m_pMulti->HasRotation()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/text/itrform2.cxx"
":" "1160" ": "), "%s", "Rotated number portion trouble"); }
} while (false)
1160 "Rotated number portion trouble" )do { if (true && (!(( ! rInf.IsMulti() && ! m_pMulti
) || m_pMulti->HasRotation()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/text/itrform2.cxx"
":" "1160" ": "), "%s", "Rotated number portion trouble"); }
} while (false)
;
1161
1162 // If we're in the follow, then of course not
1163 if (GetTextFrame()->GetTextNodeForParaProps()->GetNumRule())
1164 pPor = NewNumberPortion( rInf );
1165 rInf.SetNumDone( true );
1166 }
1167 // 8. The DropCaps
1168 if( !pPor && GetDropFormat() && ! rInf.IsMulti() )
1169 pPor = NewDropPortion( rInf );
1170
1171 // 9. Kerning portions at beginning of line in grid mode
1172 if ( !pPor && !m_pCurr->GetNextPortion() )
1173 {
1174 SwTextGridItem const*const pGrid(
1175 GetGridItem(GetTextFrame()->FindPageFrame()));
1176 if ( pGrid )
1177 pPor = new SwKernPortion( *m_pCurr );
1178 }
1179 }
1180
1181 // 10. Decimal tab portion at the beginning of each line in table cells
1182 if ( !pPor && !m_pCurr->GetNextPortion() &&
1183 GetTextFrame()->IsInTab() &&
1184 GetTextFrame()->GetDoc().getIDocumentSettingAccess().get(DocumentSettingId::TAB_COMPAT))
1185 {
1186 pPor = NewTabPortion( rInf, true );
1187 }
1188
1189 // 11. suffix of meta-field
1190 if (!pPor)
1191 {
1192 pPor = TryNewNoLengthPortion(rInf);
1193 }
1194
1195 // 12. bookmarks
1196 // check this *last* so that BuildMultiPortion() can find it!
1197 if (!pPor && rInf.CheckCurrentPosBookmark())
1198 {
1199 auto const bookmark(m_pScriptInfo->GetBookmark(rInf.GetIdx()));
1200 if (static_cast<bool>(bookmark))
1201 {
1202 sal_Unicode mark;
1203 if ((bookmark & (SwScriptInfo::MarkKind::Start|SwScriptInfo::MarkKind::End))
1204 == (SwScriptInfo::MarkKind::Start|SwScriptInfo::MarkKind::End))
1205 {
1206 //mark = u'\u2336'; // not in OpenSymbol :(
1207 mark = '|';
1208 // hmm ... paint U+2345 over U+2346 should be same width?
1209 // and U+237F // or U+2E20/U+2E21
1210 }
1211 else if (bookmark & SwScriptInfo::MarkKind::Start)
1212 {
1213 mark = '[';
1214 }
1215 else if (bookmark & SwScriptInfo::MarkKind::End)
1216 {
1217 mark = ']';
1218 }
1219 else
1220 {
1221 assert(bookmark & SwScriptInfo::MarkKind::Point)(static_cast <bool> (bookmark & SwScriptInfo::MarkKind
::Point) ? void (0) : __assert_fail ("bookmark & SwScriptInfo::MarkKind::Point"
, "/home/maarten/src/libreoffice/core/sw/source/core/text/itrform2.cxx"
, 1221, __extension__ __PRETTY_FUNCTION__))
;
1222 mark = '|';
1223 }
1224 pPor = new SwBookmarkPortion(mark);
1225 }
1226 }
1227
1228 return pPor;
1229}
1230
1231static bool lcl_OldFieldRest( const SwLineLayout* pCurr )
1232{
1233 if( !pCurr->GetNext() )
1234 return false;
1235 const SwLinePortion *pPor = pCurr->GetNext()->GetNextPortion();
1236 bool bRet = false;
1237 while( pPor && !bRet )
1238 {
1239 bRet = (pPor->InFieldGrp() && static_cast<const SwFieldPortion*>(pPor)->IsFollow()) ||
1240 (pPor->IsMultiPortion() && static_cast<const SwMultiPortion*>(pPor)->IsFollowField());
1241 if( !pPor->GetLen() )
1242 break;
1243 pPor = pPor->GetNextPortion();
1244 }
1245 return bRet;
1246}
1247
1248/* NewPortion sets rInf.nLen
1249 * A SwTextPortion is limited by a tab, break, txtatr or attr change
1250 * We can have three cases:
1251 * 1) The line is full and the wrap was not emulated
1252 * -> return 0;
1253 * 2) The line is full and a wrap was emulated
1254 * -> Reset width and return new FlyPortion
1255 * 3) We need to construct a new portion
1256 * -> CalcFlyWidth emulates the width and return portion, if needed
1257 */
1258
1259SwLinePortion *SwTextFormatter::NewPortion( SwTextFormatInfo &rInf )
1260{
1261 // Underflow takes precedence
1262 rInf.SetStopUnderflow( false );
1263 if( rInf.GetUnderflow() )
1264 {
1265 OSL_ENSURE( rInf.IsFull(), "SwTextFormatter::NewPortion: underflow but not full" )do { if (true && (!(rInf.IsFull()))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/text/itrform2.cxx"
":" "1265" ": "), "%s", "SwTextFormatter::NewPortion: underflow but not full"
); } } while (false)
;
1266 return Underflow( rInf );
1267 }
1268
1269 // If the line is full, flys and Underflow portions could be waiting ...
1270 if( rInf.IsFull() )
1271 {
1272 // LineBreaks and Flys (bug05.sdw)
1273 // IsDummy()
1274 if( rInf.IsNewLine() && (!rInf.GetFly() || !m_pCurr->IsDummy()) )
1275 return nullptr;
1276
1277 // When the text bumps into the Fly, or when the Fly comes first because
1278 // it juts out over the left edge, GetFly() is returned.
1279 // When IsFull() and no GetFly() is available, naturally zero is returned.
1280 if( rInf.GetFly() )
1281 {
1282 if( rInf.GetLast()->IsBreakPortion() )
1283 {
1284 delete rInf.GetFly();
1285 rInf.SetFly( nullptr );
1286 }
1287
1288 return rInf.GetFly();
1289 }
1290
1291 // A nasty special case: A frame without wrap overlaps the Footnote area.
1292 // We must declare the Footnote portion as rest of line, so that
1293 // SwTextFrame::Format doesn't abort (the text mass already was formatted).
1294 if( rInf.GetRest() )
1295 rInf.SetNewLine( true );
1296 else
1297 {
1298 // When the next line begins with a rest of a field, but now no
1299 // rest remains, the line must definitely be formatted anew!
1300 if( lcl_OldFieldRest( GetCurr() ) )
1301 rInf.SetNewLine( true );
1302 else
1303 {
1304 SwLinePortion *pFirst = WhichFirstPortion( rInf );
1305 if( pFirst )
1306 {
1307 rInf.SetNewLine( true );
1308 if( pFirst->InNumberGrp() )
1309 rInf.SetNumDone( false) ;
1310 delete pFirst;
1311 }
1312 }
1313 }
1314
1315 return nullptr;
1316 }
1317
1318 SwLinePortion *pPor = WhichFirstPortion( rInf );
1319
1320 // Check for Hidden Portion:
1321 if ( !pPor )
1322 {
1323 TextFrameIndex nEnd = rInf.GetIdx();
1324 if ( ::lcl_BuildHiddenPortion( rInf, nEnd ) )
1325 pPor = new SwHiddenTextPortion( nEnd - rInf.GetIdx() );
1326 }
1327
1328 if( !pPor )
1329 {
1330 if( ( !m_pMulti || m_pMulti->IsBidi() ) &&
1331 // i#42734
1332 // No multi portion if there is a hook character waiting:
1333 ( !rInf.GetRest() || '\0' == rInf.GetHookChar() ) )
1334 {
1335 // We open a multiportion part, if we enter a multi-line part
1336 // of the paragraph.
1337 TextFrameIndex nEnd = rInf.GetIdx();
1338 std::unique_ptr<SwMultiCreator> pCreate = rInf.GetMultiCreator( nEnd, m_pMulti );
1339 if( pCreate )
1340 {
1341 SwMultiPortion* pTmp = nullptr;
1342
1343 if ( SwMultiCreatorId::Bidi == pCreate->nId )
1344 pTmp = new SwBidiPortion( nEnd, pCreate->nLevel );
1345 else if ( SwMultiCreatorId::Ruby == pCreate->nId )
1346 {
1347 pTmp = new SwRubyPortion( *pCreate, *rInf.GetFont(),
1348 GetTextFrame()->GetDoc().getIDocumentSettingAccess(),
1349 nEnd, TextFrameIndex(0), rInf );
1350 }
1351 else if( SwMultiCreatorId::Rotate == pCreate->nId )
1352 {
1353 pTmp = new SwRotatedPortion( *pCreate, nEnd,
1354 GetTextFrame()->IsRightToLeft() );
1355 GetTextFrame()->SetHasRotatedPortions(true);
1356 }
1357 else
1358 pTmp = new SwDoubleLinePortion( *pCreate, nEnd );
1359
1360 pCreate.reset();
1361 CalcFlyWidth( rInf );
1362
1363 return pTmp;
1364 }
1365 }
1366 // Tabs and Fields
1367 sal_Unicode cChar = rInf.GetHookChar();
1368
1369 if( cChar )
1370 {
1371 /* We fetch cChar again to be sure that the tab is pending now and
1372 * didn't move to the next line (as happens behind frames).
1373 * However, when a FieldPortion is in the rest, we must naturally fetch
1374 * the cChar from the field content, e.g. DecimalTabs and fields (22615)
1375 */
1376 if( !rInf.GetRest() || !rInf.GetRest()->InFieldGrp() )
1377 cChar = rInf.GetChar( rInf.GetIdx() );
1378 rInf.ClearHookChar();
1379 }
1380 else
1381 {
1382 if (rInf.GetIdx() >= TextFrameIndex(rInf.GetText().getLength()))
1383 {
1384 rInf.SetFull(true);
1385 CalcFlyWidth( rInf );
1386 return pPor;
1387 }
1388 cChar = rInf.GetChar( rInf.GetIdx() );
1389 }
1390
1391 switch( cChar )
1392 {
1393 case CH_TAB:
1394 pPor = NewTabPortion( rInf, false ); break;
1395
1396 case CH_BREAK:
1397 pPor = new SwBreakPortion( *rInf.GetLast() ); break;
1398
1399 case CHAR_SOFTHYPHENu'\x00AD': // soft hyphen
1400 pPor = new SwSoftHyphPortion; break;
1401
1402 case CHAR_HARDBLANKu'\x00A0': // no-break space
1403 // Please check tdf#115067 if you want to edit the char
1404 pPor = new SwBlankPortion( cChar ); break;
1405
1406 case CHAR_HARDHYPHENu'\x2011': // non-breaking hyphen
1407 pPor = new SwBlankPortion( '-' ); break;
1408
1409 case CHAR_ZWSPu'\x200B': // zero width space
1410 case CHAR_ZWNBSPu'\x2060' : // word joiner
1411 pPor = new SwControlCharPortion( cChar ); break;
1412
1413 case CH_TXTATR_BREAKWORDu'\x0001':
1414 case CH_TXTATR_INWORDu'\xFFF9':
1415 if( rInf.HasHint( rInf.GetIdx() ) )
1416 {
1417 pPor = NewExtraPortion( rInf );
1418 break;
1419 }
1420 [[fallthrough]];
1421 default :
1422 {
1423 SwTabPortion* pLastTabPortion = rInf.GetLastTab();
1424 if ( pLastTabPortion && cChar == rInf.GetTabDecimal() )
1425 {
1426 // Abandon dec. tab position if line is full
1427 // We have a decimal tab portion in the line and the next character has to be
1428 // aligned at the tab stop position. We store the width from the beginning of
1429 // the tab stop portion up to the portion containing the decimal separator:
1430 if (GetTextFrame()->GetDoc().getIDocumentSettingAccess().get(DocumentSettingId::TAB_COMPAT) /*rInf.GetVsh()->IsTabCompat();*/ &&
1431 PortionType::TabDecimal == pLastTabPortion->GetWhichPor() )
1432 {
1433 OSL_ENSURE( rInf.X() >= pLastTabPortion->GetFix(), "Decimal tab stop position cannot be calculated" )do { if (true && (!(rInf.X() >= pLastTabPortion->
GetFix()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/text/itrform2.cxx"
":" "1433" ": "), "%s", "Decimal tab stop position cannot be calculated"
); } } while (false)
;
1434 const sal_uInt16 nWidthOfPortionsUpToDecimalPosition = static_cast<sal_uInt16>(rInf.X() - pLastTabPortion->GetFix() );
1435 static_cast<SwTabDecimalPortion*>(pLastTabPortion)->SetWidthOfPortionsUpToDecimalPosition( nWidthOfPortionsUpToDecimalPosition );
1436 rInf.SetTabDecimal( 0 );
1437 }
1438 else
1439 rInf.SetFull( rInf.GetLastTab()->Format( rInf ) );
1440 }
1441
1442 if( rInf.GetRest() )
1443 {
1444 if( rInf.IsFull() )
1445 {
1446 rInf.SetNewLine(true);
1447 return nullptr;
1448 }
1449 pPor = rInf.GetRest();
1450 rInf.SetRest(nullptr);
1451 }
1452 else
1453 {
1454 if( rInf.IsFull() )
1455 return nullptr;
1456 pPor = NewTextPortion( rInf );
1457 }
1458 break;
1459 }
1460 }
1461
1462 // if a portion is created despite there being a pending RestPortion,
1463 // then it is a field which has been split (e.g. because it contains a Tab)
1464 if( pPor && rInf.GetRest() )
1465 pPor->SetLen(TextFrameIndex(0));
1466
1467 // robust:
1468 if( !pPor || rInf.IsStop() )
1469 {
1470 delete pPor;
1471 return nullptr;
1472 }
1473 }
1474
1475 assert(pPor && "can only reach here with pPor existing")(static_cast <bool> (pPor && "can only reach here with pPor existing"
) ? void (0) : __assert_fail ("pPor && \"can only reach here with pPor existing\""
, "/home/maarten/src/libreoffice/core/sw/source/core/text/itrform2.cxx"
, 1475, __extension__ __PRETTY_FUNCTION__))
;
1476
1477 // Special portions containing numbers (footnote anchor, footnote number,
1478 // numbering) can be contained in a rotated portion, if the user
1479 // choose a rotated character attribute.
1480 if (!m_pMulti)
1481 {
1482 if ( pPor->IsFootnotePortion() )
1483 {
1484 const SwTextFootnote* pTextFootnote = static_cast<SwFootnotePortion*>(pPor)->GetTextFootnote();
1485
1486 if ( pTextFootnote )
1487 {
1488 SwFormatFootnote& rFootnote = const_cast<SwFormatFootnote&>(pTextFootnote->GetFootnote());
1489 const SwDoc *const pDoc = &rInf.GetTextFrame()->GetDoc();
1490 const SwEndNoteInfo* pInfo;
1491 if( rFootnote.IsEndNote() )
1492 pInfo = &pDoc->GetEndNoteInfo();
1493 else
1494 pInfo = &pDoc->GetFootnoteInfo();
1495 const SwAttrSet& rSet = pInfo->GetAnchorCharFormat(const_cast<SwDoc&>(*pDoc))->GetAttrSet();
1496
1497 const SfxPoolItem* pItem;
1498 sal_uInt16 nDir = 0;
1499 if( SfxItemState::SET == rSet.GetItemState( RES_CHRATR_ROTATE,
1500 true, &pItem ))
1501 nDir = static_cast<const SvxCharRotateItem*>(pItem)->GetValue();
1502
1503 if ( 0 != nDir )
1504 {
1505 delete pPor;
1506 pPor = new SwRotatedPortion(rInf.GetIdx() + TextFrameIndex(1),
1507 900 == nDir
1508 ? DIR_BOTTOM2TOP1
1509 : DIR_TOP2BOTTOM3 );
1510 }
1511 }
1512 }
1513 else if ( pPor->InNumberGrp() )
1514 {
1515 const SwFont* pNumFnt = static_cast<SwFieldPortion*>(pPor)->GetFont();
1516
1517 if ( pNumFnt )
1518 {
1519 sal_uInt16 nDir = pNumFnt->GetOrientation( rInf.GetTextFrame()->IsVertical() );
1520 if ( 0 != nDir )
1521 {
1522 delete pPor;
1523 pPor = new SwRotatedPortion(TextFrameIndex(0), 900 == nDir
1524 ? DIR_BOTTOM2TOP1
1525 : DIR_TOP2BOTTOM3 );
1526
1527 rInf.SetNumDone( false );
1528 rInf.SetFootnoteDone( false );
1529 }
1530 }
1531 }
1532 }
1533
1534 // The font is set in output device,
1535 // the ascent and the height will be calculated.
1536 if( !pPor->GetAscent() && !pPor->Height() )
1537 CalcAscent( rInf, pPor );
1538 rInf.SetLen( pPor->GetLen() );
1539
1540 // In CalcFlyWidth Width() will be shortened if a FlyPortion is present.
1541 CalcFlyWidth( rInf );
1542
1543 // One must not forget that pCurr as GetLast() must provide reasonable values:
1544 if( !m_pCurr->Height() )
1545 {
1546 OSL_ENSURE( m_pCurr->Height(), "SwTextFormatter::NewPortion: limbo dance" )do { if (true && (!(m_pCurr->Height()))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/text/itrform2.cxx"
":" "1546" ": "), "%s", "SwTextFormatter::NewPortion: limbo dance"
); } } while (false)
;
1547 m_pCurr->Height( pPor->Height(), false );
1548 m_pCurr->SetAscent( pPor->GetAscent() );
1549 }
1550
1551 OSL_ENSURE(pPor->Height(), "SwTextFormatter::NewPortion: something went wrong")do { if (true && (!(pPor->Height()))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/text/itrform2.cxx"
":" "1551" ": "), "%s", "SwTextFormatter::NewPortion: something went wrong"
); } } while (false)
;
1552 if( pPor->IsPostItsPortion() && rInf.X() >= rInf.Width() && rInf.GetFly() )
1553 {
1554 delete pPor;
1555 pPor = rInf.GetFly();
1556 }
1557 return pPor;
1558}
1559
1560TextFrameIndex SwTextFormatter::FormatLine(TextFrameIndex const nStartPos)
1561{
1562 OSL_ENSURE( ! m_pFrame->IsVertical() || m_pFrame->IsSwapped(),do { if (true && (!(! m_pFrame->IsVertical() || m_pFrame
->IsSwapped()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/text/itrform2.cxx"
":" "1563" ": "), "%s", "SwTextFormatter::FormatLine( nStartPos ) with unswapped frame"
); } } while (false)
1563 "SwTextFormatter::FormatLine( nStartPos ) with unswapped frame" )do { if (true && (!(! m_pFrame->IsVertical() || m_pFrame
->IsSwapped()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/text/itrform2.cxx"
":" "1563" ": "), "%s", "SwTextFormatter::FormatLine( nStartPos ) with unswapped frame"
); } } while (false)
;
1564
1565 // For the formatting routines, we set pOut to the reference device.
1566 SwHookOut aHook( GetInfo() );
1567 if (GetInfo().GetLen() < TextFrameIndex(GetInfo().GetText().getLength()))
1568 GetInfo().SetLen(TextFrameIndex(GetInfo().GetText().getLength()));
1569
1570 bool bBuild = true;
1571 SetFlyInCntBase( false );
1572 GetInfo().SetLineHeight( 0 );
1573 GetInfo().SetLineNetHeight( 0 );
1574
1575 // Recycling must be suppressed by changed line height and also
1576 // by changed ascent (lowering of baseline).
1577 const sal_uInt16 nOldHeight = m_pCurr->Height();
1578 const sal_uInt16 nOldAscent = m_pCurr->GetAscent();
1579
1580 m_pCurr->SetEndHyph( false );
1581 m_pCurr->SetMidHyph( false );
1582
1583 // fly positioning can make it necessary format a line several times
1584 // for this, we have to keep a copy of our rest portion
1585 SwLinePortion* pField = GetInfo().GetRest();
1586 std::unique_ptr<SwFieldPortion> xSaveField;
1587
1588 if ( pField && pField->InFieldGrp() && !pField->IsFootnotePortion() )
1589 xSaveField.reset(new SwFieldPortion( *static_cast<SwFieldPortion*>(pField) ));
1590
1591 // for an optimal repaint rectangle, we want to compare fly portions
1592 // before and after the BuildPortions call
1593 const bool bOptimizeRepaint = AllowRepaintOpt();
1594 TextFrameIndex const nOldLineEnd = nStartPos + m_pCurr->GetLen();
1595 std::vector<long> flyStarts;
1596
1597 // these are the conditions for a fly position comparison
1598 if ( bOptimizeRepaint && m_pCurr->IsFly() )
1599 {
1600 SwLinePortion* pPor = m_pCurr->GetFirstPortion();
1601 long nPOfst = 0;
1602 while ( pPor )
1603 {
1604 if ( pPor->IsFlyPortion() )
1605 // insert start value of fly portion
1606 flyStarts.push_back( nPOfst );
1607
1608 nPOfst += pPor->Width();
1609 pPor = pPor->GetNextPortion();
1610 }
1611 }
1612
1613 // Here soon the underflow check follows.
1614 while( bBuild )
1615 {
1616 GetInfo().SetFootnoteInside( false );
1617 GetInfo().SetOtherThanFootnoteInside( false );
1618
1619 // These values must not be reset by FormatReset();
1620 const bool bOldNumDone = GetInfo().IsNumDone();
1621 const bool bOldArrowDone = GetInfo().IsArrowDone();
1622 const bool bOldErgoDone = GetInfo().IsErgoDone();
1623
1624 // besides other things, this sets the repaint offset to 0
1625 FormatReset( GetInfo() );
1626
1627 GetInfo().SetNumDone( bOldNumDone );
1628 GetInfo().SetArrowDone( bOldArrowDone );
1629 GetInfo().SetErgoDone( bOldErgoDone );
1630
1631 // build new portions for this line
1632 BuildPortions( GetInfo() );
1633
1634 if( GetInfo().IsStop() )
1635 {
1636 m_pCurr->SetLen(TextFrameIndex(0));
1637 m_pCurr->Height( GetFrameRstHeight() + 1, false );
1638 m_pCurr->SetRealHeight( GetFrameRstHeight() + 1 );
1639 m_pCurr->Width(0);
1640 m_pCurr->Truncate();
1641 return nStartPos;
1642 }
1643 else if( GetInfo().IsDropInit() )
1644 {
1645 DropInit();
1646 GetInfo().SetDropInit( false );
1647 }
1648
1649 m_pCurr->CalcLine( *this, GetInfo() );
1650 CalcRealHeight( GetInfo().IsNewLine() );
1651
1652 //i#120864 For Special case that at the first calculation couldn't get
1653 //correct height. And need to recalculate for the right height.
1654 SwLinePortion* pPorTmp = m_pCurr->GetNextPortion();
1655 if ( IsFlyInCntBase() && (!IsQuick() || (pPorTmp && pPorTmp->IsFlyCntPortion() && !pPorTmp->GetNextPortion() &&
1656 m_pCurr->Height() > pPorTmp->Height())))
1657 {
1658 sal_uInt16 nTmpAscent, nTmpHeight;
1659 CalcAscentAndHeight( nTmpAscent, nTmpHeight );
1660 AlignFlyInCntBase( Y() + long( nTmpAscent ) );
1661 m_pCurr->CalcLine( *this, GetInfo() );
1662 CalcRealHeight();
1663 }
1664
1665 // bBuild decides if another lap of honor is done
1666 if ( m_pCurr->GetRealHeight() <= GetInfo().GetLineHeight() )
1667 {
1668 m_pCurr->SetRealHeight( GetInfo().GetLineHeight() );
1669 bBuild = false;
1670 }
1671 else
1672 {
1673 bBuild = ( GetInfo().GetTextFly().IsOn() && ChkFlyUnderflow(GetInfo()) )
1674 || GetInfo().CheckFootnotePortion(m_pCurr);
1675 if( bBuild )
1676 {
1677 GetInfo().SetNumDone( bOldNumDone );
1678 GetInfo().ResetMaxWidthDiff();
1679
1680 // delete old rest
1681 if ( GetInfo().GetRest() )
1682 {
1683 delete GetInfo().GetRest();
1684 GetInfo().SetRest( nullptr );
1685 }
1686
1687 // set original rest portion
1688 if ( xSaveField )
1689 GetInfo().SetRest( new SwFieldPortion( *xSaveField ) );
1690
1691 m_pCurr->SetLen(TextFrameIndex(0));
1692 m_pCurr->Width(0);
1693 m_pCurr->Truncate();
1694 }
1695 }
1696 }
1697
1698 // In case of compat mode, it's possible that a tab portion is wider after
1699 // formatting than before. If this is the case, we also have to make sure
1700 // the SwLineLayout is wider as well.
1701 if (GetInfo().GetTextFrame()->GetDoc().getIDocumentSettingAccess().get(DocumentSettingId::TAB_OVER_MARGIN))
1702 {
1703 sal_uInt16 nSum = 0;
1704 SwLinePortion* pPor = m_pCurr->GetFirstPortion();
1705
1706 while (pPor)
1707 {
1708 nSum += pPor->Width();
1709 pPor = pPor->GetNextPortion();
1710 }
1711
1712 if (nSum > m_pCurr->Width())
1713 m_pCurr->Width(nSum);
1714 }
1715
1716 // calculate optimal repaint rectangle
1717 if ( bOptimizeRepaint )
1718 {
1719 GetInfo().SetPaintOfst( ::lcl_CalcOptRepaint( *this, *m_pCurr, nOldLineEnd, flyStarts ) );
1720 flyStarts.clear();
1721 }
1722 else
1723 // Special case: we do not allow an optimization of the repaint
1724 // area, but during formatting the repaint offset is set to indicate
1725 // a maximum value for the offset. This value has to be reset:
1726 GetInfo().SetPaintOfst( 0 );
1727
1728 // This corrects the start of the reformat range if something has
1729 // moved to the next line. Otherwise IsFirstReformat in AllowRepaintOpt
1730 // will give us a wrong result if we have to reformat another line
1731 GetInfo().GetParaPortion()->GetReformat().LeftMove( GetInfo().GetIdx() );
1732
1733 // delete master copy of rest portion
1734 xSaveField.reset();
1735
1736 TextFrameIndex const nNewStart = nStartPos + m_pCurr->GetLen();
1737
1738 // adjust text if kana compression is enabled
1739 if ( GetInfo().CompressLine() )
1740 {
1741 SwTwips nRepaintOfst = CalcKanaAdj( m_pCurr );
1742
1743 // adjust repaint offset
1744 if ( nRepaintOfst < GetInfo().GetPaintOfst() )
1745 GetInfo().SetPaintOfst( nRepaintOfst );
1746 }
1747
1748 CalcAdjustLine( m_pCurr );
1749
1750 if( nOldHeight != m_pCurr->Height() || nOldAscent != m_pCurr->GetAscent() )
1751 {
1752 SetFlyInCntBase();
1753 GetInfo().SetPaintOfst( 0 ); // changed line height => no recycling
1754 // all following line must be painted and when Flys are around,
1755 // also formatted
1756 GetInfo().SetShift( true );
1757 }
1758
1759 if ( IsFlyInCntBase() && !IsQuick() )
1760 UpdatePos( m_pCurr, GetTopLeft(), GetStart() );
1761
1762 return nNewStart;
1763}
1764
1765void SwTextFormatter::RecalcRealHeight()
1766{
1767 do
1768 {
1769 CalcRealHeight();
1770 } while (Next());
1771}
1772
1773void SwTextFormatter::CalcRealHeight( bool bNewLine )
1774{
1775 sal_uInt16 nLineHeight = m_pCurr->Height();
1776 m_pCurr->SetClipping( false );
1777
1778 SwTextGridItem const*const pGrid(GetGridItem(m_pFrame->FindPageFrame()));
1779 if ( pGrid && GetInfo().SnapToGrid() )
1780 {
1781 const sal_uInt16 nGridWidth = pGrid->GetBaseHeight();
1782 const sal_uInt16 nRubyHeight = pGrid->GetRubyHeight();
1783 const bool bRubyTop = ! pGrid->GetRubyTextBelow();
1784
1785 nLineHeight = nGridWidth + nRubyHeight;
1786 const sal_uInt16 nAmpRatio = (m_pCurr->Height() + nLineHeight - 1)/nLineHeight;
1787 nLineHeight *= nAmpRatio;
1788
1789 const sal_uInt16 nAsc = m_pCurr->GetAscent() +
1790 ( bRubyTop ?
1791 ( nLineHeight - m_pCurr->Height() + nRubyHeight ) / 2 :
1792 ( nLineHeight - m_pCurr->Height() - nRubyHeight ) / 2 );
1793
1794 m_pCurr->Height( nLineHeight, false );
1795 m_pCurr->SetAscent( nAsc );
1796 m_pInf->GetParaPortion()->SetFixLineHeight();
1797
1798 // we ignore any line spacing options except from ...
1799 const SvxLineSpacingItem* pSpace = m_aLineInf.GetLineSpacing();
1800 if ( ! IsParaLine() && pSpace &&
1801 SvxInterLineSpaceRule::Prop == pSpace->GetInterLineSpaceRule() )
1802 {
1803 sal_uLong nTmp = pSpace->GetPropLineSpace();
1804
1805 if( nTmp < 100 )
1806 nTmp = 100;
1807
1808 nTmp *= nLineHeight;
1809 nLineHeight = static_cast<sal_uInt16>(nTmp / 100);
1810 }
1811
1812 m_pCurr->SetRealHeight( nLineHeight );
1813 return;
1814 }
1815
1816 // The dummy flag is set on lines that only contain flyportions, these shouldn't
1817 // consider register-true and so on. Unfortunately an empty line can be at
1818 // the end of a paragraph (empty paragraphs or behind a Shift-Return),
1819 // which should consider the register.
1820 if (!m_pCurr->IsDummy() || (!m_pCurr->GetNext()
1821 && GetStart() >= TextFrameIndex(GetTextFrame()->GetText().getLength())
1822 && !bNewLine))
1823 {
1824 const SvxLineSpacingItem *pSpace = m_aLineInf.GetLineSpacing();
1825 if( pSpace )
1826 {
1827 switch( pSpace->GetLineSpaceRule() )
1828 {
1829 case SvxLineSpaceRule::Auto:
1830 // shrink first line of paragraph too on spacing < 100%
1831 if (IsParaLine() &&
1832 pSpace->GetInterLineSpaceRule() == SvxInterLineSpaceRule::Prop
1833 && GetTextFrame()->GetDoc().getIDocumentSettingAccess().get(DocumentSettingId::PROP_LINE_SPACING_SHRINKS_FIRST_LINE))
1834 {
1835 long nTmp = pSpace->GetPropLineSpace();
1836 // Word will render < 50% too but it's just not readable
1837 if( nTmp < 50 )
1838 nTmp = nTmp ? 50 : 100;
1839 if (nTmp<100) { // code adapted from fixed line height
1840 nTmp *= nLineHeight;
1841 nTmp /= 100;
1842 if( !nTmp )
1843 ++nTmp;
1844 nLineHeight = static_cast<sal_uInt16>(nTmp);
1845 sal_uInt16 nAsc = ( 4 * nLineHeight ) / 5; // 80%
1846#if 0
1847 // could do clipping here (like Word does)
1848 // but at 0.5 its unreadable either way...
1849 if( nAsc < pCurr->GetAscent() ||
1850 nLineHeight - nAsc < pCurr->Height() -
1851 pCurr->GetAscent() )
1852 pCurr->SetClipping( true );
1853#endif
1854 m_pCurr->SetAscent( nAsc );
1855 m_pCurr->Height( nLineHeight, false );
1856 m_pInf->GetParaPortion()->SetFixLineHeight();
1857 }
1858 }
1859 break;
1860 case SvxLineSpaceRule::Min:
1861 {
1862 if( nLineHeight < pSpace->GetLineHeight() )
1863 nLineHeight = pSpace->GetLineHeight();
1864 break;
1865 }
1866 case SvxLineSpaceRule::Fix:
1867 {
1868 nLineHeight = pSpace->GetLineHeight();
1869 const sal_uInt16 nAsc = ( 4 * nLineHeight ) / 5; // 80%
1870 if( nAsc < m_pCurr->GetAscent() ||
1871 nLineHeight - nAsc < m_pCurr->Height() - m_pCurr->GetAscent() )
1872 m_pCurr->SetClipping( true );
1873 m_pCurr->Height( nLineHeight, false );
1874 m_pCurr->SetAscent( nAsc );
1875 m_pInf->GetParaPortion()->SetFixLineHeight();
1876 }
1877 break;
1878 default: OSL_FAIL( ": unknown LineSpaceRule" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/text/itrform2.cxx"
":" "1878" ": "), "%s", ": unknown LineSpaceRule"); } } while
(false)
;
1879 }
1880 // Note: for the _first_ line the line spacing of the previous
1881 // paragraph is applied in SwFlowFrame::CalcUpperSpace()
1882 if( !IsParaLine() )
1883 switch( pSpace->GetInterLineSpaceRule() )
1884 {
1885 case SvxInterLineSpaceRule::Off:
1886 break;
1887 case SvxInterLineSpaceRule::Prop:
1888 {
1889 long nTmp = pSpace->GetPropLineSpace();
1890 // 50% is the minimum, if 0% we switch to the
1891 // default value 100% ...
1892 if( nTmp < 50 )
1893 nTmp = nTmp ? 50 : 100;
1894
1895 // extend line height by (nPropLineSpace - 100) percent of the font height
1896 nTmp -= 100;
1897 nTmp *= m_pCurr->GetTextHeight();
1898 nTmp /= 100;
1899 nTmp += nLineHeight;
1900 if (nTmp < 1)
1901 nTmp = 1;
1902 nLineHeight = static_cast<sal_uInt16>(nTmp);
1903 break;
1904 }
1905 case SvxInterLineSpaceRule::Fix:
1906 {
1907 nLineHeight = nLineHeight + pSpace->GetInterLineSpace();
1908 break;
1909 }
1910 default: OSL_FAIL( ": unknown InterLineSpaceRule" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/text/itrform2.cxx"
":" "1910" ": "), "%s", ": unknown InterLineSpaceRule"); } }
while (false)
;
1911 }
1912 }
1913
1914 if( IsRegisterOn() )
1915 {
1916 SwTwips nTmpY = Y() + m_pCurr->GetAscent() + nLineHeight - m_pCurr->Height();
1917 SwRectFnSet aRectFnSet(m_pFrame);
1918 if ( aRectFnSet.IsVert() )
1919 nTmpY = m_pFrame->SwitchHorizontalToVertical( nTmpY );
1920 nTmpY = aRectFnSet.YDiff( nTmpY, RegStart() );
1921 const sal_uInt16 nDiff = sal_uInt16( nTmpY % RegDiff() );
1922 if( nDiff )
1923 nLineHeight += RegDiff() - nDiff;
1924 }
1925 }
1926 m_pCurr->SetRealHeight( nLineHeight );
1927}
1928
1929void SwTextFormatter::FeedInf( SwTextFormatInfo &rInf ) const
1930{
1931 // delete Fly in any case!
1932 ClearFly( rInf );
1933 rInf.Init();
1934
1935 rInf.ChkNoHyph( CntEndHyph(), CntMidHyph() );
1936 rInf.SetRoot( m_pCurr );
1937 rInf.SetLineStart( m_nStart );
1938 rInf.SetIdx( m_nStart );
1939 rInf.Left( Left() );
1940 rInf.Right( Right() );
1941 rInf.First( FirstLeft() );
1942 rInf.LeftMargin(GetLeftMargin());
1943
1944 rInf.RealWidth( sal_uInt16(rInf.Right() - GetLeftMargin()) );
1945 rInf.Width( rInf.RealWidth() );
1946 if( const_cast<SwTextFormatter*>(this)->GetRedln() )
1947 {
1948 const_cast<SwTextFormatter*>(this)->GetRedln()->Clear( const_cast<SwTextFormatter*>(this)->GetFnt() );
1949 const_cast<SwTextFormatter*>(this)->GetRedln()->Reset();
1950 }
1951}
1952
1953void SwTextFormatter::FormatReset( SwTextFormatInfo &rInf )
1954{
1955 m_pFirstOfBorderMerge = nullptr;
1956 m_pCurr->Truncate();
1957 m_pCurr->Init();
1958
1959 // delete pSpaceAdd and pKanaComp
1960 m_pCurr->FinishSpaceAdd();
1961 m_pCurr->FinishKanaComp();
1962 m_pCurr->ResetFlags();
1963 FeedInf( rInf );
1964}
1965
1966bool SwTextFormatter::CalcOnceMore()
1967{
1968 if( m_pDropFormat )
1969 {
1970 const sal_uInt16 nOldDrop = GetDropHeight();
1971 CalcDropHeight( m_pDropFormat->GetLines() );
1972 m_bOnceMore = nOldDrop != GetDropHeight();
1973 }
1974 else
1975 m_bOnceMore = false;
1976 return m_bOnceMore;
1977}
1978
1979SwTwips SwTextFormatter::CalcBottomLine() const
1980{
1981 SwTwips nRet = Y() + GetLineHeight();
1982 SwTwips nMin = GetInfo().GetTextFly().GetMinBottom();
1983 if( nMin && ++nMin > nRet )
1984 {
1985 SwTwips nDist = m_pFrame->getFrameArea().Height() - m_pFrame->getFramePrintArea().Height()
1986 - m_pFrame->getFramePrintArea().Top();
1987 if( nRet + nDist < nMin )
1988 {
1989 const bool bRepaint = HasTruncLines() &&
1990 GetInfo().GetParaPortion()->GetRepaint().Bottom() == nRet-1;
1991 nRet = nMin - nDist;
1992 if( bRepaint )
1993 {
1994 const_cast<SwRepaint&>(GetInfo().GetParaPortion()
1995 ->GetRepaint()).Bottom( nRet-1 );
1996 const_cast<SwTextFormatInfo&>(GetInfo()).SetPaintOfst( 0 );
1997 }
1998 }
1999 }
2000 return nRet;
2001}
2002
2003// FME/OD: This routine does a limited text formatting.
2004SwTwips SwTextFormatter::CalcFitToContent_()
2005{
2006 FormatReset( GetInfo() );
2007 BuildPortions( GetInfo() );
2008 m_pCurr->CalcLine( *this, GetInfo() );
2009 return m_pCurr->Width();
2010}
2011
2012// determines if the calculation of a repaint offset is allowed
2013// otherwise each line is painted from 0 (this is a copy of the beginning
2014// of the former SwTextFormatter::Recycle() function
2015bool SwTextFormatter::AllowRepaintOpt() const
2016{
2017 // reformat position in front of current line? Only in this case
2018 // we want to set the repaint offset
2019 bool bOptimizeRepaint = m_nStart < GetInfo().GetReformatStart() &&
2020 m_pCurr->GetLen();
2021
2022 // a special case is the last line of a block adjusted paragraph:
2023 if ( bOptimizeRepaint )
2024 {
2025 switch( GetAdjust() )
2026 {
2027 case SvxAdjust::Block:
2028 {
2029 if( IsLastBlock() || IsLastCenter() )
2030 bOptimizeRepaint = false;
2031 else
2032 {
2033 // ????: blank in the last master line (blocksat.sdw)
2034 bOptimizeRepaint = nullptr == m_pCurr->GetNext() && !m_pFrame->GetFollow();
2035 if ( bOptimizeRepaint )
2036 {
2037 SwLinePortion *pPos = m_pCurr->GetFirstPortion();
2038 while ( pPos && !pPos->IsFlyPortion() )
2039 pPos = pPos->GetNextPortion();
2040 bOptimizeRepaint = !pPos;
2041 }
2042 }
2043 break;
2044 }
2045 case SvxAdjust::Center:
2046 case SvxAdjust::Right:
2047 bOptimizeRepaint = false;
2048 break;
2049 default: ;
2050 }
2051 }
2052
2053 // Again another special case: invisible SoftHyphs
2054 const TextFrameIndex nReformat = GetInfo().GetReformatStart();
2055 if (bOptimizeRepaint && TextFrameIndex(COMPLETE_STRING) != nReformat)
2056 {
2057 const sal_Unicode cCh = nReformat >= TextFrameIndex(GetInfo().GetText().getLength())
2058 ? 0
2059 : GetInfo().GetText()[ sal_Int32(nReformat) ];
2060 bOptimizeRepaint = ( CH_TXTATR_BREAKWORDu'\x0001' != cCh && CH_TXTATR_INWORDu'\xFFF9' != cCh )
2061 || ! GetInfo().HasHint( nReformat );
2062 }
2063
2064 return bOptimizeRepaint;
2065}
2066
2067void SwTextFormatter::CalcUnclipped( SwTwips& rTop, SwTwips& rBottom )
2068{
2069 OSL_ENSURE( ! m_pFrame->IsVertical() || m_pFrame->IsSwapped(),do { if (true && (!(! m_pFrame->IsVertical() || m_pFrame
->IsSwapped()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/text/itrform2.cxx"
":" "2070" ": "), "%s", "SwTextFormatter::CalcUnclipped with unswapped frame"
); } } while (false)
2070 "SwTextFormatter::CalcUnclipped with unswapped frame" )do { if (true && (!(! m_pFrame->IsVertical() || m_pFrame
->IsSwapped()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/text/itrform2.cxx"
":" "2070" ": "), "%s", "SwTextFormatter::CalcUnclipped with unswapped frame"
); } } while (false)
;
2071
2072 long nFlyAsc, nFlyDesc;
2073 m_pCurr->MaxAscentDescent( rTop, rBottom, nFlyAsc, nFlyDesc );
2074 rTop = Y() + GetCurr()->GetAscent();
2075 rBottom = rTop + nFlyDesc;
2076 rTop -= nFlyAsc;
2077}
2078
2079void SwTextFormatter::UpdatePos( SwLineLayout *pCurrent, Point aStart,
2080 TextFrameIndex const nStartIdx, bool bAlways) const
2081{
2082 OSL_ENSURE( ! m_pFrame->IsVertical() || m_pFrame->IsSwapped(),do { if (true && (!(! m_pFrame->IsVertical() || m_pFrame
->IsSwapped()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/text/itrform2.cxx"
":" "2083" ": "), "%s", "SwTextFormatter::UpdatePos with unswapped frame"
); } } while (false)
2083 "SwTextFormatter::UpdatePos with unswapped frame" )do { if (true && (!(! m_pFrame->IsVertical() || m_pFrame
->IsSwapped()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/text/itrform2.cxx"
":" "2083" ": "), "%s", "SwTextFormatter::UpdatePos with unswapped frame"
); } } while (false)
;
2084
2085 if( GetInfo().IsTest() )
2086 return;
2087 SwLinePortion *pFirst = pCurrent->GetFirstPortion();
2088 SwLinePortion *pPos = pFirst;
2089 SwTextPaintInfo aTmpInf( GetInfo() );
2090 aTmpInf.SetpSpaceAdd( pCurrent->GetpLLSpaceAdd() );
2091 aTmpInf.ResetSpaceIdx();
2092 aTmpInf.SetKanaComp( pCurrent->GetpKanaComp() );
2093 aTmpInf.ResetKanaIdx();
2094
2095 // The frame's size
2096 aTmpInf.SetIdx( nStartIdx );
2097 aTmpInf.SetPos( aStart );
2098
2099 long nTmpAscent, nTmpDescent, nFlyAsc, nFlyDesc;
2100 pCurrent->MaxAscentDescent( nTmpAscent, nTmpDescent, nFlyAsc, nFlyDesc );
2101
2102 const sal_uInt16 nTmpHeight = pCurrent->GetRealHeight();
2103 sal_uInt16 nAscent = pCurrent->GetAscent() + nTmpHeight - pCurrent->Height();
2104 AsCharFlags nFlags = AsCharFlags::UlSpace;
2105 if( GetMulti() )
2106 {
2107 aTmpInf.SetDirection( GetMulti()->GetDirection() );
2108 if( GetMulti()->HasRotation() )
2109 {
2110 nFlags |= AsCharFlags::Rotate;
2111 if( GetMulti()->IsRevers() )
2112 {
2113 nFlags |= AsCharFlags::Reverse;
2114 aTmpInf.X( aTmpInf.X() - nAscent );
2115 }
2116 else
2117 aTmpInf.X( aTmpInf.X() + nAscent );
2118 }
2119 else
2120 {
2121 if ( GetMulti()->IsBidi() )
2122 nFlags |= AsCharFlags::Bidi;
2123 aTmpInf.Y( aTmpInf.Y() + nAscent );
2124 }
2125 }
2126 else
2127 aTmpInf.Y( aTmpInf.Y() + nAscent );
2128
2129 while( pPos )
2130 {
2131 // We only know one case where changing the position (caused by the
2132 // adjustment) could be relevant for a portion: We need to SetRefPoint
2133 // for FlyCntPortions.
2134 if( ( pPos->IsFlyCntPortion() || pPos->IsGrfNumPortion() )
2135 && ( bAlways || !IsQuick() ) )
2136 {
2137 pCurrent->MaxAscentDescent( nTmpAscent, nTmpDescent, nFlyAsc, nFlyDesc, pPos );
2138
2139 if( pPos->IsGrfNumPortion() )
2140 {
2141 if( !nFlyAsc && !nFlyDesc )
2142 {
2143 nTmpAscent = nAscent;
2144 nFlyAsc = nAscent;
2145 nTmpDescent = nTmpHeight - nAscent;
2146 nFlyDesc = nTmpDescent;
2147 }
2148 static_cast<SwGrfNumPortion*>(pPos)->SetBase( nTmpAscent, nTmpDescent,
2149 nFlyAsc, nFlyDesc );
2150 }
2151 else
2152 {
2153 Point aBase( aTmpInf.GetPos() );
2154 if ( GetInfo().GetTextFrame()->IsVertical() )
2155 GetInfo().GetTextFrame()->SwitchHorizontalToVertical( aBase );
2156
2157 static_cast<SwFlyCntPortion*>(pPos)->SetBase( *aTmpInf.GetTextFrame(),
2158 aBase, nTmpAscent, nTmpDescent, nFlyAsc,
2159 nFlyDesc, nFlags );
2160 }
2161 }
2162 if( pPos->IsMultiPortion() && static_cast<SwMultiPortion*>(pPos)->HasFlyInContent() )
2163 {
2164 OSL_ENSURE( !GetMulti(), "Too much multi" )do { if (true && (!(!GetMulti()))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/text/itrform2.cxx"
":" "2164" ": "), "%s", "Too much multi"); } } while (false)
;
2165 const_cast<SwTextFormatter*>(this)->m_pMulti = static_cast<SwMultiPortion*>(pPos);
2166 SwLineLayout *pLay = &GetMulti()->GetRoot();
2167 Point aSt( aTmpInf.X(), aStart.Y() );
2168
2169 if ( GetMulti()->HasBrackets() )
2170 {
2171 OSL_ENSURE( GetMulti()->IsDouble(), "Brackets only for doubles")do { if (true && (!(GetMulti()->IsDouble()))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/text/itrform2.cxx"
":" "2171" ": "), "%s", "Brackets only for doubles"); } } while
(false)
;
2172 aSt.AdjustX(static_cast<SwDoubleLinePortion*>(GetMulti())->PreWidth() );
2173 }
2174 else if( GetMulti()->HasRotation() )
2175 {
2176 aSt.AdjustY(pCurrent->GetAscent() - GetMulti()->GetAscent() );
2177 if( GetMulti()->IsRevers() )
2178 aSt.AdjustX(GetMulti()->Width() );
2179 else
2180 aSt.AdjustY(GetMulti()->Height() );
2181 }
2182 else if ( GetMulti()->IsBidi() )
2183 // jump to end of the bidi portion
2184 aSt.AdjustX(pLay->Width() );
2185
2186 TextFrameIndex nStIdx = aTmpInf.GetIdx();
2187 do
2188 {
2189 UpdatePos( pLay, aSt, nStIdx, bAlways );
2190 nStIdx = nStIdx + pLay->GetLen();
2191 aSt.AdjustY(pLay->Height() );
2192 pLay = pLay->GetNext();
2193 } while ( pLay );
2194 const_cast<SwTextFormatter*>(this)->m_pMulti = nullptr;
2195 }
2196 pPos->Move( aTmpInf );
2197 pPos = pPos->GetNextPortion();
2198 }
2199}
2200
2201void SwTextFormatter::AlignFlyInCntBase( long nBaseLine ) const
2202{
2203 OSL_ENSURE( ! m_pFrame->IsVertical() || m_pFrame->IsSwapped(),do { if (true && (!(! m_pFrame->IsVertical() || m_pFrame
->IsSwapped()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/text/itrform2.cxx"
":" "2204" ": "), "%s", "SwTextFormatter::AlignFlyInCntBase with unswapped frame"
); } } while (false)
2204 "SwTextFormatter::AlignFlyInCntBase with unswapped frame" )do { if (true && (!(! m_pFrame->IsVertical() || m_pFrame
->IsSwapped()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/text/itrform2.cxx"
":" "2204" ": "), "%s", "SwTextFormatter::AlignFlyInCntBase with unswapped frame"
); } } while (false)
;
2205
2206 if( GetInfo().IsTest() )
2207 return;
2208 SwLinePortion *pFirst = m_pCurr->GetFirstPortion();
2209 SwLinePortion *pPos = pFirst;
2210 AsCharFlags nFlags = AsCharFlags::None;
2211 if( GetMulti() && GetMulti()->HasRotation() )
2212 {
2213 nFlags |= AsCharFlags::Rotate;
2214 if( GetMulti()->IsRevers() )
2215 nFlags |= AsCharFlags::Reverse;
2216 }
2217
2218 long nTmpAscent, nTmpDescent, nFlyAsc, nFlyDesc;
2219
2220 while( pPos )
2221 {
2222 if( pPos->IsFlyCntPortion() || pPos->IsGrfNumPortion() )
2223 {
2224 m_pCurr->MaxAscentDescent( nTmpAscent, nTmpDescent, nFlyAsc, nFlyDesc, pPos );
2225
2226 if( pPos->IsGrfNumPortion() )
2227 static_cast<SwGrfNumPortion*>(pPos)->SetBase( nTmpAscent, nTmpDescent,
2228 nFlyAsc, nFlyDesc );
2229 else
2230 {
2231 Point aBase;
2232 if ( GetInfo().GetTextFrame()->IsVertical() )
2233 {
2234 nBaseLine = GetInfo().GetTextFrame()->SwitchHorizontalToVertical( nBaseLine );
2235 aBase = Point( nBaseLine, static_cast<SwFlyCntPortion*>(pPos)->GetRefPoint().Y() );
2236 }
2237 else
2238 aBase = Point( static_cast<SwFlyCntPortion*>(pPos)->GetRefPoint().X(), nBaseLine );
2239
2240 static_cast<SwFlyCntPortion*>(pPos)->SetBase( *GetInfo().GetTextFrame(), aBase, nTmpAscent, nTmpDescent,
2241 nFlyAsc, nFlyDesc, nFlags );
2242 }
2243 }
2244 pPos = pPos->GetNextPortion();
2245 }
2246}
2247
2248bool SwTextFormatter::ChkFlyUnderflow( SwTextFormatInfo &rInf ) const
2249{
2250 OSL_ENSURE( rInf.GetTextFly().IsOn(), "SwTextFormatter::ChkFlyUnderflow: why?" )do { if (true && (!(rInf.GetTextFly().IsOn()))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/text/itrform2.cxx"
":" "2250" ": "), "%s", "SwTextFormatter::ChkFlyUnderflow: why?"
); } } while (false)
;
2251 if( GetCurr() )
2252 {
2253 // First we check, whether a fly overlaps with the line.
2254 // = GetLineHeight()
2255 const sal_uInt16 nHeight = GetCurr()->GetRealHeight();
2256 SwRect aLine( GetLeftMargin(), Y(), rInf.RealWidth(), nHeight );
2257
2258 SwRect aLineVert( aLine );
2259 if ( m_pFrame->IsVertical() )
2260 m_pFrame->SwitchHorizontalToVertical( aLineVert );
2261 SwRect aInter( rInf.GetTextFly().GetFrame( aLineVert ) );
2262 if ( m_pFrame->IsVertical() )
2263 m_pFrame->SwitchVerticalToHorizontal( aInter );
2264
2265 if( !aInter.HasArea() )
2266 return false;
2267
2268 // We now check every portion that could have lowered for overlapping
2269 // with the fly.
2270 const SwLinePortion *pPos = GetCurr()->GetFirstPortion();
2271 aLine.Pos().setY( Y() + GetCurr()->GetRealHeight() - GetCurr()->Height() );
2272 aLine.Height( GetCurr()->Height() );
2273
2274 while( pPos )
2275 {
2276 aLine.Width( pPos->Width() );
2277
2278 aLineVert = aLine;
2279 if ( m_pFrame->IsVertical() )
2280 m_pFrame->SwitchHorizontalToVertical( aLineVert );
2281 aInter = rInf.GetTextFly().GetFrame( aLineVert );
2282 if ( m_pFrame->IsVertical() )
2283 m_pFrame->SwitchVerticalToHorizontal( aInter );
2284
2285 // New flys from below?
2286 if( !pPos->IsFlyPortion() )
2287 {
2288 if( aInter.IsOver( aLine ) )
2289 {
2290 aInter.Intersection_( aLine );
2291 if( aInter.HasArea() )
2292 {
2293 // To be evaluated during reformat of this line:
2294 // RealHeight including spacing
2295 rInf.SetLineHeight( nHeight );
2296 // Height without extra spacing
2297 rInf.SetLineNetHeight( m_pCurr->Height() );
2298 return true;
2299 }
2300 }
2301 }
2302 else
2303 {
2304 // The fly portion is not intersected by a fly anymore
2305 if ( ! aInter.IsOver( aLine ) )
2306 {
2307 rInf.SetLineHeight( nHeight );
2308 rInf.SetLineNetHeight( m_pCurr->Height() );
2309 return true;
2310 }
2311 else
2312 {
2313 aInter.Intersection_( aLine );
2314
2315 // No area means a fly has become invalid because of
2316 // lowering the line => reformat the line
2317 // we also have to reformat the line, if the fly size
2318 // differs from the intersection interval's size.
2319 if( ! aInter.HasArea() ||
2320 static_cast<const SwFlyPortion*>(pPos)->GetFixWidth() != aInter.Width() )
2321 {
2322 rInf.SetLineHeight( nHeight );
2323 rInf.SetLineNetHeight( m_pCurr->Height() );
2324 return true;
2325 }
2326 }
2327 }
2328
2329 aLine.Left( aLine.Left() + pPos->Width() );
2330 pPos = pPos->GetNextPortion();
2331 }
2332 }
2333 return false;
2334}
2335
2336void SwTextFormatter::CalcFlyWidth( SwTextFormatInfo &rInf )
2337{
2338 if( GetMulti() || rInf.GetFly() )
2339 return;
2340
2341 SwTextFly& rTextFly = rInf.GetTextFly();
2342 if( !rTextFly.IsOn() || rInf.IsIgnoreFly() )
2343 return;
2344
2345 const SwLinePortion *pLast = rInf.GetLast();
2346
2347 long nAscent;
2348 long nTop = Y();
2349 long nHeight;
2350
2351 if( rInf.GetLineHeight() )
2352 {
2353 // Real line height has already been calculated, we only have to
2354 // search for intersections in the lower part of the strip
2355 nAscent = m_pCurr->GetAscent();
2356 nHeight = rInf.GetLineNetHeight();
2357 nTop += rInf.GetLineHeight() - nHeight;
2358 }
2359 else
2360 {
2361 // We make a first guess for the lines real height
2362 if ( ! m_pCurr->GetRealHeight() )
2363 CalcRealHeight();
2364
2365 nAscent = pLast->GetAscent();
2366 nHeight = pLast->Height();
2367
2368 if ( m_pCurr->GetRealHeight() > nHeight )
2369 nTop += m_pCurr->GetRealHeight() - nHeight;
2370 else
2371 // Important for fixed space between lines
2372 nHeight = m_pCurr->GetRealHeight();
2373 }
2374
2375 const long nLeftMar = GetLeftMargin();
2376 const long nLeftMin = (rInf.X() || GetDropLeft()) ? nLeftMar : GetLeftMin();
2377
2378 SwRect aLine( rInf.X() + nLeftMin, nTop, rInf.RealWidth() - rInf.X()
2379 + nLeftMar - nLeftMin , nHeight );
2380
2381 // tdf#116486: consider also the upper margin from getFramePrintArea because intersections
2382 // with this additional space should lead to repositioning of paragraphs
2383 // For compatibility we grab a related compat flag:
2384 if (GetTextFrame()->GetDoc().getIDocumentSettingAccess().get(DocumentSettingId::ADD_VERTICAL_FLY_OFFSETS)
2385 && IsFirstTextLine())
2386 {
2387 const long nUpper = m_pFrame->getFramePrintArea().Top();
2388 // Increase the rectangle
2389 if( nUpper > 0 && nTop >= nUpper )
2390 aLine.SubTop( nUpper );
2391 }
2392 SwRect aLineVert( aLine );
2393 if ( m_pFrame->IsRightToLeft() )
2394 m_pFrame->SwitchLTRtoRTL( aLineVert );
2395
2396 if ( m_pFrame->IsVertical() )
2397 m_pFrame->SwitchHorizontalToVertical( aLineVert );
2398
2399 // GetFrame(...) determines and returns the intersection rectangle
2400 SwRect aInter( rTextFly.GetFrame( aLineVert ) );
2401
2402 if ( m_pFrame->IsRightToLeft() )
2403 m_pFrame->SwitchRTLtoLTR( aInter );
2404
2405 if ( m_pFrame->IsVertical() )
2406 m_pFrame->SwitchVerticalToHorizontal( aInter );
2407
2408 if (!aInter.IsEmpty() && aInter.Bottom() < nTop)
2409 {
2410 // Intersects with the frame area (with upper margin), but not with the print area (without
2411 // upper margin). Don't reserve space for the fly portion in this case, text is allowed to
2412 // flow there.
2413 aInter.Height(0);
2414 }
2415
2416 if( !aInter.IsOver( aLine ) )
2417 return;
2418
2419 aLine.Left( rInf.X() + nLeftMar );
2420 bool bForced = false;
2421 if( aInter.Left() <= nLeftMin )
2422 {
2423 SwTwips nFrameLeft = GetTextFrame()->getFrameArea().Left();
2424 if( GetTextFrame()->getFramePrintArea().Left() < 0 )
2425 nFrameLeft += GetTextFrame()->getFramePrintArea().Left();
2426 if( aInter.Left() < nFrameLeft )
2427 aInter.Left( nFrameLeft );
2428
2429 long nAddMar = 0;
2430 if ( m_pFrame->IsRightToLeft() )
2431 {
2432 nAddMar = m_pFrame->getFrameArea().Right() - Right();
2433 if ( nAddMar < 0 )
2434 nAddMar = 0;
2435 }
2436 else
2437 nAddMar = nLeftMar - nFrameLeft;
2438
2439 aInter.Width( aInter.Width() + nAddMar );
2440 // For a negative first line indent, we set this flag to show
2441 // that the indentation/margin has been moved.
2442 // This needs to be respected by the DefaultTab at the zero position.
2443 if( IsFirstTextLine() && HasNegFirst() )
2444 bForced = true;
2445 }
2446 aInter.Intersection( aLine );
2447 if( !aInter.HasArea() )
2448 return;
2449
2450 const bool bFullLine = aLine.Left() == aInter.Left() &&
2451 aLine.Right() == aInter.Right();
2452
2453 // Although no text is left, we need to format another line,
2454 // because also empty lines need to avoid a Fly with no wrapping.
2455 if (bFullLine && rInf.GetIdx() == TextFrameIndex(rInf.GetText().getLength()))
2456 {
2457 rInf.SetNewLine( true );
2458 // We know that for dummies, it holds ascent == height
2459 m_pCurr->SetDummy(true);
2460 }
2461
2462 // aInter becomes frame-local
2463 aInter.Pos().AdjustX( -nLeftMar );
2464 SwFlyPortion *pFly = new SwFlyPortion( aInter );
2465 if( bForced )
2466 {
2467 m_pCurr->SetForcedLeftMargin();
2468 rInf.ForcedLeftMargin( static_cast<sal_uInt16>(aInter.Width()) );
2469 }
2470
2471 if( bFullLine )
2472 {
2473 // In order to properly flow around Flys with different
2474 // wrapping attributes, we need to increase by units of line height.
2475 // The last avoiding line should be adjusted in height, so that
2476 // we don't get a frame spacing effect.
2477 // It is important that ascent == height, because the FlyPortion
2478 // values are transferred to pCurr in CalcLine and IsDummy() relies
2479 // on this behaviour.
2480 // To my knowledge we only have two places where DummyLines can be
2481 // created: here and in MakeFlyDummies.
2482 // IsDummy() is evaluated in IsFirstTextLine(), when moving lines
2483 // and in relation with DropCaps.
2484 pFly->Height( sal_uInt16(aInter.Height()) );
2485
2486 // nNextTop now contains the margin's bottom edge, which we avoid
2487 // or the next margin's top edge, which we need to respect.
2488 // That means we can comfortably grow up to this value; that's how
2489 // we save a few empty lines.
2490 long nNextTop = rTextFly.GetNextTop();
2491 if ( m_pFrame->IsVertical() )
2492 nNextTop = m_pFrame->SwitchVerticalToHorizontal( nNextTop );
2493 if( nNextTop > aInter.Bottom() )
2494 {
2495 SwTwips nH = nNextTop - aInter.Top();
2496 if( nH < SAL_MAX_UINT16((sal_uInt16) 0xFFFF) )
2497 pFly->Height( sal_uInt16( nH ) );
2498 }
2499 if( nAscent < pFly->Height() )
2500 pFly->SetAscent( sal_uInt16(nAscent) );
2501 else
2502 pFly->SetAscent( pFly->Height() );
2503 }
2504 else
2505 {
2506 if (rInf.GetIdx() == TextFrameIndex(rInf.GetText().getLength()))
2507 {
2508 // Don't use nHeight, or we have a huge descent
2509 pFly->Height( pLast->Height() );
2510 pFly->SetAscent( pLast->GetAscent() );
2511 }
2512 else
2513 {
2514 pFly->Height( sal_uInt16(aInter.Height()) );
2515 if( nAscent < pFly->Height() )
2516 pFly->SetAscent( sal_uInt16(nAscent) );
2517 else
2518 pFly->SetAscent( pFly->Height() );
2519 }
2520 }
2521
2522 rInf.SetFly( pFly );
2523
2524 if( pFly->GetFix() < rInf.Width() )
2525 rInf.Width( pFly->GetFix() );
2526
2527 SwTextGridItem const*const pGrid(GetGridItem(m_pFrame->FindPageFrame()));
2528 if ( !pGrid )
2529 return;
2530
2531 const SwPageFrame* pPageFrame = m_pFrame->FindPageFrame();
2532 const SwLayoutFrame* pBody = pPageFrame->FindBodyCont();
2533
2534 SwRectFnSet aRectFnSet(pPageFrame);
2535
2536 const long nGridOrigin = pBody ?
2537 aRectFnSet.GetPrtLeft(*pBody) :
2538 aRectFnSet.GetPrtLeft(*pPageFrame);
2539
2540 const SwDoc & rDoc = rInf.GetTextFrame()->GetDoc();
2541 const sal_uInt16 nGridWidth = GetGridWidth(*pGrid, rDoc);
2542
2543 SwTwips nStartX = GetLeftMargin();
2544 if ( aRectFnSet.IsVert() )
2545 {
2546 Point aPoint( nStartX, 0 );
2547 m_pFrame->SwitchHorizontalToVertical( aPoint );
2548 nStartX = aPoint.Y();
2549 }
2550
2551 const SwTwips nOfst = nStartX - nGridOrigin;
2552 const SwTwips nTmpWidth = rInf.Width() + nOfst;
2553
2554 const sal_uLong i = nTmpWidth / nGridWidth + 1;
2555
2556 const long nNewWidth = ( i - 1 ) * nGridWidth - nOfst;
2557 if ( nNewWidth > 0 )
2558 rInf.Width( static_cast<sal_uInt16>(nNewWidth) );
2559 else
2560 rInf.Width( 0 );
2561
2562
2563}
2564
2565SwFlyCntPortion *SwTextFormatter::NewFlyCntPortion( SwTextFormatInfo &rInf,
2566 SwTextAttr *pHint ) const
2567{
2568 const SwFrame *pFrame = m_pFrame;
2569
2570 SwFlyInContentFrame *pFly;
2571 SwFrameFormat* pFrameFormat = static_cast<SwTextFlyCnt*>(pHint)->GetFlyCnt().GetFrameFormat();
2572 if( RES_FLYFRMFMT == pFrameFormat->Which() )
2573 pFly = static_cast<SwTextFlyCnt*>(pHint)->GetFlyFrame(pFrame);
2574 else
2575 pFly = nullptr;
2576 // aBase is the document-global position, from which the new extra portion is placed
2577 // aBase.X() = Offset in the line after the current position
2578 // aBase.Y() = LineIter.Y() + Ascent of the current position
2579
2580 long nTmpAscent, nTmpDescent, nFlyAsc, nFlyDesc;
2581 // i#11859 - use new method <SwLineLayout::MaxAscentDescent(..)>
2582 // to change line spacing behaviour at paragraph - Compatibility to MS Word
2583 //SwLinePortion *pPos = pCurr->GetFirstPortion();
2584 //lcl_MaxAscDescent( pPos, nTmpAscent, nTmpDescent, nFlyAsc, nFlyDesc );
2585 m_pCurr->MaxAscentDescent( nTmpAscent, nTmpDescent, nFlyAsc, nFlyDesc );
2586
2587 // If the ascent of the frame is larger than the ascent of the current position,
2588 // we use this one when calculating the base, or the frame would be positioned
2589 // too much to the top, sliding down after all causing a repaint in an area
2590 // he actually never was in.
2591 sal_uInt16 nAscent = 0;
2592
2593 const bool bTextFrameVertical = GetInfo().GetTextFrame()->IsVertical();
2594
2595 const bool bUseFlyAscent = pFly && pFly->isFrameAreaPositionValid() &&
2596 0 != ( bTextFrameVertical ?
2597 pFly->GetRefPoint().X() :
2598 pFly->GetRefPoint().Y() );
2599
2600 if ( bUseFlyAscent )
2601 nAscent = static_cast<sal_uInt16>( std::abs( int( bTextFrameVertical ?
2602 pFly->GetRelPos().X() :
2603 pFly->GetRelPos().Y() ) ) );
2604
2605 // Check if be prefer to use the ascent of the last portion:
2606 if ( IsQuick() ||
2607 !bUseFlyAscent ||
2608 nAscent < rInf.GetLast()->GetAscent() )
2609 {
2610 nAscent = rInf.GetLast()->GetAscent();
2611 }
2612 else if( nAscent > nFlyAsc )
2613 nFlyAsc = nAscent;
2614
2615 Point aBase( GetLeftMargin() + rInf.X(), Y() + nAscent );
2616 AsCharFlags nMode = IsQuick() ? AsCharFlags::Quick : AsCharFlags::None;
2617 if( GetMulti() && GetMulti()->HasRotation() )
2618 {
2619 nMode |= AsCharFlags::Rotate;
2620 if( GetMulti()->IsRevers() )
2621 nMode |= AsCharFlags::Reverse;
2622 }
2623
2624 Point aTmpBase( aBase );
2625 if ( GetInfo().GetTextFrame()->IsVertical() )
2626 GetInfo().GetTextFrame()->SwitchHorizontalToVertical( aTmpBase );
2627
2628 SwFlyCntPortion* pRet(nullptr);
2629 if( pFly )
2630 {
2631 pRet = sw::FlyContentPortion::Create(*GetInfo().GetTextFrame(), pFly, aTmpBase, nTmpAscent, nTmpDescent, nFlyAsc, nFlyDesc, nMode);
2632 // We need to make sure that our font is set again in the OutputDevice
2633 // It could be that the FlyInCnt was added anew and GetFlyFrame() would
2634 // in turn cause, that it'd be created anew again.
2635 // This one's frames get formatted right away, which change the font.
2636 rInf.SelectFont();
2637 if( pRet->GetAscent() > nAscent )
2638 {
2639 aBase.setY( Y() + pRet->GetAscent() );
2640 nMode |= AsCharFlags::UlSpace;
2641 if( !rInf.IsTest() )
2642 {
2643 aTmpBase = aBase;
2644 if ( GetInfo().GetTextFrame()->IsVertical() )
2645 GetInfo().GetTextFrame()->SwitchHorizontalToVertical( aTmpBase );
2646
2647 pRet->SetBase( *rInf.GetTextFrame(), aTmpBase, nTmpAscent,
2648 nTmpDescent, nFlyAsc, nFlyDesc, nMode );
2649 }
2650 }
2651 }
2652 else
2653 {
2654 pRet = sw::DrawFlyCntPortion::Create(*rInf.GetTextFrame(), *pFrameFormat, aTmpBase, nTmpAscent, nTmpDescent, nFlyAsc, nFlyDesc, nMode);
2655 }
2656 return pRet;
2657}
2658
2659/* Drop portion is a special case, because it has parts which aren't portions
2660 but we have handle them just like portions */
2661void SwTextFormatter::MergeCharacterBorder( SwDropPortion const & rPortion )
2662{
2663 if( rPortion.GetLines() <= 1 )
2664 return;
2665
2666 SwDropPortionPart* pCurrPart = rPortion.GetPart();
2667 while( pCurrPart )
2668 {
2669 if( pCurrPart->GetFollow() &&
2670 ::lcl_HasSameBorder(pCurrPart->GetFont(), pCurrPart->GetFollow()->GetFont()) )
2671 {
2672 pCurrPart->SetJoinBorderWithNext(true);
2673 pCurrPart->GetFollow()->SetJoinBorderWithPrev(true);
2674 }
2675 pCurrPart = pCurrPart->GetFollow();
2676 }
2677}
2678
2679void SwTextFormatter::MergeCharacterBorder( SwLinePortion& rPortion, SwLinePortion const *pPrev, SwTextFormatInfo& rInf )
2680{
2681 const SwFont aCurFont = *rInf.GetFont();
2682 if( !aCurFont.HasBorder() )
2683 return;
2684
2685 if (pPrev && pPrev->GetJoinBorderWithNext() )
2686 {
2687 // In some case border merge is called twice to the portion
2688 if( !rPortion.GetJoinBorderWithPrev() )
2689 {
2690 rPortion.SetJoinBorderWithPrev(true);
2691 if( rPortion.InTextGrp() && rPortion.Width() > aCurFont.GetLeftBorderSpace() )
2692 rPortion.Width(rPortion.Width() - aCurFont.GetLeftBorderSpace());
2693 }
2694 }
2695 else
2696 {
2697 rPortion.SetJoinBorderWithPrev(false);
2698 m_pFirstOfBorderMerge = &rPortion;
2699 }
2700
2701 // Get next portion's font
2702 bool bSeek = false;
2703 if (!rInf.IsFull() && // Not the last portion of the line (in case of line break)
2704 rInf.GetIdx() + rPortion.GetLen() != TextFrameIndex(rInf.GetText().getLength())) // Not the last portion of the paragraph
2705 {
2706 bSeek = Seek(rInf.GetIdx() + rPortion.GetLen());
2707 }
2708 // Don't join the next portion if SwKernPortion sits between two different boxes.
2709 bool bDisconnect = rPortion.IsKernPortion() && !rPortion.GetJoinBorderWithPrev();
2710 // If next portion has the same border then merge
2711 if( bSeek && GetFnt()->HasBorder() && ::lcl_HasSameBorder(aCurFont, *GetFnt()) && !bDisconnect )
2712 {
2713 // In some case border merge is called twice to the portion
2714 if( !rPortion.GetJoinBorderWithNext() )
2715 {
2716 rPortion.SetJoinBorderWithNext(true);
2717 if( rPortion.InTextGrp() && rPortion.Width() > aCurFont.GetRightBorderSpace() )
2718 rPortion.Width(rPortion.Width() - aCurFont.GetRightBorderSpace());
2719 }
2720 }
2721 // If this is the last portion of the merge group then make the real height merge
2722 else
2723 {
2724 rPortion.SetJoinBorderWithNext(false);
2725 if( m_pFirstOfBorderMerge != &rPortion )
2726 {
2727 // Calculate maximum height and ascent
2728 SwLinePortion* pActPor = m_pFirstOfBorderMerge;
2729 sal_uInt16 nMaxAscent = 0;
2730 sal_uInt16 nMaxHeight = 0;
2731 bool bReachCurrent = false;
2732 while( pActPor )
2733 {
2734 if( nMaxHeight < pActPor->Height() )
2735 nMaxHeight = pActPor->Height();
2736 if( nMaxAscent < pActPor->GetAscent() )
2737 nMaxAscent = pActPor->GetAscent();
2738
2739 pActPor = pActPor->GetNextPortion();
2740 if( !pActPor && !bReachCurrent )
2741 {
2742 pActPor = &rPortion;
2743 bReachCurrent = true;
2744 }
2745 }
2746
2747 // Change all portion's height and ascent
2748 pActPor = m_pFirstOfBorderMerge;
2749 bReachCurrent = false;
2750 while( pActPor )
2751 {
2752 if( nMaxHeight > pActPor->Height() )
2753 pActPor->Height(nMaxHeight);
2754 if( nMaxAscent > pActPor->GetAscent() )
2755 pActPor->SetAscent(nMaxAscent);
2756
2757 pActPor = pActPor->GetNextPortion();
2758 if( !pActPor && !bReachCurrent )
2759 {
2760 pActPor = &rPortion;
2761 bReachCurrent = true;
2762 }
2763 }
2764 m_pFirstOfBorderMerge = nullptr;
2765 }
2766 }
2767 Seek(rInf.GetIdx());
2768}
2769
2770namespace {
2771 // calculates and sets optimal repaint offset for the current line
2772 long lcl_CalcOptRepaint( SwTextFormatter &rThis,
2773 SwLineLayout const &rCurr,
2774 TextFrameIndex const nOldLineEnd,
2775 const std::vector<long> &rFlyStarts )
2776 {
2777 SwTextFormatInfo& txtFormatInfo = rThis.GetInfo();
2778 if ( txtFormatInfo.GetIdx() < txtFormatInfo.GetReformatStart() )
2779 // the reformat position is behind our new line, that means
2780 // something of our text has moved to the next line
2781 return 0;
2782
2783 TextFrameIndex nReformat = std::min(txtFormatInfo.GetReformatStart(), nOldLineEnd);
2784
2785 // in case we do not have any fly in our line, our repaint position
2786 // is the changed position - 1
2787 if ( rFlyStarts.empty() && ! rCurr.IsFly() )
2788 {
2789 // this is the maximum repaint offset determined during formatting
2790 // for example: the beginning of the first right tab stop
2791 // if this value is 0, this means that we do not have an upper
2792 // limit for the repaint offset
2793 const long nFormatRepaint = txtFormatInfo.GetPaintOfst();
2794
2795 if (nReformat < txtFormatInfo.GetLineStart() + TextFrameIndex(3))
2796 return 0;
2797
2798 // step back two positions for smoother repaint
2799 nReformat -= TextFrameIndex(2);
2800
2801 // i#28795, i#34607, i#38388
2802 // step back more characters, this is required by complex scripts
2803 // e.g., for Khmer (thank you, Javier!)
2804 static const TextFrameIndex nMaxContext(10);
2805 if (nReformat > txtFormatInfo.GetLineStart() + nMaxContext)
2806 nReformat = nReformat - nMaxContext;
2807 else
2808 {
2809 nReformat = txtFormatInfo.GetLineStart();
2810 //reset the margin flag - prevent loops
2811 SwTextCursor::SetRightMargin(false);
2812 }
2813
2814 // Weird situation: Our line used to end with a hole portion
2815 // and we delete some characters at the end of our line. We have
2816 // to take care for repainting the blanks which are not anymore
2817 // covered by the hole portion
2818 while ( nReformat > txtFormatInfo.GetLineStart() &&
2819 CH_BLANK == txtFormatInfo.GetChar( nReformat ) )
2820 --nReformat;
2821
2822 OSL_ENSURE( nReformat < txtFormatInfo.GetIdx(), "Reformat too small for me!" )do { if (true && (!(nReformat < txtFormatInfo.GetIdx
()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/sw/source/core/text/itrform2.cxx"
":" "2822" ": "), "%s", "Reformat too small for me!"); } } while
(false)
;
2823 SwRect aRect;
2824
2825 // Note: GetChareRect is not const. It definitely changes the
2826 // bMulti flag. We have to save and restore the old value.
2827 bool bOldMulti = txtFormatInfo.IsMulti();
2828 rThis.GetCharRect( &aRect, nReformat );
2829 txtFormatInfo.SetMulti( bOldMulti );
2830
2831 return nFormatRepaint ? std::min( aRect.Left(), nFormatRepaint ) :
2832 aRect.Left();
2833 }
2834 else
2835 {
2836 // nReformat may be wrong, if something around flys has changed:
2837 // we compare the former and the new fly positions in this line
2838 // if anything has changed, we carefully have to adjust the right
2839 // repaint position
2840 long nPOfst = 0;
2841 size_t nCnt = 0;
2842 long nX = 0;
2843 TextFrameIndex nIdx = rThis.GetInfo().GetLineStart();
2844 SwLinePortion* pPor = rCurr.GetFirstPortion();
2845
2846 while ( pPor )
2847 {
2848 if ( pPor->IsFlyPortion() )
2849 {
2850 // compare start of fly with former start of fly
2851 if (nCnt < rFlyStarts.size() &&
2852 nX == rFlyStarts[ nCnt ] &&
2853 nIdx < nReformat
2854 )
2855 // found fix position, nothing has changed left from nX
2856 nPOfst = nX + pPor->Width();
2857 else
2858 break;
2859
2860 nCnt++;
2861 }
2862 nX = nX + pPor->Width();
2863 nIdx = nIdx + pPor->GetLen();
2864 pPor = pPor->GetNextPortion();
2865 }
2866
2867 return nPOfst + rThis.GetLeftMargin();
2868 }
2869 }
2870
2871 // Determine if we need to build hidden portions
2872 bool lcl_BuildHiddenPortion(const SwTextSizeInfo& rInf, TextFrameIndex & rPos)
2873 {
2874 // Only if hidden text should not be shown:
2875 // if ( rInf.GetVsh() && rInf.GetVsh()->GetWin() && rInf.GetOpt().IsShowHiddenChar() )
2876 const bool bShowInDocView = rInf.GetVsh() && rInf.GetVsh()->GetWin() && rInf.GetOpt().IsShowHiddenChar();
2877 const bool bShowForPrinting = rInf.GetOpt().IsShowHiddenChar( true ) && rInf.GetOpt().IsPrinting();
2878 if (bShowInDocView || bShowForPrinting)
2879 return false;
2880
2881 const SwScriptInfo& rSI = rInf.GetParaPortion()->GetScriptInfo();
2882 TextFrameIndex nHiddenStart;
2883 TextFrameIndex nHiddenEnd;
2884 rSI.GetBoundsOfHiddenRange( rPos, nHiddenStart, nHiddenEnd );
2885 if ( nHiddenEnd )
2886 {
2887 rPos = nHiddenEnd;
2888 return true;
2889 }
2890
2891 return false;
2892 }
2893
2894 bool lcl_HasSameBorder(const SwFont& rFirst, const SwFont& rSecond)
2895 {
2896 return
2897 rFirst.GetTopBorder() == rSecond.GetTopBorder() &&
2898 rFirst.GetBottomBorder() == rSecond.GetBottomBorder() &&
2899 rFirst.GetLeftBorder() == rSecond.GetLeftBorder() &&
2900 rFirst.GetRightBorder() == rSecond.GetRightBorder() &&
2901 rFirst.GetTopBorderDist() == rSecond.GetTopBorderDist() &&
2902 rFirst.GetBottomBorderDist() == rSecond.GetBottomBorderDist() &&
2903 rFirst.GetLeftBorderDist() == rSecond.GetLeftBorderDist() &&
2904 rFirst.GetRightBorderDist() == rSecond.GetRightBorderDist() &&
2905 rFirst.GetOrientation() == rSecond.GetOrientation() &&
2906 rFirst.GetShadowColor() == rSecond.GetShadowColor() &&
2907 rFirst.GetShadowWidth() == rSecond.GetShadowWidth() &&
2908 rFirst.GetShadowLocation() == rSecond.GetShadowLocation();
2909 }
2910
2911} //end unnamed namespace
2912
2913/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

/home/maarten/src/libreoffice/core/sw/source/core/text/porlin.hxx

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#ifndef INCLUDED_SW_SOURCE_CORE_TEXT_PORLIN_HXX
20#define INCLUDED_SW_SOURCE_CORE_TEXT_PORLIN_HXX
21
22#include "possiz.hxx"
23#include <txttypes.hxx>
24#include <TextFrameIndex.hxx>
25#include <rtl/ustring.hxx>
26
27class SwTextSizeInfo;
28class SwTextPaintInfo;
29class SwTextFormatInfo;
30class SwPortionHandler;
31
32/// Portion groups
33/// @see enum PortionType in txttypes.hxx
34#define PORGRP_TXT0x8000 0x8000
35#define PORGRP_EXP0x4000 0x4000
36#define PORGRP_FLD0x2000 0x2000
37#define PORGRP_HYPH0x1000 0x1000
38#define PORGRP_NUMBER0x0800 0x0800
39#define PORGRP_GLUE0x0400 0x0400
40#define PORGRP_FIX0x0200 0x0200
41#define PORGRP_TAB0x0100 0x0100
42// Small special groups
43#define PORGRP_FIXMARG0x0040 0x0040
44//#define PORGRP_? 0x0020
45#define PORGRP_TABNOTLFT0x0010 0x0010
46#define PORGRP_TOXREF0x0008 0x0008
47
48/// Base class for anything that can be part of a line in the Writer layout.
49/// Typically owned by SwLineLayout.
50class SwLinePortion: public SwPosSize
51{
52protected:
53 // Here we have areas with different attributes
54 SwLinePortion *mpNextPortion;
55 // Count of chars and spaces on the line
56 TextFrameIndex nLineLength;
57 sal_uInt16 nAscent; // Maximum ascender
58
59 SwLinePortion();
60private:
61 PortionType nWhichPor; // Who's who?
62 bool m_bJoinBorderWithPrev;
63 bool m_bJoinBorderWithNext;
64
65 void Truncate_();
66
67public:
68 explicit inline SwLinePortion(const SwLinePortion &rPortion);
69 virtual ~SwLinePortion();
70
71 // Access methods
72 SwLinePortion *GetNextPortion() const { return mpNextPortion; }
73 inline SwLinePortion &operator=(const SwLinePortion &rPortion);
74 TextFrameIndex GetLen() const { return nLineLength; }
75 void SetLen(TextFrameIndex const nLen) { nLineLength = nLen; }
76 void SetNextPortion( SwLinePortion *pNew ){ mpNextPortion = pNew; }
77 sal_uInt16 &GetAscent() { return nAscent; }
78 sal_uInt16 GetAscent() const { return nAscent; }
79 void SetAscent( const sal_uInt16 nNewAsc ) { nAscent = nNewAsc; }
80 void PrtWidth( sal_uInt16 nNewWidth ) { Width( nNewWidth ); }
81 sal_uInt16 PrtWidth() const { return Width(); }
82 void AddPrtWidth( const sal_uInt16 nNew ) { Width( Width() + nNew ); }
83 void SubPrtWidth( const sal_uInt16 nNew ) { Width( Width() - nNew ); }
84
85 // Insert methods
86 virtual SwLinePortion *Insert( SwLinePortion *pPortion );
87 virtual SwLinePortion *Append( SwLinePortion *pPortion );
88 SwLinePortion *Cut( SwLinePortion *pVictim );
89 inline void Truncate();
90
91 // Returns 0, if there's no payload
92 virtual SwLinePortion *Compress();
93
94 void SetWhichPor( const PortionType nNew ) { nWhichPor = nNew; }
95 PortionType GetWhichPor( ) const { return nWhichPor; }
96
97// Group queries
98 bool InTextGrp() const { return (sal_uInt16(nWhichPor) & PORGRP_TXT0x8000) != 0; }
99 bool InGlueGrp() const { return (sal_uInt16(nWhichPor) & PORGRP_GLUE0x0400) != 0; }
100 bool InTabGrp() const { return (sal_uInt16(nWhichPor) & PORGRP_TAB0x0100) != 0; }
101 bool InHyphGrp() const { return (sal_uInt16(nWhichPor) & PORGRP_HYPH0x1000) != 0; }
102 bool InNumberGrp() const { return (sal_uInt16(nWhichPor) & PORGRP_NUMBER0x0800) != 0; }
103 bool InFixGrp() const { return (sal_uInt16(nWhichPor) & PORGRP_FIX0x0200) != 0; }
104 bool InFieldGrp() const { return (sal_uInt16(nWhichPor) & PORGRP_FLD0x2000) != 0; }
39
Assuming the condition is false
40
Returning zero, which participates in a condition later
105 bool InToxRefGrp() const { return (sal_uInt16(nWhichPor) & PORGRP_TOXREF0x0008) != 0; }
106 bool InToxRefOrFieldGrp() const { return (sal_uInt16(nWhichPor) & ( PORGRP_FLD0x2000 | PORGRP_TOXREF0x0008 )) != 0; }
107 bool InExpGrp() const { return (sal_uInt16(nWhichPor) & PORGRP_EXP0x4000) != 0; }
108 bool InFixMargGrp() const { return (sal_uInt16(nWhichPor) & PORGRP_FIXMARG0x0040) != 0; }
109 bool InSpaceGrp() const { return InTextGrp() || IsMultiPortion(); }
110// Individual queries
111 bool IsGrfNumPortion() const { return nWhichPor == PortionType::GrfNum; }
112 bool IsFlyCntPortion() const { return nWhichPor == PortionType::FlyCnt; }
113 bool IsBlankPortion() const { return nWhichPor == PortionType::Blank; }
114 bool IsBreakPortion() const { return nWhichPor == PortionType::Break; }
115 bool IsErgoSumPortion() const { return nWhichPor == PortionType::ErgoSum; }
116 bool IsQuoVadisPortion() const { return nWhichPor == PortionType::QuoVadis; }
51
Assuming field 'nWhichPor' is not equal to QuoVadis
52
Returning zero, which participates in a condition later
117 bool IsTabLeftPortion() const { return nWhichPor == PortionType::TabLeft; }
118 bool IsTabRightPortion() const { return nWhichPor == PortionType::TabRight; }
119 bool IsFootnoteNumPortion() const { return nWhichPor == PortionType::FootnoteNum; }
120 bool IsFootnotePortion() const { return nWhichPor == PortionType::Footnote; }
121 bool IsDropPortion() const { return nWhichPor == PortionType::Drop; }
122 bool IsLayPortion() const { return nWhichPor == PortionType::Lay; }
123 bool IsParaPortion() const { return nWhichPor == PortionType::Para; }
124 bool IsMarginPortion() const { return nWhichPor == PortionType::Margin; }
125 bool IsFlyPortion() const { return nWhichPor == PortionType::Fly; }
126 bool IsHolePortion() const { return nWhichPor == PortionType::Hole; }
127 bool IsSoftHyphPortion() const { return nWhichPor == PortionType::SoftHyphen; }
128 bool IsPostItsPortion() const { return nWhichPor == PortionType::PostIts; }
129 bool IsCombinedPortion() const { return nWhichPor == PortionType::Combined; }
130 bool IsTextPortion() const { return nWhichPor == PortionType::Text; }
131 bool IsHangingPortion() const { return nWhichPor == PortionType::Hanging; }
132 bool IsKernPortion() const { return nWhichPor == PortionType::Kern; }
133 bool IsArrowPortion() const { return nWhichPor == PortionType::Arrow; }
134 bool IsMultiPortion() const { return nWhichPor == PortionType::Multi; }
135 bool IsNumberPortion() const { return nWhichPor == PortionType::Number; } // #i23726#
136 bool IsControlCharPortion() const { return nWhichPor == PortionType::ControlChar || nWhichPor == PortionType::Bookmark; }
137
138 // Positioning
139 SwLinePortion *FindPrevPortion( const SwLinePortion *pRoot );
140 SwLinePortion *FindLastPortion();
141
142 /// the parameter is actually SwTwips apparently?
143 virtual TextFrameIndex GetModelPositionForViewPoint(sal_uInt16 nOfst) const;
144 virtual SwPosSize GetTextSize( const SwTextSizeInfo &rInfo ) const;
145 void CalcTextSize( const SwTextSizeInfo &rInfo );
146
147 // Output
148 virtual void Paint( const SwTextPaintInfo &rInf ) const = 0;
149 void PrePaint( const SwTextPaintInfo &rInf, const SwLinePortion *pLast ) const;
150
151 virtual bool Format( SwTextFormatInfo &rInf );
152 // Is called for the line's last portion
153 virtual void FormatEOL( SwTextFormatInfo &rInf );
154 void Move( SwTextPaintInfo &rInf );
155
156 // For SwTextSlot
157 virtual bool GetExpText( const SwTextSizeInfo &rInf, OUString &rText ) const;
158
159 // For SwFieldPortion, SwSoftHyphPortion
160 virtual sal_uInt16 GetViewWidth( const SwTextSizeInfo &rInf ) const;
161
162 // for text- and multi-portions
163 virtual long CalcSpacing( long nSpaceAdd, const SwTextSizeInfo &rInf ) const;
164
165 // Accessibility: pass information about this portion to the PortionHandler
166 virtual void HandlePortion( SwPortionHandler& rPH ) const;
167
168 bool GetJoinBorderWithPrev() const { return m_bJoinBorderWithPrev; }
169 bool GetJoinBorderWithNext() const { return m_bJoinBorderWithNext; }
170 void SetJoinBorderWithPrev( const bool bJoinPrev ) { m_bJoinBorderWithPrev = bJoinPrev; }
171 void SetJoinBorderWithNext( const bool bJoinNext ) { m_bJoinBorderWithNext = bJoinNext; }
172};
173
174inline SwLinePortion &SwLinePortion::operator=(const SwLinePortion &rPortion)
175{
176 *static_cast<SwPosSize*>(this) = rPortion;
177 nLineLength = rPortion.nLineLength;
178 nAscent = rPortion.nAscent;
179 nWhichPor = rPortion.nWhichPor;
180 m_bJoinBorderWithPrev = rPortion.m_bJoinBorderWithPrev;
181 m_bJoinBorderWithNext = rPortion.m_bJoinBorderWithNext;
182 return *this;
183}
184
185inline SwLinePortion::SwLinePortion(const SwLinePortion &rPortion) :
186 SwPosSize( rPortion ),
187 mpNextPortion( nullptr ),
188 nLineLength( rPortion.nLineLength ),
189 nAscent( rPortion.nAscent ),
190 nWhichPor( rPortion.nWhichPor ),
191 m_bJoinBorderWithPrev( rPortion.m_bJoinBorderWithPrev ),
192 m_bJoinBorderWithNext( rPortion.m_bJoinBorderWithNext )
193{
194}
195
196inline void SwLinePortion::Truncate()
197{
198 if ( mpNextPortion )
199 Truncate_();
200}
201
202#endif
203
204/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

/home/maarten/src/libreoffice/core/include/o3tl/strong_int.hxx

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#ifndef INCLUDED_O3TL_STRONG_INT_HXX
21#define INCLUDED_O3TL_STRONG_INT_HXX
22
23#include <sal/config.h>
24#include <limits>
25#include <cassert>
26#include <type_traits>
27
28namespace o3tl
29{
30
31#if !defined __COVERITY__
32
33namespace detail {
34
35template<typename T1, typename T2> constexpr
36typename std::enable_if<
37 std::is_signed<T1>::value && std::is_signed<T2>::value, bool>::type
38isInRange(T2 value) {
39 return value >= std::numeric_limits<T1>::min()
40 && value <= std::numeric_limits<T1>::max();
41}
42
43template<typename T1, typename T2> constexpr
44typename std::enable_if<
45 std::is_signed<T1>::value && std::is_unsigned<T2>::value, bool>::type
46isInRange(T2 value) {
47 return value
48 <= static_cast<typename std::make_unsigned<T1>::type>(
49 std::numeric_limits<T1>::max());
50}
51
52template<typename T1, typename T2> constexpr
53typename std::enable_if<
54 std::is_unsigned<T1>::value && std::is_signed<T2>::value, bool>::type
55isInRange(T2 value) {
56 return value >= 0
57 && (static_cast<typename std::make_unsigned<T2>::type>(value)
58 <= std::numeric_limits<T1>::max());
59}
60
61template<typename T1, typename T2> constexpr
62typename std::enable_if<
63 std::is_unsigned<T1>::value && std::is_unsigned<T2>::value, bool>::type
64isInRange(T2 value) {
65 return value <= std::numeric_limits<T1>::max();
66}
67
68}
69
70#endif
71
72///
73/// Wrap up an integer type so that we prevent accidental conversion to other integer types.
74///
75/// e.g.
76/// typedef o3tl::strong_int<unsigned, struct MyIntTag> MyInt;
77///
78/// \param UNDERLYING_TYPE the underlying scalar type
79/// \param PHANTOM_TYPE a type tag, used to distinguish this instantiation of the template
80/// from other instantiations with the same UNDERLYING_TYPE.
81///
82template <typename UNDERLYING_TYPE, typename PHANTOM_TYPE>
83struct strong_int
84{
85public:
86 template<typename T> explicit constexpr strong_int(
87 T value,
88 typename std::enable_if<std::is_integral<T>::value, int>::type = 0):
89 m_value(value)
90 {
91#if !defined __COVERITY__
92 // catch attempts to pass in out-of-range values early
93 assert(detail::isInRange<UNDERLYING_TYPE>(value)(static_cast <bool> (detail::isInRange<UNDERLYING_TYPE
>(value) && "out of range") ? void (0) : __assert_fail
("detail::isInRange<UNDERLYING_TYPE>(value) && \"out of range\""
, "/home/maarten/src/libreoffice/core/include/o3tl/strong_int.hxx"
, 94, __extension__ __PRETTY_FUNCTION__))
94 && "out of range")(static_cast <bool> (detail::isInRange<UNDERLYING_TYPE
>(value) && "out of range") ? void (0) : __assert_fail
("detail::isInRange<UNDERLYING_TYPE>(value) && \"out of range\""
, "/home/maarten/src/libreoffice/core/include/o3tl/strong_int.hxx"
, 94, __extension__ __PRETTY_FUNCTION__))
;
95#endif
96 }
97 strong_int() : m_value(0) {}
98
99 explicit constexpr operator UNDERLYING_TYPE() const { return m_value; }
100 explicit operator bool() const { return m_value != 0; }
62
Returning zero, which participates in a condition later
65
Assuming field 'm_value' is not equal to 0
66
Returning the value 1, which participates in a condition later
101 UNDERLYING_TYPE get() const { return m_value; }
102
103 bool operator<(strong_int const & other) const { return m_value < other.m_value; }
104 bool operator<=(strong_int const & other) const { return m_value <= other.m_value; }
105 bool operator>(strong_int const & other) const { return m_value > other.m_value; }
106 bool operator>=(strong_int const & other) const { return m_value >= other.m_value; }
107 bool operator==(strong_int const & other) const { return m_value == other.m_value; }
47
Assuming 'm_value' is equal to 'other.m_value'
48
Returning the value 1, which participates in a condition later
108 bool operator!=(strong_int const & other) const { return m_value != other.m_value; }
109 strong_int& operator++() { ++m_value; return *this; }
110 strong_int operator++(int) { UNDERLYING_TYPE nOldValue = m_value; ++m_value; return strong_int(nOldValue); }
111 strong_int& operator--() { --m_value; return *this; }
112 strong_int operator--(int) { UNDERLYING_TYPE nOldValue = m_value; --m_value; return strong_int(nOldValue); }
113 strong_int& operator+=(strong_int const & other) { m_value += other.m_value; return *this; }
114 strong_int& operator-=(strong_int const & other) { m_value -= other.m_value; return *this; }
115
116 bool anyOf(strong_int v) const {
117 return *this == v;
118 }
119
120 template<typename... Args>
121 bool anyOf(strong_int first, Args... args) const {
122 return *this == first || anyOf(args...);
123 }
124
125private:
126 UNDERLYING_TYPE m_value;
127};
128
129template <typename UT, typename PT>
130strong_int<UT,PT> operator+(strong_int<UT,PT> const & lhs, strong_int<UT,PT> const & rhs)
131{
132 return strong_int<UT,PT>(lhs.get() + rhs.get());
133}
134
135template <typename UT, typename PT>
136strong_int<UT,PT> operator-(strong_int<UT,PT> const & lhs, strong_int<UT,PT> const & rhs)
137{
138 return strong_int<UT,PT>(lhs.get() - rhs.get());
139}
140
141}; // namespace o3tl
142
143#endif /* INCLUDED_O3TL_STRONG_INT_HXX */
144
145/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx

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#ifndef INCLUDED_RTL_USTRING_HXX
21#define INCLUDED_RTL_USTRING_HXX
22
23#include "sal/config.h"
24
25#include <cassert>
26#include <cstddef>
27#include <cstdlib>
28#include <limits>
29#include <new>
30#include <ostream>
31#include <utility>
32
33#if defined LIBO_INTERNAL_ONLY1
34#include <string_view>
35#include <type_traits>
36#endif
37
38#include "rtl/ustring.h"
39#include "rtl/string.hxx"
40#include "rtl/stringutils.hxx"
41#include "rtl/textenc.h"
42
43#ifdef LIBO_INTERNAL_ONLY1 // "RTL_FAST_STRING"
44#include "config_global.h"
45#include "rtl/stringconcat.hxx"
46#endif
47
48#ifdef RTL_STRING_UNITTEST
49extern bool rtl_string_unittest_invalid_conversion;
50#endif
51
52// The unittest uses slightly different code to help check that the proper
53// calls are made. The class is put into a different namespace to make
54// sure the compiler generates a different (if generating also non-inline)
55// copy of the function and does not merge them together. The class
56// is "brought" into the proper rtl namespace by a typedef below.
57#ifdef RTL_STRING_UNITTEST
58#define rtl rtlunittest
59#endif
60
61namespace rtl
62{
63
64class OUStringBuffer;
65
66#ifdef RTL_STRING_UNITTEST
67#undef rtl
68#endif
69
70#if defined LIBO_INTERNAL_ONLY1 // "RTL_FAST_STRING"
71/// @cond INTERNAL
72
73/**
74A wrapper dressing a string literal as a static-refcount rtl_uString.
75
76This class is not part of public API and is meant to be used only in LibreOffice code.
77@since LibreOffice 4.0
78*/
79template<std::size_t N> class SAL_WARN_UNUSED__attribute__((warn_unused)) OUStringLiteral {
80 static_assert(N != 0);
81 static_assert(N - 1 <= std::numeric_limits<sal_Int32>::max(), "literal too long");
82
83public:
84#if HAVE_CPP_CONSTEVAL0
85 consteval
86#else
87 constexpr
88#endif
89 OUStringLiteral(char16_t const (&literal)[N]) {
90 assertLayout();
91 assert(literal[N - 1] == '\0')(static_cast <bool> (literal[N - 1] == '\0') ? void (0)
: __assert_fail ("literal[N - 1] == '\\0'", "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 91, __extension__ __PRETTY_FUNCTION__))
;
92 //TODO: Use C++20 constexpr std::copy_n (P0202R3):
93 for (std::size_t i = 0; i != N; ++i) {
94 buffer[i] = literal[i];
95 }
96 }
97
98 constexpr sal_Int32 getLength() const { return length; }
99
100 constexpr sal_Unicode const * getStr() const SAL_RETURNS_NONNULL__attribute__((returns_nonnull)) { return buffer; }
101
102 constexpr operator std::u16string_view() const { return {buffer, sal_uInt32(length)}; }
103
104private:
105 static constexpr void assertLayout() {
106 // These static_asserts verifying the layout compatibility with rtl_uString cannot be class
107 // member declarations, as offsetof requires a complete type, so defer them to here:
108 static_assert(offsetof(OUStringLiteral, refCount)__builtin_offsetof(OUStringLiteral, refCount) == offsetof(rtl_uString, refCount)__builtin_offsetof(rtl_uString, refCount));
109 static_assert(std::is_same_v<decltype(refCount), decltype(rtl_uString::refCount)>);
110 static_assert(offsetof(OUStringLiteral, length)__builtin_offsetof(OUStringLiteral, length) == offsetof(rtl_uString, length)__builtin_offsetof(rtl_uString, length));
111 static_assert(std::is_same_v<decltype(length), decltype(rtl_uString::length)>);
112 static_assert(offsetof(OUStringLiteral, buffer)__builtin_offsetof(OUStringLiteral, buffer) == offsetof(rtl_uString, buffer)__builtin_offsetof(rtl_uString, buffer));
113 static_assert(
114 std::is_same_v<
115 std::remove_extent_t<decltype(buffer)>,
116 std::remove_extent_t<decltype(rtl_uString::buffer)>>);
117 }
118
119 // Same layout as rtl_uString (include/rtl/ustring.h):
120 oslInterlockedCount refCount = 0x40000000; // SAL_STRING_STATIC_FLAG (sal/rtl/strimp.hxx)
121 sal_Int32 length = N - 1;
122 sal_Unicode buffer[N] = {}; //TODO: drop initialization for C++20 (P1331R2)
123};
124
125#if defined RTL_STRING_UNITTEST
126namespace libreoffice_internal {
127template<std::size_t N> struct ExceptConstCharArrayDetector<OUStringLiteral<N>> {};
128template<std::size_t N> struct ExceptCharArrayDetector<OUStringLiteral<N>> {};
129}
130#endif
131
132/// @endcond
133#endif
134
135/* ======================================================================= */
136
137/**
138 This String class provides base functionality for C++ like Unicode
139 character array handling. The advantage of this class is that it
140 handles all the memory management for you - and it does it
141 more efficiently. If you assign a string to another string, the
142 data of both strings are shared (without any copy operation or
143 memory allocation) as long as you do not change the string. This class
144 also stores the length of the string, so that many operations are
145 faster than the C-str-functions.
146
147 This class provides only readonly string handling. So you could create
148 a string and you could only query the content from this string.
149 It provides also functionality to change the string, but this results
150 in every case in a new string instance (in the most cases with a
151 memory allocation). You don't have functionality to change the
152 content of the string. If you want to change the string content, then
153 you should use the OStringBuffer class, which provides these
154 functionalities and avoids too much memory allocation.
155
156 The design of this class is similar to the string classes in Java so
157 less people should have understanding problems when they use this class.
158*/
159
160class SAL_WARN_UNUSED__attribute__((warn_unused)) SAL_DLLPUBLIC_RTTI__attribute__ ((type_visibility("default"))) OUString
161{
162public:
163 /// @cond INTERNAL
164 rtl_uString * pData;
165 /// @endcond
166
167 /**
168 New string containing no characters.
169 */
170 OUString()
171 {
172 pData = NULL__null;
173 rtl_uString_new( &pData );
174 }
175
176 /**
177 New string from OUString.
178
179 @param str an OUString.
180 */
181 OUString( const OUString & str )
182 {
183 pData = str.pData;
184 rtl_uString_acquire( pData );
185 }
186
187#if defined LIBO_INTERNAL_ONLY1
188 /**
189 Move constructor.
190
191 @param str an OUString.
192 @since LibreOffice 5.2
193 */
194 OUString( OUString && str ) noexcept
195 {
196 pData = str.pData;
197 str.pData = nullptr;
198 rtl_uString_new( &str.pData );
199 }
200#endif
201
202 /**
203 New string from OUString data.
204
205 @param str an OUString data.
206 */
207 OUString( rtl_uString * str )
208 {
209 pData = str;
210 rtl_uString_acquire( pData );
211 }
212
213 /** New OUString from OUString data without acquiring it. Takeover of ownership.
214
215 The SAL_NO_ACQUIRE dummy parameter is only there to distinguish this
216 from other constructors.
217
218 @param str
219 OUString data
220 */
221 OUString( rtl_uString * str, __sal_NoAcquire )
222 { pData = str; }
223
224 /**
225 New string from a single Unicode character.
226
227 @param value a Unicode character.
228 */
229 explicit OUString( sal_Unicode value )
230 : pData (NULL__null)
231 {
232 rtl_uString_newFromStr_WithLength( &pData, &value, 1 );
233 }
234
235#if defined LIBO_INTERNAL_ONLY1 && !defined RTL_STRING_UNITTEST_CONCAT
236 /// @cond INTERNAL
237 // Catch inadvertent conversions to the above ctor (but still allow
238 // construction from char literals):
239 OUString(int) = delete;
240 explicit OUString(char c):
241 OUString(sal_Unicode(static_cast<unsigned char>(c)))
242 {}
243 /// @endcond
244#endif
245
246#if defined LIBO_INTERNAL_ONLY1
247
248 template<typename T> explicit OUString(
249 T const & value,
250 typename libreoffice_internal::CharPtrDetector<T, libreoffice_internal::Dummy>::TypeUtf16
251 = libreoffice_internal::Dummy()):
252 pData(nullptr)
253 { rtl_uString_newFromStr(&pData, value); }
254
255 template<typename T> explicit OUString(
256 T & value,
257 typename
258 libreoffice_internal::NonConstCharArrayDetector<T, libreoffice_internal::Dummy>::TypeUtf16
259 = libreoffice_internal::Dummy()):
260 pData(nullptr)
261 { rtl_uString_newFromStr(&pData, value); }
262
263#else
264
265 /**
266 New string from a Unicode character buffer array.
267
268 @param value a NULL-terminated Unicode character array.
269 */
270 OUString( const sal_Unicode * value )
271 {
272 pData = NULL__null;
273 rtl_uString_newFromStr( &pData, value );
274 }
275
276#endif
277
278 /**
279 New string from a Unicode character buffer array.
280
281 @param value a Unicode character array.
282 @param length the number of character which should be copied.
283 The character array length must be greater than
284 or equal to this value.
285 */
286 OUString( const sal_Unicode * value, sal_Int32 length )
287 {
288 pData = NULL__null;
289 rtl_uString_newFromStr_WithLength( &pData, value, length );
290 }
291
292 /**
293 New string from an 8-Bit string literal that is expected to contain only
294 characters in the ASCII set (i.e. first 128 characters). This constructor
295 allows an efficient and convenient way to create OUString
296 instances from ASCII literals. When creating strings from data that
297 is not pure ASCII, it needs to be converted to OUString by explicitly
298 providing the encoding to use for the conversion.
299
300 If there are any embedded \0's in the string literal, the result is undefined.
301 Use the overload that explicitly accepts length.
302
303 @param literal the 8-bit ASCII string literal
304
305 @since LibreOffice 3.6
306 */
307 template< typename T >
308 OUString( T& literal, typename libreoffice_internal::ConstCharArrayDetector< T, libreoffice_internal::Dummy >::Type = libreoffice_internal::Dummy() )
309 {
310 assert((static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 311, __extension__ __PRETTY_FUNCTION__))
311 libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 311, __extension__ __PRETTY_FUNCTION__))
;
312 pData = NULL__null;
313 if (libreoffice_internal::ConstCharArrayDetector<T>::length == 0) {
314 rtl_uString_new(&pData);
315 } else {
316 rtl_uString_newFromLiteral(
317 &pData,
318 libreoffice_internal::ConstCharArrayDetector<T>::toPointer(
319 literal),
320 libreoffice_internal::ConstCharArrayDetector<T>::length, 0);
321 }
322#ifdef RTL_STRING_UNITTEST
323 rtl_string_unittest_const_literal = true;
324#endif
325 }
326
327#if defined LIBO_INTERNAL_ONLY1
328 /** @overload @since LibreOffice 5.3 */
329 template<typename T> OUString(
330 T & literal,
331 typename libreoffice_internal::ConstCharArrayDetector<
332 T, libreoffice_internal::Dummy>::TypeUtf16
333 = libreoffice_internal::Dummy()):
334 pData(nullptr)
335 {
336 assert((static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 337, __extension__ __PRETTY_FUNCTION__))
337 libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 337, __extension__ __PRETTY_FUNCTION__))
;
338 if (libreoffice_internal::ConstCharArrayDetector<T>::length == 0) {
339 rtl_uString_new(&pData);
340 } else {
341 rtl_uString_newFromStr_WithLength(
342 &pData,
343 libreoffice_internal::ConstCharArrayDetector<T>::toPointer(
344 literal),
345 libreoffice_internal::ConstCharArrayDetector<T>::length);
346 }
347 }
348#endif
349
350#if defined LIBO_INTERNAL_ONLY1 && defined RTL_STRING_UNITTEST
351 /// @cond INTERNAL
352 /**
353 * Only used by unittests to detect incorrect conversions.
354 * @internal
355 */
356 template< typename T >
357 OUString( T&, typename libreoffice_internal::ExceptConstCharArrayDetector< T >::Type = libreoffice_internal::Dummy() )
358 {
359 pData = NULL__null;
360 rtl_uString_newFromLiteral( &pData, "!!br0ken!!", 10, 0 ); // set to garbage
361 rtl_string_unittest_invalid_conversion = true;
362 }
363 /**
364 * Only used by unittests to detect incorrect conversions.
365 * @internal
366 */
367 template< typename T >
368 OUString( const T&, typename libreoffice_internal::ExceptCharArrayDetector< T >::Type = libreoffice_internal::Dummy() )
369 {
370 pData = NULL__null;
371 rtl_uString_newFromLiteral( &pData, "!!br0ken!!", 10, 0 ); // set to garbage
372 rtl_string_unittest_invalid_conversion = true;
373 }
374 /// @endcond
375#endif
376
377#ifdef LIBO_INTERNAL_ONLY1 // "RTL_FAST_STRING"
378 /// @cond INTERNAL
379 /**
380 New string from a string literal.
381
382 @since LibreOffice 5.0
383 */
384 template<std::size_t N> OUString(OUStringLiteral<N> const & literal):
385 pData(const_cast<rtl_uString *>(reinterpret_cast<rtl_uString const *>(&literal))) {}
386 template<std::size_t N> OUString(OUStringLiteral<N> &&) = delete;
387 /// @endcond
388#endif
389
390 /**
391 New string from an 8-Bit character buffer array.
392
393 @param value An 8-Bit character array.
394 @param length The number of character which should be converted.
395 The 8-Bit character array length must be
396 greater than or equal to this value.
397 @param encoding The text encoding from which the 8-Bit character
398 sequence should be converted.
399 @param convertFlags Flags which control the conversion.
400 see RTL_TEXTTOUNICODE_FLAGS_...
401
402 @exception std::bad_alloc is thrown if an out-of-memory condition occurs
403 */
404 OUString( const char * value, sal_Int32 length,
405 rtl_TextEncoding encoding,
406 sal_uInt32 convertFlags = OSTRING_TO_OUSTRING_CVTFLAGS(((sal_uInt32)0x0003) | ((sal_uInt32)0x0030) | ((sal_uInt32)0x0300
))
)
407 {
408 pData = NULL__null;
409 rtl_string2UString( &pData, value, length, encoding, convertFlags );
410 if (pData == NULL__null) {
411 throw std::bad_alloc();
412 }
413 }
414
415 /** Create a new string from an array of Unicode code points.
416
417 @param codePoints
418 an array of at least codePointCount code points, which each must be in
419 the range from 0 to 0x10FFFF, inclusive. May be null if codePointCount
420 is zero.
421
422 @param codePointCount
423 the non-negative number of code points.
424
425 @exception std::bad_alloc
426 is thrown if either an out-of-memory condition occurs or the resulting
427 number of UTF-16 code units would have been larger than SAL_MAX_INT32.
428
429 @since UDK 3.2.7
430 */
431 explicit OUString(
432 sal_uInt32 const * codePoints, sal_Int32 codePointCount):
433 pData(NULL__null)
434 {
435 rtl_uString_newFromCodePoints(&pData, codePoints, codePointCount);
436 if (pData == NULL__null) {
437 throw std::bad_alloc();
438 }
439 }
440
441#ifdef LIBO_INTERNAL_ONLY1 // "RTL_FAST_STRING"
442 /**
443 @overload
444 @internal
445 */
446 template< typename T1, typename T2 >
447 OUString( OUStringConcat< T1, T2 >&& c )
448 {
449 const sal_Int32 l = c.length();
450 pData = rtl_uString_alloc( l );
451 if (l != 0)
452 {
453 sal_Unicode* end = c.addData( pData->buffer );
454 pData->length = l;
455 *end = '\0';
456 // TODO realloc in case pData->length is noticeably smaller than l?
457 }
458 }
459
460 /**
461 @overload
462 @internal
463 */
464 template< typename T >
465 OUString( OUStringNumber< T >&& n )
466 : OUString( n.buf, n.length )
467 {}
468#endif
469
470#if defined LIBO_INTERNAL_ONLY1
471 OUString(std::u16string_view sv) {
472 if (sv.size() > sal_uInt32(std::numeric_limits<sal_Int32>::max())) {
473 throw std::bad_alloc();
474 }
475 pData = nullptr;
476 rtl_uString_newFromStr_WithLength(&pData, sv.data(), sv.size());
477 }
478#endif
479
480 /**
481 Release the string data.
482 */
483 ~OUString()
484 {
485 rtl_uString_release( pData );
486 }
487
488 /** Provides an OUString const & passing a storage pointer of an
489 rtl_uString * handle.
490 It is more convenient to use C++ OUString member functions when dealing
491 with rtl_uString * handles. Using this function avoids unnecessary
492 acquire()/release() calls for a temporary OUString object.
493
494 @param ppHandle
495 pointer to storage
496 @return
497 OUString const & based on given storage
498 */
499 static OUString const & unacquired( rtl_uString * const * ppHandle )
500 { return * reinterpret_cast< OUString const * >( ppHandle ); }
501
502 /**
503 Assign a new string.
504
505 @param str an OUString.
506 */
507 OUString & operator=( const OUString & str )
508 {
509 rtl_uString_assign( &pData, str.pData );
510 return *this;
511 }
512
513#if defined LIBO_INTERNAL_ONLY1
514 /**
515 Move assign a new string.
516
517 @param str an OUString.
518 @since LibreOffice 5.2
519 */
520 OUString & operator=( OUString && str ) noexcept
521 {
522 rtl_uString_release( pData );
523 pData = str.pData;
524 str.pData = nullptr;
525 rtl_uString_new( &str.pData );
526 return *this;
527 }
528#endif
529
530 /**
531 Assign a new string from an 8-Bit string literal that is expected to contain only
532 characters in the ASCII set (i.e. first 128 characters). This operator
533 allows an efficient and convenient way to assign OUString
534 instances from ASCII literals. When assigning strings from data that
535 is not pure ASCII, it needs to be converted to OUString by explicitly
536 providing the encoding to use for the conversion.
537
538 @param literal the 8-bit ASCII string literal
539
540 @since LibreOffice 3.6
541 */
542 template< typename T >
543 typename libreoffice_internal::ConstCharArrayDetector< T, OUString& >::Type operator=( T& literal )
544 {
545 assert((static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 546, __extension__ __PRETTY_FUNCTION__))
546 libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 546, __extension__ __PRETTY_FUNCTION__))
;
547 if (libreoffice_internal::ConstCharArrayDetector<T>::length == 0) {
548 rtl_uString_new(&pData);
549 } else {
550 rtl_uString_newFromLiteral(
551 &pData,
552 libreoffice_internal::ConstCharArrayDetector<T>::toPointer(
553 literal),
554 libreoffice_internal::ConstCharArrayDetector<T>::length, 0);
555 }
556 return *this;
557 }
558
559#if defined LIBO_INTERNAL_ONLY1
560 /** @overload @since LibreOffice 5.3 */
561 template<typename T>
562 typename
563 libreoffice_internal::ConstCharArrayDetector<T, OUString &>::TypeUtf16
564 operator =(T & literal) {
565 if (libreoffice_internal::ConstCharArrayDetector<T>::length == 0) {
566 rtl_uString_new(&pData);
567 } else {
568 rtl_uString_newFromStr_WithLength(
569 &pData,
570 libreoffice_internal::ConstCharArrayDetector<T>::toPointer(
571 literal),
572 libreoffice_internal::ConstCharArrayDetector<T>::length);
573 }
574 return *this;
575 }
576
577 /** @overload @since LibreOffice 5.4 */
578 template<std::size_t N> OUString & operator =(OUStringLiteral<N> const & literal) {
579 if (literal.getLength() == 0) {
580 rtl_uString_new(&pData);
581 } else {
582 rtl_uString_newFromStr_WithLength(&pData, literal.getStr(), literal.getLength());
583 }
584 return *this;
585 }
586
587 template<typename T>
588 OUString & operator =(OUStringNumber<T> && n) {
589 // n.length should never be zero, so no need to add an optimization for that case
590 rtl_uString_newFromStr_WithLength(&pData, n.buf, n.length);
591 return *this;
592 }
593
594 OUString & operator =(std::u16string_view sv) {
595 if (sv.empty()) {
596 rtl_uString_new(&pData);
597 } else {
598 rtl_uString_newFromStr_WithLength(&pData, sv.data(), sv.size());
599 }
600 return *this;
601 }
602#endif
603
604#if defined LIBO_INTERNAL_ONLY1
605 /**
606 Append the contents of an OUStringBuffer to this string.
607
608 @param str an OUStringBuffer.
609
610 @exception std::bad_alloc is thrown if an out-of-memory condition occurs
611 @since LibreOffice 6.2
612 */
613 inline OUString & operator+=( const OUStringBuffer & str ) &;
614#endif
615
616 /**
617 Append a string to this string.
618
619 @param str an OUString.
620
621 @exception std::bad_alloc is thrown if an out-of-memory condition occurs
622 */
623 OUString & operator+=( const OUString & str )
624#if defined LIBO_INTERNAL_ONLY1
625 &
626#endif
627 {
628 return internalAppend(str.pData);
629 }
630#if defined LIBO_INTERNAL_ONLY1
631 void operator+=(OUString const &) && = delete;
632#endif
633
634 /** Append an ASCII string literal to this string.
635
636 @param literal an 8-bit ASCII-only string literal
637
638 @since LibreOffice 5.1
639 */
640 template<typename T>
641 typename libreoffice_internal::ConstCharArrayDetector<T, OUString &>::Type
642 operator +=(T & literal)
643#if defined LIBO_INTERNAL_ONLY1
644 &
645#endif
646 {
647 assert((static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 648, __extension__ __PRETTY_FUNCTION__))
648 libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 648, __extension__ __PRETTY_FUNCTION__))
;
649 rtl_uString_newConcatAsciiL(
650 &pData, pData,
651 libreoffice_internal::ConstCharArrayDetector<T>::toPointer(literal),
652 libreoffice_internal::ConstCharArrayDetector<T>::length);
653 return *this;
654 }
655#if defined LIBO_INTERNAL_ONLY1
656 template<typename T>
657 typename libreoffice_internal::ConstCharArrayDetector<T, OUString &>::Type
658 operator +=(T &) && = delete;
659#endif
660
661#if defined LIBO_INTERNAL_ONLY1
662 /** @overload @since LibreOffice 5.3 */
663 template<typename T>
664 typename
665 libreoffice_internal::ConstCharArrayDetector<T, OUString &>::TypeUtf16
666 operator +=(T & literal) & {
667 rtl_uString_newConcatUtf16L(
668 &pData, pData,
669 libreoffice_internal::ConstCharArrayDetector<T>::toPointer(literal),
670 libreoffice_internal::ConstCharArrayDetector<T>::length);
671 return *this;
672 }
673 template<typename T>
674 typename
675 libreoffice_internal::ConstCharArrayDetector<T, OUString &>::TypeUtf16
676 operator +=(T &) && = delete;
677
678 /** @overload @since LibreOffice 5.4 */
679 template<std::size_t N> OUString & operator +=(OUStringLiteral<N> const & literal) & {
680 rtl_uString_newConcatUtf16L(&pData, pData, literal.getStr(), literal.getLength());
681 return *this;
682 }
683 template<std::size_t N> void operator +=(OUStringLiteral<N> const &) && = delete;
684
685 OUString & operator +=(std::u16string_view sv) & {
686 if (sv.size() > sal_uInt32(std::numeric_limits<sal_Int32>::max())) {
687 throw std::bad_alloc();
688 }
689 rtl_uString_newConcatUtf16L(&pData, pData, sv.data(), sv.size());
690 return *this;
691 }
692 void operator +=(std::u16string_view) && = delete;
693#endif
694
695#ifdef LIBO_INTERNAL_ONLY1 // "RTL_FAST_STRING"
696 /**
697 @overload
698 @internal
699 */
700 template< typename T1, typename T2 >
701 OUString& operator+=( OUStringConcat< T1, T2 >&& c ) & {
702 sal_Int32 l = c.length();
703 if( l == 0 )
704 return *this;
705 l += pData->length;
706 rtl_uString_ensureCapacity( &pData, l );
707 sal_Unicode* end = c.addData( pData->buffer + pData->length );
708 *end = '\0';
709 pData->length = l;
710 return *this;
711 }
712 template<typename T1, typename T2> void operator +=(
713 OUStringConcat<T1, T2> &&) && = delete;
714
715 /**
716 @overload
717 @internal
718 */
719 template< typename T >
720 OUString& operator+=( OUStringNumber< T >&& n ) & {
721 sal_Int32 l = n.length;
722 if( l == 0 )
723 return *this;
724 l += pData->length;
725 rtl_uString_ensureCapacity( &pData, l );
726 sal_Unicode* end = addDataHelper( pData->buffer + pData->length, n.buf, n.length );
727 *end = '\0';
728 pData->length = l;
729 return *this;
730 }
731 template<typename T> void operator +=(
732 OUStringNumber<T> &&) && = delete;
733#endif
734
735 /**
736 Clears the string, i.e, makes a zero-character string
737 @since LibreOffice 4.4
738 */
739 void clear()
740 {
741 rtl_uString_new( &pData );
742 }
743
744 /**
745 Returns the length of this string.
746
747 The length is equal to the number of Unicode characters in this string.
748
749 @return the length of the sequence of characters represented by this
750 object.
751 */
752 sal_Int32 getLength() const { return pData->length; }
753
754 /**
755 Checks if a string is empty.
756
757 @return true if the string is empty;
758 false, otherwise.
759
760 @since LibreOffice 3.4
761 */
762 bool isEmpty() const
763 {
764 return pData->length == 0;
57
Assuming field 'length' is not equal to 0
58
Returning zero, which participates in a condition later
765 }
766
767 /**
768 Returns a pointer to the Unicode character buffer for this string.
769
770 It isn't necessarily NULL terminated.
771
772 @return a pointer to the Unicode characters buffer for this object.
773 */
774 const sal_Unicode * getStr() const SAL_RETURNS_NONNULL__attribute__((returns_nonnull)) { return pData->buffer; }
775
776 /**
777 Access to individual characters.
778
779 @param index must be non-negative and less than length.
780
781 @return the character at the given index.
782
783 @since LibreOffice 3.5
784 */
785 sal_Unicode operator [](sal_Int32 index) const {
786 // silence spurious -Werror=strict-overflow warnings from GCC 4.8.2
787 assert(index >= 0 && static_cast<sal_uInt32>(index) < static_cast<sal_uInt32>(getLength()))(static_cast <bool> (index >= 0 && static_cast
<sal_uInt32>(index) < static_cast<sal_uInt32>(
getLength())) ? void (0) : __assert_fail ("index >= 0 && static_cast<sal_uInt32>(index) < static_cast<sal_uInt32>(getLength())"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 787, __extension__ __PRETTY_FUNCTION__))
;
788 return getStr()[index];
789 }
790
791 /**
792 Compares two strings.
793
794 The comparison is based on the numeric value of each character in
795 the strings and return a value indicating their relationship.
796 This function can't be used for language specific sorting.
797
798 @param str the object to be compared.
799 @return 0 - if both strings are equal
800 < 0 - if this string is less than the string argument
801 > 0 - if this string is greater than the string argument
802 */
803 sal_Int32 compareTo( const OUString & str ) const
804 {
805 return rtl_ustr_compare_WithLength( pData->buffer, pData->length,
806 str.pData->buffer, str.pData->length );
807 }
808
809 /**
810 Compares two strings with a maximum count of characters.
811
812 The comparison is based on the numeric value of each character in
813 the strings and return a value indicating their relationship.
814 This function can't be used for language specific sorting.
815
816 @param str the object to be compared.
817 @param maxLength the maximum count of characters to be compared.
818 @return 0 - if both strings are equal
819 < 0 - if this string is less than the string argument
820 > 0 - if this string is greater than the string argument
821
822 @since UDK 3.2.7
823 */
824 sal_Int32 compareTo( const OUString & str, sal_Int32 maxLength ) const
825 {
826 return rtl_ustr_shortenedCompare_WithLength( pData->buffer, pData->length,
827 str.pData->buffer, str.pData->length, maxLength );
828 }
829
830 /**
831 Compares two strings in reverse order.
832
833 The comparison is based on the numeric value of each character in
834 the strings and return a value indicating their relationship.
835 This function can't be used for language specific sorting.
836
837 @param str the object to be compared.
838 @return 0 - if both strings are equal
839 < 0 - if this string is less than the string argument
840 > 0 - if this string is greater than the string argument
841 */
842#if defined LIBO_INTERNAL_ONLY1
843 sal_Int32 reverseCompareTo(std::u16string_view sv) const {
844 return rtl_ustr_reverseCompare_WithLength(
845 pData->buffer, pData->length, sv.data(), sv.size());
846 }
847#else
848 sal_Int32 reverseCompareTo( const OUString & str ) const
849 {
850 return rtl_ustr_reverseCompare_WithLength( pData->buffer, pData->length,
851 str.pData->buffer, str.pData->length );
852 }
853#endif
854
855 /**
856 @overload
857 This function accepts an ASCII string literal as its argument.
858 @since LibreOffice 4.1
859 */
860 template< typename T >
861 typename libreoffice_internal::ConstCharArrayDetector< T, sal_Int32 >::Type reverseCompareTo( T& literal ) const
862 {
863 assert((static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 864, __extension__ __PRETTY_FUNCTION__))
864 libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 864, __extension__ __PRETTY_FUNCTION__))
;
865 return rtl_ustr_asciil_reverseCompare_WithLength(
866 pData->buffer, pData->length,
867 libreoffice_internal::ConstCharArrayDetector<T>::toPointer(literal),
868 libreoffice_internal::ConstCharArrayDetector<T>::length);
869 }
870
871 /**
872 Perform a comparison of two strings.
873
874 The result is true if and only if second string
875 represents the same sequence of characters as the first string.
876 This function can't be used for language specific comparison.
877
878 @param str the object to be compared.
879 @return true if the strings are equal;
880 false, otherwise.
881 */
882 bool equals( const OUString & str ) const
883 {
884 if ( pData->length != str.pData->length )
885 return false;
886 if ( pData == str.pData )
887 return true;
888 return rtl_ustr_reverseCompare_WithLength( pData->buffer, pData->length,
889 str.pData->buffer, str.pData->length ) == 0;
890 }
891
892 /**
893 Perform an ASCII lowercase comparison of two strings.
894
895 The result is true if and only if second string
896 represents the same sequence of characters as the first string,
897 ignoring the case.
898 Character values between 65 and 90 (ASCII A-Z) are interpreted as
899 values between 97 and 122 (ASCII a-z).
900 This function can't be used for language specific comparison.
901
902 @param str the object to be compared.
903 @return true if the strings are equal;
904 false, otherwise.
905 */
906#if defined LIBO_INTERNAL_ONLY1
907 bool equalsIgnoreAsciiCase(std::u16string_view sv) const {
908 return
909 rtl_ustr_compareIgnoreAsciiCase_WithLength(
910 pData->buffer, pData->length, sv.data(), sv.size())
911 == 0;
912 }
913#else
914 bool equalsIgnoreAsciiCase( const OUString & str ) const
915 {
916 if ( pData->length != str.pData->length )
917 return false;
918 if ( pData == str.pData )
919 return true;
920 return rtl_ustr_compareIgnoreAsciiCase_WithLength( pData->buffer, pData->length,
921 str.pData->buffer, str.pData->length ) == 0;
922 }
923#endif
924
925 /**
926 Perform an ASCII lowercase comparison of two strings.
927
928 Compare the two strings with uppercase ASCII
929 character values between 65 and 90 (ASCII A-Z) interpreted as
930 values between 97 and 122 (ASCII a-z).
931 This function can't be used for language specific comparison.
932
933 @param str the object to be compared.
934 @return 0 - if both strings are equal
935 < 0 - if this string is less than the string argument
936 > 0 - if this string is greater than the string argument
937
938 @since LibreOffice 4.0
939 */
940#if defined LIBO_INTERNAL_ONLY1
941 sal_Int32 compareToIgnoreAsciiCase(std::u16string_view sv) const {
942 return rtl_ustr_compareIgnoreAsciiCase_WithLength(
943 pData->buffer, pData->length, sv.data(), sv.size());
944 }
945#else
946 sal_Int32 compareToIgnoreAsciiCase( const OUString & str ) const
947 {
948 return rtl_ustr_compareIgnoreAsciiCase_WithLength( pData->buffer, pData->length,
949 str.pData->buffer, str.pData->length );
950 }
951#endif
952
953 /**
954 @overload
955 This function accepts an ASCII string literal as its argument.
956 @since LibreOffice 3.6
957 */
958 template< typename T >
959 typename libreoffice_internal::ConstCharArrayDetector< T, bool >::Type equalsIgnoreAsciiCase( T& literal ) const
960 {
961 assert((static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 962, __extension__ __PRETTY_FUNCTION__))
962 libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 962, __extension__ __PRETTY_FUNCTION__))
;
963 return
964 (pData->length
965 == libreoffice_internal::ConstCharArrayDetector<T>::length)
966 && (rtl_ustr_ascii_compareIgnoreAsciiCase_WithLength(
967 pData->buffer, pData->length,
968 libreoffice_internal::ConstCharArrayDetector<T>::toPointer(
969 literal))
970 == 0);
971 }
972
973 /**
974 Match against a substring appearing in this string.
975
976 The result is true if and only if the second string appears as a substring
977 of this string, at the given position.
978 This function can't be used for language specific comparison.
979
980 @param str the object (substring) to be compared.
981 @param fromIndex the index to start the comparison from.
982 The index must be greater than or equal to 0
983 and less or equal as the string length.
984 @return true if str match with the characters in the string
985 at the given position;
986 false, otherwise.
987 */
988#if defined LIBO_INTERNAL_ONLY1
989 bool match(std::u16string_view sv, sal_Int32 fromIndex = 0) const {
990 return
991 rtl_ustr_shortenedCompare_WithLength(
992 pData->buffer + fromIndex, pData->length - fromIndex, sv.data(), sv.size(),
993 sv.size())
994 == 0;
995 }
996#else
997 bool match( const OUString & str, sal_Int32 fromIndex = 0 ) const
998 {
999 return rtl_ustr_shortenedCompare_WithLength( pData->buffer+fromIndex, pData->length-fromIndex,
1000 str.pData->buffer, str.pData->length, str.pData->length ) == 0;
1001 }
1002#endif
1003
1004 /**
1005 @overload
1006 This function accepts an ASCII string literal as its argument.
1007 @since LibreOffice 3.6
1008 */
1009 template< typename T >
1010 typename libreoffice_internal::ConstCharArrayDetector< T, bool >::Type match( T& literal, sal_Int32 fromIndex = 0 ) const
1011 {
1012 assert((static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 1013, __extension__ __PRETTY_FUNCTION__))
1013 libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 1013, __extension__ __PRETTY_FUNCTION__))
;
1014 return
1015 rtl_ustr_ascii_shortenedCompare_WithLength(
1016 pData->buffer+fromIndex, pData->length-fromIndex,
1017 libreoffice_internal::ConstCharArrayDetector<T>::toPointer(
1018 literal),
1019 libreoffice_internal::ConstCharArrayDetector<T>::length)
1020 == 0;
1021 }
1022
1023 /**
1024 Match against a substring appearing in this string, ignoring the case of
1025 ASCII letters.
1026
1027 The result is true if and only if the second string appears as a substring
1028 of this string, at the given position.
1029 Character values between 65 and 90 (ASCII A-Z) are interpreted as
1030 values between 97 and 122 (ASCII a-z).
1031 This function can't be used for language specific comparison.
1032
1033 @param str the object (substring) to be compared.
1034 @param fromIndex the index to start the comparison from.
1035 The index must be greater than or equal to 0
1036 and less than or equal to the string length.
1037 @return true if str match with the characters in the string
1038 at the given position;
1039 false, otherwise.
1040 */
1041#if defined LIBO_INTERNAL_ONLY1
1042 bool matchIgnoreAsciiCase(std::u16string_view sv, sal_Int32 fromIndex = 0) const {
1043 return
1044 rtl_ustr_shortenedCompareIgnoreAsciiCase_WithLength(
1045 pData->buffer + fromIndex, pData->length - fromIndex, sv.data(), sv.size(),
1046 sv.size())
1047 == 0;
1048 }
1049#else
1050 bool matchIgnoreAsciiCase( const OUString & str, sal_Int32 fromIndex = 0 ) const
1051 {
1052 return rtl_ustr_shortenedCompareIgnoreAsciiCase_WithLength( pData->buffer+fromIndex, pData->length-fromIndex,
1053 str.pData->buffer, str.pData->length,
1054 str.pData->length ) == 0;
1055 }
1056#endif
1057
1058 /**
1059 @overload
1060 This function accepts an ASCII string literal as its argument.
1061 @since LibreOffice 3.6
1062 */
1063 template< typename T >
1064 typename libreoffice_internal::ConstCharArrayDetector< T, bool >::Type matchIgnoreAsciiCase( T& literal, sal_Int32 fromIndex = 0 ) const
1065 {
1066 assert((static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 1067, __extension__ __PRETTY_FUNCTION__))
1067 libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 1067, __extension__ __PRETTY_FUNCTION__))
;
1068 return
1069 rtl_ustr_ascii_shortenedCompareIgnoreAsciiCase_WithLength(
1070 pData->buffer+fromIndex, pData->length-fromIndex,
1071 libreoffice_internal::ConstCharArrayDetector<T>::toPointer(
1072 literal),
1073 libreoffice_internal::ConstCharArrayDetector<T>::length)
1074 == 0;
1075 }
1076
1077 /**
1078 Compares two strings.
1079
1080 The comparison is based on the numeric value of each character in
1081 the strings and return a value indicating their relationship.
1082 Since this method is optimized for performance, the ASCII character
1083 values are not converted in any way. The caller has to make sure that
1084 all ASCII characters are in the allowed range between 0 and 127.
1085 The ASCII string must be NULL-terminated.
1086 This function can't be used for language specific sorting.
1087
1088 @param asciiStr the 8-Bit ASCII character string to be compared.
1089 @return 0 - if both strings are equal
1090 < 0 - if this string is less than the string argument
1091 > 0 - if this string is greater than the string argument
1092 */
1093 sal_Int32 compareToAscii( const char* asciiStr ) const
1094 {
1095 return rtl_ustr_ascii_compare_WithLength( pData->buffer, pData->length, asciiStr );
1096 }
1097
1098 /**
1099 Compares two strings with a maximum count of characters.
1100
1101 The comparison is based on the numeric value of each character in
1102 the strings and return a value indicating their relationship.
1103 Since this method is optimized for performance, the ASCII character
1104 values are not converted in any way. The caller has to make sure that
1105 all ASCII characters are in the allowed range between 0 and 127.
1106 The ASCII string must be NULL-terminated.
1107 This function can't be used for language specific sorting.
1108
1109 @deprecated This is a confusing overload with unexpectedly different
1110 semantics from the one-parameter form, so it is marked as deprecated.
1111 Practically all uses compare the return value against zero and can thus
1112 be replaced with uses of startsWith.
1113
1114 @param asciiStr the 8-Bit ASCII character string to be compared.
1115 @param maxLength the maximum count of characters to be compared.
1116 @return 0 - if both strings are equal
1117 < 0 - if this string is less than the string argument
1118 > 0 - if this string is greater than the string argument
1119 */
1120 SAL_DEPRECATED(__attribute__((deprecated("replace s1.compareToAscii(s2, strlen(s2)) == 0 with s1.startsWith(s2)"
)))
1121 "replace s1.compareToAscii(s2, strlen(s2)) == 0 with s1.startsWith(s2)")__attribute__((deprecated("replace s1.compareToAscii(s2, strlen(s2)) == 0 with s1.startsWith(s2)"
)))
1122 sal_Int32 compareToAscii( const char * asciiStr, sal_Int32 maxLength ) const
1123 {
1124 return rtl_ustr_ascii_shortenedCompare_WithLength( pData->buffer, pData->length,
1125 asciiStr, maxLength );
1126 }
1127
1128 /**
1129 Compares two strings in reverse order.
1130
1131 This could be useful, if normally both strings start with the same
1132 content. The comparison is based on the numeric value of each character
1133 in the strings and return a value indicating their relationship.
1134 Since this method is optimized for performance, the ASCII character
1135 values are not converted in any way. The caller has to make sure that
1136 all ASCII characters are in the allowed range between 0 and 127.
1137 The ASCII string must be NULL-terminated and must be greater than
1138 or equal to asciiStrLength.
1139 This function can't be used for language specific sorting.
1140
1141 @param asciiStr the 8-Bit ASCII character string to be compared.
1142 @param asciiStrLength the length of the ascii string
1143 @return 0 - if both strings are equal
1144 < 0 - if this string is less than the string argument
1145 > 0 - if this string is greater than the string argument
1146 */
1147 sal_Int32 reverseCompareToAsciiL( const char * asciiStr, sal_Int32 asciiStrLength ) const
1148 {
1149 return rtl_ustr_asciil_reverseCompare_WithLength( pData->buffer, pData->length,
1150 asciiStr, asciiStrLength );
1151 }
1152
1153 /**
1154 Perform a comparison of two strings.
1155
1156 The result is true if and only if second string
1157 represents the same sequence of characters as the first string.
1158 Since this method is optimized for performance, the ASCII character
1159 values are not converted in any way. The caller has to make sure that
1160 all ASCII characters are in the allowed range between 0 and 127.
1161 The ASCII string must be NULL-terminated.
1162 This function can't be used for language specific comparison.
1163
1164 @param asciiStr the 8-Bit ASCII character string to be compared.
1165 @return true if the strings are equal;
1166 false, otherwise.
1167 */
1168 bool equalsAscii( const char* asciiStr ) const
1169 {
1170 return rtl_ustr_ascii_compare_WithLength( pData->buffer, pData->length,
1171 asciiStr ) == 0;
1172 }
1173
1174 /**
1175 Perform a comparison of two strings.
1176
1177 The result is true if and only if second string
1178 represents the same sequence of characters as the first string.
1179 Since this method is optimized for performance, the ASCII character
1180 values are not converted in any way. The caller has to make sure that
1181 all ASCII characters are in the allowed range between 0 and 127.
1182 The ASCII string must be NULL-terminated and must be greater than
1183 or equal to asciiStrLength.
1184 This function can't be used for language specific comparison.
1185
1186 @param asciiStr the 8-Bit ASCII character string to be compared.
1187 @param asciiStrLength the length of the ascii string
1188 @return true if the strings are equal;
1189 false, otherwise.
1190 */
1191 bool equalsAsciiL( const char* asciiStr, sal_Int32 asciiStrLength ) const
1192 {
1193 if ( pData->length != asciiStrLength )
1194 return false;
1195
1196 return rtl_ustr_asciil_reverseEquals_WithLength(
1197 pData->buffer, asciiStr, asciiStrLength );
1198 }
1199
1200 /**
1201 Perform an ASCII lowercase comparison of two strings.
1202
1203 The result is true if and only if second string
1204 represents the same sequence of characters as the first string,
1205 ignoring the case.
1206 Character values between 65 and 90 (ASCII A-Z) are interpreted as
1207 values between 97 and 122 (ASCII a-z).
1208 Since this method is optimized for performance, the ASCII character
1209 values are not converted in any way. The caller has to make sure that
1210 all ASCII characters are in the allowed range between 0 and 127.
1211 The ASCII string must be NULL-terminated.
1212 This function can't be used for language specific comparison.
1213
1214 @param asciiStr the 8-Bit ASCII character string to be compared.
1215 @return true if the strings are equal;
1216 false, otherwise.
1217 */
1218 bool equalsIgnoreAsciiCaseAscii( const char * asciiStr ) const
1219 {
1220 return rtl_ustr_ascii_compareIgnoreAsciiCase_WithLength( pData->buffer, pData->length, asciiStr ) == 0;
1221 }
1222
1223 /**
1224 Compares two ASCII strings ignoring case
1225
1226 The comparison is based on the numeric value of each character in
1227 the strings and return a value indicating their relationship.
1228 Since this method is optimized for performance, the ASCII character
1229 values are not converted in any way. The caller has to make sure that
1230 all ASCII characters are in the allowed range between 0 and 127.
1231 The ASCII string must be NULL-terminated.
1232 This function can't be used for language specific sorting.
1233
1234 @param asciiStr the 8-Bit ASCII character string to be compared.
1235 @return 0 - if both strings are equal
1236 < 0 - if this string is less than the string argument
1237 > 0 - if this string is greater than the string argument
1238
1239 @since LibreOffice 3.5
1240 */
1241 sal_Int32 compareToIgnoreAsciiCaseAscii( const char * asciiStr ) const
1242 {
1243 return rtl_ustr_ascii_compareIgnoreAsciiCase_WithLength( pData->buffer, pData->length, asciiStr );
1244 }
1245
1246 /**
1247 Perform an ASCII lowercase comparison of two strings.
1248
1249 The result is true if and only if second string
1250 represents the same sequence of characters as the first string,
1251 ignoring the case.
1252 Character values between 65 and 90 (ASCII A-Z) are interpreted as
1253 values between 97 and 122 (ASCII a-z).
1254 Since this method is optimized for performance, the ASCII character
1255 values are not converted in any way. The caller has to make sure that
1256 all ASCII characters are in the allowed range between 0 and 127.
1257 The ASCII string must be NULL-terminated and must be greater than
1258 or equal to asciiStrLength.
1259 This function can't be used for language specific comparison.
1260
1261 @param asciiStr the 8-Bit ASCII character string to be compared.
1262 @param asciiStrLength the length of the ascii string
1263 @return true if the strings are equal;
1264 false, otherwise.
1265 */
1266 bool equalsIgnoreAsciiCaseAsciiL( const char * asciiStr, sal_Int32 asciiStrLength ) const
1267 {
1268 if ( pData->length != asciiStrLength )
1269 return false;
1270
1271 return rtl_ustr_ascii_compareIgnoreAsciiCase_WithLength( pData->buffer, pData->length, asciiStr ) == 0;
1272 }
1273
1274 /**
1275 Match against a substring appearing in this string.
1276
1277 The result is true if and only if the second string appears as a substring
1278 of this string, at the given position.
1279 Since this method is optimized for performance, the ASCII character
1280 values are not converted in any way. The caller has to make sure that
1281 all ASCII characters are in the allowed range between 0 and 127.
1282 The ASCII string must be NULL-terminated and must be greater than or
1283 equal to asciiStrLength.
1284 This function can't be used for language specific comparison.
1285
1286 @param asciiStr the object (substring) to be compared.
1287 @param asciiStrLength the length of asciiStr.
1288 @param fromIndex the index to start the comparison from.
1289 The index must be greater than or equal to 0
1290 and less than or equal to the string length.
1291 @return true if str match with the characters in the string
1292 at the given position;
1293 false, otherwise.
1294 */
1295 bool matchAsciiL( const char* asciiStr, sal_Int32 asciiStrLength, sal_Int32 fromIndex = 0 ) const
1296 {
1297 return rtl_ustr_ascii_shortenedCompare_WithLength( pData->buffer+fromIndex, pData->length-fromIndex,
1298 asciiStr, asciiStrLength ) == 0;
1299 }
1300
1301 // This overload is left undefined, to detect calls of matchAsciiL that
1302 // erroneously use RTL_CONSTASCII_USTRINGPARAM instead of
1303 // RTL_CONSTASCII_STRINGPARAM (but would lead to ambiguities on 32 bit
1304 // platforms):
1305#if SAL_TYPES_SIZEOFLONG8 == 8
1306 void matchAsciiL(char const *, sal_Int32, rtl_TextEncoding) const;
1307#endif
1308
1309 /**
1310 Match against a substring appearing in this string, ignoring the case of
1311 ASCII letters.
1312
1313 The result is true if and only if the second string appears as a substring
1314 of this string, at the given position.
1315 Character values between 65 and 90 (ASCII A-Z) are interpreted as
1316 values between 97 and 122 (ASCII a-z).
1317 Since this method is optimized for performance, the ASCII character
1318 values are not converted in any way. The caller has to make sure that
1319 all ASCII characters are in the allowed range between 0 and 127.
1320 The ASCII string must be NULL-terminated and must be greater than or
1321 equal to asciiStrLength.
1322 This function can't be used for language specific comparison.
1323
1324 @param asciiStr the 8-Bit ASCII character string to be compared.
1325 @param asciiStrLength the length of the ascii string
1326 @param fromIndex the index to start the comparison from.
1327 The index must be greater than or equal to 0
1328 and less than or equal to the string length.
1329 @return true if str match with the characters in the string
1330 at the given position;
1331 false, otherwise.
1332 */
1333 bool matchIgnoreAsciiCaseAsciiL( const char* asciiStr, sal_Int32 asciiStrLength, sal_Int32 fromIndex = 0 ) const
1334 {
1335 return rtl_ustr_ascii_shortenedCompareIgnoreAsciiCase_WithLength( pData->buffer+fromIndex, pData->length-fromIndex,
1336 asciiStr, asciiStrLength ) == 0;
1337 }
1338
1339 // This overload is left undefined, to detect calls of
1340 // matchIgnoreAsciiCaseAsciiL that erroneously use
1341 // RTL_CONSTASCII_USTRINGPARAM instead of RTL_CONSTASCII_STRINGPARAM (but
1342 // would lead to ambiguities on 32 bit platforms):
1343#if SAL_TYPES_SIZEOFLONG8 == 8
1344 void matchIgnoreAsciiCaseAsciiL(char const *, sal_Int32, rtl_TextEncoding)
1345 const;
1346#endif
1347
1348 /**
1349 Check whether this string starts with a given substring.
1350
1351 @param str the substring to be compared
1352
1353 @param rest if non-null, and this function returns true, then assign a
1354 copy of the remainder of this string to *rest. Available since
1355 LibreOffice 4.2
1356
1357 @return true if and only if the given str appears as a substring at the
1358 start of this string
1359
1360 @since LibreOffice 4.0
1361 */
1362#if defined LIBO_INTERNAL_ONLY1
1363 bool startsWith(std::u16string_view sv, OUString * rest = nullptr) const {
1364 auto const b = match(sv);
1365 if (b && rest != nullptr) {
1366 *rest = copy(sv.size());
1367 }
1368 return b;
1369 }
1370#else
1371 bool startsWith(OUString const & str, OUString * rest = NULL__null) const {
1372 bool b = match(str);
1373 if (b && rest != NULL__null) {
1374 *rest = copy(str.getLength());
1375 }
1376 return b;
1377 }
1378#endif
1379
1380 /**
1381 @overload
1382 This function accepts an ASCII string literal as its argument.
1383 @since LibreOffice 4.0
1384 */
1385 template< typename T >
1386 typename libreoffice_internal::ConstCharArrayDetector< T, bool >::Type startsWith(
1387 T & literal, OUString * rest = NULL__null) const
1388 {
1389 assert((static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 1390, __extension__ __PRETTY_FUNCTION__))
1390 libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 1390, __extension__ __PRETTY_FUNCTION__))
;
1391 bool b
1392 = (libreoffice_internal::ConstCharArrayDetector<T>::length
1393 <= sal_uInt32(pData->length))
1394 && rtl_ustr_asciil_reverseEquals_WithLength(
1395 pData->buffer,
1396 libreoffice_internal::ConstCharArrayDetector<T>::toPointer(
1397 literal),
1398 libreoffice_internal::ConstCharArrayDetector<T>::length);
1399 if (b && rest != NULL__null) {
1400 *rest = copy(
1401 libreoffice_internal::ConstCharArrayDetector<T>::length);
1402 }
1403 return b;
1404 }
1405
1406 /**
1407 Check whether this string starts with a given string, ignoring the case of
1408 ASCII letters.
1409
1410 Character values between 65 and 90 (ASCII A-Z) are interpreted as
1411 values between 97 and 122 (ASCII a-z).
1412 This function can't be used for language specific comparison.
1413
1414 @param str the substring to be compared
1415
1416 @param rest if non-null, and this function returns true, then assign a
1417 copy of the remainder of this string to *rest. Available since
1418 LibreOffice 4.2
1419
1420 @return true if and only if the given str appears as a substring at the
1421 start of this string, ignoring the case of ASCII letters ("A"--"Z" and
1422 "a"--"z")
1423
1424 @since LibreOffice 4.0
1425 */
1426#if defined LIBO_INTERNAL_ONLY1
1427 bool startsWithIgnoreAsciiCase(std::u16string_view sv, OUString * rest = nullptr) const {
1428 auto const b = matchIgnoreAsciiCase(sv);
1429 if (b && rest != nullptr) {
1430 *rest = copy(sv.size());
1431 }
1432 return b;
1433 }
1434#else
1435 bool startsWithIgnoreAsciiCase(OUString const & str, OUString * rest = NULL__null)
1436 const
1437 {
1438 bool b = matchIgnoreAsciiCase(str);
1439 if (b && rest != NULL__null) {
1440 *rest = copy(str.getLength());
1441 }
1442 return b;
1443 }
1444#endif
1445
1446 /**
1447 @overload
1448 This function accepts an ASCII string literal as its argument.
1449 @since LibreOffice 4.0
1450 */
1451 template< typename T >
1452 typename libreoffice_internal::ConstCharArrayDetector< T, bool >::Type
1453 startsWithIgnoreAsciiCase(T & literal, OUString * rest = NULL__null) const
1454 {
1455 assert((static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 1456, __extension__ __PRETTY_FUNCTION__))
1456 libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 1456, __extension__ __PRETTY_FUNCTION__))
;
1457 bool b
1458 = (rtl_ustr_ascii_compareIgnoreAsciiCase_WithLengths(
1459 pData->buffer,
1460 libreoffice_internal::ConstCharArrayDetector<T>::length,
1461 libreoffice_internal::ConstCharArrayDetector<T>::toPointer(
1462 literal),
1463 libreoffice_internal::ConstCharArrayDetector<T>::length)
1464 == 0);
1465 if (b && rest != NULL__null) {
1466 *rest = copy(
1467 libreoffice_internal::ConstCharArrayDetector<T>::length);
1468 }
1469 return b;
1470 }
1471
1472 /**
1473 Check whether this string ends with a given substring.
1474
1475 @param str the substring to be compared
1476
1477 @param rest if non-null, and this function returns true, then assign a
1478 copy of the remainder of this string to *rest. Available since
1479 LibreOffice 4.2
1480
1481 @return true if and only if the given str appears as a substring at the
1482 end of this string
1483
1484 @since LibreOffice 3.6
1485 */
1486#if defined LIBO_INTERNAL_ONLY1
1487 bool endsWith(std::u16string_view sv, OUString * rest = nullptr) const {
1488 auto const b = sv.size() <= sal_uInt32(pData->length)
1489 && match(sv, pData->length - sv.size());
1490 if (b && rest != nullptr) {
1491 *rest = copy(0, (pData->length - sv.size()));
1492 }
1493 return b;
1494 }
1495#else
1496 bool endsWith(OUString const & str, OUString * rest = NULL__null) const {
1497 bool b = str.getLength() <= getLength()
1498 && match(str, getLength() - str.getLength());
1499 if (b && rest != NULL__null) {
1500 *rest = copy(0, getLength() - str.getLength());
1501 }
1502 return b;
1503 }
1504#endif
1505
1506 /**
1507 @overload
1508 This function accepts an ASCII string literal as its argument.
1509 @since LibreOffice 3.6
1510 */
1511 template< typename T >
1512 typename libreoffice_internal::ConstCharArrayDetector< T, bool >::Type
1513 endsWith(T & literal, OUString * rest = NULL__null) const
1514 {
1515 assert((static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 1516, __extension__ __PRETTY_FUNCTION__))
1516 libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 1516, __extension__ __PRETTY_FUNCTION__))
;
1517 bool b
1518 = (libreoffice_internal::ConstCharArrayDetector<T>::length
1519 <= sal_uInt32(pData->length))
1520 && rtl_ustr_asciil_reverseEquals_WithLength(
1521 (pData->buffer + pData->length
1522 - libreoffice_internal::ConstCharArrayDetector<T>::length),
1523 libreoffice_internal::ConstCharArrayDetector<T>::toPointer(
1524 literal),
1525 libreoffice_internal::ConstCharArrayDetector<T>::length);
1526 if (b && rest != NULL__null) {
1527 *rest = copy(
1528 0,
1529 (getLength()
1530 - libreoffice_internal::ConstCharArrayDetector<T>::length));
1531 }
1532 return b;
1533 }
1534
1535 /**
1536 Check whether this string ends with a given ASCII string.
1537
1538 @param asciiStr a sequence of at least asciiStrLength ASCII characters
1539 (bytes in the range 0x00--0x7F)
1540 @param asciiStrLength the length of asciiStr; must be non-negative
1541 @return true if this string ends with asciiStr; otherwise, false is
1542 returned
1543
1544 @since UDK 3.2.7
1545 */
1546 bool endsWithAsciiL(char const * asciiStr, sal_Int32 asciiStrLength)
1547 const
1548 {
1549 return asciiStrLength <= pData->length
1550 && rtl_ustr_asciil_reverseEquals_WithLength(
1551 pData->buffer + pData->length - asciiStrLength, asciiStr,
1552 asciiStrLength);
1553 }
1554
1555 /**
1556 Check whether this string ends with a given string, ignoring the case of
1557 ASCII letters.
1558
1559 Character values between 65 and 90 (ASCII A-Z) are interpreted as
1560 values between 97 and 122 (ASCII a-z).
1561 This function can't be used for language specific comparison.
1562
1563 @param str the substring to be compared
1564
1565 @param rest if non-null, and this function returns true, then assign a
1566 copy of the remainder of this string to *rest. Available since
1567 LibreOffice 4.2
1568
1569 @return true if and only if the given str appears as a substring at the
1570 end of this string, ignoring the case of ASCII letters ("A"--"Z" and
1571 "a"--"z")
1572
1573 @since LibreOffice 3.6
1574 */
1575#if defined LIBO_INTERNAL_ONLY1
1576 bool endsWithIgnoreAsciiCase(std::u16string_view sv, OUString * rest = nullptr) const {
1577 auto const b = sv.size() <= sal_uInt32(pData->length)
1578 && matchIgnoreAsciiCase(sv, pData->length - sv.size());
1579 if (b && rest != nullptr) {
1580 *rest = copy(0, pData->length - sv.size());
1581 }
1582 return b;
1583 }
1584#else
1585 bool endsWithIgnoreAsciiCase(OUString const & str, OUString * rest = NULL__null) const
1586 {
1587 bool b = str.getLength() <= getLength()
1588 && matchIgnoreAsciiCase(str, getLength() - str.getLength());
1589 if (b && rest != NULL__null) {
1590 *rest = copy(0, getLength() - str.getLength());
1591 }
1592 return b;
1593 }
1594#endif
1595
1596 /**
1597 @overload
1598 This function accepts an ASCII string literal as its argument.
1599 @since LibreOffice 3.6
1600 */
1601 template< typename T >
1602 typename libreoffice_internal::ConstCharArrayDetector< T, bool >::Type
1603 endsWithIgnoreAsciiCase(T & literal, OUString * rest = NULL__null) const
1604 {
1605 assert((static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 1606, __extension__ __PRETTY_FUNCTION__))
1606 libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 1606, __extension__ __PRETTY_FUNCTION__))
;
1607 bool b
1608 = (libreoffice_internal::ConstCharArrayDetector<T>::length
1609 <= sal_uInt32(pData->length))
1610 && (rtl_ustr_ascii_compareIgnoreAsciiCase_WithLengths(
1611 (pData->buffer + pData->length
1612 - libreoffice_internal::ConstCharArrayDetector<T>::length),
1613 libreoffice_internal::ConstCharArrayDetector<T>::length,
1614 libreoffice_internal::ConstCharArrayDetector<T>::toPointer(
1615 literal),
1616 libreoffice_internal::ConstCharArrayDetector<T>::length)
1617 == 0);
1618 if (b && rest != NULL__null) {
1619 *rest = copy(
1620 0,
1621 (getLength()
1622 - libreoffice_internal::ConstCharArrayDetector<T>::length));
1623 }
1624 return b;
1625 }
1626
1627 /**
1628 Check whether this string ends with a given ASCII string, ignoring the
1629 case of ASCII letters.
1630
1631 @param asciiStr a sequence of at least asciiStrLength ASCII characters
1632 (bytes in the range 0x00--0x7F)
1633 @param asciiStrLength the length of asciiStr; must be non-negative
1634 @return true if this string ends with asciiStr, ignoring the case of ASCII
1635 letters ("A"--"Z" and "a"--"z"); otherwise, false is returned
1636 */
1637 bool endsWithIgnoreAsciiCaseAsciiL(
1638 char const * asciiStr, sal_Int32 asciiStrLength) const
1639 {
1640 return asciiStrLength <= pData->length
1641 && (rtl_ustr_ascii_compareIgnoreAsciiCase_WithLengths(
1642 pData->buffer + pData->length - asciiStrLength,
1643 asciiStrLength, asciiStr, asciiStrLength)
1644 == 0);
1645 }
1646
1647 friend bool operator == ( const OUString& rStr1, const OUString& rStr2 )
1648 { return rStr1.equals(rStr2); }
1649
1650 friend bool operator != ( const OUString& rStr1, const OUString& rStr2 )
1651 { return !(operator == ( rStr1, rStr2 )); }
1652
1653 friend bool operator < ( const OUString& rStr1, const OUString& rStr2 )
1654 { return rStr1.compareTo( rStr2 ) < 0; }
1655 friend bool operator > ( const OUString& rStr1, const OUString& rStr2 )
1656 { return rStr1.compareTo( rStr2 ) > 0; }
1657 friend bool operator <= ( const OUString& rStr1, const OUString& rStr2 )
1658 { return rStr1.compareTo( rStr2 ) <= 0; }
1659 friend bool operator >= ( const OUString& rStr1, const OUString& rStr2 )
1660 { return rStr1.compareTo( rStr2 ) >= 0; }
1661
1662#if defined LIBO_INTERNAL_ONLY1
1663
1664 template<typename T> friend typename libreoffice_internal::CharPtrDetector<T, bool>::TypeUtf16
1665 operator ==(OUString const & s1, T const & s2) {
1666 return rtl_ustr_compare_WithLength(s1.getStr(), s1.getLength(), s2, rtl_ustr_getLength(s2))
1667 == 0;
1668 }
1669
1670 template<typename T>
1671 friend typename libreoffice_internal::NonConstCharArrayDetector<T, bool>::TypeUtf16
1672 operator ==(OUString const & s1, T & s2) {
1673 return rtl_ustr_compare_WithLength(s1.getStr(), s1.getLength(), s2, rtl_ustr_getLength(s2))
1674 == 0;
1675 }
1676
1677 template<typename T> friend typename libreoffice_internal::CharPtrDetector<T, bool>::TypeUtf16
1678 operator ==(T const & s1, OUString const & s2) {
1679 return rtl_ustr_compare_WithLength(s1, rtl_ustr_getLength(s1), s2.getStr(), s2.getLength())
1680 == 0;
1681 }
1682
1683 template<typename T>
1684 friend typename libreoffice_internal::NonConstCharArrayDetector<T, bool>::TypeUtf16
1685 operator ==(T & s1, OUString const & s2) {
1686 return rtl_ustr_compare_WithLength(s1, rtl_ustr_getLength(s1), s2.getStr(), s2.getLength())
1687 == 0;
1688 }
1689
1690 template<typename T> friend typename libreoffice_internal::CharPtrDetector<T, bool>::TypeUtf16
1691 operator !=(OUString const & s1, T const & s2) { return !(s1 == s2); }
1692
1693 template<typename T>
1694 friend typename libreoffice_internal::NonConstCharArrayDetector<T, bool>::TypeUtf16
1695 operator !=(OUString const & s1, T & s2) { return !(s1 == s2); }
1696
1697 template<typename T> friend typename libreoffice_internal::CharPtrDetector<T, bool>::TypeUtf16
1698 operator !=(T const & s1, OUString const & s2) { return !(s1 == s2); }
1699
1700 template<typename T>
1701 friend typename libreoffice_internal::NonConstCharArrayDetector<T, bool>::TypeUtf16
1702 operator !=(T & s1, OUString const & s2) { return !(s1 == s2); }
1703
1704#else
1705
1706 friend bool operator == ( const OUString& rStr1, const sal_Unicode * pStr2 )
1707 { return rStr1.compareTo( pStr2 ) == 0; }
1708 friend bool operator == ( const sal_Unicode * pStr1, const OUString& rStr2 )
1709 { return OUString( pStr1 ).compareTo( rStr2 ) == 0; }
1710
1711 friend bool operator != ( const OUString& rStr1, const sal_Unicode * pStr2 )
1712 { return !(operator == ( rStr1, pStr2 )); }
1713 friend bool operator != ( const sal_Unicode * pStr1, const OUString& rStr2 )
1714 { return !(operator == ( pStr1, rStr2 )); }
1715
1716#endif
1717
1718 /**
1719 * Compare string to an ASCII string literal.
1720 *
1721 * This operator is equal to calling equalsAsciiL().
1722 *
1723 * @since LibreOffice 3.6
1724 */
1725 template< typename T >
1726 friend typename libreoffice_internal::ConstCharArrayDetector< T, bool >::Type operator==( const OUString& rString, T& literal )
1727 {
1728 assert((static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 1729, __extension__ __PRETTY_FUNCTION__))
1729 libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 1729, __extension__ __PRETTY_FUNCTION__))
;
1730 return rString.equalsAsciiL(
1731 libreoffice_internal::ConstCharArrayDetector<T>::toPointer(literal),
1732 libreoffice_internal::ConstCharArrayDetector<T>::length);
1733 }
1734 /**
1735 * Compare string to an ASCII string literal.
1736 *
1737 * This operator is equal to calling equalsAsciiL().
1738 *
1739 * @since LibreOffice 3.6
1740 */
1741 template< typename T >
1742 friend typename libreoffice_internal::ConstCharArrayDetector< T, bool >::Type operator==( T& literal, const OUString& rString )
1743 {
1744 assert((static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 1745, __extension__ __PRETTY_FUNCTION__))
1745 libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 1745, __extension__ __PRETTY_FUNCTION__))
;
1746 return rString.equalsAsciiL(
1747 libreoffice_internal::ConstCharArrayDetector<T>::toPointer(literal),
1748 libreoffice_internal::ConstCharArrayDetector<T>::length);
1749 }
1750 /**
1751 * Compare string to an ASCII string literal.
1752 *
1753 * This operator is equal to calling !equalsAsciiL().
1754 *
1755 * @since LibreOffice 3.6
1756 */
1757 template< typename T >
1758 friend typename libreoffice_internal::ConstCharArrayDetector< T, bool >::Type operator!=( const OUString& rString, T& literal )
1759 {
1760 assert((static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 1761, __extension__ __PRETTY_FUNCTION__))
1761 libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 1761, __extension__ __PRETTY_FUNCTION__))
;
1762 return !rString.equalsAsciiL(
1763 libreoffice_internal::ConstCharArrayDetector<T>::toPointer(literal),
1764 libreoffice_internal::ConstCharArrayDetector<T>::length);
1765 }
1766 /**
1767 * Compare string to an ASCII string literal.
1768 *
1769 * This operator is equal to calling !equalsAsciiL().
1770 *
1771 * @since LibreOffice 3.6
1772 */
1773 template< typename T >
1774 friend typename libreoffice_internal::ConstCharArrayDetector< T, bool >::Type operator!=( T& literal, const OUString& rString )
1775 {
1776 assert((static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 1777, __extension__ __PRETTY_FUNCTION__))
1777 libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 1777, __extension__ __PRETTY_FUNCTION__))
;
1778 return !rString.equalsAsciiL(
1779 libreoffice_internal::ConstCharArrayDetector<T>::toPointer(literal),
1780 libreoffice_internal::ConstCharArrayDetector<T>::length);
1781 }
1782
1783#if defined LIBO_INTERNAL_ONLY1
1784 /** @overload @since LibreOffice 5.3 */
1785 template<typename T> friend typename libreoffice_internal::ConstCharArrayDetector<T, bool>::TypeUtf16
1786 operator ==(OUString const & string, T & literal) {
1787 return
1788 rtl_ustr_reverseCompare_WithLength(
1789 string.pData->buffer, string.pData->length,
1790 libreoffice_internal::ConstCharArrayDetector<T>::toPointer(
1791 literal),
1792 libreoffice_internal::ConstCharArrayDetector<T>::length)
1793 == 0;
1794 }
1795 /** @overload @since LibreOffice 5.3 */
1796 template<typename T> friend typename libreoffice_internal::ConstCharArrayDetector<T, bool>::TypeUtf16
1797 operator ==(T & literal, OUString const & string) {
1798 return
1799 rtl_ustr_reverseCompare_WithLength(
1800 libreoffice_internal::ConstCharArrayDetector<T>::toPointer(
1801 literal),
1802 libreoffice_internal::ConstCharArrayDetector<T>::length,
1803 string.pData->buffer, string.pData->length)
1804 == 0;
1805 }
1806 /** @overload @since LibreOffice 5.3 */
1807 template<typename T> friend typename libreoffice_internal::ConstCharArrayDetector<T, bool>::TypeUtf16
1808 operator !=(OUString const & string, T & literal) {
1809 return
1810 rtl_ustr_reverseCompare_WithLength(
1811 string.pData->buffer, string.pData->length,
1812 libreoffice_internal::ConstCharArrayDetector<T>::toPointer(
1813 literal),
1814 libreoffice_internal::ConstCharArrayDetector<T>::length)
1815 != 0;
1816 }
1817 /** @overload @since LibreOffice 5.3 */
1818 template<typename T> friend typename libreoffice_internal::ConstCharArrayDetector<T, bool>::TypeUtf16
1819 operator !=(T & literal, OUString const & string) {
1820 return
1821 rtl_ustr_reverseCompare_WithLength(
1822 libreoffice_internal::ConstCharArrayDetector<T>::toPointer(
1823 literal),
1824 libreoffice_internal::ConstCharArrayDetector<T>::length,
1825 string.pData->buffer, string.pData->length)
1826 != 0;
1827 }
1828#endif
1829
1830#if defined LIBO_INTERNAL_ONLY1
1831 /// @cond INTERNAL
1832
1833 /* Comparison between OUString and OUStringLiteral.
1834
1835 @since LibreOffice 5.0
1836 */
1837
1838 template<std::size_t N>
1839 friend bool operator ==(OUString const & lhs, OUStringLiteral<N> const & rhs) {
1840 return
1841 rtl_ustr_reverseCompare_WithLength(
1842 lhs.pData->buffer, lhs.pData->length, rhs.getStr(), rhs.getLength())
1843 == 0;
1844 }
1845
1846 template<std::size_t N>
1847 friend bool operator !=(OUString const & lhs, OUStringLiteral<N> const & rhs) {
1848 return
1849 rtl_ustr_reverseCompare_WithLength(
1850 lhs.pData->buffer, lhs.pData->length, rhs.getStr(), rhs.getLength())
1851 != 0;
1852 }
1853
1854 template<std::size_t N>
1855 friend bool operator <(OUString const & lhs, OUStringLiteral<N> const & rhs) {
1856 return
1857 (rtl_ustr_compare_WithLength(
1858 lhs.pData->buffer, lhs.pData->length, rhs.getStr(), rhs.getLength()))
1859 < 0;
1860 }
1861
1862 template<std::size_t N>
1863 friend bool operator <=(OUString const & lhs, OUStringLiteral<N> const & rhs) {
1864 return
1865 (rtl_ustr_compare_WithLength(
1866 lhs.pData->buffer, lhs.pData->length, rhs.getStr(), rhs.getLength()))
1867 <= 0;
1868 }
1869
1870 template<std::size_t N>
1871 friend bool operator >(OUString const & lhs, OUStringLiteral<N> const & rhs) {
1872 return
1873 (rtl_ustr_compare_WithLength(
1874 lhs.pData->buffer, lhs.pData->length, rhs.getStr(), rhs.getLength()))
1875 > 0;
1876 }
1877
1878 template<std::size_t N>
1879 friend bool operator >=(OUString const & lhs, OUStringLiteral<N> const & rhs) {
1880 return
1881 (rtl_ustr_compare_WithLength(
1882 lhs.pData->buffer, lhs.pData->length, rhs.getStr(), rhs.getLength()))
1883 >= 0;
1884 }
1885
1886 template<std::size_t N>
1887 friend bool operator ==(OUStringLiteral<N> const & lhs, OUString const & rhs) {
1888 return
1889 rtl_ustr_reverseCompare_WithLength(
1890 lhs.getStr(), lhs.getLength(), rhs.pData->buffer, rhs.pData->length)
1891 == 0;
1892 }
1893
1894 template<std::size_t N>
1895 friend bool operator !=(OUStringLiteral<N> const & lhs, OUString const & rhs) {
1896 return
1897 rtl_ustr_reverseCompare_WithLength(
1898 lhs.getStr(), lhs.getLength(), rhs.pData->buffer, rhs.pData->length)
1899 != 0;
1900 }
1901
1902 template<std::size_t N>
1903 friend bool operator <(OUStringLiteral<N> const & lhs, OUString const & rhs) {
1904 return
1905 (rtl_ustr_compare_WithLength(
1906 lhs.getStr(), lhs.getLength(), rhs.pData->buffer, rhs.pData->length))
1907 < 0;
1908 }
1909
1910 template<std::size_t N>
1911 friend bool operator <=(OUStringLiteral<N> const & lhs, OUString const & rhs) {
1912 return
1913 (rtl_ustr_compare_WithLength(
1914 lhs.getStr(), lhs.getLength(), rhs.pData->buffer, rhs.pData->length))
1915 <= 0;
1916 }
1917
1918 template<std::size_t N>
1919 friend bool operator >(OUStringLiteral<N> const & lhs, OUString const & rhs) {
1920 return
1921 (rtl_ustr_compare_WithLength(
1922 lhs.getStr(), lhs.getLength(), rhs.pData->buffer, rhs.pData->length))
1923 > 0;
1924 }
1925
1926 template<std::size_t N>
1927 friend bool operator >=(OUStringLiteral<N> const & lhs, OUString const & rhs) {
1928 return
1929 (rtl_ustr_compare_WithLength(
1930 lhs.getStr(), lhs.getLength(), rhs.pData->buffer, rhs.pData->length))
1931 >= 0;
1932 }
1933
1934 /// @endcond
1935#endif
1936
1937#if defined LIBO_INTERNAL_ONLY1
1938 friend bool operator ==(OUString const & lhs, std::u16string_view rhs) {
1939 return
1940 rtl_ustr_reverseCompare_WithLength(
1941 lhs.pData->buffer, lhs.pData->length, rhs.data(), rhs.size())
1942 == 0;
1943 }
1944
1945 friend bool operator !=(OUString const & lhs, std::u16string_view rhs) {
1946 return
1947 rtl_ustr_reverseCompare_WithLength(
1948 lhs.pData->buffer, lhs.pData->length, rhs.data(), rhs.size())
1949 != 0;
1950 }
1951
1952 friend bool operator <(OUString const & lhs, std::u16string_view rhs) {
1953 return
1954 (rtl_ustr_compare_WithLength(
1955 lhs.pData->buffer, lhs.pData->length, rhs.data(), rhs.size()))
1956 < 0;
1957 }
1958
1959 friend bool operator <=(OUString const & lhs, std::u16string_view rhs) {
1960 return
1961 (rtl_ustr_compare_WithLength(
1962 lhs.pData->buffer, lhs.pData->length, rhs.data(), rhs.size()))
1963 <= 0;
1964 }
1965
1966 friend bool operator >(OUString const & lhs, std::u16string_view rhs) {
1967 return
1968 (rtl_ustr_compare_WithLength(
1969 lhs.pData->buffer, lhs.pData->length, rhs.data(), rhs.size()))
1970 > 0;
1971 }
1972
1973 friend bool operator >=(OUString const & lhs, std::u16string_view rhs) {
1974 return
1975 (rtl_ustr_compare_WithLength(
1976 lhs.pData->buffer, lhs.pData->length, rhs.data(), rhs.size()))
1977 >= 0;
1978 }
1979
1980 friend bool operator ==(std::u16string_view lhs, OUString const & rhs) {
1981 return
1982 rtl_ustr_reverseCompare_WithLength(
1983 lhs.data(), lhs.size(), rhs.pData->buffer, rhs.pData->length)
1984 == 0;
1985 }
1986
1987 friend bool operator !=(std::u16string_view lhs, OUString const & rhs) {
1988 return
1989 rtl_ustr_reverseCompare_WithLength(
1990 lhs.data(), lhs.size(), rhs.pData->buffer, rhs.pData->length)
1991 != 0;
1992 }
1993
1994 friend bool operator <(std::u16string_view lhs, OUString const & rhs) {
1995 return
1996 (rtl_ustr_compare_WithLength(
1997 lhs.data(), lhs.size(), rhs.pData->buffer, rhs.pData->length))
1998 < 0;
1999 }
2000
2001 friend bool operator <=(std::u16string_view lhs, OUString const & rhs) {
2002 return
2003 (rtl_ustr_compare_WithLength(
2004 lhs.data(), lhs.size(), rhs.pData->buffer, rhs.pData->length))
2005 <= 0;
2006 }
2007
2008 friend bool operator >(std::u16string_view lhs, OUString const & rhs) {
2009 return
2010 (rtl_ustr_compare_WithLength(
2011 lhs.data(), lhs.size(), rhs.pData->buffer, rhs.pData->length))
2012 > 0;
2013 }
2014
2015 friend bool operator >=(std::u16string_view lhs, OUString const & rhs) {
2016 return
2017 (rtl_ustr_compare_WithLength(
2018 lhs.data(), lhs.size(), rhs.pData->buffer, rhs.pData->length))
2019 >= 0;
2020 }
2021#endif
2022
2023 /**
2024 Returns a hashcode for this string.
2025
2026 @return a hash code value for this object.
2027
2028 @see rtl::OUStringHash for convenient use of std::unordered_map
2029 */
2030 sal_Int32 hashCode() const
2031 {
2032 return rtl_ustr_hashCode_WithLength( pData->buffer, pData->length );
2033 }
2034
2035 /**
2036 Returns the index within this string of the first occurrence of the
2037 specified character, starting the search at the specified index.
2038
2039 @param ch character to be located.
2040 @param fromIndex the index to start the search from.
2041 The index must be greater than or equal to 0
2042 and less than or equal to the string length.
2043 @return the index of the first occurrence of the character in the
2044 character sequence represented by this string that is
2045 greater than or equal to fromIndex, or
2046 -1 if the character does not occur.
2047 */
2048 sal_Int32 indexOf( sal_Unicode ch, sal_Int32 fromIndex = 0 ) const
2049 {
2050 sal_Int32 ret = rtl_ustr_indexOfChar_WithLength( pData->buffer+fromIndex, pData->length-fromIndex, ch );
2051 return (ret < 0 ? ret : ret+fromIndex);
2052 }
2053
2054 /**
2055 Returns the index within this string of the last occurrence of the
2056 specified character, searching backward starting at the end.
2057
2058 @param ch character to be located.
2059 @return the index of the last occurrence of the character in the
2060 character sequence represented by this string, or
2061 -1 if the character does not occur.
2062 */
2063 sal_Int32 lastIndexOf( sal_Unicode ch ) const
2064 {
2065 return rtl_ustr_lastIndexOfChar_WithLength( pData->buffer, pData->length, ch );
2066 }
2067
2068 /**
2069 Returns the index within this string of the last occurrence of the
2070 specified character, searching backward starting before the specified
2071 index.
2072
2073 @param ch character to be located.
2074 @param fromIndex the index before which to start the search.
2075 @return the index of the last occurrence of the character in the
2076 character sequence represented by this string that
2077 is less than fromIndex, or -1
2078 if the character does not occur before that point.
2079 */
2080 sal_Int32 lastIndexOf( sal_Unicode ch, sal_Int32 fromIndex ) const
2081 {
2082 return rtl_ustr_lastIndexOfChar_WithLength( pData->buffer, fromIndex, ch );
2083 }
2084
2085 /**
2086 Returns the index within this string of the first occurrence of the
2087 specified substring, starting at the specified index.
2088
2089 If str doesn't include any character, always -1 is
2090 returned. This is also the case, if both strings are empty.
2091
2092 @param str the substring to search for.
2093 @param fromIndex the index to start the search from.
2094 @return If the string argument occurs one or more times as a substring
2095 within this string at the starting index, then the index
2096 of the first character of the first such substring is
2097 returned. If it does not occur as a substring starting
2098 at fromIndex or beyond, -1 is returned.
2099 */
2100#if defined LIBO_INTERNAL_ONLY1
2101 sal_Int32 indexOf(std::u16string_view sv, sal_Int32 fromIndex = 0) const {
2102 auto const n = rtl_ustr_indexOfStr_WithLength(
2103 pData->buffer + fromIndex, pData->length - fromIndex, sv.data(), sv.size());
2104 return n < 0 ? n : n + fromIndex;
2105 }
2106#else
2107 sal_Int32 indexOf( const OUString & str, sal_Int32 fromIndex = 0 ) const
2108 {
2109 sal_Int32 ret = rtl_ustr_indexOfStr_WithLength( pData->buffer+fromIndex, pData->length-fromIndex,
2110 str.pData->buffer, str.pData->length );
2111 return (ret < 0 ? ret : ret+fromIndex);
2112 }
2113#endif
2114
2115 /**
2116 @overload
2117 This function accepts an ASCII string literal as its argument.
2118 @since LibreOffice 3.6
2119 */
2120 template< typename T >
2121 typename libreoffice_internal::ConstCharArrayDetector< T, sal_Int32 >::Type indexOf( T& literal, sal_Int32 fromIndex = 0 ) const
2122 {
2123 assert((static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 2124, __extension__ __PRETTY_FUNCTION__))
2124 libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 2124, __extension__ __PRETTY_FUNCTION__))
;
2125 sal_Int32 n = rtl_ustr_indexOfAscii_WithLength(
2126 pData->buffer + fromIndex, pData->length - fromIndex,
2127 libreoffice_internal::ConstCharArrayDetector<T>::toPointer(literal),
2128 libreoffice_internal::ConstCharArrayDetector<T>::length);
2129 return n < 0 ? n : n + fromIndex;
2130 }
2131
2132 /**
2133 Returns the index within this string of the first occurrence of the
2134 specified ASCII substring, starting at the specified index.
2135
2136 @param str
2137 the substring to be searched for. Need not be null-terminated, but must
2138 be at least as long as the specified len. Must only contain characters
2139 in the ASCII range 0x00--7F.
2140
2141 @param len
2142 the length of the substring; must be non-negative.
2143
2144 @param fromIndex
2145 the index to start the search from. Must be in the range from zero to
2146 the length of this string, inclusive.
2147
2148 @return
2149 the index (starting at 0) of the first character of the first occurrence
2150 of the substring within this string starting at the given fromIndex, or
2151 -1 if the substring does not occur. If len is zero, -1 is returned.
2152
2153 @since UDK 3.2.7
2154 */
2155 sal_Int32 indexOfAsciiL(
2156 char const * str, sal_Int32 len, sal_Int32 fromIndex = 0) const
2157 {
2158 sal_Int32 ret = rtl_ustr_indexOfAscii_WithLength(
2159 pData->buffer + fromIndex, pData->length - fromIndex, str, len);
2160 return ret < 0 ? ret : ret + fromIndex;
2161 }
2162
2163 // This overload is left undefined, to detect calls of indexOfAsciiL that
2164 // erroneously use RTL_CONSTASCII_USTRINGPARAM instead of
2165 // RTL_CONSTASCII_STRINGPARAM (but would lead to ambiguities on 32 bit
2166 // platforms):
2167#if SAL_TYPES_SIZEOFLONG8 == 8
2168 void indexOfAsciiL(char const *, sal_Int32 len, rtl_TextEncoding) const;
2169#endif
2170
2171 /**
2172 Returns the index within this string of the last occurrence of
2173 the specified substring, searching backward starting at the end.
2174
2175 The returned index indicates the starting index of the substring
2176 in this string.
2177 If str doesn't include any character, always -1 is
2178 returned. This is also the case, if both strings are empty.
2179
2180 @param str the substring to search for.
2181 @return If the string argument occurs one or more times as a substring
2182 within this string, then the index of the first character of
2183 the last such substring is returned. If it does not occur as
2184 a substring, -1 is returned.
2185 */
2186#if defined LIBO_INTERNAL_ONLY1
2187 sal_Int32 lastIndexOf(std::u16string_view sv) const {
2188 return rtl_ustr_lastIndexOfStr_WithLength(
2189 pData->buffer, pData->length, sv.data(), sv.size());
2190 }
2191#else
2192 sal_Int32 lastIndexOf( const OUString & str ) const
2193 {
2194 return rtl_ustr_lastIndexOfStr_WithLength( pData->buffer, pData->length,
2195 str.pData->buffer, str.pData->length );
2196 }
2197#endif
2198
2199 /**
2200 Returns the index within this string of the last occurrence of
2201 the specified substring, searching backward starting before the specified
2202 index.
2203
2204 The returned index indicates the starting index of the substring
2205 in this string.
2206 If str doesn't include any character, always -1 is
2207 returned. This is also the case, if both strings are empty.
2208
2209 @param str the substring to search for.
2210 @param fromIndex the index before which to start the search.
2211 @return If the string argument occurs one or more times as a substring
2212 within this string before the starting index, then the index
2213 of the first character of the last such substring is
2214 returned. Otherwise, -1 is returned.
2215 */
2216#if defined LIBO_INTERNAL_ONLY1
2217 sal_Int32 lastIndexOf(std::u16string_view sv, sal_Int32 fromIndex) const {
2218 return rtl_ustr_lastIndexOfStr_WithLength(pData->buffer, fromIndex, sv.data(), sv.size());
2219 }
2220#else
2221 sal_Int32 lastIndexOf( const OUString & str, sal_Int32 fromIndex ) const
2222 {
2223 return rtl_ustr_lastIndexOfStr_WithLength( pData->buffer, fromIndex,
2224 str.pData->buffer, str.pData->length );
2225 }
2226#endif
2227
2228 /**
2229 @overload
2230 This function accepts an ASCII string literal as its argument.
2231 @since LibreOffice 3.6
2232 */
2233 template< typename T >
2234 typename libreoffice_internal::ConstCharArrayDetector< T, sal_Int32 >::Type lastIndexOf( T& literal ) const
2235 {
2236 assert((static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 2237, __extension__ __PRETTY_FUNCTION__))
2237 libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T>::isValid(literal)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(literal)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 2237, __extension__ __PRETTY_FUNCTION__))
;
2238 return rtl_ustr_lastIndexOfAscii_WithLength(
2239 pData->buffer, pData->length,
2240 libreoffice_internal::ConstCharArrayDetector<T>::toPointer(literal),
2241 libreoffice_internal::ConstCharArrayDetector<T>::length);
2242 }
2243
2244 /**
2245 Returns the index within this string of the last occurrence of the
2246 specified ASCII substring.
2247
2248 @param str
2249 the substring to be searched for. Need not be null-terminated, but must
2250 be at least as long as the specified len. Must only contain characters
2251 in the ASCII range 0x00--7F.
2252
2253 @param len
2254 the length of the substring; must be non-negative.
2255
2256 @return
2257 the index (starting at 0) of the first character of the last occurrence
2258 of the substring within this string, or -1 if the substring does not
2259 occur. If len is zero, -1 is returned.
2260
2261 @since UDK 3.2.7
2262 */
2263 sal_Int32 lastIndexOfAsciiL(char const * str, sal_Int32 len) const
2264 {
2265 return rtl_ustr_lastIndexOfAscii_WithLength(
2266 pData->buffer, pData->length, str, len);
2267 }
2268
2269 /**
2270 Returns a new string that is a substring of this string.
2271
2272 The substring begins at the specified beginIndex. If
2273 beginIndex is negative or be greater than the length of
2274 this string, behaviour is undefined.
2275
2276 @param beginIndex the beginning index, inclusive.
2277 @return the specified substring.
2278 */
2279 SAL_WARN_UNUSED_RESULT[[nodiscard]] OUString copy( sal_Int32 beginIndex ) const
2280 {
2281 return copy(beginIndex, getLength() - beginIndex);
2282 }
2283
2284 /**
2285 Returns a new string that is a substring of this string.
2286
2287 The substring begins at the specified beginIndex and contains count
2288 characters. If either beginIndex or count are negative,
2289 or beginIndex + count are greater than the length of this string
2290 then behaviour is undefined.
2291
2292 @param beginIndex the beginning index, inclusive.
2293 @param count the number of characters.
2294 @return the specified substring.
2295 */
2296 SAL_WARN_UNUSED_RESULT[[nodiscard]] OUString copy( sal_Int32 beginIndex, sal_Int32 count ) const
2297 {
2298 rtl_uString *pNew = NULL__null;
2299 rtl_uString_newFromSubString( &pNew, pData, beginIndex, count );
2300 return OUString( pNew, SAL_NO_ACQUIRE );
2301 }
2302
2303 /**
2304 Concatenates the specified string to the end of this string.
2305
2306 @param str the string that is concatenated to the end
2307 of this string.
2308 @return a string that represents the concatenation of this string
2309 followed by the string argument.
2310 */
2311 SAL_WARN_UNUSED_RESULT[[nodiscard]] OUString concat( const OUString & str ) const
2312 {
2313 rtl_uString* pNew = NULL__null;
2314 rtl_uString_newConcat( &pNew, pData, str.pData );
2315 return OUString( pNew, SAL_NO_ACQUIRE );
2316 }
2317
2318#ifndef LIBO_INTERNAL_ONLY1 // "RTL_FAST_STRING"
2319 friend OUString operator+( const OUString& rStr1, const OUString& rStr2 )
2320 {
2321 return rStr1.concat( rStr2 );
2322 }
2323#endif
2324
2325 /**
2326 Returns a new string resulting from replacing n = count characters
2327 from position index in this string with newStr.
2328
2329 @param index the replacing index in str.
2330 The index must be greater than or equal to 0 and
2331 less than or equal to the length of the string.
2332 @param count the count of characters that will be replaced
2333 The count must be greater than or equal to 0 and
2334 less than or equal to the length of the string minus index.
2335 @param newStr the new substring.
2336 @return the new string.
2337 */
2338 SAL_WARN_UNUSED_RESULT[[nodiscard]] OUString replaceAt( sal_Int32 index, sal_Int32 count, const OUString& newStr ) const
2339 {
2340 rtl_uString* pNew = NULL__null;
2341 rtl_uString_newReplaceStrAt( &pNew, pData, index, count, newStr.pData );
2342 return OUString( pNew, SAL_NO_ACQUIRE );
2343 }
2344
2345 /**
2346 Returns a new string resulting from replacing all occurrences of
2347 oldChar in this string with newChar.
2348
2349 If the character oldChar does not occur in the character sequence
2350 represented by this object, then the string is assigned with
2351 str.
2352
2353 @param oldChar the old character.
2354 @param newChar the new character.
2355 @return a string derived from this string by replacing every
2356 occurrence of oldChar with newChar.
2357 */
2358 SAL_WARN_UNUSED_RESULT[[nodiscard]] OUString replace( sal_Unicode oldChar, sal_Unicode newChar ) const
2359 {
2360 rtl_uString* pNew = NULL__null;
2361 rtl_uString_newReplace( &pNew, pData, oldChar, newChar );
2362 return OUString( pNew, SAL_NO_ACQUIRE );
2363 }
2364
2365 /**
2366 Returns a new string resulting from replacing the first occurrence of a
2367 given substring with another substring.
2368
2369 @param from the substring to be replaced
2370
2371 @param to the replacing substring
2372
2373 @param[in,out] index pointer to a start index; if the pointer is
2374 non-null: upon entry to the function, its value is the index into this
2375 string at which to start searching for the \p from substring, the value
2376 must be non-negative and not greater than this string's length; upon exiting
2377 the function its value is the index into this string at which the
2378 replacement took place or -1 if no replacement took place; if the pointer
2379 is null, searching always starts at index 0
2380
2381 @since LibreOffice 3.6
2382 */
2383#if defined LIBO_INTERNAL_ONLY1
2384 [[nodiscard]] OUString replaceFirst(
2385 std::u16string_view from, std::u16string_view to, sal_Int32 * index = nullptr) const
2386 {
2387 rtl_uString * s = nullptr;
2388 sal_Int32 i = 0;
2389 rtl_uString_newReplaceFirstUtf16LUtf16L(
2390 &s, pData, from.data(), from.size(), to.data(), to.size(),
2391 index == nullptr ? &i : index);
2392 return OUString(s, SAL_NO_ACQUIRE);
2393 }
2394#else
2395 SAL_WARN_UNUSED_RESULT[[nodiscard]] OUString replaceFirst(
2396 OUString const & from, OUString const & to, sal_Int32 * index = NULL__null) const
2397 {
2398 rtl_uString * s = NULL__null;
2399 sal_Int32 i = 0;
2400 rtl_uString_newReplaceFirst(
2401 &s, pData, from.pData, to.pData, index == NULL__null ? &i : index);
2402 return OUString(s, SAL_NO_ACQUIRE);
2403 }
2404#endif
2405
2406 /**
2407 Returns a new string resulting from replacing the first occurrence of a
2408 given substring with another substring.
2409
2410 @param from ASCII string literal, the substring to be replaced
2411
2412 @param to the replacing substring
2413
2414 @param[in,out] index pointer to a start index; if the pointer is
2415 non-null: upon entry to the function, its value is the index into the this
2416 string at which to start searching for the \p from substring, the value
2417 must be non-negative and not greater than this string's length; upon exiting
2418 the function its value is the index into this string at which the
2419 replacement took place or -1 if no replacement took place; if the pointer
2420 is null, searching always starts at index 0
2421
2422 @since LibreOffice 3.6
2423 */
2424#if defined LIBO_INTERNAL_ONLY1
2425 template<typename T> [[nodiscard]]
2426 typename libreoffice_internal::ConstCharArrayDetector<T, OUString >::Type replaceFirst(
2427 T & from, std::u16string_view to, sal_Int32 * index = nullptr) const
2428 {
2429 assert(libreoffice_internal::ConstCharArrayDetector<T>::isValid(from))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T>::isValid(from)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(from)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 2429, __extension__ __PRETTY_FUNCTION__))
;
2430 rtl_uString * s = nullptr;
2431 sal_Int32 i = 0;
2432 rtl_uString_newReplaceFirstAsciiLUtf16L(
2433 &s, pData, libreoffice_internal::ConstCharArrayDetector<T>::toPointer(from),
2434 libreoffice_internal::ConstCharArrayDetector<T>::length, to.data(), to.size(),
2435 index == nullptr ? &i : index);
2436 return OUString(s, SAL_NO_ACQUIRE);
2437 }
2438#else
2439 template< typename T >
2440 SAL_WARN_UNUSED_RESULT[[nodiscard]] typename libreoffice_internal::ConstCharArrayDetector< T, OUString >::Type replaceFirst( T& from, OUString const & to,
2441 sal_Int32 * index = NULL__null) const
2442 {
2443 assert(libreoffice_internal::ConstCharArrayDetector<T>::isValid(from))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T>::isValid(from)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(from)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 2443, __extension__ __PRETTY_FUNCTION__))
;
2444 rtl_uString * s = NULL__null;
2445 sal_Int32 i = 0;
2446 rtl_uString_newReplaceFirstAsciiL(
2447 &s, pData,
2448 libreoffice_internal::ConstCharArrayDetector<T>::toPointer(from),
2449 libreoffice_internal::ConstCharArrayDetector<T>::length, to.pData,
2450 index == NULL__null ? &i : index);
2451 return OUString(s, SAL_NO_ACQUIRE);
2452 }
2453#endif
2454
2455 /**
2456 Returns a new string resulting from replacing the first occurrence of a
2457 given substring with another substring.
2458
2459 @param from the substring to be replaced
2460
2461 @param to ASCII string literal, the replacing substring
2462
2463 @param[in,out] index pointer to a start index; if the pointer is
2464 non-null: upon entry to the function, its value is the index into the this
2465 string at which to start searching for the \p from substring, the value
2466 must be non-negative and not greater than this string's length; upon exiting
2467 the function its value is the index into this string at which the
2468 replacement took place or -1 if no replacement took place; if the pointer
2469 is null, searching always starts at index 0
2470
2471 @since LibreOffice 5.1
2472 */
2473#if defined LIBO_INTERNAL_ONLY1
2474 template<typename T> [[nodiscard]]
2475 typename libreoffice_internal::ConstCharArrayDetector<T, OUString >::Type replaceFirst(
2476 std::u16string_view from, T & to, sal_Int32 * index = nullptr) const
2477 {
2478 assert(libreoffice_internal::ConstCharArrayDetector<T>::isValid(to))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T>::isValid(to)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(to)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 2478, __extension__ __PRETTY_FUNCTION__))
;
2479 rtl_uString * s = nullptr;
2480 sal_Int32 i = 0;
2481 rtl_uString_newReplaceFirstUtf16LAsciiL(
2482 &s, pData, from.data(), from.size(),
2483 libreoffice_internal::ConstCharArrayDetector<T>::toPointer(to),
2484 libreoffice_internal::ConstCharArrayDetector<T>::length, index == nullptr ? &i : index);
2485 return OUString(s, SAL_NO_ACQUIRE);
2486 }
2487#else
2488 template< typename T >
2489 SAL_WARN_UNUSED_RESULT[[nodiscard]] typename libreoffice_internal::ConstCharArrayDetector< T, OUString >::Type replaceFirst( OUString const & from, T& to,
2490 sal_Int32 * index = NULL__null) const
2491 {
2492 assert(libreoffice_internal::ConstCharArrayDetector<T>::isValid(to))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T>::isValid(to)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(to)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 2492, __extension__ __PRETTY_FUNCTION__))
;
2493 rtl_uString * s = NULL__null;
2494 sal_Int32 i = 0;
2495 rtl_uString_newReplaceFirstToAsciiL(
2496 &s, pData, from.pData,
2497 libreoffice_internal::ConstCharArrayDetector<T>::toPointer(to),
2498 libreoffice_internal::ConstCharArrayDetector<T>::length,
2499 index == NULL__null ? &i : index);
2500 return OUString(s, SAL_NO_ACQUIRE);
2501 }
2502#endif
2503
2504 /**
2505 Returns a new string resulting from replacing the first occurrence of a
2506 given substring with another substring.
2507
2508 @param from ASCII string literal, the substring to be replaced
2509
2510 @param to ASCII string literal, the substring to be replaced
2511
2512 @param[in,out] index pointer to a start index; if the pointer is
2513 non-null: upon entry to the function, its value is the index into the this
2514 string at which to start searching for the \p from substring, the value
2515 must be non-negative and not greater than this string's length; upon exiting
2516 the function its value is the index into this string at which the
2517 replacement took place or -1 if no replacement took place; if the pointer
2518 is null, searching always starts at index 0
2519
2520 @since LibreOffice 3.6
2521 */
2522 template< typename T1, typename T2 >
2523 SAL_WARN_UNUSED_RESULT[[nodiscard]] typename libreoffice_internal::ConstCharArrayDetector< T1, typename libreoffice_internal::ConstCharArrayDetector< T2, OUString >::Type >::Type
2524 replaceFirst( T1& from, T2& to, sal_Int32 * index = NULL__null) const
2525 {
2526 assert(libreoffice_internal::ConstCharArrayDetector<T1>::isValid(from))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T1>::isValid(from)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T1>::isValid(from)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 2526, __extension__ __PRETTY_FUNCTION__))
;
2527 assert(libreoffice_internal::ConstCharArrayDetector<T2>::isValid(to))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T2>::isValid(to)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T2>::isValid(to)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 2527, __extension__ __PRETTY_FUNCTION__))
;
2528 rtl_uString * s = NULL__null;
2529 sal_Int32 i = 0;
2530 rtl_uString_newReplaceFirstAsciiLAsciiL(
2531 &s, pData,
2532 libreoffice_internal::ConstCharArrayDetector<T1>::toPointer(from),
2533 libreoffice_internal::ConstCharArrayDetector<T1>::length,
2534 libreoffice_internal::ConstCharArrayDetector<T2>::toPointer(to),
2535 libreoffice_internal::ConstCharArrayDetector<T2>::length,
2536 index == NULL__null ? &i : index);
2537 return OUString(s, SAL_NO_ACQUIRE);
2538 }
2539
2540 /**
2541 Returns a new string resulting from replacing all occurrences of a given
2542 substring with another substring.
2543
2544 Replacing subsequent occurrences picks up only after a given replacement.
2545 That is, replacing from "xa" to "xx" in "xaa" results in "xxa", not "xxx".
2546
2547 @param from the substring to be replaced
2548
2549 @param to the replacing substring
2550
2551 @param fromIndex the position in the string where we will begin searching
2552
2553 @since LibreOffice 4.0
2554 */
2555#if defined LIBO_INTERNAL_ONLY1
2556 [[nodiscard]] OUString replaceAll(
2557 std::u16string_view from, std::u16string_view to, sal_Int32 fromIndex = 0) const
2558 {
2559 rtl_uString * s = nullptr;
2560 rtl_uString_newReplaceAllFromIndexUtf16LUtf16L(
2561 &s, pData, from.data(), from.size(), to.data(), to.size(), fromIndex);
2562 return OUString(s, SAL_NO_ACQUIRE);
2563 }
2564#else
2565 SAL_WARN_UNUSED_RESULT[[nodiscard]] OUString replaceAll(
2566 OUString const & from, OUString const & to, sal_Int32 fromIndex = 0) const
2567 {
2568 rtl_uString * s = NULL__null;
2569 rtl_uString_newReplaceAllFromIndex(&s, pData, from.pData, to.pData, fromIndex);
2570 return OUString(s, SAL_NO_ACQUIRE);
2571 }
2572#endif
2573
2574 /**
2575 Returns a new string resulting from replacing all occurrences of a given
2576 substring with another substring.
2577
2578 Replacing subsequent occurrences picks up only after a given replacement.
2579 That is, replacing from "xa" to "xx" in "xaa" results in "xxa", not "xxx".
2580
2581 @param from ASCII string literal, the substring to be replaced
2582
2583 @param to the replacing substring
2584
2585 @since LibreOffice 3.6
2586 */
2587#if defined LIBO_INTERNAL_ONLY1
2588 template<typename T> [[nodiscard]]
2589 typename libreoffice_internal::ConstCharArrayDetector<T, OUString >::Type replaceAll(
2590 T & from, std::u16string_view to) const
2591 {
2592 assert(libreoffice_internal::ConstCharArrayDetector<T>::isValid(from))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T>::isValid(from)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(from)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 2592, __extension__ __PRETTY_FUNCTION__))
;
2593 rtl_uString * s = nullptr;
2594 rtl_uString_newReplaceAllAsciiLUtf16L(
2595 &s, pData, libreoffice_internal::ConstCharArrayDetector<T>::toPointer(from),
2596 libreoffice_internal::ConstCharArrayDetector<T>::length, to.data(), to.size());
2597 return OUString(s, SAL_NO_ACQUIRE);
2598 }
2599#else
2600 template< typename T >
2601 SAL_WARN_UNUSED_RESULT[[nodiscard]] typename libreoffice_internal::ConstCharArrayDetector< T, OUString >::Type replaceAll( T& from, OUString const & to) const
2602 {
2603 assert(libreoffice_internal::ConstCharArrayDetector<T>::isValid(from))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T>::isValid(from)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(from)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 2603, __extension__ __PRETTY_FUNCTION__))
;
2604 rtl_uString * s = NULL__null;
2605 rtl_uString_newReplaceAllAsciiL(
2606 &s, pData,
2607 libreoffice_internal::ConstCharArrayDetector<T>::toPointer(from),
2608 libreoffice_internal::ConstCharArrayDetector<T>::length, to.pData);
2609 return OUString(s, SAL_NO_ACQUIRE);
2610 }
2611#endif
2612
2613 /**
2614 Returns a new string resulting from replacing all occurrences of a given
2615 substring with another substring.
2616
2617 Replacing subsequent occurrences picks up only after a given replacement.
2618 That is, replacing from "xa" to "xx" in "xaa" results in "xxa", not "xxx".
2619
2620 @param from the substring to be replaced
2621
2622 @param to ASCII string literal, the replacing substring
2623
2624 @since LibreOffice 5.1
2625 */
2626#if defined LIBO_INTERNAL_ONLY1
2627 template<typename T> [[nodiscard]]
2628 typename libreoffice_internal::ConstCharArrayDetector<T, OUString >::Type replaceAll(
2629 std::u16string_view from, T & to) const
2630 {
2631 assert(libreoffice_internal::ConstCharArrayDetector<T>::isValid(to))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T>::isValid(to)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(to)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 2631, __extension__ __PRETTY_FUNCTION__))
;
2632 rtl_uString * s = nullptr;
2633 rtl_uString_newReplaceAllUtf16LAsciiL(
2634 &s, pData, from.data(), from.size(),
2635 libreoffice_internal::ConstCharArrayDetector<T>::toPointer(to),
2636 libreoffice_internal::ConstCharArrayDetector<T>::length);
2637 return OUString(s, SAL_NO_ACQUIRE);
2638 }
2639#else
2640 template< typename T >
2641 SAL_WARN_UNUSED_RESULT[[nodiscard]] typename libreoffice_internal::ConstCharArrayDetector< T, OUString >::Type replaceAll( OUString const & from, T& to) const
2642 {
2643 assert(libreoffice_internal::ConstCharArrayDetector<T>::isValid(to))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T>::isValid(to)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T>::isValid(to)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 2643, __extension__ __PRETTY_FUNCTION__))
;
2644 rtl_uString * s = NULL__null;
2645 rtl_uString_newReplaceAllToAsciiL(
2646 &s, pData, from.pData,
2647 libreoffice_internal::ConstCharArrayDetector<T>::toPointer(to),
2648 libreoffice_internal::ConstCharArrayDetector<T>::length);
2649 return OUString(s, SAL_NO_ACQUIRE);
2650 }
2651#endif
2652
2653 /**
2654 Returns a new string resulting from replacing all occurrences of a given
2655 substring with another substring.
2656
2657 Replacing subsequent occurrences picks up only after a given replacement.
2658 That is, replacing from "xa" to "xx" in "xaa" results in "xxa", not "xxx".
2659
2660 @param from ASCII string literal, the substring to be replaced
2661
2662 @param to ASCII string literal, the substring to be replaced
2663
2664 @since LibreOffice 3.6
2665 */
2666 template< typename T1, typename T2 >
2667 SAL_WARN_UNUSED_RESULT[[nodiscard]] typename libreoffice_internal::ConstCharArrayDetector< T1, typename libreoffice_internal::ConstCharArrayDetector< T2, OUString >::Type >::Type
2668 replaceAll( T1& from, T2& to ) const
2669 {
2670 assert(libreoffice_internal::ConstCharArrayDetector<T1>::isValid(from))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T1>::isValid(from)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T1>::isValid(from)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 2670, __extension__ __PRETTY_FUNCTION__))
;
2671 assert(libreoffice_internal::ConstCharArrayDetector<T2>::isValid(to))(static_cast <bool> (libreoffice_internal::ConstCharArrayDetector
<T2>::isValid(to)) ? void (0) : __assert_fail ("libreoffice_internal::ConstCharArrayDetector<T2>::isValid(to)"
, "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 2671, __extension__ __PRETTY_FUNCTION__))
;
2672 rtl_uString * s = NULL__null;
2673 rtl_uString_newReplaceAllAsciiLAsciiL(
2674 &s, pData,
2675 libreoffice_internal::ConstCharArrayDetector<T1>::toPointer(from),
2676 libreoffice_internal::ConstCharArrayDetector<T1>::length,
2677 libreoffice_internal::ConstCharArrayDetector<T2>::toPointer(to),
2678 libreoffice_internal::ConstCharArrayDetector<T2>::length);
2679 return OUString(s, SAL_NO_ACQUIRE);
2680 }
2681
2682 /**
2683 Converts from this string all ASCII uppercase characters (65-90)
2684 to ASCII lowercase characters (97-122).
2685
2686 This function can't be used for language specific conversion.
2687 If the string doesn't contain characters which must be converted,
2688 then the new string is assigned with str.
2689
2690 @return the string, converted to ASCII lowercase.
2691 */
2692 SAL_WARN_UNUSED_RESULT[[nodiscard]] OUString toAsciiLowerCase() const
2693 {
2694 rtl_uString* pNew = NULL__null;
2695 rtl_uString_newToAsciiLowerCase( &pNew, pData );
2696 return OUString( pNew, SAL_NO_ACQUIRE );
2697 }
2698
2699 /**
2700 Converts from this string all ASCII lowercase characters (97-122)
2701 to ASCII uppercase characters (65-90).
2702
2703 This function can't be used for language specific conversion.
2704 If the string doesn't contain characters which must be converted,
2705 then the new string is assigned with str.
2706
2707 @return the string, converted to ASCII uppercase.
2708 */
2709 SAL_WARN_UNUSED_RESULT[[nodiscard]] OUString toAsciiUpperCase() const
2710 {
2711 rtl_uString* pNew = NULL__null;
2712 rtl_uString_newToAsciiUpperCase( &pNew, pData );
2713 return OUString( pNew, SAL_NO_ACQUIRE );
2714 }
2715
2716 /**
2717 Returns a new string resulting from removing white space from both ends
2718 of the string.
2719
2720 All characters that have codes less than or equal to
2721 32 (the space character), and Unicode General Punctuation area Space
2722 and some Control characters are considered to be white space (see
2723 rtl_ImplIsWhitespace).
2724 If the string doesn't contain white spaces at both ends,
2725 then the new string is assigned with str.
2726
2727 @return the string, with white space removed from the front and end.
2728 */
2729 SAL_WARN_UNUSED_RESULT[[nodiscard]] OUString trim() const
2730 {
2731 rtl_uString* pNew = NULL__null;
2732 rtl_uString_newTrim( &pNew, pData );
2733 return OUString( pNew, SAL_NO_ACQUIRE );
2734 }
2735
2736 /**
2737 Returns a token in the string.
2738
2739 Example:
2740 sal_Int32 nIndex = 0;
2741 do
2742 {
2743 ...
2744 OUString aToken = aStr.getToken( 0, ';', nIndex );
2745 ...
2746 }
2747 while ( nIndex >= 0 );
2748
2749 @param token the number of the token to return
2750 @param cTok the character which separate the tokens.
2751 @param index the position at which the token is searched in the
2752 string.
2753 The index must not be greater than the length of the
2754 string.
2755 This param is set to the position of the
2756 next token or to -1, if it is the last token.
2757 @return the token; if either token or index is negative, an empty token
2758 is returned (and index is set to -1)
2759 */
2760 OUString getToken( sal_Int32 token, sal_Unicode cTok, sal_Int32& index ) const
2761 {
2762 rtl_uString * pNew = NULL__null;
2763 index = rtl_uString_getToken( &pNew, pData, token, cTok, index );
2764 return OUString( pNew, SAL_NO_ACQUIRE );
2765 }
2766
2767 /**
2768 Returns a token from the string.
2769
2770 The same as getToken(sal_Int32, sal_Unicode, sal_Int32 &), but always
2771 passing in 0 as the start index in the third argument.
2772
2773 @param count the number of the token to return, starting with 0
2774 @param separator the character which separates the tokens
2775
2776 @return the given token, or an empty string
2777
2778 @since LibreOffice 3.6
2779 */
2780 OUString getToken(sal_Int32 count, sal_Unicode separator) const {
2781 sal_Int32 n = 0;
2782 return getToken(count, separator, n);
2783 }
2784
2785 /**
2786 Returns the Boolean value from this string.
2787
2788 This function can't be used for language specific conversion.
2789
2790 @return true, if the string is 1 or "True" in any ASCII case.
2791 false in any other case.
2792 */
2793 bool toBoolean() const
2794 {
2795 return rtl_ustr_toBoolean( pData->buffer );
2796 }
2797
2798 /**
2799 Returns the first character from this string.
2800
2801 @return the first character from this string or 0, if this string
2802 is empty.
2803 */
2804 sal_Unicode toChar() const
2805 {
2806 return pData->buffer[0];
2807 }
2808
2809 /**
2810 Returns the int32 value from this string.
2811
2812 This function can't be used for language specific conversion.
2813
2814 @param radix the radix (between 2 and 36)
2815 @return the int32 represented from this string.
2816 0 if this string represents no number or one of too large
2817 magnitude.
2818 */
2819 sal_Int32 toInt32( sal_Int16 radix = 10 ) const
2820 {
2821 return rtl_ustr_toInt32( pData->buffer, radix );
2822 }
2823
2824 /**
2825 Returns the uint32 value from this string.
2826
2827 This function can't be used for language specific conversion.
2828
2829 @param radix the radix (between 2 and 36)
2830 @return the uint32 represented from this string.
2831 0 if this string represents no number or one of too large
2832 magnitude.
2833
2834 @since LibreOffice 4.2
2835 */
2836 sal_uInt32 toUInt32( sal_Int16 radix = 10 ) const
2837 {
2838 return rtl_ustr_toUInt32( pData->buffer, radix );
2839 }
2840
2841 /**
2842 Returns the int64 value from this string.
2843
2844 This function can't be used for language specific conversion.
2845
2846 @param radix the radix (between 2 and 36)
2847 @return the int64 represented from this string.
2848 0 if this string represents no number or one of too large
2849 magnitude.
2850 */
2851 sal_Int64 toInt64( sal_Int16 radix = 10 ) const
2852 {
2853 return rtl_ustr_toInt64( pData->buffer, radix );
2854 }
2855
2856 /**
2857 Returns the uint64 value from this string.
2858
2859 This function can't be used for language specific conversion.
2860
2861 @param radix the radix (between 2 and 36)
2862 @return the uint64 represented from this string.
2863 0 if this string represents no number or one of too large
2864 magnitude.
2865
2866 @since LibreOffice 4.1
2867 */
2868 sal_uInt64 toUInt64( sal_Int16 radix = 10 ) const
2869 {
2870 return rtl_ustr_toUInt64( pData->buffer, radix );
2871 }
2872
2873 /**
2874 Returns the float value from this string.
2875
2876 This function can't be used for language specific conversion.
2877
2878 @return the float represented from this string.
2879 0.0 if this string represents no number.
2880 */
2881 float toFloat() const
2882 {
2883 return rtl_ustr_toFloat( pData->buffer );
2884 }
2885
2886 /**
2887 Returns the double value from this string.
2888
2889 This function can't be used for language specific conversion.
2890
2891 @return the double represented from this string.
2892 0.0 if this string represents no number.
2893 */
2894 double toDouble() const
2895 {
2896 return rtl_ustr_toDouble( pData->buffer );
2897 }
2898
2899
2900 /**
2901 Return a canonical representation for a string.
2902
2903 A pool of strings, initially empty is maintained privately
2904 by the string class. On invocation, if present in the pool
2905 the original string will be returned. Otherwise this string,
2906 or a copy thereof will be added to the pool and returned.
2907
2908 @return
2909 a version of the string from the pool.
2910
2911 @exception std::bad_alloc is thrown if an out-of-memory condition occurs
2912
2913 @since UDK 3.2.7
2914 */
2915 OUString intern() const
2916 {
2917 rtl_uString * pNew = NULL__null;
2918 rtl_uString_intern( &pNew, pData );
2919 if (pNew == NULL__null) {
2920 throw std::bad_alloc();
2921 }
2922 return OUString( pNew, SAL_NO_ACQUIRE );
2923 }
2924
2925 /**
2926 Return a canonical representation for a converted string.
2927
2928 A pool of strings, initially empty is maintained privately
2929 by the string class. On invocation, if present in the pool
2930 the original string will be returned. Otherwise this string,
2931 or a copy thereof will be added to the pool and returned.
2932
2933 @param value a 8-Bit character array.
2934 @param length the number of character which should be converted.
2935 The 8-Bit character array length must be
2936 greater than or equal to this value.
2937 @param encoding the text encoding from which the 8-Bit character
2938 sequence should be converted.
2939 @param convertFlags flags which controls the conversion.
2940 see RTL_TEXTTOUNICODE_FLAGS_...
2941 @param pInfo pointer to return conversion status or NULL.
2942
2943 @return
2944 a version of the converted string from the pool.
2945
2946 @exception std::bad_alloc is thrown if an out-of-memory condition occurs
2947
2948 @since UDK 3.2.7
2949 */
2950 static OUString intern( const char * value, sal_Int32 length,
2951 rtl_TextEncoding encoding,
2952 sal_uInt32 convertFlags = OSTRING_TO_OUSTRING_CVTFLAGS(((sal_uInt32)0x0003) | ((sal_uInt32)0x0030) | ((sal_uInt32)0x0300
))
,
2953 sal_uInt32 *pInfo = NULL__null )
2954 {
2955 rtl_uString * pNew = NULL__null;
2956 rtl_uString_internConvert( &pNew, value, length, encoding,
2957 convertFlags, pInfo );
2958 if (pNew == NULL__null) {
2959 throw std::bad_alloc();
2960 }
2961 return OUString( pNew, SAL_NO_ACQUIRE );
2962 }
2963
2964 /**
2965 Converts to an OString, signalling failure.
2966
2967 @param pTarget
2968 An out parameter receiving the converted OString. Must not be null; the
2969 contents are not modified if conversion fails (convertToOString returns
2970 false).
2971
2972 @param nEncoding
2973 The text encoding to convert into. Must be an octet encoding (i.e.,
2974 rtl_isOctetTextEncoding(nEncoding) must return true).
2975
2976 @param nFlags
2977 A combination of RTL_UNICODETOTEXT_FLAGS that detail how to do the
2978 conversion (see rtl_convertUnicodeToText). RTL_UNICODETOTEXT_FLAGS_FLUSH
2979 need not be included, it is implicitly assumed. Typical uses are either
2980 RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR |
2981 RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR (fail if a Unicode character cannot
2982 be converted to the target nEncoding) or OUSTRING_TO_OSTRING_CVTFLAGS
2983 (make a best efforts conversion).
2984
2985 @return
2986 True if the conversion succeeded, false otherwise.
2987 */
2988 bool convertToString(OString * pTarget, rtl_TextEncoding nEncoding,
2989 sal_uInt32 nFlags) const
2990 {
2991 return rtl_convertUStringToString(&pTarget->pData, pData->buffer,
2992 pData->length, nEncoding, nFlags);
2993 }
2994
2995 /** Iterate through this string based on code points instead of UTF-16 code
2996 units.
2997
2998 See Chapter 3 of The Unicode Standard 5.0 (Addison--Wesley, 2006) for
2999 definitions of the various terms used in this description.
3000
3001 This string is interpreted as a sequence of zero or more UTF-16 code
3002 units. For each index into this sequence (from zero to one less than
3003 the length of the sequence, inclusive), a code point represented
3004 starting at the given index is computed as follows:
3005
3006 - If the UTF-16 code unit addressed by the index constitutes a
3007 well-formed UTF-16 code unit sequence, the computed code point is the
3008 scalar value encoded by that UTF-16 code unit sequence.
3009
3010 - Otherwise, if the index is at least two UTF-16 code units away from
3011 the end of the sequence, and the sequence of two UTF-16 code units
3012 addressed by the index constitutes a well-formed UTF-16 code unit
3013 sequence, the computed code point is the scalar value encoded by that
3014 UTF-16 code unit sequence.
3015
3016 - Otherwise, the computed code point is the UTF-16 code unit addressed
3017 by the index. (This last case catches unmatched surrogates as well as
3018 indices pointing into the middle of surrogate pairs.)
3019
3020 @param indexUtf16
3021 pointer to a UTF-16 based index into this string; must not be null. On
3022 entry, the index must be in the range from zero to the length of this
3023 string (in UTF-16 code units), inclusive. Upon successful return, the
3024 index will be updated to address the UTF-16 code unit that is the given
3025 incrementCodePoints away from the initial index.
3026
3027 @param incrementCodePoints
3028 the number of code points to move the given *indexUtf16. If
3029 non-negative, moving is done after determining the code point at the
3030 index. If negative, moving is done before determining the code point
3031 at the (then updated) index. The value must be such that the resulting
3032 UTF-16 based index is in the range from zero to the length of this
3033 string (in UTF-16 code units), inclusive.
3034
3035 @return
3036 the code point (an integer in the range from 0 to 0x10FFFF, inclusive)
3037 that is represented within this string starting at the index computed as
3038 follows: If incrementCodePoints is non-negative, the index is the
3039 initial value of *indexUtf16; if incrementCodePoints is negative, the
3040 index is the updated value of *indexUtf16. In either case, the computed
3041 index must be in the range from zero to one less than the length of this
3042 string (in UTF-16 code units), inclusive.
3043
3044 @since UDK 3.2.7
3045 */
3046 sal_uInt32 iterateCodePoints(
3047 sal_Int32 * indexUtf16, sal_Int32 incrementCodePoints = 1) const
3048 {
3049 return rtl_uString_iterateCodePoints(
3050 pData, indexUtf16, incrementCodePoints);
3051 }
3052
3053 /**
3054 * Convert an OString to an OUString, assuming that the OString is
3055 * UTF-8-encoded.
3056 *
3057 * @param rSource
3058 * an OString to convert
3059 *
3060 * @since LibreOffice 4.4
3061 */
3062 static OUString fromUtf8(const OString& rSource)
3063 {
3064 OUString aTarget;
3065 bool bSuccess = rtl_convertStringToUString(&aTarget.pData,
3066 rSource.getStr(),
3067 rSource.getLength(),
3068 RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76)),
3069 RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR((sal_uInt32)0x0001)|RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR((sal_uInt32)0x0010)|RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR((sal_uInt32)0x0100));
3070 (void) bSuccess;
3071 assert(bSuccess)(static_cast <bool> (bSuccess) ? void (0) : __assert_fail
("bSuccess", "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 3071, __extension__ __PRETTY_FUNCTION__))
;
3072 return aTarget;
3073 }
3074
3075 /**
3076 * Convert this string to an OString, assuming that the string can be
3077 * UTF-8-encoded successfully.
3078 *
3079 * In other words, you must not use this method on a random sequence of
3080 * UTF-16 code units, but only at places where it is assumed that the
3081 * content is a proper string.
3082 *
3083 * @since LibreOffice 4.4
3084 */
3085 OString toUtf8() const
3086 {
3087 OString aTarget;
3088 bool bSuccess = rtl_convertUStringToString(&aTarget.pData,
3089 getStr(),
3090 getLength(),
3091 RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76)),
3092 RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR((sal_uInt32)0x0001)|RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR((sal_uInt32)0x0010));
3093 (void) bSuccess;
3094 assert(bSuccess)(static_cast <bool> (bSuccess) ? void (0) : __assert_fail
("bSuccess", "/home/maarten/src/libreoffice/core/include/rtl/ustring.hxx"
, 3094, __extension__ __PRETTY_FUNCTION__))
;
3095 return aTarget;
3096 }
3097
3098#ifdef LIBO_INTERNAL_ONLY1 // "RTL_FAST_STRING"
3099
3100 static OUStringNumber< int > number( int i, sal_Int16 radix = 10 )
3101 {
3102 return OUStringNumber< int >( i, radix );
3103 }
3104 static OUStringNumber< long long > number( long long ll, sal_Int16 radix = 10 )
3105 {
3106 return OUStringNumber< long long >( ll, radix );
3107 }
3108 static OUStringNumber< unsigned long long > number( unsigned long long ll, sal_Int16 radix = 10 )
3109 {
3110 return OUStringNumber< unsigned long long >( ll, radix );
3111 }
3112 static OUStringNumber< unsigned long long > number( unsigned int i, sal_Int16 radix = 10 )
3113 {
3114 return number( static_cast< unsigned long long >( i ), radix );
3115 }
3116 static OUStringNumber< long long > number( long i, sal_Int16 radix = 10)
3117 {
3118 return number( static_cast< long long >( i ), radix );
3119 }
3120 static OUStringNumber< unsigned long long > number( unsigned long i, sal_Int16 radix = 10 )
3121 {
3122 return number( static_cast< unsigned long long >( i ), radix );
3123 }
3124 static OUStringNumber< float > number( float f )
3125 {
3126 return OUStringNumber< float >( f );
3127 }
3128 static OUStringNumber< double > number( double d )
3129 {
3130 return OUStringNumber< double >( d );
3131 }
3132#else
3133 /**
3134 Returns the string representation of the integer argument.
3135
3136 This function can't be used for language specific conversion.
3137
3138 @param i an integer value
3139 @param radix the radix (between 2 and 36)
3140 @return a string with the string representation of the argument.
3141 @since LibreOffice 4.1
3142 */
3143 static OUString number( int i, sal_Int16 radix = 10 )
3144 {
3145 sal_Unicode aBuf[RTL_USTR_MAX_VALUEOFINT3233];
3146 return OUString(aBuf, rtl_ustr_valueOfInt32(aBuf, i, radix));
3147 }
3148 /// @overload
3149 /// @since LibreOffice 4.1
3150 static OUString number( unsigned int i, sal_Int16 radix = 10 )
3151 {
3152 return number( static_cast< unsigned long long >( i ), radix );
3153 }
3154 /// @overload
3155 /// @since LibreOffice 4.1
3156 static OUString number( long i, sal_Int16 radix = 10)
3157 {
3158 return number( static_cast< long long >( i ), radix );
3159 }
3160 /// @overload
3161 /// @since LibreOffice 4.1
3162 static OUString number( unsigned long i, sal_Int16 radix = 10 )
3163 {
3164 return number( static_cast< unsigned long long >( i ), radix );
3165 }
3166 /// @overload
3167 /// @since LibreOffice 4.1
3168 static OUString number( long long ll, sal_Int16 radix = 10 )
3169 {
3170 sal_Unicode aBuf[RTL_USTR_MAX_VALUEOFINT6465];
3171 return OUString(aBuf, rtl_ustr_valueOfInt64(aBuf, ll, radix));
3172 }
3173 /// @overload
3174 /// @since LibreOffice 4.1
3175 static OUString number( unsigned long long ll, sal_Int16 radix = 10 )
3176 {
3177 sal_Unicode aBuf[RTL_USTR_MAX_VALUEOFUINT6465];
3178 return OUString(aBuf, rtl_ustr_valueOfUInt64(aBuf, ll, radix));
3179 }
3180
3181 /**
3182 Returns the string representation of the float argument.
3183
3184 This function can't be used for language specific conversion.
3185
3186 @param f a float.
3187 @return a string with the decimal representation of the argument.
3188 @since LibreOffice 4.1
3189 */
3190 static OUString number( float f )
3191 {
3192 sal_Unicode aBuf[RTL_USTR_MAX_VALUEOFFLOAT15];
3193 return OUString(aBuf, rtl_ustr_valueOfFloat(aBuf, f));
3194 }
3195
3196 /**
3197 Returns the string representation of the double argument.
3198
3199 This function can't be used for language specific conversion.
3200
3201 @param d a double.
3202 @return a string with the decimal representation of the argument.
3203 @since LibreOffice 4.1
3204 */
3205 static OUString number( double d )
3206 {
3207 sal_Unicode aBuf[RTL_USTR_MAX_VALUEOFDOUBLE25];
3208 return OUString(aBuf, rtl_ustr_valueOfDouble(aBuf, d));
3209 }
3210#endif
3211
3212 /**
3213 Returns the string representation of the sal_Bool argument.
3214
3215 If the sal_Bool is true, the string "true" is returned.
3216 If the sal_Bool is false, the string "false" is returned.
3217 This function can't be used for language specific conversion.
3218
3219 @param b a sal_Bool.
3220 @return a string with the string representation of the argument.
3221 @deprecated use boolean()
3222 */
3223 SAL_DEPRECATED("use boolean()")__attribute__((deprecated("use boolean()"))) static OUString valueOf( sal_Bool b )
3224 {
3225 return boolean(b);
3226 }
3227
3228 /**
3229 Returns the string representation of the boolean argument.
3230
3231 If the argument is true, the string "true" is returned.
3232 If the argument is false, the string "false" is returned.
3233 This function can't be used for language specific conversion.
3234
3235 @param b a bool.
3236 @return a string with the string representation of the argument.
3237 @since LibreOffice 4.1
3238 */
3239 static OUString boolean( bool b )
3240 {
3241 sal_Unicode aBuf[RTL_USTR_MAX_VALUEOFBOOLEAN6];
3242 return OUString(aBuf, rtl_ustr_valueOfBoolean(aBuf, b));
3243 }
3244
3245 /**
3246 Returns the string representation of the char argument.
3247
3248 @param c a character.
3249 @return a string with the string representation of the argument.
3250 @deprecated use operator, function or constructor taking char or sal_Unicode argument
3251 */
3252 SAL_DEPRECATED("convert to OUString or use directly")__attribute__((deprecated("convert to OUString or use directly"
)))
static OUString valueOf( sal_Unicode c )
3253 {
3254 return OUString( &c, 1 );
3255 }
3256
3257 /**
3258 Returns the string representation of the int argument.
3259
3260 This function can't be used for language specific conversion.
3261
3262 @param i a int32.
3263 @param radix the radix (between 2 and 36)
3264 @return a string with the string representation of the argument.
3265 @deprecated use number()
3266 */
3267 SAL_DEPRECATED("use number()")__attribute__((deprecated("use number()"))) static OUString valueOf( sal_Int32 i, sal_Int16 radix = 10 )
3268 {
3269 return number( i, radix );
3270 }
3271
3272 /**
3273 Returns the string representation of the long argument.
3274
3275 This function can't be used for language specific conversion.
3276
3277 @param ll a int64.
3278 @param radix the radix (between 2 and 36)
3279 @return a string with the string representation of the argument.
3280 @deprecated use number()
3281 */
3282 SAL_DEPRECATED("use number()")__attribute__((deprecated("use number()"))) static OUString valueOf( sal_Int64 ll, sal_Int16 radix = 10 )
3283 {
3284 return number( ll, radix );
3285 }
3286
3287 /**
3288 Returns the string representation of the float argument.
3289
3290 This function can't be used for language specific conversion.
3291
3292 @param f a float.
3293 @return a string with the string representation of the argument.
3294 @deprecated use number()
3295 */
3296 SAL_DEPRECATED("use number()")__attribute__((deprecated("use number()"))) static OUString valueOf( float f )
3297 {
3298 return number(f);
3299 }
3300
3301 /**
3302 Returns the string representation of the double argument.
3303
3304 This function can't be used for language specific conversion.
3305
3306 @param d a double.
3307 @return a string with the string representation of the argument.
3308 @deprecated use number()
3309 */
3310 SAL_DEPRECATED("use number()")__attribute__((deprecated("use number()"))) static OUString valueOf( double d )
3311 {
3312 return number(d);
3313 }
3314
3315 /**
3316 Returns an OUString copied without conversion from an ASCII
3317 character string.
3318
3319 Since this method is optimized for performance, the ASCII character
3320 values are not converted in any way. The caller has to make sure that
3321 all ASCII characters are in the allowed range between 0 and 127.
3322 The ASCII string must be NULL-terminated.
3323
3324 Note that for string literals it is simpler and more efficient
3325 to directly use the OUString constructor.
3326
3327 @param value the 8-Bit ASCII character string
3328 @return a string with the string representation of the argument.
3329 */
3330 static OUString createFromAscii( const char * value )
3331 {
3332 rtl_uString* pNew = NULL__null;
3333 rtl_uString_newFromAscii( &pNew, value );
3334 return OUString( pNew, SAL_NO_ACQUIRE );
3335 }
3336
3337#if defined LIBO_INTERNAL_ONLY1
3338 static OUString createFromAscii(std::string_view value) {
3339 rtl_uString * p = nullptr;
3340 rtl_uString_newFromLiteral(&p, value.data(), value.size(), 0); //TODO: check for overflow
3341 return OUString(p, SAL_NO_ACQUIRE);
3342 }
3343 #endif
3344
3345#if defined LIBO_INTERNAL_ONLY1
3346 operator std::u16string_view() const { return {getStr(), sal_uInt32(getLength())}; }
3347#endif
3348
3349#if defined LIBO_INTERNAL_ONLY1
3350 // A wrapper for the first expression in an
3351 //
3352 // OUString::Concat(e1) + e2 + ...
3353 //
3354 // concatenation chain, when neither of the first two e1, e2 is one of our rtl string-related
3355 // classes (so something like
3356 //
3357 // OUString s = "a" + (b ? std::u16string_view(u"c") : std::u16string_view(u"dd"));
3358 //
3359 // would not compile):
3360 template<typename T> [[nodiscard]] static
3361 typename std::enable_if_t<
3362 ToStringHelper<T>::allowOUStringConcat, OUStringConcat<OUStringConcatMarker, T>>
3363 Concat(T const & value) { return OUStringConcat<OUStringConcatMarker, T>({}, value); }
3364
3365 // This overload is needed so that an argument of type 'char const[N]' ends up as
3366 // 'OUStringConcat<rtl::OUStringConcatMarker, char const[N]>' rather than as
3367 // 'OUStringConcat<rtl::OUStringConcatMarker, char[N]>':
3368 template<typename T, std::size_t N> [[nodiscard]] static
3369 typename std::enable_if_t<
3370 ToStringHelper<T[N]>::allowOUStringConcat, OUStringConcat<OUStringConcatMarker, T[N]>>
3371 Concat(T (& value)[N]) { return OUStringConcat<OUStringConcatMarker, T[N]>({}, value); }
3372#endif
3373
3374private:
3375 OUString & internalAppend( rtl_uString* pOtherData )
3376 {
3377 rtl_uString* pNewData = NULL__null;
3378 rtl_uString_newConcat( &pNewData, pData, pOtherData );
3379 if (pNewData == NULL__null) {
3380 throw std::bad_alloc();
3381 }
3382 rtl_uString_assign(&pData, pNewData);
3383 rtl_uString_release(pNewData);
3384 return *this;
3385 }
3386
3387};
3388
3389#if defined LIBO_INTERNAL_ONLY1
3390// Prevent the operator ==/!= overloads with 'sal_Unicode const *' parameter from
3391// being selected for nonsensical code like
3392//
3393// if (ouIdAttr == nullptr)
3394//
3395void operator ==(OUString const &, std::nullptr_t) = delete;
3396void operator ==(std::nullptr_t, OUString const &) = delete;
3397void operator !=(OUString const &, std::nullptr_t) = delete;
3398void operator !=(std::nullptr_t, OUString const &) = delete;
3399#endif
3400
3401#if defined LIBO_INTERNAL_ONLY1 // "RTL_FAST_STRING"
3402/// @cond INTERNAL
3403
3404/**
3405 @internal
3406*/
3407template<>
3408struct ToStringHelper< OUString >
3409 {
3410 static std::size_t length( const OUString& s ) { return s.getLength(); }
3411 static sal_Unicode* addData( sal_Unicode* buffer, const OUString& s ) { return addDataHelper( buffer, s.getStr(), s.getLength()); }
3412 static const bool allowOStringConcat = false;
3413 static const bool allowOUStringConcat = true;
3414 };
3415
3416/**
3417 @internal
3418*/
3419template<std::size_t N>
3420struct ToStringHelper< OUStringLiteral<N> >
3421 {
3422 static std::size_t length( const OUStringLiteral<N>& str ) { return str.getLength(); }
3423 static sal_Unicode* addData( sal_Unicode* buffer, const OUStringLiteral<N>& str ) { return addDataHelper( buffer, str.getStr(), str.getLength() ); }
3424 static const bool allowOStringConcat = false;
3425 static const bool allowOUStringConcat = true;
3426 };
3427
3428/**
3429 @internal
3430*/
3431template< typename charT, typename traits, typename T1, typename T2 >
3432inline std::basic_ostream<charT, traits> & operator <<(
3433 std::basic_ostream<charT, traits> & stream, OUStringConcat< T1, T2 >&& concat)
3434{
3435 return stream << OUString( std::move(concat) );
3436}
3437
3438/// @endcond
3439#endif
3440
3441/** A helper to use OUStrings with hash maps.
3442
3443 Instances of this class are unary function objects that can be used as
3444 hash function arguments to std::unordered_map and similar constructs.
3445 */
3446struct OUStringHash
3447{
3448 /** Compute a hash code for a string.
3449
3450 @param rString
3451 a string.
3452
3453 @return
3454 a hash code for the string. This hash code should not be stored
3455 persistently, as its computation may change in later revisions.
3456 */
3457 size_t operator()(const OUString& rString) const
3458 { return static_cast<size_t>(rString.hashCode()); }
3459};
3460
3461/* ======================================================================= */
3462
3463/** Convert an OString to an OUString, using a specific text encoding.
3464
3465 The lengths of the two strings may differ (e.g., for double-byte
3466 encodings, UTF-7, UTF-8).
3467
3468 @param rStr
3469 an OString to convert.
3470
3471 @param encoding
3472 the text encoding to use for conversion.
3473
3474 @param convertFlags
3475 flags which control the conversion. Either use
3476 OSTRING_TO_OUSTRING_CVTFLAGS, or see
3477 <http://udk.openoffice.org/cpp/man/spec/textconversion.html> for more
3478 details.
3479 */
3480inline OUString OStringToOUString( const OString & rStr,
3481 rtl_TextEncoding encoding,
3482 sal_uInt32 convertFlags = OSTRING_TO_OUSTRING_CVTFLAGS(((sal_uInt32)0x0003) | ((sal_uInt32)0x0030) | ((sal_uInt32)0x0300
))
)
3483{
3484 return OUString( rStr.getStr(), rStr.getLength(), encoding, convertFlags );
3485}
3486
3487/** Convert an OUString to an OString, using a specific text encoding.
3488
3489 The lengths of the two strings may differ (e.g., for double-byte
3490 encodings, UTF-7, UTF-8).
3491
3492 @param rUnicode
3493 an OUString to convert.
3494
3495 @param encoding
3496 the text encoding to use for conversion.
3497
3498 @param convertFlags
3499 flags which control the conversion. Either use
3500 OUSTRING_TO_OSTRING_CVTFLAGS, or see
3501 <http://udk.openoffice.org/cpp/man/spec/textconversion.html> for more
3502 details.
3503 */
3504inline OString OUStringToOString( const OUString & rUnicode,
3505 rtl_TextEncoding encoding,
3506 sal_uInt32 convertFlags = OUSTRING_TO_OSTRING_CVTFLAGS(((sal_uInt32)0x0006) | ((sal_uInt32)0x0060) | ((sal_uInt32)0x0100
) | ((sal_uInt32)0x0400))
)
3507{
3508 return OString( rUnicode.getStr(), rUnicode.getLength(), encoding, convertFlags );
3509}
3510
3511/* ======================================================================= */
3512
3513/**
3514 Support for rtl::OUString in std::ostream (and thus in
3515 CPPUNIT_ASSERT or SAL_INFO macros, for example).
3516
3517 The rtl::OUString is converted to UTF-8.
3518
3519 @since LibreOffice 3.5.
3520*/
3521template< typename charT, typename traits >
3522inline std::basic_ostream<charT, traits> & operator <<(
3523 std::basic_ostream<charT, traits> & stream, OUString const & rString)
3524{
3525 return stream <<
3526 OUStringToOString(rString, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76)));
3527 // best effort; potentially loses data due to conversion failures
3528 // (stray surrogate halves) and embedded null characters
3529}
3530
3531} // namespace
3532
3533#ifdef RTL_STRING_UNITTEST
3534namespace rtl
3535{
3536typedef rtlunittest::OUString OUString;
3537}
3538#endif
3539
3540// In internal code, allow to use classes like OUString without having to
3541// explicitly refer to the rtl namespace, which is kind of superfluous given
3542// that OUString itself is namespaced by its OU prefix:
3543#if defined LIBO_INTERNAL_ONLY1 && !defined RTL_STRING_UNITTEST
3544using ::rtl::OUString;
3545using ::rtl::OUStringHash;
3546using ::rtl::OStringToOUString;
3547using ::rtl::OUStringToOString;
3548using ::rtl::OUStringLiteral;
3549using ::rtl::OUStringChar;
3550#endif
3551
3552/// @cond INTERNAL
3553/**
3554 Make OUString hashable by default for use in STL containers.
3555
3556 @since LibreOffice 6.0
3557*/
3558#if defined LIBO_INTERNAL_ONLY1
3559namespace std {
3560
3561template<>
3562struct hash<::rtl::OUString>
3563{
3564 std::size_t operator()(::rtl::OUString const & s) const
3565 { return std::size_t(s.hashCode()); }
3566};
3567
3568}
3569
3570#endif
3571/// @endcond
3572
3573#endif /* _RTL_USTRING_HXX */
3574
3575/* vim:set shiftwidth=4 softtabstop=4 expandtab: */