Bug Summary

File:home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx
Warning:line 1859, column 47
Called C++ object pointer is null

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name texteng.cxx -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=all -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -isystem /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/glm -isystem /usr/include/glib-2.0 -isystem /usr/lib64/glib-2.0/include -isystem /usr/include/libmount -isystem /usr/include/blkid -isystem /usr/include/cairo -isystem /usr/include/glib-2.0 -isystem /usr/lib64/glib-2.0/include -isystem /usr/include/pixman-1 -isystem /usr/include/freetype2 -isystem /usr/include/libpng16 -isystem /usr/include/libxml2 -isystem /usr/include/freetype2 -isystem /usr/include/libpng16 -isystem /usr/include/dbus-1.0 -isystem /usr/lib64/dbus-1.0/include -isystem /usr/include/freetype2 -isystem /usr/include/libpng16 -D BOOST_ERROR_CODE_HEADER_ONLY -D BOOST_SYSTEM_NO_DEPRECATED -D CPPU_ENV=gcc3 -D LINUX -D OSL_DEBUG_LEVEL=1 -D SAL_LOG_INFO -D SAL_LOG_WARN -D UNIX -D UNX -D X86_64 -D _PTHREADS -D _REENTRANT -D VCL_DLLIMPLEMENTATION -D DLLIMPLEMENTATION_UITEST -D CUI_DLL_NAME="libcuilo.so" -D DESKTOP_DETECTOR_DLL_NAME="libdesktop_detectorlo.so" -D TK_DLL_NAME="libtklo.so" -D SYSTEM_ZLIB -D GLM_FORCE_CTOR_INIT -D SK_USER_CONFIG_HEADER=</home/maarten/src/libreoffice/core/config_host/config_skia.h> -D SKIA_DLL -D ENABLE_CUPS -D HAVE_VALGRIND_HEADERS -D EXCEPTIONS_ON -D LIBO_INTERNAL_ONLY -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/epoxy/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/skia/include/core -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/skia/include/effects -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/skia/include/gpu -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/skia/include/config -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/skia/include/ports -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/skia/include/third_party/vulkan -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/skia/tools/gpu -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/skia -I /home/maarten/src/libreoffice/core/external/skia/inc/ -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/mdds/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/lcms2/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source/i18n -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source/common -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/harfbuzz/src -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/graphite/include -I /home/maarten/src/libreoffice/core/external/boost/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/boost -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/pdfium -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/pdfium/public -D COMPONENT_BUILD -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/libpng -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/libjpeg-turbo -I /home/maarten/src/libreoffice/core/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include/linux -I /home/maarten/src/libreoffice/core/config_host -I /home/maarten/src/libreoffice/core/vcl/inc -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/udkapi/normal -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/offapi/normal -I /home/maarten/src/libreoffice/core/workdir/CustomTarget/officecfg/registry -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libxml2 -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10 -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/x86_64-redhat-linux -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/backward -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O0 -Wno-missing-braces -std=c++17 -fdeprecated-macro -fdebug-compilation-dir /home/maarten/src/libreoffice/core -ferror-limit 19 -fvisibility hidden -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcxx-exceptions -fexceptions -debug-info-kind=constructor -analyzer-output=html -faddrsig -o /home/maarten/tmp/wis/scan-build-libreoffice/output/report/2020-10-07-141433-9725-1 -x c++ /home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20#include <tools/stream.hxx>
21
22#include <vcl/texteng.hxx>
23#include <vcl/textview.hxx>
24#include <vcl/commandevent.hxx>
25#include <vcl/inputctx.hxx>
26#include "textdoc.hxx"
27#include "textdat2.hxx"
28#include "textundo.hxx"
29#include "textund2.hxx"
30#include <svl/ctloptions.hxx>
31#include <vcl/window.hxx>
32#include <vcl/settings.hxx>
33#include <vcl/toolkit/edit.hxx>
34#include <vcl/virdev.hxx>
35#include <sal/log.hxx>
36#include <osl/diagnose.h>
37
38#include <com/sun/star/i18n/XBreakIterator.hpp>
39
40#include <com/sun/star/i18n/CharacterIteratorMode.hpp>
41
42#include <com/sun/star/i18n/WordType.hpp>
43
44#include <com/sun/star/i18n/InputSequenceChecker.hpp>
45#include <com/sun/star/i18n/InputSequenceCheckMode.hpp>
46#include <com/sun/star/i18n/ScriptType.hpp>
47
48#include <comphelper/processfactory.hxx>
49
50#include <unotools/localedatawrapper.hxx>
51#include <vcl/unohelp.hxx>
52
53#include <vcl/svapp.hxx>
54
55#include <unicode/ubidi.h>
56
57#include <algorithm>
58#include <cstddef>
59#include <cstdlib>
60#include <memory>
61#include <set>
62#include <string_view>
63#include <vector>
64
65using namespace ::com::sun::star;
66using namespace ::com::sun::star::uno;
67
68TextEngine::TextEngine()
69 : mpActiveView {nullptr}
70 , maTextColor {COL_BLACK}
71 , mnMaxTextLen {0}
72 , mnMaxTextWidth {0}
73 , mnCharHeight {0}
74 , mnCurTextWidth {-1}
75 , mnCurTextHeight {0}
76 , mnDefTab {0}
77 , meAlign {TxtAlign::Left}
78 , mbIsFormatting {false}
79 , mbFormatted {false}
80 , mbUpdate {true}
81 , mbModified {false}
82 , mbUndoEnabled {false}
83 , mbIsInUndo {false}
84 , mbDowning {false}
85 , mbRightToLeft {false}
86 , mbHasMultiLineParas {false}
87{
88 mpViews.reset( new TextViews );
89
90 mpIdleFormatter.reset( new IdleFormatter );
91 mpIdleFormatter->SetInvokeHandler( LINK( this, TextEngine, IdleFormatHdl )::tools::detail::makeLink( ::tools::detail::castTo<TextEngine
*>(this), &TextEngine::LinkStubIdleFormatHdl)
);
92 mpIdleFormatter->SetDebugName( "vcl::TextEngine mpIdleFormatter" );
93
94 mpRefDev = VclPtr<VirtualDevice>::Create();
95
96 ImpInitLayoutMode( mpRefDev );
97
98 ImpInitDoc();
99
100 vcl::Font aFont;
101 aFont.SetTransparent( false );
102 Color aFillColor( aFont.GetFillColor() );
103 aFillColor.SetTransparency( 0 );
104 aFont.SetFillColor( aFillColor );
105 SetFont( aFont );
106}
107
108TextEngine::~TextEngine()
109{
110 mbDowning = true;
111
112 mpIdleFormatter.reset();
113 mpDoc.reset();
114 mpTEParaPortions.reset();
115 mpViews.reset(); // only the list, not the Views
116 mpRefDev.disposeAndClear();
117 mpUndoManager.reset();
118 mpIMEInfos.reset();
119 mpLocaleDataWrapper.reset();
120}
121
122void TextEngine::InsertView( TextView* pTextView )
123{
124 mpViews->push_back( pTextView );
125 pTextView->SetSelection( TextSelection() );
126
127 if ( !GetActiveView() )
128 SetActiveView( pTextView );
129}
130
131void TextEngine::RemoveView( TextView* pTextView )
132{
133 TextViews::iterator it = std::find( mpViews->begin(), mpViews->end(), pTextView );
134 if( it != mpViews->end() )
135 {
136 pTextView->HideCursor();
137 mpViews->erase( it );
138 if ( pTextView == GetActiveView() )
139 SetActiveView( nullptr );
140 }
141}
142
143sal_uInt16 TextEngine::GetViewCount() const
144{
145 return mpViews->size();
146}
147
148TextView* TextEngine::GetView( sal_uInt16 nView ) const
149{
150 return (*mpViews)[ nView ];
151}
152
153
154void TextEngine::SetActiveView( TextView* pTextView )
155{
156 if ( pTextView != mpActiveView )
157 {
158 if ( mpActiveView )
159 mpActiveView->HideSelection();
160
161 mpActiveView = pTextView;
162
163 if ( mpActiveView )
164 mpActiveView->ShowSelection();
165 }
166}
167
168void TextEngine::SetFont( const vcl::Font& rFont )
169{
170 if ( rFont == maFont )
171 return;
172
173 maFont = rFont;
174 // #i40221# As the font's color now defaults to transparent (since i35764)
175 // we have to choose a useful textcolor in this case.
176 // Otherwise maTextColor and maFont.GetColor() are both transparent...
177 if( rFont.GetColor() == COL_TRANSPARENT )
178 maTextColor = COL_BLACK;
179 else
180 maTextColor = rFont.GetColor();
181
182 // Do not allow transparent fonts because of selection
183 // (otherwise delete the background in ImplPaint later differently)
184 maFont.SetTransparent( false );
185 // Tell VCL not to use the font color, use text color from OutputDevice
186 maFont.SetColor( COL_TRANSPARENT );
187 Color aFillColor( maFont.GetFillColor() );
188 aFillColor.SetTransparency( 0 );
189 maFont.SetFillColor( aFillColor );
190
191 maFont.SetAlignment( ALIGN_TOP );
192 mpRefDev->SetFont( maFont );
193 mnDefTab = mpRefDev->GetTextWidth(" ");
194 if ( !mnDefTab )
195 mnDefTab = mpRefDev->GetTextWidth("XXXX");
196 if ( !mnDefTab )
197 mnDefTab = 1;
198 mnCharHeight = mpRefDev->GetTextHeight();
199
200 FormatFullDoc();
201 UpdateViews();
202
203 for ( auto nView = mpViews->size(); nView; )
204 {
205 TextView* pView = (*mpViews)[ --nView ];
206 pView->GetWindow()->SetInputContext( InputContext( GetFont(), !pView->IsReadOnly() ? InputContextFlags::Text|InputContextFlags::ExtText : InputContextFlags::NONE ) );
207 }
208
209}
210
211void TextEngine::SetMaxTextLen( sal_Int32 nLen )
212{
213 mnMaxTextLen = nLen>=0 ? nLen : EDIT_NOLIMIT((sal_Int32) 0x7FFFFFFF);
214}
215
216void TextEngine::SetMaxTextWidth( long nMaxWidth )
217{
218 if ( nMaxWidth>=0 && nMaxWidth != mnMaxTextWidth )
219 {
220 mnMaxTextWidth = nMaxWidth;
221 FormatFullDoc();
222 UpdateViews();
223 }
224}
225
226const sal_Unicode static_aLFText[] = { '\n', 0 };
227const sal_Unicode static_aCRText[] = { '\r', 0 };
228const sal_Unicode static_aCRLFText[] = { '\r', '\n', 0 };
229
230static const sal_Unicode* static_getLineEndText( LineEnd aLineEnd )
231{
232 const sal_Unicode* pRet = nullptr;
233
234 switch( aLineEnd )
235 {
236 case LINEEND_LF:
237 pRet = static_aLFText;
238 break;
239 case LINEEND_CR:
240 pRet = static_aCRText;
241 break;
242 case LINEEND_CRLF:
243 pRet = static_aCRLFText;
244 break;
245 }
246 return pRet;
247}
248
249void TextEngine::ReplaceText(const TextSelection& rSel, const OUString& rText)
250{
251 ImpInsertText( rSel, rText );
252}
253
254OUString TextEngine::GetText( LineEnd aSeparator ) const
255{
256 return mpDoc->GetText( static_getLineEndText( aSeparator ) );
257}
258
259OUString TextEngine::GetTextLines( LineEnd aSeparator ) const
260{
261 OUStringBuffer aText;
262 const sal_uInt32 nParas = mpTEParaPortions->Count();
263 const sal_Unicode* pSep = static_getLineEndText( aSeparator );
264 for ( sal_uInt32 nP = 0; nP < nParas; ++nP )
265 {
266 TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nP );
267
268 const size_t nLines = pTEParaPortion->GetLines().size();
269 for ( size_t nL = 0; nL < nLines; ++nL )
270 {
271 TextLine& rLine = pTEParaPortion->GetLines()[nL];
272 aText.append( std::u16string_view(pTEParaPortion->GetNode()->GetText()).substr(rLine.GetStart(), rLine.GetEnd() - rLine.GetStart()) );
273 if ( pSep && ( ( (nP+1) < nParas ) || ( (nL+1) < nLines ) ) )
274 aText.append(pSep);
275 }
276 }
277 return aText.makeStringAndClear();
278}
279
280OUString TextEngine::GetText( sal_uInt32 nPara ) const
281{
282 return mpDoc->GetText( nPara );
283}
284
285sal_Int32 TextEngine::GetTextLen() const
286{
287 return mpDoc->GetTextLen( static_getLineEndText( LINEEND_LF ) );
288}
289
290sal_Int32 TextEngine::GetTextLen( const TextSelection& rSel ) const
291{
292 TextSelection aSel( rSel );
293 aSel.Justify();
294 ValidateSelection( aSel );
295 return mpDoc->GetTextLen( static_getLineEndText( LINEEND_LF ), &aSel );
296}
297
298sal_Int32 TextEngine::GetTextLen( const sal_uInt32 nPara ) const
299{
300 return mpDoc->GetNodes()[ nPara ]->GetText().getLength();
301}
302
303void TextEngine::SetUpdateMode( bool bUpdate )
304{
305 if ( bUpdate != mbUpdate )
306 {
307 mbUpdate = bUpdate;
308 if ( mbUpdate )
309 {
310 FormatAndUpdate( GetActiveView() );
311 if ( GetActiveView() )
312 GetActiveView()->ShowCursor();
313 }
314 }
315}
316
317bool TextEngine::DoesKeyChangeText( const KeyEvent& rKeyEvent )
318{
319 bool bDoesChange = false;
320
321 KeyFuncType eFunc = rKeyEvent.GetKeyCode().GetFunction();
322 if ( eFunc != KeyFuncType::DONTKNOW )
323 {
324 switch ( eFunc )
325 {
326 case KeyFuncType::UNDO:
327 case KeyFuncType::REDO:
328 case KeyFuncType::CUT:
329 case KeyFuncType::PASTE:
330 bDoesChange = true;
331 break;
332 default:
333 // might get handled below
334 eFunc = KeyFuncType::DONTKNOW;
335 }
336 }
337 if ( eFunc == KeyFuncType::DONTKNOW )
338 {
339 switch ( rKeyEvent.GetKeyCode().GetCode() )
340 {
341 case KEY_DELETE:
342 case KEY_BACKSPACE:
343 if ( !rKeyEvent.GetKeyCode().IsMod2() )
344 bDoesChange = true;
345 break;
346 case KEY_RETURN:
347 case KEY_TAB:
348 if ( !rKeyEvent.GetKeyCode().IsMod1() && !rKeyEvent.GetKeyCode().IsMod2() )
349 bDoesChange = true;
350 break;
351 default:
352 bDoesChange = TextEngine::IsSimpleCharInput( rKeyEvent );
353 }
354 }
355 return bDoesChange;
356}
357
358bool TextEngine::IsSimpleCharInput( const KeyEvent& rKeyEvent )
359{
360 return rKeyEvent.GetCharCode() >= 32 && rKeyEvent.GetCharCode() != 127 &&
361 KEY_MOD1 != (rKeyEvent.GetKeyCode().GetModifier() & ~KEY_SHIFT) && // (ssa) #i45714#:
362 KEY_MOD2 != (rKeyEvent.GetKeyCode().GetModifier() & ~KEY_SHIFT); // check for Ctrl and Alt separately
363}
364
365void TextEngine::ImpInitDoc()
366{
367 if ( mpDoc )
368 mpDoc->Clear();
369 else
370 mpDoc.reset( new TextDoc );
371
372 mpTEParaPortions.reset(new TEParaPortions);
373
374 std::unique_ptr<TextNode> pNode(new TextNode( OUString() ));
375 mpDoc->GetNodes().insert( mpDoc->GetNodes().begin(), std::move(pNode) );
376
377 TEParaPortion* pIniPortion = new TEParaPortion( mpDoc->GetNodes().begin()->get() );
378 mpTEParaPortions->Insert( pIniPortion, 0 );
379
380 mbFormatted = false;
381
382 ImpParagraphRemoved( TEXT_PARA_ALL((sal_uInt32) 0xFFFFFFFF) );
383 ImpParagraphInserted( 0 );
384}
385
386OUString TextEngine::GetText( const TextSelection& rSel, LineEnd aSeparator ) const
387{
388 if ( !rSel.HasRange() )
389 return OUString();
390
391 TextSelection aSel( rSel );
392 aSel.Justify();
393
394 OUStringBuffer aText;
395 const sal_uInt32 nStartPara = aSel.GetStart().GetPara();
396 const sal_uInt32 nEndPara = aSel.GetEnd().GetPara();
397 const sal_Unicode* pSep = static_getLineEndText( aSeparator );
398 for ( sal_uInt32 nNode = aSel.GetStart().GetPara(); nNode <= nEndPara; ++nNode )
399 {
400 TextNode* pNode = mpDoc->GetNodes()[ nNode ].get();
401
402 sal_Int32 nStartPos = 0;
403 sal_Int32 nEndPos = pNode->GetText().getLength();
404 if ( nNode == nStartPara )
405 nStartPos = aSel.GetStart().GetIndex();
406 if ( nNode == nEndPara ) // may also be == nStart!
407 nEndPos = aSel.GetEnd().GetIndex();
408
409 aText.append(std::u16string_view(pNode->GetText()).substr(nStartPos, nEndPos-nStartPos));
410 if ( nNode < nEndPara )
411 aText.append(pSep);
412 }
413 return aText.makeStringAndClear();
414}
415
416void TextEngine::ImpRemoveText()
417{
418 ImpInitDoc();
419
420 const TextSelection aEmptySel;
421 for (TextView* pView : *mpViews)
422 {
423 pView->ImpSetSelection( aEmptySel );
424 }
425 ResetUndo();
426}
427
428void TextEngine::SetText( const OUString& rText )
429{
430 ImpRemoveText();
431
432 const bool bUndoCurrentlyEnabled = IsUndoEnabled();
433 // the manually inserted text cannot be reversed by the user
434 EnableUndo( false );
435
436 const TextSelection aEmptySel;
437
438 TextPaM aPaM;
439 if ( !rText.isEmpty() )
440 aPaM = ImpInsertText( aEmptySel, rText );
441
442 for (TextView* pView : *mpViews)
443 {
444 pView->ImpSetSelection( aEmptySel );
445
446 // if no text, then no Format&Update => the text remains
447 if ( rText.isEmpty() && GetUpdateMode() )
448 pView->Invalidate();
449 }
450
451 if( rText.isEmpty() ) // otherwise needs invalidation later; !bFormatted is sufficient
452 mnCurTextHeight = 0;
453
454 FormatAndUpdate();
455
456 EnableUndo( bUndoCurrentlyEnabled );
457 SAL_WARN_IF( HasUndoManager() && GetUndoManager().GetUndoActionCount(), "vcl", "SetText: Undo!" )do { if (true && (HasUndoManager() && GetUndoManager
().GetUndoActionCount())) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "SetText: Undo!") == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "457" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "SetText: Undo!"), 0); } else { ::std::
ostringstream sal_detail_stream; sal_detail_stream << "SetText: Undo!"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"),
("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "457" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "SetText: Undo!") == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "457" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "SetText: Undo!"), 0); } else { ::std::
ostringstream sal_detail_stream; sal_detail_stream << "SetText: Undo!"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"),
("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "457" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
458}
459
460void TextEngine::CursorMoved( sal_uInt32 nNode )
461{
462 // delete empty attribute; but only if paragraph is not empty!
463 TextNode* pNode = mpDoc->GetNodes()[ nNode ].get();
464 if ( pNode && pNode->GetCharAttribs().HasEmptyAttribs() && !pNode->GetText().isEmpty() )
465 pNode->GetCharAttribs().DeleteEmptyAttribs();
466}
467
468void TextEngine::ImpRemoveChars( const TextPaM& rPaM, sal_Int32 nChars )
469{
470 SAL_WARN_IF( !nChars, "vcl", "ImpRemoveChars: 0 Chars?!" )do { if (true && (!nChars)) { switch (sal_detail_log_report
(::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE
: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail
::getResult( ::sal::detail::StreamStart() << "ImpRemoveChars: 0 Chars?!"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"
), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "470" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "ImpRemoveChars: 0 Chars?!"), 0); } else
{ ::std::ostringstream sal_detail_stream; sal_detail_stream <<
"ImpRemoveChars: 0 Chars?!"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "470" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "ImpRemoveChars: 0 Chars?!") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "470" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "ImpRemoveChars: 0 Chars?!"), 0); } else
{ ::std::ostringstream sal_detail_stream; sal_detail_stream <<
"ImpRemoveChars: 0 Chars?!"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "470" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
471 if ( IsUndoEnabled() && !IsInUndo() )
472 {
473 // attributes have to be saved for UNDO before RemoveChars!
474 TextNode* pNode = mpDoc->GetNodes()[ rPaM.GetPara() ].get();
475 OUString aStr( pNode->GetText().copy( rPaM.GetIndex(), nChars ) );
476
477 // check if attributes are being deleted or changed
478 const sal_Int32 nStart = rPaM.GetIndex();
479 const sal_Int32 nEnd = nStart + nChars;
480 for ( sal_uInt16 nAttr = pNode->GetCharAttribs().Count(); nAttr; )
481 {
482 TextCharAttrib& rAttr = pNode->GetCharAttribs().GetAttrib( --nAttr );
483 if ( ( rAttr.GetEnd() >= nStart ) && ( rAttr.GetStart() < nEnd ) )
484 {
485 break; // for
486 }
487 }
488 InsertUndo( std::make_unique<TextUndoRemoveChars>( this, rPaM, aStr ) );
489 }
490
491 mpDoc->RemoveChars( rPaM, nChars );
492 ImpCharsRemoved( rPaM.GetPara(), rPaM.GetIndex(), nChars );
493}
494
495TextPaM TextEngine::ImpConnectParagraphs( sal_uInt32 nLeft, sal_uInt32 nRight )
496{
497 SAL_WARN_IF( nLeft == nRight, "vcl", "ImpConnectParagraphs: connect the very same paragraph ?" )do { if (true && (nLeft == nRight)) { switch (sal_detail_log_report
(::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE
: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail
::getResult( ::sal::detail::StreamStart() << "ImpConnectParagraphs: connect the very same paragraph ?"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"
), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "497" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "ImpConnectParagraphs: connect the very same paragraph ?"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "ImpConnectParagraphs: connect the very same paragraph ?"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"),
("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "497" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "ImpConnectParagraphs: connect the very same paragraph ?"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"
), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "497" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "ImpConnectParagraphs: connect the very same paragraph ?"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "ImpConnectParagraphs: connect the very same paragraph ?"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"),
("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "497" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
498
499 TextNode* pLeft = mpDoc->GetNodes()[ nLeft ].get();
500 TextNode* pRight = mpDoc->GetNodes()[ nRight ].get();
501
502 if ( IsUndoEnabled() && !IsInUndo() )
503 InsertUndo( std::make_unique<TextUndoConnectParas>( this, nLeft, pLeft->GetText().getLength() ) );
504
505 // first lookup Portions, as pRight is gone after ConnectParagraphs
506 TEParaPortion* pLeftPortion = mpTEParaPortions->GetObject( nLeft );
507 TEParaPortion* pRightPortion = mpTEParaPortions->GetObject( nRight );
508 SAL_WARN_IF( !pLeft || !pLeftPortion, "vcl", "ImpConnectParagraphs(1): Hidden Portion" )do { if (true && (!pLeft || !pLeftPortion)) { switch (
sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) { case
SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "ImpConnectParagraphs(1): Hidden Portion") == 1) {
::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "508" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "ImpConnectParagraphs(1): Hidden Portion"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "ImpConnectParagraphs(1): Hidden Portion"; ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "508" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "ImpConnectParagraphs(1): Hidden Portion") == 1) {
::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "508" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "ImpConnectParagraphs(1): Hidden Portion"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "ImpConnectParagraphs(1): Hidden Portion"; ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "508" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
509 SAL_WARN_IF( !pRight || !pRightPortion, "vcl", "ImpConnectParagraphs(2): Hidden Portion" )do { if (true && (!pRight || !pRightPortion)) { switch
(sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) {
case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "ImpConnectParagraphs(2): Hidden Portion") == 1) {
::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "509" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "ImpConnectParagraphs(2): Hidden Portion"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "ImpConnectParagraphs(2): Hidden Portion"; ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "509" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "ImpConnectParagraphs(2): Hidden Portion") == 1) {
::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "509" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "ImpConnectParagraphs(2): Hidden Portion"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "ImpConnectParagraphs(2): Hidden Portion"; ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "509" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
510
511 TextPaM aPaM = mpDoc->ConnectParagraphs( pLeft, pRight );
512 ImpParagraphRemoved( nRight );
513
514 pLeftPortion->MarkSelectionInvalid( aPaM.GetIndex() );
515
516 mpTEParaPortions->Remove( nRight );
517 // the right Node is deleted by EditDoc::ConnectParagraphs()
518
519 return aPaM;
520}
521
522TextPaM TextEngine::ImpDeleteText( const TextSelection& rSel )
523{
524 if ( !rSel.HasRange() )
525 return rSel.GetStart();
526
527 TextSelection aSel( rSel );
528 aSel.Justify();
529 TextPaM aStartPaM( aSel.GetStart() );
530 TextPaM aEndPaM( aSel.GetEnd() );
531
532 CursorMoved( aStartPaM.GetPara() ); // so that newly-adjusted attributes vanish
533 CursorMoved( aEndPaM.GetPara() ); // so that newly-adjusted attributes vanish
534
535 SAL_WARN_IF( !mpDoc->IsValidPaM( aStartPaM ), "vcl", "ImpDeleteText(1): bad Index" )do { if (true && (!mpDoc->IsValidPaM( aStartPaM ))
) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "ImpDeleteText(1): bad Index") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "535" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "ImpDeleteText(1): bad Index"), 0); } else
{ ::std::ostringstream sal_detail_stream; sal_detail_stream <<
"ImpDeleteText(1): bad Index"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "535" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "ImpDeleteText(1): bad Index") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "535" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "ImpDeleteText(1): bad Index"), 0); } else
{ ::std::ostringstream sal_detail_stream; sal_detail_stream <<
"ImpDeleteText(1): bad Index"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "535" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
536 SAL_WARN_IF( !mpDoc->IsValidPaM( aEndPaM ), "vcl", "ImpDeleteText(2): bad Index" )do { if (true && (!mpDoc->IsValidPaM( aEndPaM ))) {
switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN, "vcl"
)) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "ImpDeleteText(2): bad Index") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "536" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "ImpDeleteText(2): bad Index"), 0); } else
{ ::std::ostringstream sal_detail_stream; sal_detail_stream <<
"ImpDeleteText(2): bad Index"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "536" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "ImpDeleteText(2): bad Index") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "536" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "ImpDeleteText(2): bad Index"), 0); } else
{ ::std::ostringstream sal_detail_stream; sal_detail_stream <<
"ImpDeleteText(2): bad Index"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "536" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
537
538 const sal_uInt32 nStartNode = aStartPaM.GetPara();
539 sal_uInt32 nEndNode = aEndPaM.GetPara();
540
541 // remove all Nodes inbetween
542 for ( sal_uInt32 z = nStartNode+1; z < nEndNode; ++z )
543 {
544 // always nStartNode+1, because of Remove()!
545 ImpRemoveParagraph( nStartNode+1 );
546 }
547
548 if ( nStartNode != nEndNode )
549 {
550 // the remainder of StartNodes...
551 TextNode* pLeft = mpDoc->GetNodes()[ nStartNode ].get();
552 sal_Int32 nChars = pLeft->GetText().getLength() - aStartPaM.GetIndex();
553 if ( nChars )
554 {
555 ImpRemoveChars( aStartPaM, nChars );
556 TEParaPortion* pPortion = mpTEParaPortions->GetObject( nStartNode );
557 SAL_WARN_IF( !pPortion, "vcl", "ImpDeleteText(3): bad Index" )do { if (true && (!pPortion)) { switch (sal_detail_log_report
(::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE
: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail
::getResult( ::sal::detail::StreamStart() << "ImpDeleteText(3): bad Index"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"
), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "557" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "ImpDeleteText(3): bad Index"), 0); } else
{ ::std::ostringstream sal_detail_stream; sal_detail_stream <<
"ImpDeleteText(3): bad Index"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "557" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "ImpDeleteText(3): bad Index") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "557" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "ImpDeleteText(3): bad Index"), 0); } else
{ ::std::ostringstream sal_detail_stream; sal_detail_stream <<
"ImpDeleteText(3): bad Index"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "557" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
558 pPortion->MarkSelectionInvalid( aStartPaM.GetIndex() );
559 }
560
561 // the beginning of EndNodes...
562 nEndNode = nStartNode+1; // the other paragraphs were deleted
563 nChars = aEndPaM.GetIndex();
564 if ( nChars )
565 {
566 aEndPaM.GetPara() = nEndNode;
567 aEndPaM.GetIndex() = 0;
568 ImpRemoveChars( aEndPaM, nChars );
569 TEParaPortion* pPortion = mpTEParaPortions->GetObject( nEndNode );
570 SAL_WARN_IF( !pPortion, "vcl", "ImpDeleteText(4): bad Index" )do { if (true && (!pPortion)) { switch (sal_detail_log_report
(::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE
: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail
::getResult( ::sal::detail::StreamStart() << "ImpDeleteText(4): bad Index"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"
), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "570" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "ImpDeleteText(4): bad Index"), 0); } else
{ ::std::ostringstream sal_detail_stream; sal_detail_stream <<
"ImpDeleteText(4): bad Index"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "570" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "ImpDeleteText(4): bad Index") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "570" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "ImpDeleteText(4): bad Index"), 0); } else
{ ::std::ostringstream sal_detail_stream; sal_detail_stream <<
"ImpDeleteText(4): bad Index"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "570" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
571 pPortion->MarkSelectionInvalid( 0 );
572 }
573
574 // connect...
575 aStartPaM = ImpConnectParagraphs( nStartNode, nEndNode );
576 }
577 else
578 {
579 const sal_Int32 nChars = aEndPaM.GetIndex() - aStartPaM.GetIndex();
580 ImpRemoveChars( aStartPaM, nChars );
581 TEParaPortion* pPortion = mpTEParaPortions->GetObject( nStartNode );
582 SAL_WARN_IF( !pPortion, "vcl", "ImpDeleteText(5): bad Index" )do { if (true && (!pPortion)) { switch (sal_detail_log_report
(::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE
: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail
::getResult( ::sal::detail::StreamStart() << "ImpDeleteText(5): bad Index"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"
), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "582" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "ImpDeleteText(5): bad Index"), 0); } else
{ ::std::ostringstream sal_detail_stream; sal_detail_stream <<
"ImpDeleteText(5): bad Index"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "582" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "ImpDeleteText(5): bad Index") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "582" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "ImpDeleteText(5): bad Index"), 0); } else
{ ::std::ostringstream sal_detail_stream; sal_detail_stream <<
"ImpDeleteText(5): bad Index"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "582" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
583 pPortion->MarkInvalid( aEndPaM.GetIndex(), aStartPaM.GetIndex() - aEndPaM.GetIndex() );
584 }
585
586// UpdateSelections();
587 TextModified();
588 return aStartPaM;
589}
590
591void TextEngine::ImpRemoveParagraph( sal_uInt32 nPara )
592{
593 std::unique_ptr<TextNode> pNode = std::move(mpDoc->GetNodes()[ nPara ]);
594
595 // the Node is handled by Undo and is deleted if appropriate
596 mpDoc->GetNodes().erase( mpDoc->GetNodes().begin() + nPara );
597 if ( IsUndoEnabled() && !IsInUndo() )
598 InsertUndo( std::make_unique<TextUndoDelPara>( this, pNode.release(), nPara ) );
599
600 mpTEParaPortions->Remove( nPara );
601
602 ImpParagraphRemoved( nPara );
603}
604
605uno::Reference < i18n::XExtendedInputSequenceChecker > const & TextEngine::GetInputSequenceChecker()
606{
607 if ( !mxISC.is() )
608 {
609 mxISC = i18n::InputSequenceChecker::create( ::comphelper::getProcessComponentContext() );
610 }
611 return mxISC;
612}
613
614bool TextEngine::IsInputSequenceCheckingRequired( sal_Unicode c, const TextSelection& rCurSel ) const
615{
616 SvtCTLOptions aCTLOptions;
617
618 // get the index that really is first
619 const sal_Int32 nFirstPos = std::min(rCurSel.GetStart().GetIndex(), rCurSel.GetEnd().GetIndex());
620
621 bool bIsSequenceChecking =
622 aCTLOptions.IsCTLFontEnabled() &&
623 aCTLOptions.IsCTLSequenceChecking() &&
624 nFirstPos != 0; /* first char needs not to be checked */
625
626 if (bIsSequenceChecking)
627 {
628 uno::Reference< i18n::XBreakIterator > xBI = const_cast<TextEngine *>(this)->GetBreakIterator();
629 bIsSequenceChecking = xBI.is() && i18n::ScriptType::COMPLEX == xBI->getScriptType( OUString( c ), 0 );
630 }
631
632 return bIsSequenceChecking;
633}
634
635TextPaM TextEngine::ImpInsertText( const TextSelection& rCurSel, sal_Unicode c, bool bOverwrite )
636{
637 return ImpInsertText( c, rCurSel, bOverwrite );
638}
639
640TextPaM TextEngine::ImpInsertText( sal_Unicode c, const TextSelection& rCurSel, bool bOverwrite, bool bIsUserInput )
641{
642 SAL_WARN_IF( c == '\n', "vcl", "InsertText: NewLine!" )do { if (true && (c == '\n')) { switch (sal_detail_log_report
(::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE
: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail
::getResult( ::sal::detail::StreamStart() << "InsertText: NewLine!"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"
), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "642" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "InsertText: NewLine!"), 0); } else { ::
std::ostringstream sal_detail_stream; sal_detail_stream <<
"InsertText: NewLine!"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "642" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "InsertText: NewLine!") == 1) { ::sal_detail_log(
(::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "642" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "InsertText: NewLine!"), 0); } else { ::
std::ostringstream sal_detail_stream; sal_detail_stream <<
"InsertText: NewLine!"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "642" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
643 SAL_WARN_IF( c == '\r', "vcl", "InsertText: NewLine!" )do { if (true && (c == '\r')) { switch (sal_detail_log_report
(::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE
: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail
::getResult( ::sal::detail::StreamStart() << "InsertText: NewLine!"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"
), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "643" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "InsertText: NewLine!"), 0); } else { ::
std::ostringstream sal_detail_stream; sal_detail_stream <<
"InsertText: NewLine!"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "643" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "InsertText: NewLine!") == 1) { ::sal_detail_log(
(::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "643" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "InsertText: NewLine!"), 0); } else { ::
std::ostringstream sal_detail_stream; sal_detail_stream <<
"InsertText: NewLine!"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "643" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
644
645 TextPaM aPaM( rCurSel.GetStart() );
646 TextNode* pNode = mpDoc->GetNodes()[ aPaM.GetPara() ].get();
647
648 bool bDoOverwrite = bOverwrite && ( aPaM.GetIndex() < pNode->GetText().getLength() );
649
650 bool bUndoAction = rCurSel.HasRange() || bDoOverwrite;
651
652 if ( bUndoAction )
653 UndoActionStart();
654
655 if ( rCurSel.HasRange() )
656 {
657 aPaM = ImpDeleteText( rCurSel );
658 }
659 else if ( bDoOverwrite )
660 {
661 // if selection, then don't overwrite a character
662 TextSelection aTmpSel( aPaM );
663 ++aTmpSel.GetEnd().GetIndex();
664 ImpDeleteText( aTmpSel );
665 }
666
667 if (bIsUserInput && IsInputSequenceCheckingRequired( c, rCurSel ))
668 {
669 uno::Reference < i18n::XExtendedInputSequenceChecker > xISC = GetInputSequenceChecker();
670 SvtCTLOptions aCTLOptions;
671
672 if (xISC.is())
673 {
674 sal_Int32 nTmpPos = aPaM.GetIndex();
675 sal_Int16 nCheckMode = aCTLOptions.IsCTLSequenceCheckingRestricted() ?
676 i18n::InputSequenceCheckMode::STRICT : i18n::InputSequenceCheckMode::BASIC;
677
678 // the text that needs to be checked is only the one
679 // before the current cursor position
680 OUString aOldText( mpDoc->GetText( aPaM.GetPara() ).copy(0, nTmpPos) );
681 if (aCTLOptions.IsCTLSequenceCheckingTypeAndReplace())
682 {
683 OUString aNewText( aOldText );
684 xISC->correctInputSequence( aNewText, nTmpPos - 1, c, nCheckMode );
685
686 // find position of first character that has changed
687 const sal_Int32 nOldLen = aOldText.getLength();
688 const sal_Int32 nNewLen = aNewText.getLength();
689 const sal_Unicode *pOldTxt = aOldText.getStr();
690 const sal_Unicode *pNewTxt = aNewText.getStr();
691 sal_Int32 nChgPos = 0;
692 while ( nChgPos < nOldLen && nChgPos < nNewLen &&
693 pOldTxt[nChgPos] == pNewTxt[nChgPos] )
694 ++nChgPos;
695
696 OUString aChgText( aNewText.copy( nChgPos ) );
697
698 // select text from first pos to be changed to current pos
699 TextSelection aSel( TextPaM( aPaM.GetPara(), nChgPos ), aPaM );
700
701 if (!aChgText.isEmpty())
702 // ImpInsertText implicitly handles undo...
703 return ImpInsertText( aSel, aChgText );
704 else
705 return aPaM;
706 }
707 else
708 {
709 // should the character be ignored (i.e. not get inserted) ?
710 if (!xISC->checkInputSequence( aOldText, nTmpPos - 1, c, nCheckMode ))
711 return aPaM; // nothing to be done -> no need for undo
712 }
713 }
714
715 // at this point now we will insert the character 'normally' some lines below...
716 }
717
718 if ( IsUndoEnabled() && !IsInUndo() )
719 {
720 std::unique_ptr<TextUndoInsertChars> pNewUndo(new TextUndoInsertChars( this, aPaM, OUString(c) ));
721 bool bTryMerge = !bDoOverwrite && ( c != ' ' );
722 InsertUndo( std::move(pNewUndo), bTryMerge );
723 }
724
725 TEParaPortion* pPortion = mpTEParaPortions->GetObject( aPaM.GetPara() );
726 pPortion->MarkInvalid( aPaM.GetIndex(), 1 );
727 if ( c == '\t' )
728 pPortion->SetNotSimpleInvalid();
729 aPaM = mpDoc->InsertText( aPaM, c );
730 ImpCharsInserted( aPaM.GetPara(), aPaM.GetIndex()-1, 1 );
731
732 TextModified();
733
734 if ( bUndoAction )
735 UndoActionEnd();
736
737 return aPaM;
738}
739
740TextPaM TextEngine::ImpInsertText( const TextSelection& rCurSel, const OUString& rStr )
741{
742 UndoActionStart();
743
744 TextPaM aPaM;
745
746 if ( rCurSel.HasRange() )
747 aPaM = ImpDeleteText( rCurSel );
748 else
749 aPaM = rCurSel.GetEnd();
750
751 OUString aText(convertLineEnd(rStr, LINEEND_LF));
752
753 sal_Int32 nStart = 0;
754 while ( nStart < aText.getLength() )
755 {
756 sal_Int32 nEnd = aText.indexOf( LINE_SEP0x0A, nStart );
757 if (nEnd == -1)
758 nEnd = aText.getLength(); // do not dereference!
759
760 // Start == End => empty line
761 if ( nEnd > nStart )
762 {
763 OUString aLine(aText.copy(nStart, nEnd-nStart));
764 if ( IsUndoEnabled() && !IsInUndo() )
765 InsertUndo( std::make_unique<TextUndoInsertChars>( this, aPaM, aLine ) );
766
767 TEParaPortion* pPortion = mpTEParaPortions->GetObject( aPaM.GetPara() );
768 pPortion->MarkInvalid( aPaM.GetIndex(), aLine.getLength() );
769 if (aLine.indexOf( '\t' ) != -1)
770 pPortion->SetNotSimpleInvalid();
771
772 aPaM = mpDoc->InsertText( aPaM, aLine );
773 ImpCharsInserted( aPaM.GetPara(), aPaM.GetIndex()-aLine.getLength(), aLine.getLength() );
774
775 }
776 if ( nEnd < aText.getLength() )
777 aPaM = ImpInsertParaBreak( aPaM );
778
779 if ( nEnd == aText.getLength() ) // #108611# prevent overflow in "nStart = nEnd+1" calculation
780 break;
781
782 nStart = nEnd+1;
783 }
784
785 UndoActionEnd();
786
787 TextModified();
788 return aPaM;
789}
790
791TextPaM TextEngine::ImpInsertParaBreak( const TextSelection& rCurSel )
792{
793 TextPaM aPaM;
794 if ( rCurSel.HasRange() )
795 aPaM = ImpDeleteText( rCurSel );
796 else
797 aPaM = rCurSel.GetEnd();
798
799 return ImpInsertParaBreak( aPaM );
800}
801
802TextPaM TextEngine::ImpInsertParaBreak( const TextPaM& rPaM )
803{
804 if ( IsUndoEnabled() && !IsInUndo() )
805 InsertUndo( std::make_unique<TextUndoSplitPara>( this, rPaM.GetPara(), rPaM.GetIndex() ) );
806
807 TextNode* pNode = mpDoc->GetNodes()[ rPaM.GetPara() ].get();
808 bool bFirstParaContentChanged = rPaM.GetIndex() < pNode->GetText().getLength();
809
810 TextPaM aPaM( mpDoc->InsertParaBreak( rPaM ) );
811
812 TEParaPortion* pPortion = mpTEParaPortions->GetObject( rPaM.GetPara() );
813 SAL_WARN_IF( !pPortion, "vcl", "ImpInsertParaBreak: Hidden Portion" )do { if (true && (!pPortion)) { switch (sal_detail_log_report
(::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE
: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail
::getResult( ::sal::detail::StreamStart() << "ImpInsertParaBreak: Hidden Portion"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"
), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "813" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "ImpInsertParaBreak: Hidden Portion"),
0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "ImpInsertParaBreak: Hidden Portion"; ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "813" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "ImpInsertParaBreak: Hidden Portion") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "813" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "ImpInsertParaBreak: Hidden Portion"),
0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "ImpInsertParaBreak: Hidden Portion"; ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "813" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
814 pPortion->MarkInvalid( rPaM.GetIndex(), 0 );
815
816 TextNode* pNewNode = mpDoc->GetNodes()[ aPaM.GetPara() ].get();
817 TEParaPortion* pNewPortion = new TEParaPortion( pNewNode );
818 mpTEParaPortions->Insert( pNewPortion, aPaM.GetPara() );
819 ImpParagraphInserted( aPaM.GetPara() );
820
821 CursorMoved( rPaM.GetPara() ); // if empty attribute created
822 TextModified();
823
824 if ( bFirstParaContentChanged )
825 Broadcast( TextHint( SfxHintId::TextParaContentChanged, rPaM.GetPara() ) );
826
827 return aPaM;
828}
829
830tools::Rectangle TextEngine::PaMtoEditCursor( const TextPaM& rPaM, bool bSpecial )
831{
832 SAL_WARN_IF( !GetUpdateMode(), "vcl", "PaMtoEditCursor: GetUpdateMode()" )do { if (true && (!GetUpdateMode())) { switch (sal_detail_log_report
(::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE
: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail
::getResult( ::sal::detail::StreamStart() << "PaMtoEditCursor: GetUpdateMode()"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"
), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "832" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "PaMtoEditCursor: GetUpdateMode()"), 0
); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "PaMtoEditCursor: GetUpdateMode()"; ::sal::detail::
log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "832" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "PaMtoEditCursor: GetUpdateMode()") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "832" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "PaMtoEditCursor: GetUpdateMode()"), 0
); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "PaMtoEditCursor: GetUpdateMode()"; ::sal::detail::
log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "832" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
833
834 tools::Rectangle aEditCursor;
835 long nY = 0;
836
837 if ( !mbHasMultiLineParas )
838 {
839 nY = rPaM.GetPara() * mnCharHeight;
840 }
841 else
842 {
843 for ( sal_uInt32 nPortion = 0; nPortion < rPaM.GetPara(); ++nPortion )
844 {
845 TEParaPortion* pPortion = mpTEParaPortions->GetObject(nPortion);
846 nY += pPortion->GetLines().size() * mnCharHeight;
847 }
848 }
849
850 aEditCursor = GetEditCursor( rPaM, bSpecial );
851 aEditCursor.AdjustTop(nY );
852 aEditCursor.AdjustBottom(nY );
853 return aEditCursor;
854}
855
856tools::Rectangle TextEngine::GetEditCursor( const TextPaM& rPaM, bool bSpecial, bool bPreferPortionStart )
857{
858 if ( !IsFormatted() && !IsFormatting() )
859 FormatAndUpdate();
860
861 TEParaPortion* pPortion = mpTEParaPortions->GetObject( rPaM.GetPara() );
862 //TextNode* pNode = mpDoc->GetNodes().GetObject( rPaM.GetPara() );
863
864 /*
865 bSpecial: If behind the last character of a made up line, stay at the
866 end of the line, not at the start of the next line.
867 Purpose: - really END = > behind the last character
868 - to selection...
869
870 */
871
872 long nY = 0;
873 sal_Int32 nCurIndex = 0;
874 TextLine* pLine = nullptr;
875 for (TextLine & rTmpLine : pPortion->GetLines())
876 {
877 if ( ( rTmpLine.GetStart() == rPaM.GetIndex() ) || ( rTmpLine.IsIn( rPaM.GetIndex(), bSpecial ) ) )
878 {
879 pLine = &rTmpLine;
880 break;
881 }
882
883 nCurIndex = nCurIndex + rTmpLine.GetLen();
884 nY += mnCharHeight;
885 }
886 if ( !pLine )
887 {
888 // Cursor at end of paragraph
889 SAL_WARN_IF( rPaM.GetIndex() != nCurIndex, "vcl", "GetEditCursor: Bad Index!" )do { if (true && (rPaM.GetIndex() != nCurIndex)) { switch
(sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) {
case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "GetEditCursor: Bad Index!") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "889" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "GetEditCursor: Bad Index!"), 0); } else
{ ::std::ostringstream sal_detail_stream; sal_detail_stream <<
"GetEditCursor: Bad Index!"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "889" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "GetEditCursor: Bad Index!") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "889" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "GetEditCursor: Bad Index!"), 0); } else
{ ::std::ostringstream sal_detail_stream; sal_detail_stream <<
"GetEditCursor: Bad Index!"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "889" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
890
891 pLine = & ( pPortion->GetLines().back() );
892 nY -= mnCharHeight;
893 }
894
895 tools::Rectangle aEditCursor;
896
897 aEditCursor.SetTop( nY );
898 nY += mnCharHeight;
899 aEditCursor.SetBottom( nY-1 );
900
901 // search within the line
902 long nX = ImpGetXPos( rPaM.GetPara(), pLine, rPaM.GetIndex(), bPreferPortionStart );
903 aEditCursor.SetLeft(nX);
904 aEditCursor.SetRight(nX);
905 return aEditCursor;
906}
907
908long TextEngine::ImpGetXPos( sal_uInt32 nPara, TextLine* pLine, sal_Int32 nIndex, bool bPreferPortionStart )
909{
910 SAL_WARN_IF( ( nIndex < pLine->GetStart() ) || ( nIndex > pLine->GetEnd() ) , "vcl", "ImpGetXPos: Bad parameters!" )do { if (true && (( nIndex < pLine->GetStart() )
|| ( nIndex > pLine->GetEnd() ))) { switch (sal_detail_log_report
(::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE
: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail
::getResult( ::sal::detail::StreamStart() << "ImpGetXPos: Bad parameters!"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"
), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "910" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "ImpGetXPos: Bad parameters!"), 0); } else
{ ::std::ostringstream sal_detail_stream; sal_detail_stream <<
"ImpGetXPos: Bad parameters!"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "910" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "ImpGetXPos: Bad parameters!") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "910" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "ImpGetXPos: Bad parameters!"), 0); } else
{ ::std::ostringstream sal_detail_stream; sal_detail_stream <<
"ImpGetXPos: Bad parameters!"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "910" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
911
912 bool bDoPreferPortionStart = bPreferPortionStart;
913 // Assure that the portion belongs to this line
914 if ( nIndex == pLine->GetStart() )
915 bDoPreferPortionStart = true;
916 else if ( nIndex == pLine->GetEnd() )
917 bDoPreferPortionStart = false;
918
919 TEParaPortion* pParaPortion = mpTEParaPortions->GetObject( nPara );
920
921 sal_Int32 nTextPortionStart = 0;
922 std::size_t nTextPortion = pParaPortion->GetTextPortions().FindPortion( nIndex, nTextPortionStart, bDoPreferPortionStart );
923
924 SAL_WARN_IF( ( nTextPortion < pLine->GetStartPortion() ) || ( nTextPortion > pLine->GetEndPortion() ), "vcl", "GetXPos: Portion not in current line!" )do { if (true && (( nTextPortion < pLine->GetStartPortion
() ) || ( nTextPortion > pLine->GetEndPortion() ))) { switch
(sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) {
case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "GetXPos: Portion not in current line!") == 1) { ::
sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "924" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "GetXPos: Portion not in current line!"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "GetXPos: Portion not in current line!"; ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "924" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "GetXPos: Portion not in current line!") == 1) { ::
sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "924" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "GetXPos: Portion not in current line!"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "GetXPos: Portion not in current line!"; ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "924" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
925
926 TETextPortion* pPortion = pParaPortion->GetTextPortions()[ nTextPortion ];
927
928 long nX = ImpGetPortionXOffset( nPara, pLine, nTextPortion );
929
930 long nPortionTextWidth = pPortion->GetWidth();
931
932 if ( nTextPortionStart != nIndex )
933 {
934 // Search within portion...
935 if ( nIndex == ( nTextPortionStart + pPortion->GetLen() ) )
936 {
937 // End of Portion
938 if ( ( pPortion->GetKind() == PORTIONKIND_TAB1 ) ||
939 ( !IsRightToLeft() && !pPortion->IsRightToLeft() ) ||
940 ( IsRightToLeft() && pPortion->IsRightToLeft() ) )
941 {
942 nX += nPortionTextWidth;
943 if ( ( pPortion->GetKind() == PORTIONKIND_TAB1 ) && ( (nTextPortion+1) < pParaPortion->GetTextPortions().size() ) )
944 {
945 TETextPortion* pNextPortion = pParaPortion->GetTextPortions()[ nTextPortion+1 ];
946 if (pNextPortion->GetKind() != PORTIONKIND_TAB1 && IsRightToLeft() != pNextPortion->IsRightToLeft())
947 {
948 // End of the tab portion, use start of next for cursor pos
949 SAL_WARN_IF( bPreferPortionStart, "vcl", "ImpGetXPos: How can we get here!" )do { if (true && (bPreferPortionStart)) { switch (sal_detail_log_report
(::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE
: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail
::getResult( ::sal::detail::StreamStart() << "ImpGetXPos: How can we get here!"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"
), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "949" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "ImpGetXPos: How can we get here!"), 0
); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "ImpGetXPos: How can we get here!"; ::sal::detail::
log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "949" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "ImpGetXPos: How can we get here!") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "949" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "ImpGetXPos: How can we get here!"), 0
); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "ImpGetXPos: How can we get here!"; ::sal::detail::
log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "949" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
950 nX = ImpGetXPos( nPara, pLine, nIndex, true );
951 }
952
953 }
954 }
955 }
956 else if ( pPortion->GetKind() == PORTIONKIND_TEXT0 )
957 {
958 SAL_WARN_IF( nIndex == pLine->GetStart(), "vcl", "ImpGetXPos: Strange behavior" )do { if (true && (nIndex == pLine->GetStart())) { switch
(sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) {
case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "ImpGetXPos: Strange behavior") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "958" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "ImpGetXPos: Strange behavior"), 0); }
else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "ImpGetXPos: Strange behavior"; ::sal::detail::log(
(::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "958" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "ImpGetXPos: Strange behavior") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "958" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "ImpGetXPos: Strange behavior"), 0); }
else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "ImpGetXPos: Strange behavior"; ::sal::detail::log(
(::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "958" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
959
960 long nPosInPortion = CalcTextWidth( nPara, nTextPortionStart, nIndex-nTextPortionStart );
961
962 if (IsRightToLeft() == pPortion->IsRightToLeft())
963 {
964 nX += nPosInPortion;
965 }
966 else
967 {
968 nX += nPortionTextWidth - nPosInPortion;
969 }
970 }
971 }
972 else // if ( nIndex == pLine->GetStart() )
973 {
974 if (pPortion->GetKind() != PORTIONKIND_TAB1 && IsRightToLeft() != pPortion->IsRightToLeft())
975 {
976 nX += nPortionTextWidth;
977 }
978 }
979
980 return nX;
981}
982
983const TextAttrib* TextEngine::FindAttrib( const TextPaM& rPaM, sal_uInt16 nWhich ) const
984{
985 const TextAttrib* pAttr = nullptr;
986 const TextCharAttrib* pCharAttr = FindCharAttrib( rPaM, nWhich );
987 if ( pCharAttr )
988 pAttr = &pCharAttr->GetAttr();
989 return pAttr;
990}
991
992const TextCharAttrib* TextEngine::FindCharAttrib( const TextPaM& rPaM, sal_uInt16 nWhich ) const
993{
994 const TextCharAttrib* pAttr = nullptr;
995 TextNode* pNode = mpDoc->GetNodes()[ rPaM.GetPara() ].get();
996 if (pNode && (rPaM.GetIndex() <= pNode->GetText().getLength()))
997 pAttr = pNode->GetCharAttribs().FindAttrib( nWhich, rPaM.GetIndex() );
998 return pAttr;
999}
1000
1001TextPaM TextEngine::GetPaM( const Point& rDocPos )
1002{
1003 SAL_WARN_IF( !GetUpdateMode(), "vcl", "GetPaM: GetUpdateMode()" )do { if (true && (!GetUpdateMode())) { switch (sal_detail_log_report
(::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE
: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail
::getResult( ::sal::detail::StreamStart() << "GetPaM: GetUpdateMode()"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"
), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1003" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "GetPaM: GetUpdateMode()"), 0); } else
{ ::std::ostringstream sal_detail_stream; sal_detail_stream <<
"GetPaM: GetUpdateMode()"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1003" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "GetPaM: GetUpdateMode()") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1003" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "GetPaM: GetUpdateMode()"), 0); } else
{ ::std::ostringstream sal_detail_stream; sal_detail_stream <<
"GetPaM: GetUpdateMode()"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1003" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
1004
1005 long nY = 0;
1006 for ( sal_uInt32 nPortion = 0; nPortion < mpTEParaPortions->Count(); ++nPortion )
1007 {
1008 TEParaPortion* pPortion = mpTEParaPortions->GetObject( nPortion );
1009 long nTmpHeight = pPortion->GetLines().size() * mnCharHeight;
1010 nY += nTmpHeight;
1011 if ( nY > rDocPos.Y() )
1012 {
1013 nY -= nTmpHeight;
1014 Point aPosInPara( rDocPos );
1015 aPosInPara.AdjustY( -nY );
1016
1017 TextPaM aPaM( nPortion, 0 );
1018 aPaM.GetIndex() = ImpFindIndex( nPortion, aPosInPara );
1019 return aPaM;
1020 }
1021 }
1022
1023 // not found - go to last visible
1024 const sal_uInt32 nLastNode = static_cast<sal_uInt32>(mpDoc->GetNodes().size() - 1);
1025 TextNode* pLast = mpDoc->GetNodes()[ nLastNode ].get();
1026 return TextPaM( nLastNode, pLast->GetText().getLength() );
1027}
1028
1029sal_Int32 TextEngine::ImpFindIndex( sal_uInt32 nPortion, const Point& rPosInPara )
1030{
1031 SAL_WARN_IF( !IsFormatted(), "vcl", "GetPaM: Not formatted" )do { if (true && (!IsFormatted())) { switch (sal_detail_log_report
(::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE
: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail
::getResult( ::sal::detail::StreamStart() << "GetPaM: Not formatted"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"
), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1031" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "GetPaM: Not formatted"), 0); } else
{ ::std::ostringstream sal_detail_stream; sal_detail_stream <<
"GetPaM: Not formatted"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1031" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "GetPaM: Not formatted") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1031" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "GetPaM: Not formatted"), 0); } else
{ ::std::ostringstream sal_detail_stream; sal_detail_stream <<
"GetPaM: Not formatted"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1031" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
1032 TEParaPortion* pPortion = mpTEParaPortions->GetObject( nPortion );
1033
1034 sal_Int32 nCurIndex = 0;
1035
1036 long nY = 0;
1037 TextLine* pLine = nullptr;
1038 std::vector<TextLine>::size_type nLine;
1039 for ( nLine = 0; nLine < pPortion->GetLines().size(); nLine++ )
1040 {
1041 TextLine& rmpLine = pPortion->GetLines()[ nLine ];
1042 nY += mnCharHeight;
1043 if ( nY > rPosInPara.Y() ) // that's it
1044 {
1045 pLine = &rmpLine;
1046 break; // correct Y-Position not needed
1047 }
1048 }
1049
1050 assert(pLine && "ImpFindIndex: pLine ?")(static_cast <bool> (pLine && "ImpFindIndex: pLine ?"
) ? void (0) : __assert_fail ("pLine && \"ImpFindIndex: pLine ?\""
, "/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
, 1050, __extension__ __PRETTY_FUNCTION__))
;
1051
1052 nCurIndex = GetCharPos( nPortion, nLine, rPosInPara.X() );
1053
1054 if ( nCurIndex && ( nCurIndex == pLine->GetEnd() ) &&
1055 ( pLine != &( pPortion->GetLines().back() ) ) )
1056 {
1057 uno::Reference < i18n::XBreakIterator > xBI = GetBreakIterator();
1058 sal_Int32 nCount = 1;
1059 nCurIndex = xBI->previousCharacters( pPortion->GetNode()->GetText(), nCurIndex, GetLocale(), i18n::CharacterIteratorMode::SKIPCELL, nCount, nCount );
1060 }
1061 return nCurIndex;
1062}
1063
1064sal_Int32 TextEngine::GetCharPos( sal_uInt32 nPortion, std::vector<TextLine>::size_type nLine, long nXPos )
1065{
1066
1067 TEParaPortion* pPortion = mpTEParaPortions->GetObject( nPortion );
1068 TextLine& rLine = pPortion->GetLines()[ nLine ];
1069
1070 sal_Int32 nCurIndex = rLine.GetStart();
1071
1072 long nTmpX = rLine.GetStartX();
1073 if ( nXPos <= nTmpX )
1074 return nCurIndex;
1075
1076 for ( std::size_t i = rLine.GetStartPortion(); i <= rLine.GetEndPortion(); i++ )
1077 {
1078 TETextPortion* pTextPortion = pPortion->GetTextPortions()[ i ];
1079 nTmpX += pTextPortion->GetWidth();
1080
1081 if ( nTmpX > nXPos )
1082 {
1083 if( pTextPortion->GetLen() > 1 )
1084 {
1085 nTmpX -= pTextPortion->GetWidth(); // position before Portion
1086 // TODO: Optimize: no GetTextBreak if fixed-width Font
1087 vcl::Font aFont;
1088 SeekCursor( nPortion, nCurIndex+1, aFont, nullptr );
1089 mpRefDev->SetFont( aFont);
1090 long nPosInPortion = nXPos-nTmpX;
1091 if ( IsRightToLeft() != pTextPortion->IsRightToLeft() )
1092 nPosInPortion = pTextPortion->GetWidth() - nPosInPortion;
1093 nCurIndex = mpRefDev->GetTextBreak( pPortion->GetNode()->GetText(), nPosInPortion, nCurIndex );
1094 // MT: GetTextBreak should assure that we are not within a CTL cell...
1095 }
1096 return nCurIndex;
1097 }
1098 nCurIndex += pTextPortion->GetLen();
1099 }
1100 return nCurIndex;
1101}
1102
1103long TextEngine::GetTextHeight() const
1104{
1105 SAL_WARN_IF( !GetUpdateMode(), "vcl", "GetTextHeight: GetUpdateMode()" )do { if (true && (!GetUpdateMode())) { switch (sal_detail_log_report
(::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE
: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail
::getResult( ::sal::detail::StreamStart() << "GetTextHeight: GetUpdateMode()"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"
), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1105" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "GetTextHeight: GetUpdateMode()"), 0
); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "GetTextHeight: GetUpdateMode()"; ::sal::detail::log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1105" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "GetTextHeight: GetUpdateMode()") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1105" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "GetTextHeight: GetUpdateMode()"), 0
); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "GetTextHeight: GetUpdateMode()"; ::sal::detail::log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1105" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
1106
1107 if ( !IsFormatted() && !IsFormatting() )
1108 const_cast<TextEngine*>(this)->FormatAndUpdate();
1109
1110 return mnCurTextHeight;
1111}
1112
1113long TextEngine::GetTextHeight( sal_uInt32 nParagraph ) const
1114{
1115 SAL_WARN_IF( !GetUpdateMode(), "vcl", "GetTextHeight: GetUpdateMode()" )do { if (true && (!GetUpdateMode())) { switch (sal_detail_log_report
(::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE
: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail
::getResult( ::sal::detail::StreamStart() << "GetTextHeight: GetUpdateMode()"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"
), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1115" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "GetTextHeight: GetUpdateMode()"), 0
); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "GetTextHeight: GetUpdateMode()"; ::sal::detail::log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1115" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "GetTextHeight: GetUpdateMode()") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1115" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "GetTextHeight: GetUpdateMode()"), 0
); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "GetTextHeight: GetUpdateMode()"; ::sal::detail::log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1115" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
1116
1117 if ( !IsFormatted() && !IsFormatting() )
1118 const_cast<TextEngine*>(this)->FormatAndUpdate();
1119
1120 return CalcParaHeight( nParagraph );
1121}
1122
1123long TextEngine::CalcTextWidth( sal_uInt32 nPara )
1124{
1125 long nParaWidth = 0;
1126 TEParaPortion* pPortion = mpTEParaPortions->GetObject( nPara );
1127 for ( auto nLine = pPortion->GetLines().size(); nLine; )
1128 {
1129 long nLineWidth = 0;
1130 TextLine& rLine = pPortion->GetLines()[ --nLine ];
1131 for ( std::size_t nTP = rLine.GetStartPortion(); nTP <= rLine.GetEndPortion(); nTP++ )
1132 {
1133 TETextPortion* pTextPortion = pPortion->GetTextPortions()[ nTP ];
1134 nLineWidth += pTextPortion->GetWidth();
1135 }
1136 if ( nLineWidth > nParaWidth )
1137 nParaWidth = nLineWidth;
1138 }
1139 return nParaWidth;
1140}
1141
1142long TextEngine::CalcTextWidth()
1143{
1144 if ( !IsFormatted() && !IsFormatting() )
1145 FormatAndUpdate();
1146
1147 if ( mnCurTextWidth < 0 )
1148 {
1149 mnCurTextWidth = 0;
1150 for ( sal_uInt32 nPara = mpTEParaPortions->Count(); nPara; )
1151 {
1152 const long nParaWidth = CalcTextWidth( --nPara );
1153 if ( nParaWidth > mnCurTextWidth )
1154 mnCurTextWidth = nParaWidth;
1155 }
1156 }
1157 return mnCurTextWidth+1;// wider by 1, as CreateLines breaks at >=
1158}
1159
1160long TextEngine::CalcTextHeight()
1161{
1162 SAL_WARN_IF( !GetUpdateMode(), "vcl", "CalcTextHeight: GetUpdateMode()" )do { if (true && (!GetUpdateMode())) { switch (sal_detail_log_report
(::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE
: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail
::getResult( ::sal::detail::StreamStart() << "CalcTextHeight: GetUpdateMode()"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"
), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1162" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "CalcTextHeight: GetUpdateMode()"), 0
); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "CalcTextHeight: GetUpdateMode()"; ::sal::detail::log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1162" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "CalcTextHeight: GetUpdateMode()") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1162" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "CalcTextHeight: GetUpdateMode()"), 0
); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "CalcTextHeight: GetUpdateMode()"; ::sal::detail::log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1162" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
1163
1164 long nY = 0;
1165 for ( auto nPortion = mpTEParaPortions->Count(); nPortion; )
1166 nY += CalcParaHeight( --nPortion );
1167 return nY;
1168}
1169
1170long TextEngine::CalcTextWidth( sal_uInt32 nPara, sal_Int32 nPortionStart, sal_Int32 nLen )
1171{
1172#ifdef DBG_UTIL
1173 // within the text there must not be a Portion change (attribute/tab)!
1174 sal_Int32 nTabPos = mpDoc->GetNodes()[ nPara ]->GetText().indexOf( '\t', nPortionStart );
1175 SAL_WARN_IF( nTabPos != -1 && nTabPos < (nPortionStart+nLen), "vcl", "CalcTextWidth: Tab!" )do { if (true && (nTabPos != -1 && nTabPos <
(nPortionStart+nLen))) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "CalcTextWidth: Tab!") == 1) { ::sal_detail_log( (
::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1175" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "CalcTextWidth: Tab!"), 0); } else {
::std::ostringstream sal_detail_stream; sal_detail_stream <<
"CalcTextWidth: Tab!"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1175" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "CalcTextWidth: Tab!") == 1) { ::sal_detail_log( (
::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1175" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "CalcTextWidth: Tab!"), 0); } else {
::std::ostringstream sal_detail_stream; sal_detail_stream <<
"CalcTextWidth: Tab!"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1175" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
1176#endif
1177
1178 vcl::Font aFont;
1179 SeekCursor( nPara, nPortionStart+1, aFont, nullptr );
1180 mpRefDev->SetFont( aFont );
1181 TextNode* pNode = mpDoc->GetNodes()[ nPara ].get();
1182 long nWidth = mpRefDev->GetTextWidth( pNode->GetText(), nPortionStart, nLen );
1183 return nWidth;
1184}
1185
1186void TextEngine::GetTextPortionRange(const TextPaM& rPaM, sal_Int32& nStart, sal_Int32& nEnd)
1187{
1188 nStart = 0;
1189 nEnd = 0;
1190 TEParaPortion* pParaPortion = mpTEParaPortions->GetObject( rPaM.GetPara() );
1191 for ( std::size_t i = 0; i < pParaPortion->GetTextPortions().size(); ++i )
1192 {
1193 TETextPortion* pTextPortion = pParaPortion->GetTextPortions()[ i ];
1194 if (nStart + pTextPortion->GetLen() > rPaM.GetIndex())
1195 {
1196 nEnd = nStart + pTextPortion->GetLen();
1197 return;
1198 }
1199 else
1200 {
1201 nStart += pTextPortion->GetLen();
1202 }
1203 }
1204}
1205
1206sal_uInt16 TextEngine::GetLineCount( sal_uInt32 nParagraph ) const
1207{
1208 SAL_WARN_IF( nParagraph >= mpTEParaPortions->Count(), "vcl", "GetLineCount: Out of range" )do { if (true && (nParagraph >= mpTEParaPortions->
Count())) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "GetLineCount: Out of range") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1208" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "GetLineCount: Out of range"), 0); }
else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "GetLineCount: Out of range"; ::sal::detail::log( (
::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1208" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "GetLineCount: Out of range") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1208" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "GetLineCount: Out of range"), 0); }
else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "GetLineCount: Out of range"; ::sal::detail::log( (
::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1208" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
1209
1210 TEParaPortion* pPPortion = mpTEParaPortions->GetObject( nParagraph );
1211 if ( pPPortion )
1212 return pPPortion->GetLines().size();
1213
1214 return 0;
1215}
1216
1217sal_Int32 TextEngine::GetLineLen( sal_uInt32 nParagraph, sal_uInt16 nLine ) const
1218{
1219 SAL_WARN_IF( nParagraph >= mpTEParaPortions->Count(), "vcl", "GetLineCount: Out of range" )do { if (true && (nParagraph >= mpTEParaPortions->
Count())) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "GetLineCount: Out of range") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1219" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "GetLineCount: Out of range"), 0); }
else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "GetLineCount: Out of range"; ::sal::detail::log( (
::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1219" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "GetLineCount: Out of range") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1219" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "GetLineCount: Out of range"), 0); }
else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "GetLineCount: Out of range"; ::sal::detail::log( (
::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1219" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
1220
1221 TEParaPortion* pPPortion = mpTEParaPortions->GetObject( nParagraph );
1222 if ( pPPortion && ( nLine < pPPortion->GetLines().size() ) )
1223 {
1224 return pPPortion->GetLines()[ nLine ].GetLen();
1225 }
1226
1227 return 0;
1228}
1229
1230long TextEngine::CalcParaHeight( sal_uInt32 nParagraph ) const
1231{
1232 long nHeight = 0;
1233
1234 TEParaPortion* pPPortion = mpTEParaPortions->GetObject( nParagraph );
1235 SAL_WARN_IF( !pPPortion, "vcl", "GetParaHeight: paragraph not found" )do { if (true && (!pPPortion)) { switch (sal_detail_log_report
(::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE
: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail
::getResult( ::sal::detail::StreamStart() << "GetParaHeight: paragraph not found"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"
), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1235" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "GetParaHeight: paragraph not found"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "GetParaHeight: paragraph not found"; ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1235" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "GetParaHeight: paragraph not found") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1235" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "GetParaHeight: paragraph not found"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "GetParaHeight: paragraph not found"; ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1235" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
1236 if ( pPPortion )
1237 nHeight = pPPortion->GetLines().size() * mnCharHeight;
1238
1239 return nHeight;
1240}
1241
1242Range TextEngine::GetInvalidYOffsets( sal_uInt32 nPortion )
1243{
1244 TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nPortion );
1245 sal_uInt16 nLines = pTEParaPortion->GetLines().size();
1246 sal_uInt16 nLastInvalid, nFirstInvalid = 0;
1247 sal_uInt16 nLine;
1248 for ( nLine = 0; nLine < nLines; nLine++ )
1249 {
1250 TextLine& rL = pTEParaPortion->GetLines()[ nLine ];
1251 if ( rL.IsInvalid() )
1252 {
1253 nFirstInvalid = nLine;
1254 break;
1255 }
1256 }
1257
1258 for ( nLastInvalid = nFirstInvalid; nLastInvalid < nLines; nLastInvalid++ )
1259 {
1260 TextLine& rL = pTEParaPortion->GetLines()[ nLine ];
1261 if ( rL.IsValid() )
1262 break;
1263 }
1264
1265 if ( nLastInvalid >= nLines )
1266 nLastInvalid = nLines-1;
1267
1268 return Range( nFirstInvalid*mnCharHeight, ((nLastInvalid+1)*mnCharHeight)-1 );
1269}
1270
1271sal_uInt32 TextEngine::GetParagraphCount() const
1272{
1273 return static_cast<sal_uInt32>(mpDoc->GetNodes().size());
1274}
1275
1276void TextEngine::EnableUndo( bool bEnable )
1277{
1278 // delete list when switching mode
1279 if ( bEnable != IsUndoEnabled() )
1280 ResetUndo();
1281
1282 mbUndoEnabled = bEnable;
1283}
1284
1285SfxUndoManager& TextEngine::GetUndoManager()
1286{
1287 if ( !mpUndoManager )
1288 mpUndoManager.reset( new TextUndoManager( this ) );
1289 return *mpUndoManager;
1290}
1291
1292void TextEngine::UndoActionStart( sal_uInt16 nId )
1293{
1294 if ( IsUndoEnabled() && !IsInUndo() )
1295 {
1296 GetUndoManager().EnterListAction( OUString(), OUString(), nId, ViewShellId(-1) );
1297 }
1298}
1299
1300void TextEngine::UndoActionEnd()
1301{
1302 if ( IsUndoEnabled() && !IsInUndo() )
1303 GetUndoManager().LeaveListAction();
1304}
1305
1306void TextEngine::InsertUndo( std::unique_ptr<TextUndo> pUndo, bool bTryMerge )
1307{
1308 SAL_WARN_IF( IsInUndo(), "vcl", "InsertUndo: in Undo mode!" )do { if (true && (IsInUndo())) { switch (sal_detail_log_report
(::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE
: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail
::getResult( ::sal::detail::StreamStart() << "InsertUndo: in Undo mode!"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"
), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1308" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "InsertUndo: in Undo mode!"), 0); } else
{ ::std::ostringstream sal_detail_stream; sal_detail_stream <<
"InsertUndo: in Undo mode!"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1308" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "InsertUndo: in Undo mode!") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1308" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "InsertUndo: in Undo mode!"), 0); } else
{ ::std::ostringstream sal_detail_stream; sal_detail_stream <<
"InsertUndo: in Undo mode!"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1308" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
1309 GetUndoManager().AddUndoAction( std::move(pUndo), bTryMerge );
1310}
1311
1312void TextEngine::ResetUndo()
1313{
1314 if ( mpUndoManager )
1315 mpUndoManager->Clear();
1316}
1317
1318void TextEngine::InsertContent( std::unique_ptr<TextNode> pNode, sal_uInt32 nPara )
1319{
1320 SAL_WARN_IF( !pNode, "vcl", "InsertContent: NULL-Pointer!" )do { if (true && (!pNode)) { switch (sal_detail_log_report
(::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE
: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail
::getResult( ::sal::detail::StreamStart() << "InsertContent: NULL-Pointer!"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"
), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1320" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "InsertContent: NULL-Pointer!"), 0);
} else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "InsertContent: NULL-Pointer!"; ::sal::detail::log(
(::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1320" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "InsertContent: NULL-Pointer!") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1320" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "InsertContent: NULL-Pointer!"), 0);
} else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "InsertContent: NULL-Pointer!"; ::sal::detail::log(
(::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1320" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
1321 SAL_WARN_IF( !IsInUndo(), "vcl", "InsertContent: only in Undo()!" )do { if (true && (!IsInUndo())) { switch (sal_detail_log_report
(::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE
: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail
::getResult( ::sal::detail::StreamStart() << "InsertContent: only in Undo()!"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"
), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1321" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "InsertContent: only in Undo()!"), 0
); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "InsertContent: only in Undo()!"; ::sal::detail::log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1321" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "InsertContent: only in Undo()!") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1321" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "InsertContent: only in Undo()!"), 0
); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "InsertContent: only in Undo()!"; ::sal::detail::log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1321" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
1322 TEParaPortion* pNew = new TEParaPortion( pNode.get() );
1323 mpTEParaPortions->Insert( pNew, nPara );
1324 mpDoc->GetNodes().insert( mpDoc->GetNodes().begin() + nPara, std::move(pNode) );
1325 ImpParagraphInserted( nPara );
1326}
1327
1328TextPaM TextEngine::SplitContent( sal_uInt32 nNode, sal_Int32 nSepPos )
1329{
1330#ifdef DBG_UTIL
1331 TextNode* pNode = mpDoc->GetNodes()[ nNode ].get();
1332 SAL_WARN_IF( !pNode, "vcl", "SplitContent: Invalid Node!" )do { if (true && (!pNode)) { switch (sal_detail_log_report
(::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE
: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail
::getResult( ::sal::detail::StreamStart() << "SplitContent: Invalid Node!"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"
), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1332" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "SplitContent: Invalid Node!"), 0); }
else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "SplitContent: Invalid Node!"; ::sal::detail::log( (
::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1332" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "SplitContent: Invalid Node!") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1332" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "SplitContent: Invalid Node!"), 0); }
else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "SplitContent: Invalid Node!"; ::sal::detail::log( (
::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1332" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
1333 SAL_WARN_IF( !IsInUndo(), "vcl", "SplitContent: only in Undo()!" )do { if (true && (!IsInUndo())) { switch (sal_detail_log_report
(::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE
: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail
::getResult( ::sal::detail::StreamStart() << "SplitContent: only in Undo()!"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"
), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1333" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "SplitContent: only in Undo()!"), 0)
; } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "SplitContent: only in Undo()!"; ::sal::detail::log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1333" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "SplitContent: only in Undo()!") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1333" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "SplitContent: only in Undo()!"), 0)
; } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "SplitContent: only in Undo()!"; ::sal::detail::log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1333" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
1334 SAL_WARN_IF( nSepPos > pNode->GetText().getLength(), "vcl", "SplitContent: Bad index" )do { if (true && (nSepPos > pNode->GetText().getLength
())) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "SplitContent: Bad index") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1334" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "SplitContent: Bad index"), 0); } else
{ ::std::ostringstream sal_detail_stream; sal_detail_stream <<
"SplitContent: Bad index"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1334" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "SplitContent: Bad index") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1334" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "SplitContent: Bad index"), 0); } else
{ ::std::ostringstream sal_detail_stream; sal_detail_stream <<
"SplitContent: Bad index"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1334" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
1335#endif
1336 TextPaM aPaM( nNode, nSepPos );
1337 return ImpInsertParaBreak( aPaM );
1338}
1339
1340TextPaM TextEngine::ConnectContents( sal_uInt32 nLeftNode )
1341{
1342 SAL_WARN_IF( !IsInUndo(), "vcl", "ConnectContent: only in Undo()!" )do { if (true && (!IsInUndo())) { switch (sal_detail_log_report
(::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE
: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail
::getResult( ::sal::detail::StreamStart() << "ConnectContent: only in Undo()!"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"
), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1342" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "ConnectContent: only in Undo()!"), 0
); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "ConnectContent: only in Undo()!"; ::sal::detail::log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1342" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "ConnectContent: only in Undo()!") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1342" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "ConnectContent: only in Undo()!"), 0
); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "ConnectContent: only in Undo()!"; ::sal::detail::log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1342" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
1343 return ImpConnectParagraphs( nLeftNode, nLeftNode+1 );
1344}
1345
1346void TextEngine::SeekCursor( sal_uInt32 nPara, sal_Int32 nPos, vcl::Font& rFont, OutputDevice* pOutDev )
1347{
1348 rFont = maFont;
1349 if ( pOutDev )
1350 pOutDev->SetTextColor( maTextColor );
1351
1352 TextNode* pNode = mpDoc->GetNodes()[ nPara ].get();
1353 sal_uInt16 nAttribs = pNode->GetCharAttribs().Count();
1354 for ( sal_uInt16 nAttr = 0; nAttr < nAttribs; nAttr++ )
1355 {
1356 TextCharAttrib& rAttrib = pNode->GetCharAttribs().GetAttrib( nAttr );
1357 if ( rAttrib.GetStart() > nPos )
1358 break;
1359
1360 // When seeking don't use Attr that start there!
1361 // Do not use empty attributes:
1362 // - If just being setup and empty => no effect on Font
1363 // - Characters that are setup in an empty paragraph become visible right away.
1364 if ( ( ( rAttrib.GetStart() < nPos ) && ( rAttrib.GetEnd() >= nPos ) )
1365 || pNode->GetText().isEmpty() )
1366 {
1367 if ( rAttrib.Which() != TEXTATTR_FONTCOLOR1 )
1368 {
1369 rAttrib.GetAttr().SetFont(rFont);
1370 }
1371 else
1372 {
1373 if ( pOutDev )
1374 pOutDev->SetTextColor( static_cast<const TextAttribFontColor&>(rAttrib.GetAttr()).GetColor() );
1375 }
1376 }
1377 }
1378
1379 if ( !(mpIMEInfos && mpIMEInfos->pAttribs && ( mpIMEInfos->aPos.GetPara() == nPara ) &&
1380 ( nPos > mpIMEInfos->aPos.GetIndex() ) && ( nPos <= ( mpIMEInfos->aPos.GetIndex() + mpIMEInfos->nLen ) )) )
1381 return;
1382
1383 ExtTextInputAttr nAttr = mpIMEInfos->pAttribs[ nPos - mpIMEInfos->aPos.GetIndex() - 1 ];
1384 if ( nAttr & ExtTextInputAttr::Underline )
1385 rFont.SetUnderline( LINESTYLE_SINGLE );
1386 else if ( nAttr & ExtTextInputAttr::BoldUnderline )
1387 rFont.SetUnderline( LINESTYLE_BOLD );
1388 else if ( nAttr & ExtTextInputAttr::DottedUnderline )
1389 rFont.SetUnderline( LINESTYLE_DOTTED );
1390 else if ( nAttr & ExtTextInputAttr::DashDotUnderline )
1391 rFont.SetUnderline( LINESTYLE_DOTTED );
1392 if ( nAttr & ExtTextInputAttr::RedText )
1393 rFont.SetColor( COL_RED );
1394 else if ( nAttr & ExtTextInputAttr::HalfToneText )
1395 rFont.SetColor( COL_LIGHTGRAY );
1396 if ( nAttr & ExtTextInputAttr::Highlight )
1397 {
1398 const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
1399 rFont.SetColor( rStyleSettings.GetHighlightTextColor() );
1400 rFont.SetFillColor( rStyleSettings.GetHighlightColor() );
1401 rFont.SetTransparent( false );
1402 }
1403 else if ( nAttr & ExtTextInputAttr::GrayWaveline )
1404 {
1405 rFont.SetUnderline( LINESTYLE_WAVE );
1406// if( pOut )
1407// pOut->SetTextLineColor( COL_LIGHTGRAY );
1408 }
1409}
1410
1411void TextEngine::FormatAndUpdate( TextView* pCurView )
1412{
1413 if ( mbDowning )
1414 return;
1415
1416 if ( IsInUndo() )
1417 IdleFormatAndUpdate( pCurView );
1418 else
1419 {
1420 FormatDoc();
1421 UpdateViews( pCurView );
1422 }
1423}
1424
1425void TextEngine::IdleFormatAndUpdate( TextView* pCurView, sal_uInt16 nMaxTimerRestarts )
1426{
1427 mpIdleFormatter->DoIdleFormat( pCurView, nMaxTimerRestarts );
1428}
1429
1430void TextEngine::TextModified()
1431{
1432 mbFormatted = false;
1433 mbModified = true;
1434}
1435
1436void TextEngine::UpdateViews( TextView* pCurView )
1437{
1438 if ( !GetUpdateMode() || IsFormatting() || maInvalidRect.IsEmpty() )
1439 return;
1440
1441 SAL_WARN_IF( !IsFormatted(), "vcl", "UpdateViews: Doc not formatted!" )do { if (true && (!IsFormatted())) { switch (sal_detail_log_report
(::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE
: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail
::getResult( ::sal::detail::StreamStart() << "UpdateViews: Doc not formatted!"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"
), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1441" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "UpdateViews: Doc not formatted!"), 0
); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "UpdateViews: Doc not formatted!"; ::sal::detail::log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1441" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "UpdateViews: Doc not formatted!") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1441" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "UpdateViews: Doc not formatted!"), 0
); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "UpdateViews: Doc not formatted!"; ::sal::detail::log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1441" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
1442
1443 for (TextView* pView : *mpViews)
1444 {
1445 pView->HideCursor();
1446
1447 tools::Rectangle aClipRect( maInvalidRect );
1448 const Size aOutSz = pView->GetWindow()->GetOutputSizePixel();
1449 const tools::Rectangle aVisArea( pView->GetStartDocPos(), aOutSz );
1450 aClipRect.Intersection( aVisArea );
1451 if ( !aClipRect.IsEmpty() )
1452 {
1453 // translate into window coordinates
1454 Point aNewPos = pView->GetWindowPos( aClipRect.TopLeft() );
1455 if ( IsRightToLeft() )
1456 aNewPos.AdjustX( -(aOutSz.Width() - 1) );
1457 aClipRect.SetPos( aNewPos );
1458
1459 pView->GetWindow()->Invalidate( aClipRect );
1460 }
1461 }
1462
1463 if ( pCurView )
1464 {
1465 pCurView->ShowCursor( pCurView->IsAutoScroll() );
1466 }
1467
1468 maInvalidRect = tools::Rectangle();
1469}
1470
1471IMPL_LINK_NOARG(TextEngine, IdleFormatHdl, Timer *, void)void TextEngine::LinkStubIdleFormatHdl(void * instance, Timer
* data) { return static_cast<TextEngine *>(instance)->
IdleFormatHdl(data); } void TextEngine::IdleFormatHdl(__attribute__
((unused)) Timer *)
1472{
1473 FormatAndUpdate( mpIdleFormatter->GetView() );
1474}
1475
1476void TextEngine::CheckIdleFormatter()
1477{
1478 mpIdleFormatter->ForceTimeout();
1479}
1480
1481void TextEngine::FormatFullDoc()
1482{
1483 for ( sal_uInt32 nPortion = 0; nPortion < mpTEParaPortions->Count(); ++nPortion )
1484 {
1485 TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nPortion );
1486 pTEParaPortion->MarkSelectionInvalid( 0 );
1487 }
1488 mbFormatted = false;
1489 FormatDoc();
1490}
1491
1492void TextEngine::FormatDoc()
1493{
1494 if ( IsFormatted() || !GetUpdateMode() || IsFormatting() )
1495 return;
1496
1497 mbIsFormatting = true;
1498 mbHasMultiLineParas = false;
1499
1500 long nY = 0;
1501 bool bGrow = false;
1502
1503 maInvalidRect = tools::Rectangle(); // clear
1504 for ( sal_uInt32 nPara = 0; nPara < mpTEParaPortions->Count(); ++nPara )
1505 {
1506 TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nPara );
1507 if ( pTEParaPortion->IsInvalid() )
1508 {
1509 const long nOldParaWidth = mnCurTextWidth >= 0 ? CalcTextWidth( nPara ) : -1;
1510
1511 Broadcast( TextHint( SfxHintId::TextFormatPara, nPara ) );
1512
1513 if ( CreateLines( nPara ) )
1514 bGrow = true;
1515
1516 // set InvalidRect only once
1517 if ( maInvalidRect.IsEmpty() )
1518 {
1519 // otherwise remains Empty() for Paperwidth 0 (AutoPageSize)
1520 const long nWidth = mnMaxTextWidth
1521 ? mnMaxTextWidth
1522 : std::numeric_limits<long>::max();
1523 const Range aInvRange( GetInvalidYOffsets( nPara ) );
1524 maInvalidRect = tools::Rectangle( Point( 0, nY+aInvRange.Min() ),
1525 Size( nWidth, aInvRange.Len() ) );
1526 }
1527 else
1528 {
1529 maInvalidRect.SetBottom( nY + CalcParaHeight( nPara ) );
1530 }
1531
1532 if ( mnCurTextWidth >= 0 )
1533 {
1534 const long nNewParaWidth = CalcTextWidth( nPara );
1535 if ( nNewParaWidth >= mnCurTextWidth )
1536 mnCurTextWidth = nNewParaWidth;
1537 else if ( nOldParaWidth >= mnCurTextWidth )
1538 mnCurTextWidth = -1;
1539 }
1540 }
1541 else if ( bGrow )
1542 {
1543 maInvalidRect.SetBottom( nY + CalcParaHeight( nPara ) );
1544 }
1545 nY += CalcParaHeight( nPara );
1546 if ( !mbHasMultiLineParas && pTEParaPortion->GetLines().size() > 1 )
1547 mbHasMultiLineParas = true;
1548 }
1549
1550 if ( !maInvalidRect.IsEmpty() )
1551 {
1552 const long nNewHeight = CalcTextHeight();
1553 const long nDiff = nNewHeight - mnCurTextHeight;
1554 if ( nNewHeight < mnCurTextHeight )
1555 {
1556 maInvalidRect.SetBottom( std::max( nNewHeight, mnCurTextHeight ) );
1557 if ( maInvalidRect.IsEmpty() )
1558 {
1559 maInvalidRect.SetTop( 0 );
1560 // Left and Right are not evaluated, but set because of IsEmpty
1561 maInvalidRect.SetLeft( 0 );
1562 maInvalidRect.SetRight( mnMaxTextWidth );
1563 }
1564 }
1565
1566 mnCurTextHeight = nNewHeight;
1567 if ( nDiff )
1568 {
1569 mbFormatted = true;
1570 Broadcast( TextHint( SfxHintId::TextHeightChanged ) );
1571 }
1572 }
1573
1574 mbIsFormatting = false;
1575 mbFormatted = true;
1576
1577 Broadcast( TextHint( SfxHintId::TextFormatted ) );
1578}
1579
1580void TextEngine::CreateAndInsertEmptyLine( sal_uInt32 nPara )
1581{
1582 TextNode* pNode = mpDoc->GetNodes()[ nPara ].get();
1583 TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nPara );
1584
1585 TextLine aTmpLine;
1586 aTmpLine.SetStart( pNode->GetText().getLength() );
1587 aTmpLine.SetEnd( aTmpLine.GetStart() );
1588
1589 if ( ImpGetAlign() == TxtAlign::Center )
1590 aTmpLine.SetStartX( static_cast<short>(mnMaxTextWidth / 2) );
1591 else if ( ImpGetAlign() == TxtAlign::Right )
1592 aTmpLine.SetStartX( static_cast<short>(mnMaxTextWidth) );
1593 else
1594 aTmpLine.SetStartX( mpDoc->GetLeftMargin() );
1595
1596 bool bLineBreak = !pNode->GetText().isEmpty();
1597
1598 std::unique_ptr<TETextPortion> pDummyPortion(new TETextPortion( 0 ));
1599 pDummyPortion->GetWidth() = 0;
1600 pTEParaPortion->GetTextPortions().push_back( std::move(pDummyPortion) );
1601
1602 if ( bLineBreak )
1603 {
1604 // -2: The new one is already inserted.
1605 const std::size_t nPos = pTEParaPortion->GetTextPortions().size() - 1;
1606 aTmpLine.SetStartPortion( nPos );
1607 aTmpLine.SetEndPortion( nPos );
1608 }
1609 pTEParaPortion->GetLines().push_back( aTmpLine );
1610}
1611
1612void TextEngine::ImpBreakLine( sal_uInt32 nPara, TextLine* pLine, sal_Int32 nPortionStart, long nRemainingWidth )
1613{
1614 TextNode* pNode = mpDoc->GetNodes()[ nPara ].get();
1615
1616 // Font still should be adjusted
1617 sal_Int32 nMaxBreakPos = mpRefDev->GetTextBreak( pNode->GetText(), nRemainingWidth, nPortionStart );
1618
1619 SAL_WARN_IF( nMaxBreakPos >= pNode->GetText().getLength(), "vcl", "ImpBreakLine: Break?!" )do { if (true && (nMaxBreakPos >= pNode->GetText
().getLength())) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "ImpBreakLine: Break?!") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1619" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "ImpBreakLine: Break?!"), 0); } else
{ ::std::ostringstream sal_detail_stream; sal_detail_stream <<
"ImpBreakLine: Break?!"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1619" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "ImpBreakLine: Break?!") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1619" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "ImpBreakLine: Break?!"), 0); } else
{ ::std::ostringstream sal_detail_stream; sal_detail_stream <<
"ImpBreakLine: Break?!"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1619" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
1620
1621 if ( nMaxBreakPos == -1 ) // GetTextBreak() != GetTextSize()
1622 nMaxBreakPos = pNode->GetText().getLength() - 1;
1623
1624 uno::Reference < i18n::XBreakIterator > xBI = GetBreakIterator();
1625 i18n::LineBreakHyphenationOptions aHyphOptions( nullptr, uno::Sequence< beans::PropertyValue >(), 1 );
1626
1627 i18n::LineBreakUserOptions aUserOptions;
1628 aUserOptions.forbiddenBeginCharacters = ImpGetLocaleDataWrapper()->getForbiddenCharacters().beginLine;
1629 aUserOptions.forbiddenEndCharacters = ImpGetLocaleDataWrapper()->getForbiddenCharacters().endLine;
1630 aUserOptions.applyForbiddenRules = true;
1631 aUserOptions.allowPunctuationOutsideMargin = false;
1632 aUserOptions.allowHyphenateEnglish = false;
1633
1634 static const css::lang::Locale aDefLocale;
1635 i18n::LineBreakResults aLBR = xBI->getLineBreak( pNode->GetText(), nMaxBreakPos, aDefLocale, pLine->GetStart(), aHyphOptions, aUserOptions );
1636 sal_Int32 nBreakPos = aLBR.breakIndex;
1637 if ( nBreakPos <= pLine->GetStart() )
1638 {
1639 nBreakPos = nMaxBreakPos;
1640 if ( nBreakPos <= pLine->GetStart() )
1641 nBreakPos = pLine->GetStart() + 1; // infinite loop otherwise!
1642 }
1643
1644 // the damaged Portion is the End Portion
1645 pLine->SetEnd( nBreakPos );
1646 const std::size_t nEndPortion = SplitTextPortion( nPara, nBreakPos );
1647
1648 if ( nBreakPos >= pLine->GetStart() &&
1649 nBreakPos < pNode->GetText().getLength() &&
1650 pNode->GetText()[ nBreakPos ] == ' ' )
1651 {
1652 // generally suppress blanks at the end of line
1653 TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nPara );
1654 TETextPortion* pTP = pTEParaPortion->GetTextPortions()[ nEndPortion ];
1655 SAL_WARN_IF( nBreakPos <= pLine->GetStart(), "vcl", "ImpBreakLine: SplitTextPortion at beginning of line?" )do { if (true && (nBreakPos <= pLine->GetStart(
))) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "ImpBreakLine: SplitTextPortion at beginning of line?"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"
), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1655" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "ImpBreakLine: SplitTextPortion at beginning of line?"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "ImpBreakLine: SplitTextPortion at beginning of line?"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"),
("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1655" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "ImpBreakLine: SplitTextPortion at beginning of line?"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"
), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1655" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "ImpBreakLine: SplitTextPortion at beginning of line?"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "ImpBreakLine: SplitTextPortion at beginning of line?"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"),
("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1655" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
1656 pTP->GetWidth() = CalcTextWidth( nPara, nBreakPos-pTP->GetLen(), pTP->GetLen()-1 );
1657 }
1658 pLine->SetEndPortion( nEndPortion );
1659}
1660
1661std::size_t TextEngine::SplitTextPortion( sal_uInt32 nPara, sal_Int32 nPos )
1662{
1663
1664 // the Portion at nPos is being split, unless there is already a switch at nPos
1665 if ( nPos == 0 )
1666 return 0;
1667
1668 std::size_t nSplitPortion;
1669 sal_Int32 nTmpPos = 0;
1670 TETextPortion* pTextPortion = nullptr;
1671 TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nPara );
1672 const std::size_t nPortions = pTEParaPortion->GetTextPortions().size();
1673 for ( nSplitPortion = 0; nSplitPortion < nPortions; nSplitPortion++ )
1674 {
1675 TETextPortion* pTP = pTEParaPortion->GetTextPortions()[nSplitPortion];
1676 nTmpPos += pTP->GetLen();
1677 if ( nTmpPos >= nPos )
1678 {
1679 if ( nTmpPos == nPos ) // nothing needs splitting
1680 return nSplitPortion;
1681 pTextPortion = pTP;
1682 break;
1683 }
1684 }
1685
1686 SAL_WARN_IF( !pTextPortion, "vcl", "SplitTextPortion: position outside of region!" )do { if (true && (!pTextPortion)) { switch (sal_detail_log_report
(::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE
: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail
::getResult( ::sal::detail::StreamStart() << "SplitTextPortion: position outside of region!"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"
), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1686" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "SplitTextPortion: position outside of region!"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "SplitTextPortion: position outside of region!"; ::
sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1686" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "SplitTextPortion: position outside of region!") ==
1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"
), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1686" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "SplitTextPortion: position outside of region!"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "SplitTextPortion: position outside of region!"; ::
sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1686" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
1687
1688 const sal_Int32 nOverlapp = nTmpPos - nPos;
1689 pTextPortion->GetLen() -= nOverlapp;
1690 std::unique_ptr<TETextPortion> pNewPortion( new TETextPortion( nOverlapp ) );
1691 pTEParaPortion->GetTextPortions().insert( pTEParaPortion->GetTextPortions().begin() + nSplitPortion + 1, std::move(pNewPortion) );
1692 pTextPortion->GetWidth() = CalcTextWidth( nPara, nPos-pTextPortion->GetLen(), pTextPortion->GetLen() );
1693
1694 return nSplitPortion;
1695}
1696
1697void TextEngine::CreateTextPortions( sal_uInt32 nPara, sal_Int32 nStartPos )
1698{
1699 TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nPara );
1700 TextNode* pNode = pTEParaPortion->GetNode();
1701 SAL_WARN_IF( pNode->GetText().isEmpty(), "vcl", "CreateTextPortions: should not be used for empty paragraphs!" )do { if (true && (pNode->GetText().isEmpty())) { switch
(sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) {
case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "CreateTextPortions: should not be used for empty paragraphs!"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"
), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1701" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "CreateTextPortions: should not be used for empty paragraphs!"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "CreateTextPortions: should not be used for empty paragraphs!"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"),
("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1701" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "CreateTextPortions: should not be used for empty paragraphs!"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"
), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1701" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "CreateTextPortions: should not be used for empty paragraphs!"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "CreateTextPortions: should not be used for empty paragraphs!"
; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"),
("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1701" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
1702
1703 std::set<sal_Int32> aPositions;
1704 std::set<sal_Int32>::iterator aPositionsIt;
1705 aPositions.insert(0);
1706
1707 const sal_uInt16 nAttribs = pNode->GetCharAttribs().Count();
1708 for ( sal_uInt16 nAttr = 0; nAttr < nAttribs; nAttr++ )
1709 {
1710 TextCharAttrib& rAttrib = pNode->GetCharAttribs().GetAttrib( nAttr );
1711
1712 aPositions.insert( rAttrib.GetStart() );
1713 aPositions.insert( rAttrib.GetEnd() );
1714 }
1715 aPositions.insert( pNode->GetText().getLength() );
1716
1717 const std::vector<TEWritingDirectionInfo>& rWritingDirections = pTEParaPortion->GetWritingDirectionInfos();
1718 for ( const auto& rWritingDirection : rWritingDirections )
1719 aPositions.insert( rWritingDirection.nStartPos );
1720
1721 if ( mpIMEInfos && mpIMEInfos->pAttribs && ( mpIMEInfos->aPos.GetPara() == nPara ) )
1722 {
1723 ExtTextInputAttr nLastAttr = ExtTextInputAttr(0xffff);
1724 for( sal_Int32 n = 0; n < mpIMEInfos->nLen; n++ )
1725 {
1726 if ( mpIMEInfos->pAttribs[n] != nLastAttr )
1727 {
1728 aPositions.insert( mpIMEInfos->aPos.GetIndex() + n );
1729 nLastAttr = mpIMEInfos->pAttribs[n];
1730 }
1731 }
1732 }
1733
1734 sal_Int32 nTabPos = pNode->GetText().indexOf( '\t' );
1735 while ( nTabPos != -1 )
1736 {
1737 aPositions.insert( nTabPos );
1738 aPositions.insert( nTabPos + 1 );
1739 nTabPos = pNode->GetText().indexOf( '\t', nTabPos+1 );
1740 }
1741
1742 // Delete starting with...
1743 // Unfortunately, the number of TextPortions does not have to be
1744 // equal to aPositions.Count(), because of linebreaks
1745 sal_Int32 nPortionStart = 0;
1746 std::size_t nInvPortion = 0;
1747 std::size_t nP;
1748 for ( nP = 0; nP < pTEParaPortion->GetTextPortions().size(); nP++ )
1749 {
1750 TETextPortion* pTmpPortion = pTEParaPortion->GetTextPortions()[nP];
1751 nPortionStart += pTmpPortion->GetLen();
1752 if ( nPortionStart >= nStartPos )
1753 {
1754 nPortionStart -= pTmpPortion->GetLen();
1755 nInvPortion = nP;
1756 break;
1757 }
1758 }
1759 OSL_ENSURE(nP < pTEParaPortion->GetTextPortions().size()do { if (true && (!(nP < pTEParaPortion->GetTextPortions
().size() || pTEParaPortion->GetTextPortions().empty()))) {
sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1761" ": "), "%s", "CreateTextPortions: Nothing to delete!"
); } } while (false)
1760 || pTEParaPortion->GetTextPortions().empty(),do { if (true && (!(nP < pTEParaPortion->GetTextPortions
().size() || pTEParaPortion->GetTextPortions().empty()))) {
sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1761" ": "), "%s", "CreateTextPortions: Nothing to delete!"
); } } while (false)
1761 "CreateTextPortions: Nothing to delete!")do { if (true && (!(nP < pTEParaPortion->GetTextPortions
().size() || pTEParaPortion->GetTextPortions().empty()))) {
sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1761" ": "), "%s", "CreateTextPortions: Nothing to delete!"
); } } while (false)
;
1762 if ( nInvPortion && ( nPortionStart+pTEParaPortion->GetTextPortions()[nInvPortion]->GetLen() > nStartPos ) )
1763 {
1764 // better one before...
1765 // But only if it was within the Portion; otherwise it might be
1766 // the only one in the previous line!
1767 nInvPortion--;
1768 nPortionStart -= pTEParaPortion->GetTextPortions()[nInvPortion]->GetLen();
1769 }
1770 pTEParaPortion->GetTextPortions().DeleteFromPortion( nInvPortion );
1771
1772 // a Portion might have been created by a line break
1773 aPositions.insert( nPortionStart );
1774
1775 aPositionsIt = aPositions.find( nPortionStart );
1776 SAL_WARN_IF( aPositionsIt == aPositions.end(), "vcl", "CreateTextPortions: nPortionStart not found" )do { if (true && (aPositionsIt == aPositions.end())) {
switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN, "vcl"
)) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "CreateTextPortions: nPortionStart not found") ==
1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"
), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1776" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "CreateTextPortions: nPortionStart not found"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "CreateTextPortions: nPortionStart not found"; ::sal
::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1776" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "CreateTextPortions: nPortionStart not found") ==
1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"
), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1776" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "CreateTextPortions: nPortionStart not found"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "CreateTextPortions: nPortionStart not found"; ::sal
::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1776" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
1777
1778 if ( aPositionsIt != aPositions.end() )
1779 {
1780 std::set<sal_Int32>::iterator nextIt = aPositionsIt;
1781 for ( ++nextIt; nextIt != aPositions.end(); ++aPositionsIt, ++nextIt )
1782 {
1783 std::unique_ptr<TETextPortion> pNew( new TETextPortion( *nextIt - *aPositionsIt ) );
1784 pTEParaPortion->GetTextPortions().push_back( std::move(pNew) );
1785 }
1786 }
1787 OSL_ENSURE(pTEParaPortion->GetTextPortions().size(), "CreateTextPortions: No Portions?!")do { if (true && (!(pTEParaPortion->GetTextPortions
().size()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1787" ": "), "%s", "CreateTextPortions: No Portions?!")
; } } while (false)
;
1788}
1789
1790void TextEngine::RecalcTextPortion( sal_uInt32 nPara, sal_Int32 nStartPos, sal_Int32 nNewChars )
1791{
1792 TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nPara );
1793 OSL_ENSURE(pTEParaPortion->GetTextPortions().size(), "RecalcTextPortion: no Portions!")do { if (true && (!(pTEParaPortion->GetTextPortions
().size()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1793" ": "), "%s", "RecalcTextPortion: no Portions!"); }
} while (false)
;
1
Assuming the condition is false
2
Taking false branch
3
Loop condition is false. Exiting loop
1794 OSL_ENSURE(nNewChars, "RecalcTextPortion: Diff == 0")do { if (true && (!(nNewChars))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1794" ": "), "%s", "RecalcTextPortion: Diff == 0"); } }
while (false)
;
4
Assuming 'nNewChars' is not equal to 0
5
Taking false branch
6
Loop condition is false. Exiting loop
1795
1796 TextNode* const pNode = pTEParaPortion->GetNode();
1797 if ( nNewChars > 0 )
7
Assuming 'nNewChars' is <= 0
8
Taking false branch
1798 {
1799 // If an Attribute is starting/ending at nStartPos, or there is a tab
1800 // before nStartPos => a new Portion starts.
1801 // Otherwise the Portion is extended at nStartPos.
1802 // Or if at the very beginning ( StartPos 0 ) followed by a tab...
1803 if ( ( pNode->GetCharAttribs().HasBoundingAttrib( nStartPos ) ) ||
1804 ( nStartPos && ( pNode->GetText()[ nStartPos - 1 ] == '\t' ) ) ||
1805 ( !nStartPos && ( nNewChars < pNode->GetText().getLength() ) && pNode->GetText()[ nNewChars ] == '\t' ) )
1806 {
1807 std::size_t nNewPortionPos = 0;
1808 if ( nStartPos )
1809 nNewPortionPos = SplitTextPortion( nPara, nStartPos ) + 1;
1810
1811 // Here could be an empty Portion if the paragraph was empty,
1812 // or a new line was created by a hard line-break.
1813 if ( ( nNewPortionPos < pTEParaPortion->GetTextPortions().size() ) &&
1814 !pTEParaPortion->GetTextPortions()[nNewPortionPos]->GetLen() )
1815 {
1816 // use the empty Portion
1817 pTEParaPortion->GetTextPortions()[nNewPortionPos]->GetLen() = nNewChars;
1818 }
1819 else
1820 {
1821 std::unique_ptr<TETextPortion> pNewPortion(new TETextPortion( nNewChars ));
1822 pTEParaPortion->GetTextPortions().insert( pTEParaPortion->GetTextPortions().begin() + nNewPortionPos, std::move(pNewPortion) );
1823 }
1824 }
1825 else
1826 {
1827 sal_Int32 nPortionStart {0};
1828 const std::size_t nTP = pTEParaPortion->GetTextPortions().FindPortion( nStartPos, nPortionStart );
1829 TETextPortion* const pTP = pTEParaPortion->GetTextPortions()[ nTP ];
1830 SAL_WARN_IF( !pTP, "vcl", "RecalcTextPortion: Portion not found!" )do { if (true && (!pTP)) { switch (sal_detail_log_report
(::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE
: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail
::getResult( ::sal::detail::StreamStart() << "RecalcTextPortion: Portion not found!"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"
), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1830" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "RecalcTextPortion: Portion not found!"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "RecalcTextPortion: Portion not found!"; ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1830" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "RecalcTextPortion: Portion not found!") == 1) { ::
sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1830" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "RecalcTextPortion: Portion not found!"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "RecalcTextPortion: Portion not found!"; ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1830" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
1831 pTP->GetLen() += nNewChars;
1832 pTP->GetWidth() = -1;
1833 }
1834 }
1835 else
1836 {
1837 // Shrink or remove Portion
1838 // Before calling this function, ensure that no Portions were in the deleted range!
1839
1840 // There must be no Portion reaching into or starting within,
1841 // thus: nStartPos <= nPos <= nStartPos - nNewChars(neg.)
1842 std::size_t nPortion = 0;
1843 sal_Int32 nPos = 0;
1844 const sal_Int32 nEnd = nStartPos-nNewChars;
1845 const std::size_t nPortions = pTEParaPortion->GetTextPortions().size();
1846 TETextPortion* pTP = nullptr;
9
'pTP' initialized to a null pointer value
1847 for ( nPortion = 0; nPortion < nPortions; nPortion++ )
10
Assuming 'nPortion' is >= 'nPortions'
11
Loop condition is false. Execution continues on line 1858
1848 {
1849 pTP = pTEParaPortion->GetTextPortions()[ nPortion ];
1850 if ( ( nPos+pTP->GetLen() ) > nStartPos )
1851 {
1852 SAL_WARN_IF( nPos > nStartPos, "vcl", "RecalcTextPortion: Bad Start!" )do { if (true && (nPos > nStartPos)) { switch (sal_detail_log_report
(::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE
: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail
::getResult( ::sal::detail::StreamStart() << "RecalcTextPortion: Bad Start!"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"
), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1852" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "RecalcTextPortion: Bad Start!"), 0)
; } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "RecalcTextPortion: Bad Start!"; ::sal::detail::log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1852" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "RecalcTextPortion: Bad Start!") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1852" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "RecalcTextPortion: Bad Start!"), 0)
; } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "RecalcTextPortion: Bad Start!"; ::sal::detail::log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1852" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
1853 SAL_WARN_IF( nPos+pTP->GetLen() < nEnd, "vcl", "RecalcTextPortion: Bad End!" )do { if (true && (nPos+pTP->GetLen() < nEnd)) {
switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN, "vcl"
)) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "RecalcTextPortion: Bad End!") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1853" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "RecalcTextPortion: Bad End!"), 0); }
else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "RecalcTextPortion: Bad End!"; ::sal::detail::log( (
::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1853" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "RecalcTextPortion: Bad End!") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1853" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "RecalcTextPortion: Bad End!"), 0); }
else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "RecalcTextPortion: Bad End!"; ::sal::detail::log( (
::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1853" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
1854 break;
1855 }
1856 nPos += pTP->GetLen();
1857 }
1858 SAL_WARN_IF( !pTP, "vcl", "RecalcTextPortion: Portion not found!" )do { if (true && (!pTP)) { switch (sal_detail_log_report
(::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE
: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail
::getResult( ::sal::detail::StreamStart() << "RecalcTextPortion: Portion not found!"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"
), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1858" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "RecalcTextPortion: Portion not found!"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "RecalcTextPortion: Portion not found!"; ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1858" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "RecalcTextPortion: Portion not found!") == 1) { ::
sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1858" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "RecalcTextPortion: Portion not found!"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "RecalcTextPortion: Portion not found!"; ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1858" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
12
Taking true branch
13
'Default' branch taken. Execution continues on line 1858
14
Loop condition is false. Exiting loop
1859 if ( ( nPos == nStartPos ) && ( (nPos+pTP->GetLen()) == nEnd ) )
15
Assuming 'nPos' is equal to 'nStartPos'
16
Called C++ object pointer is null
1860 {
1861 // remove Portion
1862 pTEParaPortion->GetTextPortions().erase( pTEParaPortion->GetTextPortions().begin() + nPortion );
1863 }
1864 else
1865 {
1866 SAL_WARN_IF( pTP->GetLen() <= (-nNewChars), "vcl", "RecalcTextPortion: Portion too small to shrink!" )do { if (true && (pTP->GetLen() <= (-nNewChars)
)) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "RecalcTextPortion: Portion too small to shrink!"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"
), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1866" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "RecalcTextPortion: Portion too small to shrink!"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "RecalcTextPortion: Portion too small to shrink!"; ::
sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1866" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "RecalcTextPortion: Portion too small to shrink!"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"
), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1866" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "RecalcTextPortion: Portion too small to shrink!"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "RecalcTextPortion: Portion too small to shrink!"; ::
sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1866" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
1867 pTP->GetLen() += nNewChars;
1868 }
1869 OSL_ENSURE( pTEParaPortion->GetTextPortions().size(),do { if (true && (!(pTEParaPortion->GetTextPortions
().size()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1870" ": "), "%s", "RecalcTextPortion: none are left!")
; } } while (false)
1870 "RecalcTextPortion: none are left!" )do { if (true && (!(pTEParaPortion->GetTextPortions
().size()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1870" ": "), "%s", "RecalcTextPortion: none are left!")
; } } while (false)
;
1871 }
1872}
1873
1874void TextEngine::ImpPaint( OutputDevice* pOutDev, const Point& rStartPos, tools::Rectangle const* pPaintArea, TextSelection const* pSelection )
1875{
1876 if ( !GetUpdateMode() )
1877 return;
1878
1879 if ( !IsFormatted() )
1880 FormatDoc();
1881
1882 vcl::Window* const pOutWin = dynamic_cast<vcl::Window*>(pOutDev);
1883 const bool bTransparent = (pOutWin && pOutWin->IsPaintTransparent());
1884
1885 long nY = rStartPos.Y();
1886
1887 TextPaM const* pSelStart = nullptr;
1888 TextPaM const* pSelEnd = nullptr;
1889 if ( pSelection && pSelection->HasRange() )
1890 {
1891 const bool bInvers = pSelection->GetEnd() < pSelection->GetStart();
1892 pSelStart = !bInvers ? &pSelection->GetStart() : &pSelection->GetEnd();
1893 pSelEnd = bInvers ? &pSelection->GetStart() : &pSelection->GetEnd();
1894 }
1895
1896 const StyleSettings& rStyleSettings = pOutDev->GetSettings().GetStyleSettings();
1897
1898 // for all paragraphs
1899 for ( sal_uInt32 nPara = 0; nPara < mpTEParaPortions->Count(); ++nPara )
1900 {
1901 TEParaPortion* pPortion = mpTEParaPortions->GetObject( nPara );
1902 // in case while typing Idle-Formatting, asynchronous Paint
1903 if ( pPortion->IsInvalid() )
1904 return;
1905
1906 const long nParaHeight = CalcParaHeight( nPara );
1907 if ( !pPaintArea || ( ( nY + nParaHeight ) > pPaintArea->Top() ) )
1908 {
1909 // for all lines of the paragraph
1910 sal_Int32 nIndex = 0;
1911 for ( auto & rLine : pPortion->GetLines() )
1912 {
1913 Point aTmpPos( rStartPos.X() + rLine.GetStartX(), nY );
1914
1915 if ( !pPaintArea || ( ( nY + mnCharHeight ) > pPaintArea->Top() ) )
1916 {
1917 // for all Portions of the line
1918 nIndex = rLine.GetStart();
1919 for ( std::size_t y = rLine.GetStartPortion(); y <= rLine.GetEndPortion(); y++ )
1920 {
1921 OSL_ENSURE(pPortion->GetTextPortions().size(),do { if (true && (!(pPortion->GetTextPortions().size
()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1922" ": "), "%s", "ImpPaint: Line without Textportion!"
); } } while (false)
1922 "ImpPaint: Line without Textportion!")do { if (true && (!(pPortion->GetTextPortions().size
()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1922" ": "), "%s", "ImpPaint: Line without Textportion!"
); } } while (false)
;
1923 TETextPortion* pTextPortion = pPortion->GetTextPortions()[ y ];
1924 SAL_WARN_IF( !pTextPortion, "vcl", "ImpPaint: Bad pTextPortion!" )do { if (true && (!pTextPortion)) { switch (sal_detail_log_report
(::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE
: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail
::getResult( ::sal::detail::StreamStart() << "ImpPaint: Bad pTextPortion!"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"
), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1924" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "ImpPaint: Bad pTextPortion!"), 0); }
else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "ImpPaint: Bad pTextPortion!"; ::sal::detail::log( (
::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1924" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "ImpPaint: Bad pTextPortion!") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1924" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "ImpPaint: Bad pTextPortion!"), 0); }
else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "ImpPaint: Bad pTextPortion!"; ::sal::detail::log( (
::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "1924" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
1925
1926 ImpInitLayoutMode( pOutDev /*, pTextPortion->IsRightToLeft() */);
1927
1928 const long nTxtWidth = pTextPortion->GetWidth();
1929 aTmpPos.setX( rStartPos.X() + ImpGetOutputOffset( nPara, &rLine, nIndex, nIndex ) );
1930
1931 // only print if starting in the visible region
1932 if ( ( aTmpPos.X() + nTxtWidth ) >= 0 )
1933 {
1934 switch ( pTextPortion->GetKind() )
1935 {
1936 case PORTIONKIND_TEXT0:
1937 {
1938 vcl::Font aFont;
1939 SeekCursor( nPara, nIndex+1, aFont, pOutDev );
1940 if( bTransparent )
1941 aFont.SetTransparent( true );
1942 else if ( pSelection )
1943 aFont.SetTransparent( false );
1944 pOutDev->SetFont( aFont );
1945
1946 sal_Int32 nTmpIndex = nIndex;
1947 sal_Int32 nEnd = nTmpIndex + pTextPortion->GetLen();
1948 Point aPos = aTmpPos;
1949
1950 bool bDone = false;
1951 if ( pSelStart )
1952 {
1953 // is a part of it in the selection?
1954 const TextPaM aTextStart( nPara, nTmpIndex );
1955 const TextPaM aTextEnd( nPara, nEnd );
1956 if ( ( aTextStart < *pSelEnd ) && ( aTextEnd > *pSelStart ) )
1957 {
1958 // 1) vcl::Region before Selection
1959 if ( aTextStart < *pSelStart )
1960 {
1961 const sal_Int32 nL = pSelStart->GetIndex() - nTmpIndex;
1962 pOutDev->SetFont( aFont);
1963 pOutDev->SetTextFillColor();
1964 aPos.setX( rStartPos.X() + ImpGetOutputOffset( nPara, &rLine, nTmpIndex, nTmpIndex+nL ) );
1965 pOutDev->DrawText( aPos, pPortion->GetNode()->GetText(), nTmpIndex, nL );
1966 nTmpIndex = nTmpIndex + nL;
1967
1968 }
1969 // 2) vcl::Region with Selection
1970 sal_Int32 nL = nEnd - nTmpIndex;
1971 if ( aTextEnd > *pSelEnd )
1972 nL = pSelEnd->GetIndex() - nTmpIndex;
1973 if ( nL )
1974 {
1975 const Color aOldTextColor = pOutDev->GetTextColor();
1976 pOutDev->SetTextColor( rStyleSettings.GetHighlightTextColor() );
1977 pOutDev->SetTextFillColor( rStyleSettings.GetHighlightColor() );
1978 aPos.setX( rStartPos.X() + ImpGetOutputOffset( nPara, &rLine, nTmpIndex, nTmpIndex+nL ) );
1979 pOutDev->DrawText( aPos, pPortion->GetNode()->GetText(), nTmpIndex, nL );
1980 pOutDev->SetTextColor( aOldTextColor );
1981 pOutDev->SetTextFillColor();
1982 nTmpIndex = nTmpIndex + nL;
1983 }
1984
1985 // 3) vcl::Region after Selection
1986 if ( nTmpIndex < nEnd )
1987 {
1988 nL = nEnd-nTmpIndex;
1989 pOutDev->SetTextFillColor();
1990 aPos.setX( rStartPos.X() + ImpGetOutputOffset( nPara, &rLine, nTmpIndex, nTmpIndex+nL ) );
1991 pOutDev->DrawText( aPos, pPortion->GetNode()->GetText(), nTmpIndex, nEnd-nTmpIndex );
1992 }
1993 bDone = true;
1994 }
1995 }
1996 if ( !bDone )
1997 {
1998 pOutDev->SetTextFillColor();
1999 aPos.setX( rStartPos.X() + ImpGetOutputOffset( nPara, &rLine, nTmpIndex, nEnd ) );
2000 pOutDev->DrawText( aPos, pPortion->GetNode()->GetText(), nTmpIndex, nEnd-nTmpIndex );
2001 }
2002 }
2003 break;
2004 case PORTIONKIND_TAB1:
2005 // for HideSelection() only Range, pSelection = 0.
2006 if ( pSelStart ) // also implies pSelEnd
2007 {
2008 const tools::Rectangle aTabArea( aTmpPos, Point( aTmpPos.X()+nTxtWidth, aTmpPos.Y()+mnCharHeight-1 ) );
2009 // is the Tab in the Selection???
2010 const TextPaM aTextStart(nPara, nIndex);
2011 const TextPaM aTextEnd(nPara, nIndex + 1);
2012 if ((aTextStart < *pSelEnd) && (aTextEnd > *pSelStart))
2013 {
2014 const Color aOldColor = pOutDev->GetFillColor();
2015 pOutDev->SetFillColor(
2016 rStyleSettings.GetHighlightColor());
2017 pOutDev->DrawRect(aTabArea);
2018 pOutDev->SetFillColor(aOldColor);
2019 }
2020 else
2021 {
2022 pOutDev->Erase( aTabArea );
2023 }
2024 }
2025 break;
2026 default:
2027 OSL_FAIL( "ImpPaint: Unknown Portion-Type !" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "2027" ": "), "%s", "ImpPaint: Unknown Portion-Type !");
} } while (false)
;
2028 }
2029 }
2030
2031 nIndex += pTextPortion->GetLen();
2032 }
2033 }
2034
2035 nY += mnCharHeight;
2036
2037 if ( pPaintArea && ( nY >= pPaintArea->Bottom() ) )
2038 break; // no more visible actions
2039 }
2040 }
2041 else
2042 {
2043 nY += nParaHeight;
2044 }
2045
2046 if ( pPaintArea && ( nY > pPaintArea->Bottom() ) )
2047 break; // no more visible actions
2048 }
2049}
2050
2051bool TextEngine::CreateLines( sal_uInt32 nPara )
2052{
2053 // bool: changing Height of Paragraph Yes/No - true/false
2054
2055 TextNode* pNode = mpDoc->GetNodes()[ nPara ].get();
2056 TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nPara );
2057 SAL_WARN_IF( !pTEParaPortion->IsInvalid(), "vcl", "CreateLines: Portion not invalid!" )do { if (true && (!pTEParaPortion->IsInvalid())) {
switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN, "vcl"
)) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "CreateLines: Portion not invalid!") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "2057" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "CreateLines: Portion not invalid!")
, 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "CreateLines: Portion not invalid!"; ::sal::detail::
log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "2057" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "CreateLines: Portion not invalid!") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "2057" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "CreateLines: Portion not invalid!")
, 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "CreateLines: Portion not invalid!"; ::sal::detail::
log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "2057" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
2058
2059 const auto nOldLineCount = pTEParaPortion->GetLines().size();
2060
2061 // fast special case for empty paragraphs
2062 if ( pTEParaPortion->GetNode()->GetText().isEmpty() )
2063 {
2064 if ( !pTEParaPortion->GetTextPortions().empty() )
2065 pTEParaPortion->GetTextPortions().Reset();
2066 pTEParaPortion->GetLines().clear();
2067 CreateAndInsertEmptyLine( nPara );
2068 pTEParaPortion->SetValid();
2069 return nOldLineCount != pTEParaPortion->GetLines().size();
2070 }
2071
2072 // initialization
2073 if ( pTEParaPortion->GetLines().empty() )
2074 {
2075 pTEParaPortion->GetLines().emplace_back( );
2076 }
2077
2078 const sal_Int32 nInvalidDiff = pTEParaPortion->GetInvalidDiff();
2079 const sal_Int32 nInvalidStart = pTEParaPortion->GetInvalidPosStart();
2080 const sal_Int32 nInvalidEnd = nInvalidStart + std::abs( nInvalidDiff );
2081 bool bQuickFormat = false;
2082
2083 if ( pTEParaPortion->GetWritingDirectionInfos().empty() )
2084 ImpInitWritingDirections( nPara );
2085
2086 if ( pTEParaPortion->GetWritingDirectionInfos().size() == 1 && pTEParaPortion->IsSimpleInvalid() )
2087 {
2088 bQuickFormat = nInvalidDiff != 0;
2089 if ( nInvalidDiff < 0 )
2090 {
2091 // check if deleting across Portion border
2092 sal_Int32 nPos = 0;
2093 for ( const auto & pTP : pTEParaPortion->GetTextPortions() )
2094 {
2095 // there must be no Start/End in the deleted region
2096 nPos += pTP->GetLen();
2097 if ( nPos > nInvalidStart && nPos < nInvalidEnd )
2098 {
2099 bQuickFormat = false;
2100 break;
2101 }
2102 }
2103 }
2104 }
2105
2106 if ( bQuickFormat )
2107 RecalcTextPortion( nPara, nInvalidStart, nInvalidDiff );
2108 else
2109 CreateTextPortions( nPara, nInvalidStart );
2110
2111 // search for line with InvalidPos; start a line prior
2112 // flag lines => do not remove!
2113
2114 sal_uInt16 nLine = pTEParaPortion->GetLines().size()-1;
2115 for ( sal_uInt16 nL = 0; nL <= nLine; nL++ )
2116 {
2117 TextLine& rLine = pTEParaPortion->GetLines()[ nL ];
2118 if ( rLine.GetEnd() > nInvalidStart )
2119 {
2120 nLine = nL;
2121 break;
2122 }
2123 rLine.SetValid();
2124 }
2125 // start a line before...
2126 // if typing at the end, the line before cannot change
2127 if ( nLine && ( !pTEParaPortion->IsSimpleInvalid() || ( nInvalidEnd < pNode->GetText().getLength() ) || ( nInvalidDiff <= 0 ) ) )
2128 nLine--;
2129
2130 TextLine* pLine = &( pTEParaPortion->GetLines()[ nLine ] );
2131
2132 // format all lines starting here
2133 std::size_t nDelFromLine = TETextPortionList::npos;
2134
2135 sal_Int32 nIndex = pLine->GetStart();
2136 TextLine aSaveLine( *pLine );
2137
2138 while ( nIndex < pNode->GetText().getLength() )
2139 {
2140 bool bEOL = false;
2141 sal_Int32 nPortionStart = 0;
2142 sal_Int32 nPortionEnd = 0;
2143
2144 sal_Int32 nTmpPos = nIndex;
2145 std::size_t nTmpPortion = pLine->GetStartPortion();
2146 long nTmpWidth = mpDoc->GetLeftMargin();
2147 // do not subtract margin; it is included in TmpWidth
2148 long nXWidth = std::max(
2149 mnMaxTextWidth ? mnMaxTextWidth : std::numeric_limits<long>::max(), nTmpWidth);
2150
2151 // search for Portion that does not fit anymore into line
2152 TETextPortion* pPortion = nullptr;
2153 bool bBrokenLine = false;
2154
2155 while ( ( nTmpWidth <= nXWidth ) && !bEOL && ( nTmpPortion < pTEParaPortion->GetTextPortions().size() ) )
2156 {
2157 nPortionStart = nTmpPos;
2158 pPortion = pTEParaPortion->GetTextPortions()[ nTmpPortion ];
2159 SAL_WARN_IF( !pPortion->GetLen(), "vcl", "CreateLines: Empty Portion!" )do { if (true && (!pPortion->GetLen())) { switch (
sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) { case
SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "CreateLines: Empty Portion!") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "2159" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "CreateLines: Empty Portion!"), 0); }
else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "CreateLines: Empty Portion!"; ::sal::detail::log( (
::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "2159" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "CreateLines: Empty Portion!") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "2159" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "CreateLines: Empty Portion!"), 0); }
else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "CreateLines: Empty Portion!"; ::sal::detail::log( (
::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "2159" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
2160 if ( pNode->GetText()[ nTmpPos ] == '\t' )
2161 {
2162 long nCurPos = nTmpWidth-mpDoc->GetLeftMargin();
2163 nTmpWidth = ((nCurPos/mnDefTab)+1)*mnDefTab+mpDoc->GetLeftMargin();
2164 pPortion->GetWidth() = nTmpWidth - nCurPos - mpDoc->GetLeftMargin();
2165 // infinite loop, if this is the first token of the line and nTmpWidth > aPaperSize.Width !!!
2166 if ( ( nTmpWidth >= nXWidth ) && ( nTmpPortion == pLine->GetStartPortion() ) )
2167 {
2168 // adjust Tab
2169 pPortion->GetWidth() = nXWidth-1;
2170 nTmpWidth = pPortion->GetWidth();
2171 bEOL = true;
2172 bBrokenLine = true;
2173 }
2174 pPortion->GetKind() = PORTIONKIND_TAB1;
2175 }
2176 else
2177 {
2178
2179 pPortion->GetWidth() = CalcTextWidth( nPara, nTmpPos, pPortion->GetLen() );
2180 nTmpWidth += pPortion->GetWidth();
2181
2182 pPortion->SetRightToLeft( ImpGetRightToLeft( nPara, nTmpPos+1 ) );
2183 pPortion->GetKind() = PORTIONKIND_TEXT0;
2184 }
2185
2186 nTmpPos += pPortion->GetLen();
2187 nPortionEnd = nTmpPos;
2188 nTmpPortion++;
2189 }
2190
2191 // this was perhaps one Portion too far
2192 bool bFixedEnd = false;
2193 if ( nTmpWidth > nXWidth )
2194 {
2195 nPortionEnd = nTmpPos;
2196 nTmpPos -= pPortion->GetLen();
2197 nPortionStart = nTmpPos;
2198 nTmpPortion--;
2199 bEOL = false;
2200
2201 nTmpWidth -= pPortion->GetWidth();
2202 if ( pPortion->GetKind() == PORTIONKIND_TAB1 )
2203 {
2204 bEOL = true;
2205 bFixedEnd = true;
2206 }
2207 }
2208 else
2209 {
2210 bEOL = true;
2211 pLine->SetEnd( nPortionEnd );
2212 OSL_ENSURE(pTEParaPortion->GetTextPortions().size(),do { if (true && (!(pTEParaPortion->GetTextPortions
().size()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "2213" ": "), "%s", "CreateLines: No TextPortions?"); } }
while (false)
2213 "CreateLines: No TextPortions?")do { if (true && (!(pTEParaPortion->GetTextPortions
().size()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "2213" ": "), "%s", "CreateLines: No TextPortions?"); } }
while (false)
;
2214 pLine->SetEndPortion( pTEParaPortion->GetTextPortions().size() - 1 );
2215 }
2216
2217 if ( bFixedEnd )
2218 {
2219 pLine->SetEnd( nPortionStart );
2220 pLine->SetEndPortion( nTmpPortion-1 );
2221 }
2222 else if ( bBrokenLine )
2223 {
2224 pLine->SetEnd( nPortionStart+1 );
2225 pLine->SetEndPortion( nTmpPortion-1 );
2226 }
2227 else if ( !bEOL )
2228 {
2229 SAL_WARN_IF( (nPortionEnd-nPortionStart) != pPortion->GetLen(), "vcl", "CreateLines: There is a Portion after all?!" )do { if (true && ((nPortionEnd-nPortionStart) != pPortion
->GetLen())) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "CreateLines: There is a Portion after all?!") ==
1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"
), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "2229" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "CreateLines: There is a Portion after all?!"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "CreateLines: There is a Portion after all?!"; ::sal
::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "2229" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "CreateLines: There is a Portion after all?!") ==
1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"
), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "2229" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "CreateLines: There is a Portion after all?!"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "CreateLines: There is a Portion after all?!"; ::sal
::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "2229" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
2230 const long nRemainingWidth = mnMaxTextWidth - nTmpWidth;
2231 ImpBreakLine( nPara, pLine, nPortionStart, nRemainingWidth );
2232 }
2233
2234 if ( ( ImpGetAlign() == TxtAlign::Center ) || ( ImpGetAlign() == TxtAlign::Right ) )
2235 {
2236 // adjust
2237 long nTextWidth = 0;
2238 for ( std::size_t nTP = pLine->GetStartPortion(); nTP <= pLine->GetEndPortion(); nTP++ )
2239 {
2240 TETextPortion* pTextPortion = pTEParaPortion->GetTextPortions()[ nTP ];
2241 nTextWidth += pTextPortion->GetWidth();
2242 }
2243 const long nSpace = mnMaxTextWidth - nTextWidth;
2244 if ( nSpace > 0 )
2245 {
2246 if ( ImpGetAlign() == TxtAlign::Center )
2247 pLine->SetStartX( static_cast<sal_uInt16>(nSpace / 2) );
2248 else // TxtAlign::Right
2249 pLine->SetStartX( static_cast<sal_uInt16>(nSpace) );
2250 }
2251 }
2252 else
2253 {
2254 pLine->SetStartX( mpDoc->GetLeftMargin() );
2255 }
2256
2257 // check if the line has to be printed again
2258 pLine->SetInvalid();
2259
2260 if ( pTEParaPortion->IsSimpleInvalid() )
2261 {
2262 // Change due to simple TextChange...
2263 // Do not abort formatting, as Portions might have to be split!
2264 // Once it is ok to abort, then validate the following lines!
2265 // But mark as valid, thus reduce printing...
2266 if ( pLine->GetEnd() < nInvalidStart )
2267 {
2268 if ( *pLine == aSaveLine )
2269 {
2270 pLine->SetValid();
2271 }
2272 }
2273 else
2274 {
2275 const sal_Int32 nStart = pLine->GetStart();
2276 const sal_Int32 nEnd = pLine->GetEnd();
2277
2278 if ( nStart > nInvalidEnd )
2279 {
2280 if ( ( ( nStart-nInvalidDiff ) == aSaveLine.GetStart() ) &&
2281 ( ( nEnd-nInvalidDiff ) == aSaveLine.GetEnd() ) )
2282 {
2283 pLine->SetValid();
2284 if ( bQuickFormat )
2285 {
2286 pTEParaPortion->CorrectValuesBehindLastFormattedLine( nLine );
2287 break;
2288 }
2289 }
2290 }
2291 else if ( bQuickFormat && ( nEnd > nInvalidEnd) )
2292 {
2293 // If the invalid line ends such that the next line starts
2294 // at the 'same' position as before (no change in line breaks),
2295 // the text width does not have to be recalculated.
2296 if ( nEnd == ( aSaveLine.GetEnd() + nInvalidDiff ) )
2297 {
2298 pTEParaPortion->CorrectValuesBehindLastFormattedLine( nLine );
2299 break;
2300 }
2301 }
2302 }
2303 }
2304
2305 nIndex = pLine->GetEnd(); // next line Start = previous line End
2306 // because nEnd is past the last char!
2307
2308 const std::size_t nEndPortion = pLine->GetEndPortion();
2309
2310 // next line or new line
2311 pLine = nullptr;
2312 if ( nLine < pTEParaPortion->GetLines().size()-1 )
2313 pLine = &( pTEParaPortion->GetLines()[ ++nLine ] );
2314 if ( pLine && ( nIndex >= pNode->GetText().getLength() ) )
2315 {
2316 nDelFromLine = nLine;
2317 break;
2318 }
2319 if ( !pLine )
2320 {
2321 if ( nIndex < pNode->GetText().getLength() )
2322 {
2323 ++nLine;
2324 pTEParaPortion->GetLines().insert( pTEParaPortion->GetLines().begin() + nLine, TextLine() );
2325 pLine = &pTEParaPortion->GetLines()[nLine];
2326 }
2327 else
2328 {
2329 break;
2330 }
2331 }
2332 aSaveLine = *pLine;
2333 pLine->SetStart( nIndex );
2334 pLine->SetEnd( nIndex );
2335 pLine->SetStartPortion( nEndPortion+1 );
2336 pLine->SetEndPortion( nEndPortion+1 );
2337
2338 } // while ( Index < Len )
2339
2340 if (nDelFromLine != TETextPortionList::npos)
2341 {
2342 pTEParaPortion->GetLines().erase( pTEParaPortion->GetLines().begin() + nDelFromLine,
2343 pTEParaPortion->GetLines().end() );
2344 }
2345
2346 SAL_WARN_IF( pTEParaPortion->GetLines().empty(), "vcl", "CreateLines: No Line!" )do { if (true && (pTEParaPortion->GetLines().empty
())) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "CreateLines: No Line!") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "2346" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "CreateLines: No Line!"), 0); } else
{ ::std::ostringstream sal_detail_stream; sal_detail_stream <<
"CreateLines: No Line!"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "2346" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "CreateLines: No Line!") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "2346" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "CreateLines: No Line!"), 0); } else
{ ::std::ostringstream sal_detail_stream; sal_detail_stream <<
"CreateLines: No Line!"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "2346" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
2347
2348 pTEParaPortion->SetValid();
2349
2350 return nOldLineCount != pTEParaPortion->GetLines().size();
2351}
2352
2353OUString TextEngine::GetWord( const TextPaM& rCursorPos, TextPaM* pStartOfWord, TextPaM* pEndOfWord )
2354{
2355 OUString aWord;
2356 if ( rCursorPos.GetPara() < mpDoc->GetNodes().size() )
2357 {
2358 TextSelection aSel( rCursorPos );
2359 TextNode* pNode = mpDoc->GetNodes()[ rCursorPos.GetPara() ].get();
2360 uno::Reference < i18n::XBreakIterator > xBI = GetBreakIterator();
2361 i18n::Boundary aBoundary = xBI->getWordBoundary( pNode->GetText(), rCursorPos.GetIndex(), GetLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES, true );
2362 // tdf#57879 - expand selection to the left to include connector punctuations and search for additional word boundaries
2363 if (aBoundary.startPos > 0 && aBoundary.startPos < pNode->GetText().getLength() && u_charTypeu_charType_67(pNode->GetText()[aBoundary.startPos]) == U_CONNECTOR_PUNCTUATION)
2364 {
2365 aBoundary.startPos = xBI->getWordBoundary(pNode->GetText(), aBoundary.startPos - 1,
2366 GetLocale(), css::i18n::WordType::ANYWORD_IGNOREWHITESPACES, true).startPos;
2367 }
2368 while (aBoundary.startPos > 0 && u_charTypeu_charType_67(pNode->GetText()[aBoundary.startPos - 1]) == U_CONNECTOR_PUNCTUATION)
2369 {
2370 aBoundary.startPos = std::min(aBoundary.startPos,
2371 xBI->getWordBoundary( pNode->GetText(), aBoundary.startPos - 2,
2372 GetLocale(), css::i18n::WordType::ANYWORD_IGNOREWHITESPACES, true).startPos);
2373 }
2374 // tdf#57879 - expand selection to the right to include connector punctuations and search for additional word boundaries
2375 if (aBoundary.endPos < pNode->GetText().getLength() && u_charTypeu_charType_67(pNode->GetText()[aBoundary.endPos - 1]) == U_CONNECTOR_PUNCTUATION)
2376 {
2377 aBoundary.endPos = xBI->getWordBoundary(pNode->GetText(), aBoundary.endPos,
2378 GetLocale(), css::i18n::WordType::ANYWORD_IGNOREWHITESPACES, true).endPos;
2379 }
2380 while (aBoundary.endPos < pNode->GetText().getLength() && u_charTypeu_charType_67(pNode->GetText()[aBoundary.endPos]) == U_CONNECTOR_PUNCTUATION)
2381 {
2382 aBoundary.endPos = xBI->getWordBoundary(pNode->GetText(), aBoundary.endPos + 1,
2383 GetLocale(), css::i18n::WordType::ANYWORD_IGNOREWHITESPACES, true).endPos;
2384 }
2385 aSel.GetStart().GetIndex() = aBoundary.startPos;
2386 aSel.GetEnd().GetIndex() = aBoundary.endPos;
2387 aWord = pNode->GetText().copy( aSel.GetStart().GetIndex(), aSel.GetEnd().GetIndex() - aSel.GetStart().GetIndex() );
2388 if ( pStartOfWord )
2389 *pStartOfWord = aSel.GetStart();
2390 if (pEndOfWord)
2391 *pEndOfWord = aSel.GetEnd();
2392 }
2393 return aWord;
2394}
2395
2396bool TextEngine::Read( SvStream& rInput, const TextSelection* pSel )
2397{
2398 const bool bUpdate = GetUpdateMode();
2399 SetUpdateMode( false );
2400
2401 UndoActionStart();
2402 TextSelection aSel;
2403 if ( pSel )
2404 aSel = *pSel;
2405 else
2406 {
2407 const sal_uInt32 nParas = static_cast<sal_uInt32>(mpDoc->GetNodes().size());
2408 TextNode* pNode = mpDoc->GetNodes()[ nParas - 1 ].get();
2409 aSel = TextPaM( nParas-1 , pNode->GetText().getLength() );
2410 }
2411
2412 if ( aSel.HasRange() )
2413 aSel = ImpDeleteText( aSel );
2414
2415 OString aLine;
2416 bool bDone = rInput.ReadLine( aLine );
2417 OUString aTmpStr(OStringToOUString(aLine, rInput.GetStreamCharSet()));
2418 while ( bDone )
2419 {
2420 aSel = ImpInsertText( aSel, aTmpStr );
2421 bDone = rInput.ReadLine( aLine );
2422 aTmpStr = OStringToOUString(aLine, rInput.GetStreamCharSet());
2423 if ( bDone )
2424 aSel = ImpInsertParaBreak( aSel.GetEnd() );
2425 }
2426
2427 UndoActionEnd();
2428
2429 const TextSelection aNewSel( aSel.GetEnd(), aSel.GetEnd() );
2430
2431 // so that FormatAndUpdate does not access the invalid selection
2432 if ( GetActiveView() )
2433 GetActiveView()->ImpSetSelection( aNewSel );
2434
2435 SetUpdateMode( bUpdate );
2436 FormatAndUpdate( GetActiveView() );
2437
2438 return rInput.GetError() == ERRCODE_NONEErrCode(0);
2439}
2440
2441void TextEngine::Write( SvStream& rOutput )
2442{
2443 TextSelection aSel;
2444 const sal_uInt32 nParas = static_cast<sal_uInt32>(mpDoc->GetNodes().size());
2445 TextNode* pSelNode = mpDoc->GetNodes()[ nParas - 1 ].get();
2446 aSel.GetStart() = TextPaM( 0, 0 );
2447 aSel.GetEnd() = TextPaM( nParas-1, pSelNode->GetText().getLength() );
2448
2449 for ( sal_uInt32 nPara = aSel.GetStart().GetPara(); nPara <= aSel.GetEnd().GetPara(); ++nPara )
2450 {
2451 TextNode* pNode = mpDoc->GetNodes()[ nPara ].get();
2452
2453 const sal_Int32 nStartPos = nPara == aSel.GetStart().GetPara()
2454 ? aSel.GetStart().GetIndex() : 0;
2455 const sal_Int32 nEndPos = nPara == aSel.GetEnd().GetPara()
2456 ? aSel.GetEnd().GetIndex() : pNode->GetText().getLength();
2457
2458 const OUString aText = pNode->GetText().copy( nStartPos, nEndPos-nStartPos );
2459 rOutput.WriteLine(OUStringToOString(aText, rOutput.GetStreamCharSet()));
2460 }
2461}
2462
2463void TextEngine::RemoveAttribs( sal_uInt32 nPara )
2464{
2465 if ( nPara >= mpDoc->GetNodes().size() )
2466 return;
2467
2468 TextNode* pNode = mpDoc->GetNodes()[ nPara ].get();
2469 if ( pNode->GetCharAttribs().Count() )
2470 {
2471 pNode->GetCharAttribs().Clear();
2472
2473 TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nPara );
2474 pTEParaPortion->MarkSelectionInvalid( 0 );
2475
2476 mbFormatted = false;
2477
2478 IdleFormatAndUpdate( nullptr, 0xFFFF );
2479 }
2480}
2481
2482void TextEngine::SetAttrib( const TextAttrib& rAttr, sal_uInt32 nPara, sal_Int32 nStart, sal_Int32 nEnd )
2483{
2484
2485 // For now do not check if Attributes overlap!
2486 // This function is for TextEditors that want to _quickly_ generate the Syntax-Highlight
2487
2488 // As TextEngine is currently intended only for TextEditors, there is no Undo for Attributes!
2489
2490 if ( nPara >= mpDoc->GetNodes().size() )
2491 return;
2492
2493 TextNode* pNode = mpDoc->GetNodes()[ nPara ].get();
2494 TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nPara );
2495
2496 const sal_Int32 nMax = pNode->GetText().getLength();
2497 if ( nStart > nMax )
2498 nStart = nMax;
2499 if ( nEnd > nMax )
2500 nEnd = nMax;
2501
2502 pNode->GetCharAttribs().InsertAttrib( std::make_unique<TextCharAttrib>( rAttr, nStart, nEnd ) );
2503 pTEParaPortion->MarkSelectionInvalid( nStart );
2504
2505 mbFormatted = false;
2506 IdleFormatAndUpdate( nullptr, 0xFFFF );
2507}
2508
2509void TextEngine::SetTextAlign( TxtAlign eAlign )
2510{
2511 if ( eAlign != meAlign )
2512 {
2513 meAlign = eAlign;
2514 FormatFullDoc();
2515 UpdateViews();
2516 }
2517}
2518
2519void TextEngine::ValidateSelection( TextSelection& rSel ) const
2520{
2521 ValidatePaM( rSel.GetStart() );
2522 ValidatePaM( rSel.GetEnd() );
2523}
2524
2525void TextEngine::ValidatePaM( TextPaM& rPaM ) const
2526{
2527 const sal_uInt32 nParas = static_cast<sal_uInt32>(mpDoc->GetNodes().size());
2528 if ( rPaM.GetPara() >= nParas )
2529 {
2530 rPaM.GetPara() = nParas ? nParas-1 : 0;
2531 rPaM.GetIndex() = TEXT_INDEX_ALL((sal_Int32) 0x7FFFFFFF);
2532 }
2533
2534 const sal_Int32 nMaxIndex = GetTextLen( rPaM.GetPara() );
2535 if ( rPaM.GetIndex() > nMaxIndex )
2536 rPaM.GetIndex() = nMaxIndex;
2537}
2538
2539// adjust State & Selection
2540
2541void TextEngine::ImpParagraphInserted( sal_uInt32 nPara )
2542{
2543 // No adjustment needed for the active View;
2544 // but for all passive Views the Selection needs adjusting.
2545 if ( mpViews->size() > 1 )
2546 {
2547 for ( auto nView = mpViews->size(); nView; )
2548 {
2549 TextView* pView = (*mpViews)[ --nView ];
2550 if ( pView != GetActiveView() )
2551 {
2552 for ( int n = 0; n <= 1; n++ )
2553 {
2554 TextPaM& rPaM = n ? pView->GetSelection().GetStart(): pView->GetSelection().GetEnd();
2555 if ( rPaM.GetPara() >= nPara )
2556 rPaM.GetPara()++;
2557 }
2558 }
2559 }
2560 }
2561 Broadcast( TextHint( SfxHintId::TextParaInserted, nPara ) );
2562}
2563
2564void TextEngine::ImpParagraphRemoved( sal_uInt32 nPara )
2565{
2566 if ( mpViews->size() > 1 )
2567 {
2568 for ( auto nView = mpViews->size(); nView; )
2569 {
2570 TextView* pView = (*mpViews)[ --nView ];
2571 if ( pView != GetActiveView() )
2572 {
2573 const sal_uInt32 nParas = static_cast<sal_uInt32>(mpDoc->GetNodes().size());
2574 for ( int n = 0; n <= 1; n++ )
2575 {
2576 TextPaM& rPaM = n ? pView->GetSelection().GetStart(): pView->GetSelection().GetEnd();
2577 if ( rPaM.GetPara() > nPara )
2578 rPaM.GetPara()--;
2579 else if ( rPaM.GetPara() == nPara )
2580 {
2581 rPaM.GetIndex() = 0;
2582 if ( rPaM.GetPara() >= nParas )
2583 rPaM.GetPara()--;
2584 }
2585 }
2586 }
2587 }
2588 }
2589 Broadcast( TextHint( SfxHintId::TextParaRemoved, nPara ) );
2590}
2591
2592void TextEngine::ImpCharsRemoved( sal_uInt32 nPara, sal_Int32 nPos, sal_Int32 nChars )
2593{
2594 if ( mpViews->size() > 1 )
2595 {
2596 for ( auto nView = mpViews->size(); nView; )
2597 {
2598 TextView* pView = (*mpViews)[ --nView ];
2599 if ( pView != GetActiveView() )
2600 {
2601 const sal_Int32 nEnd = nPos + nChars;
2602 for ( int n = 0; n <= 1; n++ )
2603 {
2604 TextPaM& rPaM = n ? pView->GetSelection().GetStart(): pView->GetSelection().GetEnd();
2605 if ( rPaM.GetPara() == nPara )
2606 {
2607 if ( rPaM.GetIndex() > nEnd )
2608 rPaM.GetIndex() = rPaM.GetIndex() - nChars;
2609 else if ( rPaM.GetIndex() > nPos )
2610 rPaM.GetIndex() = nPos;
2611 }
2612 }
2613 }
2614 }
2615 }
2616 Broadcast( TextHint( SfxHintId::TextParaContentChanged, nPara ) );
2617}
2618
2619void TextEngine::ImpCharsInserted( sal_uInt32 nPara, sal_Int32 nPos, sal_Int32 nChars )
2620{
2621 if ( mpViews->size() > 1 )
2622 {
2623 for ( auto nView = mpViews->size(); nView; )
2624 {
2625 TextView* pView = (*mpViews)[ --nView ];
2626 if ( pView != GetActiveView() )
2627 {
2628 for ( int n = 0; n <= 1; n++ )
2629 {
2630 TextPaM& rPaM = n ? pView->GetSelection().GetStart(): pView->GetSelection().GetEnd();
2631 if ( rPaM.GetPara() == nPara )
2632 {
2633 if ( rPaM.GetIndex() >= nPos )
2634 rPaM.GetIndex() += nChars;
2635 }
2636 }
2637 }
2638 }
2639 }
2640 Broadcast( TextHint( SfxHintId::TextParaContentChanged, nPara ) );
2641}
2642
2643void TextEngine::Draw( OutputDevice* pDev, const Point& rPos )
2644{
2645 ImpPaint( pDev, rPos, nullptr );
2646}
2647
2648void TextEngine::SetLeftMargin( sal_uInt16 n )
2649{
2650 mpDoc->SetLeftMargin( n );
2651}
2652
2653uno::Reference< i18n::XBreakIterator > const & TextEngine::GetBreakIterator()
2654{
2655 if ( !mxBreakIterator.is() )
2656 mxBreakIterator = vcl::unohelper::CreateBreakIterator();
2657 SAL_WARN_IF( !mxBreakIterator.is(), "vcl", "BreakIterator: Failed to create!" )do { if (true && (!mxBreakIterator.is())) { switch (sal_detail_log_report
(::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE
: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail
::getResult( ::sal::detail::StreamStart() << "BreakIterator: Failed to create!"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"
), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "2657" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "BreakIterator: Failed to create!"),
0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "BreakIterator: Failed to create!"; ::sal::detail::
log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "2657" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "BreakIterator: Failed to create!") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "2657" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "BreakIterator: Failed to create!"),
0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "BreakIterator: Failed to create!"; ::sal::detail::
log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx"
":" "2657" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
2658 return mxBreakIterator;
2659}
2660
2661void TextEngine::SetLocale( const css::lang::Locale& rLocale )
2662{
2663 maLocale = rLocale;
2664 mpLocaleDataWrapper.reset();
2665}
2666
2667css::lang::Locale const & TextEngine::GetLocale()
2668{
2669 if ( maLocale.Language.isEmpty() )
2670 {
2671 maLocale = Application::GetSettings().GetUILanguageTag().getLocale(); // TODO: why UI locale?
2672 }
2673 return maLocale;
2674}
2675
2676LocaleDataWrapper* TextEngine::ImpGetLocaleDataWrapper()
2677{
2678 if ( !mpLocaleDataWrapper )
2679 mpLocaleDataWrapper.reset( new LocaleDataWrapper( LanguageTag( GetLocale()) ) );
2680
2681 return mpLocaleDataWrapper.get();
2682}
2683
2684void TextEngine::SetRightToLeft( bool bR2L )
2685{
2686 if ( mbRightToLeft != bR2L )
2687 {
2688 mbRightToLeft = bR2L;
2689 meAlign = bR2L ? TxtAlign::Right : TxtAlign::Left;
2690 FormatFullDoc();
2691 UpdateViews();
2692 }
2693}
2694
2695void TextEngine::ImpInitWritingDirections( sal_uInt32 nPara )
2696{
2697 TEParaPortion* pParaPortion = mpTEParaPortions->GetObject( nPara );
2698 std::vector<TEWritingDirectionInfo>& rInfos = pParaPortion->GetWritingDirectionInfos();
2699 rInfos.clear();
2700
2701 if ( !pParaPortion->GetNode()->GetText().isEmpty() )
2702 {
2703 const UBiDiLevel nBidiLevel = IsRightToLeft() ? 1 /*RTL*/ : 0 /*LTR*/;
2704 OUString aText( pParaPortion->GetNode()->GetText() );
2705
2706 // Bidi functions from icu 2.0
2707
2708 UErrorCode nError = U_ZERO_ERROR;
2709 UBiDi* pBidi = ubidi_openSizedubidi_openSized_67( aText.getLength(), 0, &nError );
2710 nError = U_ZERO_ERROR;
2711
2712 ubidi_setParaubidi_setPara_67( pBidi, reinterpret_cast<const UChar *>(aText.getStr()), aText.getLength(), nBidiLevel, nullptr, &nError );
2713 nError = U_ZERO_ERROR;
2714
2715 long nCount = ubidi_countRunsubidi_countRuns_67( pBidi, &nError );
2716
2717 int32_t nStart = 0;
2718 int32_t nEnd;
2719 UBiDiLevel nCurrDir;
2720
2721 for ( long nIdx = 0; nIdx < nCount; ++nIdx )
2722 {
2723 ubidi_getLogicalRunubidi_getLogicalRun_67( pBidi, nStart, &nEnd, &nCurrDir );
2724 // bit 0 of nCurrDir indicates direction
2725 rInfos.emplace_back( /*bLeftToRight*/ nCurrDir % 2 == 0, nStart, nEnd );
2726 nStart = nEnd;
2727 }
2728
2729 ubidi_closeubidi_close_67( pBidi );
2730 }
2731
2732 // No infos mean no CTL and default dir is L2R...
2733 if ( rInfos.empty() )
2734 rInfos.emplace_back( 0, 0, pParaPortion->GetNode()->GetText().getLength() );
2735
2736}
2737
2738bool TextEngine::ImpGetRightToLeft( sal_uInt32 nPara, sal_Int32 nPos )
2739{
2740 bool bRightToLeft = false;
2741
2742 TextNode* pNode = mpDoc->GetNodes()[ nPara ].get();
2743 if ( pNode && !pNode->GetText().isEmpty() )
2744 {
2745 TEParaPortion* pParaPortion = mpTEParaPortions->GetObject( nPara );
2746 if ( pParaPortion->GetWritingDirectionInfos().empty() )
2747 ImpInitWritingDirections( nPara );
2748
2749 std::vector<TEWritingDirectionInfo>& rDirInfos = pParaPortion->GetWritingDirectionInfos();
2750 for ( const auto& rWritingDirectionInfo : rDirInfos )
2751 {
2752 if ( rWritingDirectionInfo.nStartPos <= nPos && rWritingDirectionInfo.nEndPos >= nPos )
2753 {
2754 bRightToLeft = !rWritingDirectionInfo.bLeftToRight;
2755 break;
2756 }
2757 }
2758 }
2759 return bRightToLeft;
2760}
2761
2762long TextEngine::ImpGetPortionXOffset( sal_uInt32 nPara, TextLine const * pLine, std::size_t nTextPortion )
2763{
2764 long nX = pLine->GetStartX();
2765
2766 TEParaPortion* pParaPortion = mpTEParaPortions->GetObject( nPara );
2767
2768 for ( std::size_t i = pLine->GetStartPortion(); i < nTextPortion; i++ )
2769 {
2770 TETextPortion* pPortion = pParaPortion->GetTextPortions()[ i ];
2771 nX += pPortion->GetWidth();
2772 }
2773
2774 TETextPortion* pDestPortion = pParaPortion->GetTextPortions()[ nTextPortion ];
2775 if ( pDestPortion->GetKind() != PORTIONKIND_TAB1 )
2776 {
2777 if ( !IsRightToLeft() && pDestPortion->IsRightToLeft() )
2778 {
2779 // Portions behind must be added, visual before this portion
2780 std::size_t nTmpPortion = nTextPortion+1;
2781 while ( nTmpPortion <= pLine->GetEndPortion() )
2782 {
2783 TETextPortion* pNextTextPortion = pParaPortion->GetTextPortions()[ nTmpPortion ];
2784 if ( pNextTextPortion->IsRightToLeft() && ( pNextTextPortion->GetKind() != PORTIONKIND_TAB1 ) )
2785 nX += pNextTextPortion->GetWidth();
2786 else
2787 break;
2788 nTmpPortion++;
2789 }
2790 // Portions before must be removed, visual behind this portion
2791 nTmpPortion = nTextPortion;
2792 while ( nTmpPortion > pLine->GetStartPortion() )
2793 {
2794 --nTmpPortion;
2795 TETextPortion* pPrevTextPortion = pParaPortion->GetTextPortions()[ nTmpPortion ];
2796 if ( pPrevTextPortion->IsRightToLeft() && ( pPrevTextPortion->GetKind() != PORTIONKIND_TAB1 ) )
2797 nX -= pPrevTextPortion->GetWidth();
2798 else
2799 break;
2800 }
2801 }
2802 else if ( IsRightToLeft() && !pDestPortion->IsRightToLeft() )
2803 {
2804 // Portions behind must be removed, visual behind this portion
2805 std::size_t nTmpPortion = nTextPortion+1;
2806 while ( nTmpPortion <= pLine->GetEndPortion() )
2807 {
2808 TETextPortion* pNextTextPortion = pParaPortion->GetTextPortions()[ nTmpPortion ];
2809 if ( !pNextTextPortion->IsRightToLeft() && ( pNextTextPortion->GetKind() != PORTIONKIND_TAB1 ) )
2810 nX += pNextTextPortion->GetWidth();
2811 else
2812 break;
2813 nTmpPortion++;
2814 }
2815 // Portions before must be added, visual before this portion
2816 nTmpPortion = nTextPortion;
2817 while ( nTmpPortion > pLine->GetStartPortion() )
2818 {
2819 --nTmpPortion;
2820 TETextPortion* pPrevTextPortion = pParaPortion->GetTextPortions()[ nTmpPortion ];
2821 if ( !pPrevTextPortion->IsRightToLeft() && ( pPrevTextPortion->GetKind() != PORTIONKIND_TAB1 ) )
2822 nX -= pPrevTextPortion->GetWidth();
2823 else
2824 break;
2825 }
2826 }
2827 }
2828
2829 return nX;
2830}
2831
2832void TextEngine::ImpInitLayoutMode( OutputDevice* pOutDev )
2833{
2834 ComplexTextLayoutFlags nLayoutMode = pOutDev->GetLayoutMode();
2835
2836 nLayoutMode &= ~ComplexTextLayoutFlags(ComplexTextLayoutFlags::BiDiRtl | ComplexTextLayoutFlags::BiDiStrong );
2837
2838 pOutDev->SetLayoutMode( nLayoutMode );
2839}
2840
2841TxtAlign TextEngine::ImpGetAlign() const
2842{
2843 TxtAlign eAlign = meAlign;
2844 if ( IsRightToLeft() )
2845 {
2846 if ( eAlign == TxtAlign::Left )
2847 eAlign = TxtAlign::Right;
2848 else if ( eAlign == TxtAlign::Right )
2849 eAlign = TxtAlign::Left;
2850 }
2851 return eAlign;
2852}
2853
2854long TextEngine::ImpGetOutputOffset( sal_uInt32 nPara, TextLine* pLine, sal_Int32 nIndex, sal_Int32 nIndex2 )
2855{
2856 TEParaPortion* pPortion = mpTEParaPortions->GetObject( nPara );
2857
2858 sal_Int32 nPortionStart {0};
2859 const std::size_t nPortion = pPortion->GetTextPortions().FindPortion( nIndex, nPortionStart, true );
2860
2861 TETextPortion* pTextPortion = pPortion->GetTextPortions()[ nPortion ];
2862
2863 long nX;
2864
2865 if ( ( nIndex == nPortionStart ) && ( nIndex == nIndex2 ) )
2866 {
2867 // Output of full portion, so we need portion x offset.
2868 // Use ImpGetPortionXOffset, because GetXPos may deliver left or right position from portion, depending on R2L, L2R
2869 nX = ImpGetPortionXOffset( nPara, pLine, nPortion );
2870 if ( IsRightToLeft() )
2871 {
2872 nX = -nX -pTextPortion->GetWidth();
2873 }
2874 }
2875 else
2876 {
2877 nX = ImpGetXPos( nPara, pLine, nIndex, nIndex == nPortionStart );
2878 if ( nIndex2 != nIndex )
2879 {
2880 const long nX2 = ImpGetXPos( nPara, pLine, nIndex2 );
2881 if ( ( !IsRightToLeft() && ( nX2 < nX ) ) ||
2882 ( IsRightToLeft() && ( nX2 > nX ) ) )
2883 {
2884 nX = nX2;
2885 }
2886 }
2887 if ( IsRightToLeft() )
2888 {
2889 nX = -nX;
2890 }
2891 }
2892
2893 return nX;
2894}
2895
2896/* vim:set shiftwidth=4 softtabstop=4 expandtab: */