File: | home/maarten/src/libreoffice/core/sw/source/core/text/itrform2.cxx |
Warning: | line 799, column 30 Called C++ object pointer is null |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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 | |||||||||
60 | using namespace ::com::sun::star; | ||||||||
61 | |||||||||
62 | namespace { | ||||||||
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 | |||||||||
75 | static void ClearFly( SwTextFormatInfo &rInf ) | ||||||||
76 | { | ||||||||
77 | delete rInf.GetFly(); | ||||||||
78 | rInf.SetFly(nullptr); | ||||||||
79 | } | ||||||||
80 | |||||||||
81 | void 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 | |||||||||
106 | SwTextFormatter::~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 | |||||||||
117 | void 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 | |||||||||
129 | sal_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 | |||||||||
146 | SwLinePortion *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 | |||||||||
294 | void 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 | |||||||||
356 | void 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) | ||||||||
| |||||||||
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); | ||||||||
370 | |||||||||
371 | if( !m_pCurr->GetAscent() && !m_pCurr->Height() ) | ||||||||
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); | ||||||||
378 | CalcFlyWidth( rInf ); | ||||||||
379 | SwFlyPortion *pFly = rInf.GetFly(); | ||||||||
380 | if( pFly ) | ||||||||
381 | { | ||||||||
382 | if ( 0 < pFly->GetFix() ) | ||||||||
383 | ClearFly( rInf ); | ||||||||
384 | else | ||||||||
385 | rInf.SetFull(true); | ||||||||
386 | } | ||||||||
387 | |||||||||
388 | SwLinePortion *pPor = NewPortion( rInf ); | ||||||||
389 | |||||||||
390 | // Asian grid stuff | ||||||||
391 | SwTextGridItem const*const pGrid(GetGridItem(m_pFrame->FindPageFrame())); | ||||||||
392 | const bool bHasGrid = pGrid && rInf.SnapToGrid() && | ||||||||
393 | GRID_LINES_CHARS == pGrid->GetGridType(); | ||||||||
394 | |||||||||
395 | |||||||||
396 | const SwDoc & rDoc = rInf.GetTextFrame()->GetDoc(); | ||||||||
397 | const sal_uInt16 nGridWidth = bHasGrid
| ||||||||
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() ) | ||||||||
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) | ||||||||
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() ) | ||||||||
419 | static_cast<SwFieldPortion*>(pPor)->CheckScript( rInf ); | ||||||||
420 | |||||||||
421 | if( ! bHasGrid
| ||||||||
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
| ||||||||
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() ) | ||||||||
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() ) | ||||||||
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 ) | ||||||||
553 | nUnderLineStart = GetLeftMargin() + rInf.X(); | ||||||||
554 | |||||||||
555 | if ( pPor->IsFlyPortion() ) | ||||||||
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() ) && | ||||||||
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() && | ||||||||
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 ) ) | ||||||||
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 ) | ||||||||
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
| ||||||||
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() | ||||||||
698 | && !pPor->IsGrfNumPortion() && ! pPor->InNumberGrp() | ||||||||
699 | && !pPor->IsMultiPortion() ) | ||||||||
700 | CalcAscent( rInf, pPor ); | ||||||||
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 | |||||||||
730 | void 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 | |||||||||
745 | void SwTextFormatter::CalcAscent( SwTextFormatInfo &rInf, SwLinePortion *pPor ) | ||||||||
746 | { | ||||||||
747 | bool bCalc = false; | ||||||||
748 | if ( pPor->InFieldGrp() && static_cast<SwFieldPortion*>(pPor)->GetFont() ) | ||||||||
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) && | ||||||||
762 | rInf.GetLast() && rInf.GetLast()->InNumberGrp() && | ||||||||
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 | ||||||||
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(); | ||||||||
789 | if ( pPor->IsQuoVadisPortion() ) | ||||||||
790 | bChg = SeekStartAndChg( rInf, true ); | ||||||||
791 | else | ||||||||
792 | { | ||||||||
793 | if( bFirstPor
| ||||||||
794 | { | ||||||||
795 | if( !rInf.GetText().isEmpty() ) | ||||||||
796 | { | ||||||||
797 | if ( pPor->GetLen() || !rInf.GetIdx() | ||||||||
798 | || ( m_pCurr != pLast && !pLast->IsFlyPortion() ) | ||||||||
799 | || !m_pCurr->IsRest() ) // instead of !rInf.GetRest() | ||||||||
| |||||||||
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 | |||||||||
841 | namespace { | ||||||||
842 | |||||||||
843 | class SwMetaPortion : public SwTextPortion | ||||||||
844 | { | ||||||||
845 | public: | ||||||||
846 | SwMetaPortion() { SetWhichPor( PortionType::Meta ); } | ||||||||
847 | virtual void Paint( const SwTextPaintInfo &rInf ) const override; | ||||||||
848 | }; | ||||||||
849 | |||||||||
850 | } | ||||||||
851 | |||||||||
852 | void SwMetaPortion::Paint( const SwTextPaintInfo &rInf ) const | ||||||||
853 | { | ||||||||
854 | if ( Width() ) | ||||||||
855 | { | ||||||||
856 | rInf.DrawViewOpt( *this, PortionType::Meta ); | ||||||||
857 | SwTextPortion::Paint( rInf ); | ||||||||
858 | } | ||||||||
859 | } | ||||||||
860 | |||||||||
861 | namespace 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 | |||||||||
884 | SwTextPortion *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 | |||||||||
989 | SwTextPortion *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 | ||||||||
1063 | SwLinePortion *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 | |||||||||
1231 | static 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 | |||||||||
1259 | SwLinePortion *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 | |||||||||
1560 | TextFrameIndex 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 | |||||||||
1765 | void SwTextFormatter::RecalcRealHeight() | ||||||||
1766 | { | ||||||||
1767 | do | ||||||||
1768 | { | ||||||||
1769 | CalcRealHeight(); | ||||||||
1770 | } while (Next()); | ||||||||
1771 | } | ||||||||
1772 | |||||||||
1773 | void 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 | |||||||||
1929 | void 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 | |||||||||
1953 | void 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 | |||||||||
1966 | bool 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 | |||||||||
1979 | SwTwips 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. | ||||||||
2004 | SwTwips 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 | ||||||||
2015 | bool 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 | |||||||||
2067 | void 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 | |||||||||
2079 | void 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 | |||||||||
2201 | void 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 | |||||||||
2248 | bool 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 | |||||||||
2336 | void 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 | |||||||||
2565 | SwFlyCntPortion *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 */ | ||||||||
2661 | void 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 | |||||||||
2679 | void 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 | |||||||||
2770 | namespace { | ||||||||
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: */ |
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 | |
27 | class SwTextSizeInfo; |
28 | class SwTextPaintInfo; |
29 | class SwTextFormatInfo; |
30 | class 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. |
50 | class SwLinePortion: public SwPosSize |
51 | { |
52 | protected: |
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(); |
60 | private: |
61 | PortionType nWhichPor; // Who's who? |
62 | bool m_bJoinBorderWithPrev; |
63 | bool m_bJoinBorderWithNext; |
64 | |
65 | void Truncate_(); |
66 | |
67 | public: |
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; } |
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; } |
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 | |
174 | inline 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 | |
185 | inline 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 | |
196 | inline void SwLinePortion::Truncate() |
197 | { |
198 | if ( mpNextPortion ) |
199 | Truncate_(); |
200 | } |
201 | |
202 | #endif |
203 | |
204 | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |
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 | |
28 | namespace o3tl |
29 | { |
30 | |
31 | #if !defined __COVERITY__ |
32 | |
33 | namespace detail { |
34 | |
35 | template<typename T1, typename T2> constexpr |
36 | typename std::enable_if< |
37 | std::is_signed<T1>::value && std::is_signed<T2>::value, bool>::type |
38 | isInRange(T2 value) { |
39 | return value >= std::numeric_limits<T1>::min() |
40 | && value <= std::numeric_limits<T1>::max(); |
41 | } |
42 | |
43 | template<typename T1, typename T2> constexpr |
44 | typename std::enable_if< |
45 | std::is_signed<T1>::value && std::is_unsigned<T2>::value, bool>::type |
46 | isInRange(T2 value) { |
47 | return value |
48 | <= static_cast<typename std::make_unsigned<T1>::type>( |
49 | std::numeric_limits<T1>::max()); |
50 | } |
51 | |
52 | template<typename T1, typename T2> constexpr |
53 | typename std::enable_if< |
54 | std::is_unsigned<T1>::value && std::is_signed<T2>::value, bool>::type |
55 | isInRange(T2 value) { |
56 | return value >= 0 |
57 | && (static_cast<typename std::make_unsigned<T2>::type>(value) |
58 | <= std::numeric_limits<T1>::max()); |
59 | } |
60 | |
61 | template<typename T1, typename T2> constexpr |
62 | typename std::enable_if< |
63 | std::is_unsigned<T1>::value && std::is_unsigned<T2>::value, bool>::type |
64 | isInRange(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 | /// |
82 | template <typename UNDERLYING_TYPE, typename PHANTOM_TYPE> |
83 | struct strong_int |
84 | { |
85 | public: |
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; } |
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; } |
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 | |
125 | private: |
126 | UNDERLYING_TYPE m_value; |
127 | }; |
128 | |
129 | template <typename UT, typename PT> |
130 | strong_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 | |
135 | template <typename UT, typename PT> |
136 | strong_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: */ |
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 |
49 | extern 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 | |
61 | namespace rtl |
62 | { |
63 | |
64 | class 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 | /** |
74 | A wrapper dressing a string literal as a static-refcount rtl_uString. |
75 | |
76 | This class is not part of public API and is meant to be used only in LibreOffice code. |
77 | @since LibreOffice 4.0 |
78 | */ |
79 | template<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 | |
83 | public: |
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 | |
104 | private: |
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 |
126 | namespace libreoffice_internal { |
127 | template<std::size_t N> struct ExceptConstCharArrayDetector<OUStringLiteral<N>> {}; |
128 | template<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 | |
160 | class SAL_WARN_UNUSED__attribute__((warn_unused)) SAL_DLLPUBLIC_RTTI__attribute__ ((type_visibility("default"))) OUString |
161 | { |
162 | public: |
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; |
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 | |
3374 | private: |
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 | // |
3395 | void operator ==(OUString const &, std::nullptr_t) = delete; |
3396 | void operator ==(std::nullptr_t, OUString const &) = delete; |
3397 | void operator !=(OUString const &, std::nullptr_t) = delete; |
3398 | void 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 | */ |
3407 | template<> |
3408 | struct 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 | */ |
3419 | template<std::size_t N> |
3420 | struct 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 | */ |
3431 | template< typename charT, typename traits, typename T1, typename T2 > |
3432 | inline 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 | */ |
3446 | struct 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 | */ |
3480 | inline 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 | */ |
3504 | inline 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 | */ |
3521 | template< typename charT, typename traits > |
3522 | inline 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 |
3534 | namespace rtl |
3535 | { |
3536 | typedef 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 |
3544 | using ::rtl::OUString; |
3545 | using ::rtl::OUStringHash; |
3546 | using ::rtl::OStringToOUString; |
3547 | using ::rtl::OUStringToOString; |
3548 | using ::rtl::OUStringLiteral; |
3549 | using ::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 |
3559 | namespace std { |
3560 | |
3561 | template<> |
3562 | struct 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: */ |