Bug Summary

File:home/maarten/src/libreoffice/core/include/rtl/ref.hxx
Warning:line 192, column 9
Use of memory after it is freed

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 impedit2.cxx -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=all -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -isystem /usr/include/libxml2 -D BOOST_ERROR_CODE_HEADER_ONLY -D BOOST_SYSTEM_NO_DEPRECATED -D CPPU_ENV=gcc3 -D LINUX -D OSL_DEBUG_LEVEL=1 -D SAL_LOG_INFO -D SAL_LOG_WARN -D UNIX -D UNX -D X86_64 -D _PTHREADS -D _REENTRANT -D EDITENG_DLLIMPLEMENTATION -D SYSTEM_LIBXML -D EXCEPTIONS_ON -D LIBO_INTERNAL_ONLY -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source/i18n -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source/common -I /home/maarten/src/libreoffice/core/external/boost/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/boost -I /home/maarten/src/libreoffice/core/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/editeng/inc -I /home/maarten/src/libreoffice/core/editeng/source/editeng -I /home/maarten/src/libreoffice/core/workdir/CustomTarget/editeng/generated -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/udkapi/normal -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/offapi/normal -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10 -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/x86_64-redhat-linux -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/backward -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O0 -Wno-missing-braces -std=c++17 -fdeprecated-macro -fdebug-compilation-dir /home/maarten/src/libreoffice/core -ferror-limit 19 -fvisibility hidden -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcxx-exceptions -fexceptions -debug-info-kind=constructor -analyzer-output=html -faddrsig -o /home/maarten/tmp/wis/scan-build-libreoffice/output/report/2020-10-07-141433-9725-1 -x c++ /home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx

/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.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 <vcl/svapp.hxx>
21#include <vcl/window.hxx>
22#include <editeng/lspcitem.hxx>
23#include <editeng/flditem.hxx>
24#include "impedit.hxx"
25#include <editeng/editeng.hxx>
26#include <editeng/editview.hxx>
27#include <eerdll2.hxx>
28#include <editeng/eerdll.hxx>
29#include <edtspell.hxx>
30#include "eeobj.hxx"
31#include <editeng/txtrange.hxx>
32#include <sfx2/app.hxx>
33#include <svtools/colorcfg.hxx>
34#include <svl/ctloptions.hxx>
35#include <unotools/securityoptions.hxx>
36#include <editeng/acorrcfg.hxx>
37#include <editeng/lrspitem.hxx>
38#include <editeng/ulspitem.hxx>
39#include <editeng/adjustitem.hxx>
40#include <editeng/frmdiritem.hxx>
41#include <editeng/justifyitem.hxx>
42
43#include <com/sun/star/i18n/CharacterIteratorMode.hpp>
44#include <com/sun/star/i18n/WordType.hpp>
45#include <com/sun/star/i18n/ScriptType.hpp>
46#include <com/sun/star/lang/Locale.hpp>
47#include <com/sun/star/i18n/InputSequenceCheckMode.hpp>
48#include <com/sun/star/system/SystemShellExecute.hpp>
49#include <com/sun/star/system/SystemShellExecuteFlags.hpp>
50#include <com/sun/star/system/XSystemShellExecute.hpp>
51
52#include <rtl/character.hxx>
53
54#include <sal/log.hxx>
55#include <o3tl/safeint.hxx>
56#include <osl/diagnose.h>
57#include <sot/exchange.hxx>
58#include <sot/formats.hxx>
59#include <svl/asiancfg.hxx>
60#include <i18nutil/unicode.hxx>
61#include <tools/diagnose_ex.h>
62#include <comphelper/lok.hxx>
63#include <comphelper/processfactory.hxx>
64#include <unotools/configmgr.hxx>
65
66#include <unicode/ubidi.h>
67#include <algorithm>
68#include <memory>
69
70#include <fstream>
71
72using namespace ::com::sun::star;
73
74static sal_uInt16 lcl_CalcExtraSpace( const SvxLineSpacingItem& rLSItem )
75{
76 sal_uInt16 nExtra = 0;
77 if ( rLSItem.GetInterLineSpaceRule() == SvxInterLineSpaceRule::Fix )
78 {
79 nExtra = rLSItem.GetInterLineSpace();
80 }
81
82 return nExtra;
83}
84
85ImpEditEngine::ImpEditEngine( EditEngine* pEE, SfxItemPool* pItemPool ) :
86 pSharedVCL(EditDLL::Get().GetSharedVclResources()),
87 aPaperSize( 0x7FFFFFFF, 0x7FFFFFFF ),
88 aMinAutoPaperSize( 0x0, 0x0 ),
89 aMaxAutoPaperSize( 0x7FFFFFFF, 0x7FFFFFFF ),
90 aEditDoc( pItemPool ),
91 pEditEngine(pEE),
92 pActiveView(nullptr),
93 pStylePool(nullptr),
94 pTextObjectPool(nullptr),
95 pUndoManager(nullptr),
96 aWordDelimiters(" .,;:-`'?!_=\"{}()[]"),
97 maBackgroundColor(COL_AUTO),
98 nStretchX(100),
99 nStretchY(100),
100 nAsianCompressionMode(CharCompressType::NONE),
101 eDefaultHorizontalTextDirection(EEHorizontalTextDirection::Default),
102 nBigTextObjectStart(20),
103 eDefLanguage(LANGUAGE_DONTKNOWLanguageType(0x03FF)),
104 nCurTextHeight(0),
105 nCurTextHeightNTP(0),
106 bKernAsianPunctuation(false),
107 bAddExtLeading(false),
108 bIsFormatting(false),
109 bFormatted(false),
110 bInSelection(false),
111 bIsInUndo(false),
112 bUpdate(true),
113 bUndoEnabled(true),
114 bDowning(false),
115 bUseAutoColor(true),
116 bForceAutoColor(false),
117 bCallParaInsertedOrDeleted(false),
118 bFirstWordCapitalization(true),
119 mbLastTryMerge(false),
120 mbReplaceLeadingSingleQuotationMark(true),
121 mbNbspRunNext(false)
122{
123 aStatus.GetControlWord() = EEControlBits::USECHARATTRIBS | EEControlBits::DOIDLEFORMAT |
124 EEControlBits::PASTESPECIAL | EEControlBits::UNDOATTRIBS |
125 EEControlBits::ALLOWBIGOBJS | EEControlBits::RTFSTYLESHEETS |
126 EEControlBits::FORMAT100;
127
128 aSelEngine.SetFunctionSet( &aSelFuncSet );
129
130 aStatusTimer.SetTimeout( 200 );
131 aStatusTimer.SetInvokeHandler( LINK( this, ImpEditEngine, StatusTimerHdl )::tools::detail::makeLink( ::tools::detail::castTo<ImpEditEngine
*>(this), &ImpEditEngine::LinkStubStatusTimerHdl)
);
132 aStatusTimer.SetDebugName( "editeng::ImpEditEngine aStatusTimer" );
133
134 aIdleFormatter.SetPriority( TaskPriority::REPAINT );
135 aIdleFormatter.SetInvokeHandler( LINK( this, ImpEditEngine, IdleFormatHdl )::tools::detail::makeLink( ::tools::detail::castTo<ImpEditEngine
*>(this), &ImpEditEngine::LinkStubIdleFormatHdl)
);
136 aIdleFormatter.SetDebugName( "editeng::ImpEditEngine aIdleFormatter" );
137
138 aOnlineSpellTimer.SetTimeout( 100 );
139 aOnlineSpellTimer.SetInvokeHandler( LINK( this, ImpEditEngine, OnlineSpellHdl )::tools::detail::makeLink( ::tools::detail::castTo<ImpEditEngine
*>(this), &ImpEditEngine::LinkStubOnlineSpellHdl)
);
140 aOnlineSpellTimer.SetDebugName( "editeng::ImpEditEngine aOnlineSpellTimer" );
141
142 // Access data already from here on!
143 SetRefDevice( nullptr );
144 InitDoc( false );
145
146 bCallParaInsertedOrDeleted = true;
147
148 aEditDoc.SetModifyHdl( LINK( this, ImpEditEngine, DocModified )::tools::detail::makeLink( ::tools::detail::castTo<ImpEditEngine
*>(this), &ImpEditEngine::LinkStubDocModified)
);
149 StartListening(*SfxGetpApp());
150}
151
152void ImpEditEngine::Dispose()
153{
154 SolarMutexGuard g;
155 auto pApp = SfxApplication::Get();
156 if(pApp)
157 EndListening(*pApp);
158 pVirtDev.disposeAndClear();
159 mpOwnDev.disposeAndClear();
160 pSharedVCL.reset();
161}
162
163ImpEditEngine::~ImpEditEngine()
164{
165 aStatusTimer.Stop();
166 aOnlineSpellTimer.Stop();
167 aIdleFormatter.Stop();
168
169 // Destroying templates may otherwise cause unnecessary formatting,
170 // when a parent template is destroyed.
171 // And this after the destruction of the data!
172 bDowning = true;
173 SetUpdateMode( false );
174
175 Dispose();
176 // it's only legal to delete the pUndoManager if it was created by
177 // ImpEditEngine; if it was set by SetUndoManager() it must be cleared
178 // before destroying the ImpEditEngine!
179 assert(!pUndoManager || typeid(*pUndoManager) == typeid(EditUndoManager))(static_cast <bool> (!pUndoManager || typeid(*pUndoManager
) == typeid(EditUndoManager)) ? void (0) : __assert_fail ("!pUndoManager || typeid(*pUndoManager) == typeid(EditUndoManager)"
, "/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
, 179, __extension__ __PRETTY_FUNCTION__))
;
180 delete pUndoManager;
181 pTextRanger.reset();
182 mpIMEInfos.reset();
183 pCTLOptions.reset();
184 pSpellInfo.reset();
185}
186
187void ImpEditEngine::SetRefDevice( OutputDevice* pRef )
188{
189 if (pRef)
190 pRefDev = pRef;
191 else
192 pRefDev = pSharedVCL->GetVirtualDevice();
193
194 nOnePixelInRef = static_cast<sal_uInt16>(pRefDev->PixelToLogic( Size( 1, 0 ) ).Width());
195
196 if ( IsFormatted() )
197 {
198 FormatFullDoc();
199 UpdateViews();
200 }
201}
202
203void ImpEditEngine::SetRefMapMode( const MapMode& rMapMode )
204{
205 if ( GetRefDevice()->GetMapMode() == rMapMode )
1
Assuming the condition is false
2
Taking false branch
206 return;
207
208 mpOwnDev.disposeAndClear();
3
Calling 'VclPtr::disposeAndClear'
209 mpOwnDev = VclPtr<VirtualDevice>::Create();
210 pRefDev = mpOwnDev;
211 pRefDev->SetMapMode(MapMode(MapUnit::MapTwip));
212 SetRefDevice( pRefDev );
213
214 pRefDev->SetMapMode( rMapMode );
215 nOnePixelInRef = static_cast<sal_uInt16>(pRefDev->PixelToLogic( Size( 1, 0 ) ).Width());
216 if ( IsFormatted() )
217 {
218 FormatFullDoc();
219 UpdateViews();
220 }
221}
222
223void ImpEditEngine::InitDoc(bool bKeepParaAttribs)
224{
225 sal_Int32 nParas = aEditDoc.Count();
226 for ( sal_Int32 n = bKeepParaAttribs ? 1 : 0; n < nParas; n++ )
227 {
228 if ( aEditDoc[n]->GetStyleSheet() )
229 EndListening( *aEditDoc[n]->GetStyleSheet() );
230 }
231
232 if ( bKeepParaAttribs )
233 aEditDoc.RemoveText();
234 else
235 aEditDoc.Clear();
236
237 GetParaPortions().Reset();
238
239 GetParaPortions().Insert(0, std::make_unique<ParaPortion>( aEditDoc[0] ));
240
241 bFormatted = false;
242
243 if ( IsCallParaInsertedOrDeleted() )
244 {
245 GetEditEnginePtr()->ParagraphDeleted( EE_PARA_ALL((sal_Int32) 0x7FFFFFFF) );
246 GetEditEnginePtr()->ParagraphInserted( 0 );
247 }
248
249 if ( GetStatus().DoOnlineSpelling() )
250 aEditDoc.GetObject( 0 )->CreateWrongList();
251}
252
253EditPaM ImpEditEngine::DeleteSelected(const EditSelection& rSel)
254{
255 EditPaM aPaM (ImpDeleteSelection(rSel));
256 return aPaM;
257}
258
259OUString ImpEditEngine::GetSelected( const EditSelection& rSel ) const
260{
261 if ( !rSel.HasRange() )
262 return OUString();
263
264 EditSelection aSel( rSel );
265 aSel.Adjust( aEditDoc );
266
267 ContentNode* pStartNode = aSel.Min().GetNode();
268 ContentNode* pEndNode = aSel.Max().GetNode();
269 sal_Int32 nStartNode = aEditDoc.GetPos( pStartNode );
270 sal_Int32 nEndNode = aEditDoc.GetPos( pEndNode );
271
272 OSL_ENSURE( nStartNode <= nEndNode, "Selection not sorted ?" )do { if (true && (!(nStartNode <= nEndNode))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "272" ": "), "%s", "Selection not sorted ?"); } } while (
false)
;
273
274 OUStringBuffer aText(256);
275 const OUString aSep = EditDoc::GetSepStr( LINEEND_LF );
276
277 // iterate over the paragraphs ...
278 for ( sal_Int32 nNode = nStartNode; nNode <= nEndNode; nNode++ )
279 {
280 OSL_ENSURE( aEditDoc.GetObject( nNode ), "Node not found: GetSelected" )do { if (true && (!(aEditDoc.GetObject( nNode )))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "280" ": "), "%s", "Node not found: GetSelected"); } } while
(false)
;
281 const ContentNode* pNode = aEditDoc.GetObject( nNode );
282
283 const sal_Int32 nStartPos = nNode==nStartNode ? aSel.Min().GetIndex() : 0;
284 const sal_Int32 nEndPos = nNode==nEndNode ? aSel.Max().GetIndex() : pNode->Len(); // can also be == nStart!
285
286 aText.append(EditDoc::GetParaAsString( pNode, nStartPos, nEndPos ));
287 if ( nNode < nEndNode )
288 aText.append(aSep);
289 }
290 return aText.makeStringAndClear();
291}
292
293bool ImpEditEngine::MouseButtonDown( const MouseEvent& rMEvt, EditView* pView )
294{
295 GetSelEngine().SetCurView( pView );
296 SetActiveView( pView );
297
298 if (!GetAutoCompleteText().isEmpty())
299 SetAutoCompleteText( OUString(), true );
300
301 GetSelEngine().SelMouseButtonDown( rMEvt );
302 // Special treatment
303 EditSelection aCurSel( pView->pImpEditView->GetEditSelection() );
304 if ( !rMEvt.IsShift() )
305 {
306 if ( rMEvt.GetClicks() == 2 )
307 {
308 // So that the SelectionEngine knows about the anchor.
309 aSelEngine.CursorPosChanging( true, false );
310
311 EditSelection aNewSelection( SelectWord( aCurSel ) );
312 pView->pImpEditView->DrawSelectionXOR();
313 pView->pImpEditView->SetEditSelection( aNewSelection );
314 pView->pImpEditView->DrawSelectionXOR();
315 pView->ShowCursor();
316 }
317 else if ( rMEvt.GetClicks() == 3 )
318 {
319 // So that the SelectionEngine knows about the anchor.
320 aSelEngine.CursorPosChanging( true, false );
321
322 EditSelection aNewSelection( aCurSel );
323 aNewSelection.Min().SetIndex( 0 );
324 aNewSelection.Max().SetIndex( aCurSel.Min().GetNode()->Len() );
325 pView->pImpEditView->DrawSelectionXOR();
326 pView->pImpEditView->SetEditSelection( aNewSelection );
327 pView->pImpEditView->DrawSelectionXOR();
328 pView->ShowCursor();
329 }
330 }
331 return true;
332}
333
334void ImpEditEngine::Command( const CommandEvent& rCEvt, EditView* pView )
335{
336 GetSelEngine().SetCurView( pView );
337 SetActiveView( pView );
338 if ( rCEvt.GetCommand() == CommandEventId::StartExtTextInput )
339 {
340 pView->DeleteSelected();
341 mpIMEInfos.reset();
342 EditPaM aPaM = pView->GetImpEditView()->GetEditSelection().Max();
343 OUString aOldTextAfterStartPos = aPaM.GetNode()->Copy( aPaM.GetIndex() );
344 sal_Int32 nMax = aOldTextAfterStartPos.indexOf( CH_FEATUREu'\x0001' );
345 if ( nMax != -1 ) // don't overwrite features!
346 aOldTextAfterStartPos = aOldTextAfterStartPos.copy( 0, nMax );
347 mpIMEInfos.reset( new ImplIMEInfos( aPaM, aOldTextAfterStartPos ) );
348 mpIMEInfos->bWasCursorOverwrite = !pView->IsInsertMode();
349 UndoActionStart( EDITUNDO_INSERT111 );
350 }
351 else if ( rCEvt.GetCommand() == CommandEventId::EndExtTextInput )
352 {
353 OSL_ENSURE( mpIMEInfos, "CommandEventId::EndExtTextInput => No start ?" )do { if (true && (!(mpIMEInfos))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "353" ": "), "%s", "CommandEventId::EndExtTextInput => No start ?"
); } } while (false)
;
354 if( mpIMEInfos )
355 {
356 // #102812# convert quotes in IME text
357 // works on the last input character, this is especially in Korean text often done
358 // quotes that are inside of the string are not replaced!
359 // Borrowed from sw: edtwin.cxx
360 if ( mpIMEInfos->nLen )
361 {
362 EditSelection aSel( mpIMEInfos->aPos );
363 aSel.Min().SetIndex( aSel.Min().GetIndex() + mpIMEInfos->nLen-1 );
364 aSel.Max().SetIndex( aSel.Max().GetIndex() + mpIMEInfos->nLen );
365 // #102812# convert quotes in IME text
366 // works on the last input character, this is especially in Korean text often done
367 // quotes that are inside of the string are not replaced!
368 const sal_Unicode nCharCode = aSel.Min().GetNode()->GetChar( aSel.Min().GetIndex() );
369 if ( ( GetStatus().DoAutoCorrect() ) && ( ( nCharCode == '\"' ) || ( nCharCode == '\'' ) ) )
370 {
371 aSel = DeleteSelected( aSel );
372 aSel = AutoCorrect( aSel, nCharCode, mpIMEInfos->bWasCursorOverwrite );
373 pView->pImpEditView->SetEditSelection( aSel );
374 }
375 }
376
377 ParaPortion* pPortion = FindParaPortion( mpIMEInfos->aPos.GetNode() );
378 pPortion->MarkSelectionInvalid( mpIMEInfos->aPos.GetIndex() );
379
380 bool bWasCursorOverwrite = mpIMEInfos->bWasCursorOverwrite;
381
382 mpIMEInfos.reset();
383
384 FormatAndUpdate( pView );
385
386 pView->SetInsertMode( !bWasCursorOverwrite );
387 }
388 UndoActionEnd();
389 }
390 else if ( rCEvt.GetCommand() == CommandEventId::ExtTextInput )
391 {
392 OSL_ENSURE( mpIMEInfos, "CommandEventId::ExtTextInput => No Start ?" )do { if (true && (!(mpIMEInfos))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "392" ": "), "%s", "CommandEventId::ExtTextInput => No Start ?"
); } } while (false)
;
393 if( mpIMEInfos )
394 {
395 const CommandExtTextInputData* pData = rCEvt.GetExtTextInputData();
396
397 if ( !pData->IsOnlyCursorChanged() )
398 {
399 EditSelection aSel( mpIMEInfos->aPos );
400 aSel.Max().SetIndex( aSel.Max().GetIndex() + mpIMEInfos->nLen );
401 aSel = DeleteSelected( aSel );
402 aSel = ImpInsertText( aSel, pData->GetText() );
403
404 if ( mpIMEInfos->bWasCursorOverwrite )
405 {
406 sal_Int32 nOldIMETextLen = mpIMEInfos->nLen;
407 sal_Int32 nNewIMETextLen = pData->GetText().getLength();
408
409 if ( ( nOldIMETextLen > nNewIMETextLen ) &&
410 ( nNewIMETextLen < mpIMEInfos->aOldTextAfterStartPos.getLength() ) )
411 {
412 // restore old characters
413 sal_Int32 nRestore = nOldIMETextLen - nNewIMETextLen;
414 EditPaM aPaM( mpIMEInfos->aPos );
415 aPaM.SetIndex( aPaM.GetIndex() + nNewIMETextLen );
416 ImpInsertText( aPaM, mpIMEInfos->aOldTextAfterStartPos.copy( nNewIMETextLen, nRestore ) );
417 }
418 else if ( ( nOldIMETextLen < nNewIMETextLen ) &&
419 ( nOldIMETextLen < mpIMEInfos->aOldTextAfterStartPos.getLength() ) )
420 {
421 // overwrite
422 sal_Int32 nOverwrite = nNewIMETextLen - nOldIMETextLen;
423 if ( ( nOldIMETextLen + nOverwrite ) > mpIMEInfos->aOldTextAfterStartPos.getLength() )
424 nOverwrite = mpIMEInfos->aOldTextAfterStartPos.getLength() - nOldIMETextLen;
425 OSL_ENSURE( nOverwrite && (nOverwrite < 0xFF00), "IME Overwrite?!" )do { if (true && (!(nOverwrite && (nOverwrite
< 0xFF00)))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "425" ": "), "%s", "IME Overwrite?!"); } } while (false)
;
426 EditPaM aPaM( mpIMEInfos->aPos );
427 aPaM.SetIndex( aPaM.GetIndex() + nNewIMETextLen );
428 EditSelection _aSel( aPaM );
429 _aSel.Max().SetIndex( _aSel.Max().GetIndex() + nOverwrite );
430 DeleteSelected( _aSel );
431 }
432 }
433 if ( pData->GetTextAttr() )
434 {
435 mpIMEInfos->CopyAttribs( pData->GetTextAttr(), pData->GetText().getLength() );
436 }
437 else
438 {
439 mpIMEInfos->DestroyAttribs();
440 mpIMEInfos->nLen = pData->GetText().getLength();
441 }
442
443 ParaPortion* pPortion = FindParaPortion( mpIMEInfos->aPos.GetNode() );
444 pPortion->MarkSelectionInvalid( mpIMEInfos->aPos.GetIndex() );
445 FormatAndUpdate( pView );
446 }
447
448 EditSelection aNewSel = EditPaM( mpIMEInfos->aPos.GetNode(), mpIMEInfos->aPos.GetIndex()+pData->GetCursorPos() );
449 pView->SetSelection( CreateESel( aNewSel ) );
450 pView->SetInsertMode( !pData->IsCursorOverwrite() );
451
452 if ( pData->IsCursorVisible() )
453 pView->ShowCursor();
454 else
455 pView->HideCursor();
456 }
457 }
458 else if ( rCEvt.GetCommand() == CommandEventId::InputContextChange )
459 {
460 }
461 else if ( rCEvt.GetCommand() == CommandEventId::CursorPos )
462 {
463 if (mpIMEInfos)
464 {
465 EditPaM aPaM( pView->pImpEditView->GetEditSelection().Max() );
466 tools::Rectangle aR1 = PaMtoEditCursor( aPaM );
467
468 sal_Int32 nInputEnd = mpIMEInfos->aPos.GetIndex() + mpIMEInfos->nLen;
469
470 if ( !IsFormatted() )
471 FormatDoc();
472
473 ParaPortion* pParaPortion = GetParaPortions().SafeGetObject( GetEditDoc().GetPos( aPaM.GetNode() ) );
474 if (pParaPortion)
475 {
476 sal_Int32 nLine = pParaPortion->GetLines().FindLine( aPaM.GetIndex(), true );
477 const EditLine& rLine = pParaPortion->GetLines()[nLine];
478 if ( nInputEnd > rLine.GetEnd() )
479 nInputEnd = rLine.GetEnd();
480 tools::Rectangle aR2 = PaMtoEditCursor( EditPaM( aPaM.GetNode(), nInputEnd ), GetCursorFlags::EndOfLine );
481 tools::Rectangle aRect = pView->GetImpEditView()->GetWindowPos( aR1 );
482 auto nExtTextInputWidth = aR2.Left() - aR1.Right();
483 if (EditViewCallbacks* pEditViewCallbacks = pView->getEditViewCallbacks())
484 pEditViewCallbacks->EditViewCursorRect(aRect, nExtTextInputWidth);
485 else if (vcl::Window* pWindow = pView->GetWindow())
486 pWindow->SetCursorRect(&aRect, nExtTextInputWidth);
487 }
488 }
489 else
490 {
491 if (vcl::Window* pWindow = pView->GetWindow())
492 pWindow->SetCursorRect();
493 }
494 }
495 else if ( rCEvt.GetCommand() == CommandEventId::SelectionChange )
496 {
497 const CommandSelectionChangeData *pData = rCEvt.GetSelectionChangeData();
498
499 ESelection aSelection = pView->GetSelection();
500 aSelection.Adjust();
501
502 if( pView->HasSelection() )
503 {
504 aSelection.nEndPos = aSelection.nStartPos;
505 aSelection.nStartPos += pData->GetStart();
506 aSelection.nEndPos += pData->GetEnd();
507 }
508 else
509 {
510 aSelection.nStartPos = pData->GetStart();
511 aSelection.nEndPos = pData->GetEnd();
512 }
513 pView->SetSelection( aSelection );
514 }
515 else if ( rCEvt.GetCommand() == CommandEventId::PrepareReconversion )
516 {
517 if ( pView->HasSelection() )
518 {
519 ESelection aSelection = pView->GetSelection();
520 aSelection.Adjust();
521
522 if ( aSelection.nStartPara != aSelection.nEndPara )
523 {
524 sal_Int32 aParaLen = pEditEngine->GetTextLen( aSelection.nStartPara );
525 aSelection.nEndPara = aSelection.nStartPara;
526 aSelection.nEndPos = aParaLen;
527 pView->SetSelection( aSelection );
528 }
529 }
530 }
531 else if ( rCEvt.GetCommand() == CommandEventId::QueryCharPosition )
532 {
533 if (mpIMEInfos)
534 {
535 EditPaM aPaM( pView->pImpEditView->GetEditSelection().Max() );
536 if ( !IsFormatted() )
537 FormatDoc();
538
539 ParaPortion* pParaPortion = GetParaPortions().SafeGetObject( GetEditDoc().GetPos( aPaM.GetNode() ) );
540 if (pParaPortion)
541 {
542 sal_Int32 nLine = pParaPortion->GetLines().FindLine( aPaM.GetIndex(), true );
543 const EditLine& rLine = pParaPortion->GetLines()[nLine];
544 std::unique_ptr<tools::Rectangle[]> aRects(new tools::Rectangle[ mpIMEInfos->nLen ]);
545 for (sal_Int32 i = 0; i < mpIMEInfos->nLen; ++i)
546 {
547 sal_Int32 nInputPos = mpIMEInfos->aPos.GetIndex() + i;
548 if ( nInputPos > rLine.GetEnd() )
549 nInputPos = rLine.GetEnd();
550 tools::Rectangle aR2 = GetEditCursor( pParaPortion, nInputPos );
551 aRects[ i ] = pView->GetImpEditView()->GetWindowPos( aR2 );
552 }
553 if (vcl::Window* pWindow = pView->GetWindow())
554 pWindow->SetCompositionCharRect( aRects.get(), mpIMEInfos->nLen );
555 }
556 }
557 }
558
559 GetSelEngine().Command( rCEvt );
560}
561
562bool ImpEditEngine::MouseButtonUp( const MouseEvent& rMEvt, EditView* pView )
563{
564 GetSelEngine().SetCurView( pView );
565 GetSelEngine().SelMouseButtonUp( rMEvt );
566
567 // in the tiled rendering case, setting bInSelection here has unexpected
568 // consequences - further tiles painting removes the selection
569 // FIXME I believe resetting bInSelection should not be here even in the
570 // non-tiled-rendering case, but it has been here since 2000 (and before)
571 // so who knows what corner case it was supposed to solve back then
572 if (!comphelper::LibreOfficeKit::isActive())
573 bInSelection = false;
574
575 // Special treatments
576 EditSelection aCurSel( pView->pImpEditView->GetEditSelection() );
577 if ( !aCurSel.HasRange() )
578 {
579 if ( ( rMEvt.GetClicks() == 1 ) && rMEvt.IsLeft() && !rMEvt.IsMod2() )
580 {
581 const OutputDevice& rOutDev = pView->getEditViewCallbacks() ? pView->getEditViewCallbacks()->EditViewOutputDevice() : *pView->GetWindow();
582 Point aLogicClick = rOutDev.PixelToLogic(rMEvt.GetPosPixel());
583 if (const SvxFieldItem* pFld = pView->GetField(aLogicClick))
584 {
585 // tdf#121039 When in edit mode, editeng is responsible for opening the URL on mouse click
586 if (auto pUrlField = dynamic_cast<const SvxURLField*>(pFld->GetField()))
587 {
588 SvtSecurityOptions aSecOpt;
589 bool bCtrlClickHappened = rMEvt.IsMod1();
590 bool bCtrlClickSecOption
591 = aSecOpt.IsOptionSet(SvtSecurityOptions::EOption::CtrlClickHyperlink);
592 if ((bCtrlClickHappened && bCtrlClickSecOption)
593 || (!bCtrlClickHappened && !bCtrlClickSecOption))
594 {
595 css::uno::Reference<css::system::XSystemShellExecute> exec(
596 css::system::SystemShellExecute::create(
597 comphelper::getProcessComponentContext()));
598 exec->execute(pUrlField->GetURL(), OUString(),
599 css::system::SystemShellExecuteFlags::DEFAULTS);
600 }
601 }
602 GetEditEnginePtr()->FieldClicked( *pFld );
603 }
604 }
605 }
606 return true;
607}
608
609void ImpEditEngine::ReleaseMouse()
610{
611 GetSelEngine().ReleaseMouse();
612}
613
614bool ImpEditEngine::MouseMove( const MouseEvent& rMEvt, EditView* pView )
615{
616 // MouseMove is called directly after ShowQuickHelp()!
617 GetSelEngine().SetCurView( pView );
618 GetSelEngine().SelMouseMove( rMEvt );
619 return true;
620}
621
622EditPaM ImpEditEngine::InsertText(const EditSelection& aSel, const OUString& rStr)
623{
624 EditPaM aPaM = ImpInsertText( aSel, rStr );
625 return aPaM;
626}
627
628void ImpEditEngine::Clear()
629{
630 InitDoc( false );
631
632 EditPaM aPaM = aEditDoc.GetStartPaM();
633 EditSelection aSel( aPaM );
634
635 nCurTextHeight = 0;
636 nCurTextHeightNTP = 0;
637
638 ResetUndoManager();
639
640 for (size_t nView = aEditViews.size(); nView; )
641 {
642 EditView* pView = aEditViews[--nView];
643 pView->pImpEditView->SetEditSelection( aSel );
644 }
645}
646
647EditPaM ImpEditEngine::RemoveText()
648{
649 InitDoc( true );
650
651 EditPaM aStartPaM = aEditDoc.GetStartPaM();
652 EditSelection aEmptySel( aStartPaM, aStartPaM );
653 for (EditView* pView : aEditViews)
654 {
655 pView->pImpEditView->SetEditSelection( aEmptySel );
656 }
657 ResetUndoManager();
658 return aEditDoc.GetStartPaM();
659}
660
661
662void ImpEditEngine::SetText(const OUString& rText)
663{
664 // RemoveText deletes the undo list!
665 EditPaM aStartPaM = RemoveText();
666 bool bUndoCurrentlyEnabled = IsUndoEnabled();
667 // The text inserted manually can not be made reversible by the user
668 EnableUndo( false );
669
670 EditSelection aEmptySel( aStartPaM, aStartPaM );
671 EditPaM aPaM = aStartPaM;
672 if (!rText.isEmpty())
673 aPaM = ImpInsertText( aEmptySel, rText );
674
675 for (EditView* pView : aEditViews)
676 {
677 pView->pImpEditView->SetEditSelection( EditSelection( aPaM, aPaM ) );
678 // If no text then also no Format&Update
679 // => The text remains.
680 if (rText.isEmpty() && GetUpdateMode())
681 {
682 tools::Rectangle aTmpRect( pView->GetOutputArea().TopLeft(),
683 Size( aPaperSize.Width(), nCurTextHeight ) );
684 aTmpRect.Intersection( pView->GetOutputArea() );
685 pView->InvalidateWindow( aTmpRect );
686 }
687 }
688 if (rText.isEmpty()) { // otherwise it must be invalidated later, !bFormatted is enough.
689 nCurTextHeight = 0;
690 nCurTextHeightNTP = 0;
691 }
692 EnableUndo( bUndoCurrentlyEnabled );
693 OSL_ENSURE( !HasUndoManager() || !GetUndoManager().GetUndoActionCount(), "Undo after SetText?" )do { if (true && (!(!HasUndoManager() || !GetUndoManager
().GetUndoActionCount()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "693" ": "), "%s", "Undo after SetText?"); } } while (false
)
;
694}
695
696
697const SfxItemSet& ImpEditEngine::GetEmptyItemSet() const
698{
699 if ( !pEmptyItemSet )
700 {
701 pEmptyItemSet = std::make_unique<SfxItemSet>(const_cast<SfxItemPool&>(aEditDoc.GetItemPool()), svl::Items<EE_ITEMS_START, EE_ITEMS_END>{});
702 for ( sal_uInt16 nWhich = EE_ITEMS_START; nWhich <= EE_CHAR_END; nWhich++)
703 {
704 pEmptyItemSet->ClearItem( nWhich );
705 }
706 }
707 return *pEmptyItemSet;
708}
709
710
711// MISC
712
713void ImpEditEngine::CursorMoved( const ContentNode* pPrevNode )
714{
715 // Delete empty attributes, but only if paragraph is not empty!
716 if (pPrevNode->GetCharAttribs().HasEmptyAttribs() && pPrevNode->Len())
717 {
718 const_cast<ContentNode*>(pPrevNode)->GetCharAttribs().DeleteEmptyAttribs(aEditDoc.GetItemPool());
719 }
720}
721
722void ImpEditEngine::TextModified()
723{
724 bFormatted = false;
725
726 if ( GetNotifyHdl().IsSet() )
727 {
728 EENotify aNotify( EE_NOTIFY_TEXTMODIFIED );
729 GetNotifyHdl().Call( aNotify );
730 }
731}
732
733
734void ImpEditEngine::ParaAttribsChanged( ContentNode const * pNode, bool bIgnoreUndoCheck )
735{
736 assert(pNode && "ParaAttribsChanged: Which one?")(static_cast <bool> (pNode && "ParaAttribsChanged: Which one?"
) ? void (0) : __assert_fail ("pNode && \"ParaAttribsChanged: Which one?\""
, "/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
, 736, __extension__ __PRETTY_FUNCTION__))
;
737
738 aEditDoc.SetModified( true );
739 bFormatted = false;
740
741 ParaPortion* pPortion = FindParaPortion( pNode );
742 OSL_ENSURE( pPortion, "ParaAttribsChanged: Portion?" )do { if (true && (!(pPortion))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "742" ": "), "%s", "ParaAttribsChanged: Portion?"); } } while
(false)
;
743 pPortion->MarkSelectionInvalid( 0 );
744
745 sal_Int32 nPara = aEditDoc.GetPos( pNode );
746 if ( bIgnoreUndoCheck || pEditEngine->IsInUndo() )
747 pEditEngine->ParaAttribsChanged( nPara );
748
749 ParaPortion* pNextPortion = GetParaPortions().SafeGetObject( nPara+1 );
750 // => is formatted again anyway, if Invalid.
751 if ( pNextPortion && !pNextPortion->IsInvalid() )
752 CalcHeight( pNextPortion );
753}
754
755
756// Cursor movements
757
758
759EditSelection const & ImpEditEngine::MoveCursor( const KeyEvent& rKeyEvent, EditView* pEditView )
760{
761 // Actually, only necessary for up/down, but whatever.
762 CheckIdleFormatter();
763
764 EditPaM aPaM( pEditView->pImpEditView->GetEditSelection().Max() );
765
766 EditPaM aOldPaM( aPaM );
767
768 TextDirectionality eTextDirection = TextDirectionality::LeftToRight_TopToBottom;
769 if (IsVertical() && IsTopToBottom())
770 eTextDirection = TextDirectionality::TopToBottom_RightToLeft;
771 else if (IsVertical() && !IsTopToBottom())
772 eTextDirection = TextDirectionality::BottomToTop_LeftToRight;
773 else if ( IsRightToLeft( GetEditDoc().GetPos( aPaM.GetNode() ) ) )
774 eTextDirection = TextDirectionality::RightToLeft_TopToBottom;
775
776 KeyEvent aTranslatedKeyEvent = rKeyEvent.LogicalTextDirectionality( eTextDirection );
777
778 bool bCtrl = aTranslatedKeyEvent.GetKeyCode().IsMod1();
779 sal_uInt16 nCode = aTranslatedKeyEvent.GetKeyCode().GetCode();
780
781 if ( DoVisualCursorTraveling() )
782 {
783 // Only for simple cursor movement...
784 if ( !bCtrl && ( ( nCode == KEY_LEFT ) || ( nCode == KEY_RIGHT ) ) )
785 {
786 aPaM = CursorVisualLeftRight( pEditView, aPaM, rKeyEvent.GetKeyCode().IsMod2() ? i18n::CharacterIteratorMode::SKIPCHARACTER : i18n::CharacterIteratorMode::SKIPCELL, rKeyEvent.GetKeyCode().GetCode() == KEY_LEFT );
787 nCode = 0; // skip switch statement
788 }
789 }
790
791 bool bKeyModifySelection = aTranslatedKeyEvent.GetKeyCode().IsShift();
792 switch ( nCode )
793 {
794 case KEY_UP: aPaM = CursorUp( aPaM, pEditView );
795 break;
796 case KEY_DOWN: aPaM = CursorDown( aPaM, pEditView );
797 break;
798 case KEY_LEFT: aPaM = bCtrl ? WordLeft( aPaM ) : CursorLeft( aPaM, aTranslatedKeyEvent.GetKeyCode().IsMod2() ? i18n::CharacterIteratorMode::SKIPCHARACTER : i18n::CharacterIteratorMode::SKIPCELL );
799 break;
800 case KEY_RIGHT: aPaM = bCtrl ? WordRight( aPaM ) : CursorRight( aPaM, aTranslatedKeyEvent.GetKeyCode().IsMod2() ? i18n::CharacterIteratorMode::SKIPCHARACTER : i18n::CharacterIteratorMode::SKIPCELL );
801 break;
802 case KEY_HOME: aPaM = bCtrl ? CursorStartOfDoc() : CursorStartOfLine( aPaM );
803 break;
804 case KEY_END: aPaM = bCtrl ? CursorEndOfDoc() : CursorEndOfLine( aPaM );
805 break;
806 case KEY_PAGEUP: aPaM = bCtrl ? CursorStartOfDoc() : PageUp( aPaM, pEditView );
807 break;
808 case KEY_PAGEDOWN: aPaM = bCtrl ? CursorEndOfDoc() : PageDown( aPaM, pEditView );
809 break;
810 case css::awt::Key::MOVE_TO_BEGIN_OF_LINE:
811 aPaM = CursorStartOfLine( aPaM );
812 bKeyModifySelection = false;
813 break;
814 case css::awt::Key::MOVE_TO_END_OF_LINE:
815 aPaM = CursorEndOfLine( aPaM );
816 bKeyModifySelection = false;
817 break;
818 case css::awt::Key::MOVE_WORD_BACKWARD:
819 aPaM = WordLeft( aPaM );
820 bKeyModifySelection = false;
821 break;
822 case css::awt::Key::MOVE_WORD_FORWARD:
823 aPaM = WordRight( aPaM );
824 bKeyModifySelection = false;
825 break;
826 case css::awt::Key::MOVE_TO_BEGIN_OF_PARAGRAPH:
827 aPaM = CursorStartOfParagraph( aPaM );
828 if( aPaM == aOldPaM )
829 {
830 aPaM = CursorLeft( aPaM );
831 aPaM = CursorStartOfParagraph( aPaM );
832 }
833 bKeyModifySelection = false;
834 break;
835 case css::awt::Key::MOVE_TO_END_OF_PARAGRAPH:
836 aPaM = CursorEndOfParagraph( aPaM );
837 if( aPaM == aOldPaM )
838 {
839 aPaM = CursorRight( aPaM );
840 aPaM = CursorEndOfParagraph( aPaM );
841 }
842 bKeyModifySelection = false;
843 break;
844 case css::awt::Key::MOVE_TO_BEGIN_OF_DOCUMENT:
845 aPaM = CursorStartOfDoc();
846 bKeyModifySelection = false;
847 break;
848 case css::awt::Key::MOVE_TO_END_OF_DOCUMENT:
849 aPaM = CursorEndOfDoc();
850 bKeyModifySelection = false;
851 break;
852 case css::awt::Key::SELECT_TO_BEGIN_OF_LINE:
853 aPaM = CursorStartOfLine( aPaM );
854 bKeyModifySelection = true;
855 break;
856 case css::awt::Key::SELECT_TO_END_OF_LINE:
857 aPaM = CursorEndOfLine( aPaM );
858 bKeyModifySelection = true;
859 break;
860 case css::awt::Key::SELECT_BACKWARD:
861 aPaM = CursorLeft( aPaM );
862 bKeyModifySelection = true;
863 break;
864 case css::awt::Key::SELECT_FORWARD:
865 aPaM = CursorRight( aPaM );
866 bKeyModifySelection = true;
867 break;
868 case css::awt::Key::SELECT_WORD_BACKWARD:
869 aPaM = WordLeft( aPaM );
870 bKeyModifySelection = true;
871 break;
872 case css::awt::Key::SELECT_WORD_FORWARD:
873 aPaM = WordRight( aPaM );
874 bKeyModifySelection = true;
875 break;
876 case css::awt::Key::SELECT_TO_BEGIN_OF_PARAGRAPH:
877 aPaM = CursorStartOfParagraph( aPaM );
878 if( aPaM == aOldPaM )
879 {
880 aPaM = CursorLeft( aPaM );
881 aPaM = CursorStartOfParagraph( aPaM );
882 }
883 bKeyModifySelection = true;
884 break;
885 case css::awt::Key::SELECT_TO_END_OF_PARAGRAPH:
886 aPaM = CursorEndOfParagraph( aPaM );
887 if( aPaM == aOldPaM )
888 {
889 aPaM = CursorRight( aPaM );
890 aPaM = CursorEndOfParagraph( aPaM );
891 }
892 bKeyModifySelection = true;
893 break;
894 case css::awt::Key::SELECT_TO_BEGIN_OF_DOCUMENT:
895 aPaM = CursorStartOfDoc();
896 bKeyModifySelection = true;
897 break;
898 case css::awt::Key::SELECT_TO_END_OF_DOCUMENT:
899 aPaM = CursorEndOfDoc();
900 bKeyModifySelection = true;
901 break;
902 }
903
904 if ( aOldPaM != aPaM )
905 {
906 CursorMoved( aOldPaM.GetNode() );
907 }
908
909 // May cause, a CreateAnchor or deselection all
910 aSelEngine.SetCurView( pEditView );
911 aSelEngine.CursorPosChanging( bKeyModifySelection, aTranslatedKeyEvent.GetKeyCode().IsMod1() );
912 EditPaM aOldEnd( pEditView->pImpEditView->GetEditSelection().Max() );
913
914 {
915 EditSelection aNewSelection(pEditView->pImpEditView->GetEditSelection());
916 aNewSelection.Max() = aPaM;
917 pEditView->pImpEditView->SetEditSelection(aNewSelection);
918 // const_cast<EditPaM&>(pEditView->pImpEditView->GetEditSelection().Max()) = aPaM;
919 }
920
921 if ( bKeyModifySelection )
922 {
923 // Then the selection is expanded ... or the whole selection is painted in case of tiled rendering.
924 EditSelection aTmpNewSel( comphelper::LibreOfficeKit::isActive() ? pEditView->pImpEditView->GetEditSelection().Min() : aOldEnd, aPaM );
925 pEditView->pImpEditView->DrawSelectionXOR( aTmpNewSel );
926 }
927 else
928 {
929 EditSelection aNewSelection(pEditView->pImpEditView->GetEditSelection());
930 aNewSelection.Min() = aPaM;
931 pEditView->pImpEditView->SetEditSelection(aNewSelection);
932 // const_cast<EditPaM&>(pEditView->pImpEditView->GetEditSelection().Min()) = aPaM;
933 }
934
935 return pEditView->pImpEditView->GetEditSelection();
936}
937
938EditPaM ImpEditEngine::CursorVisualStartEnd( EditView const * pEditView, const EditPaM& rPaM, bool bStart )
939{
940 EditPaM aPaM( rPaM );
941
942 sal_Int32 nPara = GetEditDoc().GetPos( aPaM.GetNode() );
943 ParaPortion* pParaPortion = GetParaPortions().SafeGetObject( nPara );
944 if (!pParaPortion)
945 return aPaM;
946
947 sal_Int32 nLine = pParaPortion->GetLines().FindLine( aPaM.GetIndex(), false );
948 const EditLine& rLine = pParaPortion->GetLines()[nLine];
949 bool bEmptyLine = rLine.GetStart() == rLine.GetEnd();
950
951 pEditView->pImpEditView->nExtraCursorFlags = GetCursorFlags::NONE;
952
953 if ( !bEmptyLine )
954 {
955 OUString aLine = aPaM.GetNode()->GetString().copy(rLine.GetStart(), rLine.GetEnd() - rLine.GetStart());
956
957 UErrorCode nError = U_ZERO_ERROR;
958 UBiDi* pBidi = ubidi_openSizedubidi_openSized_67( aLine.getLength(), 0, &nError );
959
960 const UBiDiLevel nBidiLevel = IsRightToLeft( nPara ) ? 1 /*RTL*/ : 0 /*LTR*/;
961 ubidi_setParaubidi_setPara_67( pBidi, reinterpret_cast<const UChar *>(aLine.getStr()), aLine.getLength(), nBidiLevel, nullptr, &nError );
962
963 sal_Int32 nVisPos = bStart ? 0 : aLine.getLength()-1;
964 const sal_Int32 nLogPos = ubidi_getLogicalIndexubidi_getLogicalIndex_67( pBidi, nVisPos, &nError );
965
966 ubidi_closeubidi_close_67( pBidi );
967
968 aPaM.SetIndex( nLogPos + rLine.GetStart() );
969
970 sal_Int32 nTmp;
971 sal_Int32 nTextPortion = pParaPortion->GetTextPortions().FindPortion( aPaM.GetIndex(), nTmp, true );
972 const TextPortion& rTextPortion = pParaPortion->GetTextPortions()[nTextPortion];
973 bool bPortionRTL = rTextPortion.IsRightToLeft();
974
975 if ( bStart )
976 {
977 pEditView->pImpEditView->SetCursorBidiLevel( bPortionRTL ? 0 : 1 );
978 // Maybe we must be *behind* the character
979 if ( bPortionRTL && pEditView->IsInsertMode() )
980 aPaM.SetIndex( aPaM.GetIndex()+1 );
981 }
982 else
983 {
984 pEditView->pImpEditView->SetCursorBidiLevel( bPortionRTL ? 1 : 0 );
985 if ( !bPortionRTL && pEditView->IsInsertMode() )
986 aPaM.SetIndex( aPaM.GetIndex()+1 );
987 }
988 }
989
990 return aPaM;
991}
992
993EditPaM ImpEditEngine::CursorVisualLeftRight( EditView const * pEditView, const EditPaM& rPaM, sal_uInt16 nCharacterIteratorMode, bool bVisualToLeft )
994{
995 EditPaM aPaM( rPaM );
996
997 sal_Int32 nPara = GetEditDoc().GetPos( aPaM.GetNode() );
998 ParaPortion* pParaPortion = GetParaPortions().SafeGetObject( nPara );
999 if (!pParaPortion)
1000 return aPaM;
1001
1002 sal_Int32 nLine = pParaPortion->GetLines().FindLine( aPaM.GetIndex(), false );
1003 const EditLine& rLine = pParaPortion->GetLines()[nLine];
1004 bool bEmptyLine = rLine.GetStart() == rLine.GetEnd();
1005
1006 pEditView->pImpEditView->nExtraCursorFlags = GetCursorFlags::NONE;
1007
1008 bool bParaRTL = IsRightToLeft( nPara );
1009
1010 bool bDone = false;
1011
1012 if ( bEmptyLine )
1013 {
1014 if ( bVisualToLeft )
1015 {
1016 aPaM = CursorUp( aPaM, pEditView );
1017 if ( aPaM != rPaM )
1018 aPaM = CursorVisualStartEnd( pEditView, aPaM, false );
1019 }
1020 else
1021 {
1022 aPaM = CursorDown( aPaM, pEditView );
1023 if ( aPaM != rPaM )
1024 aPaM = CursorVisualStartEnd( pEditView, aPaM, true );
1025 }
1026
1027 bDone = true;
1028 }
1029
1030 bool bLogicalBackward = bParaRTL ? !bVisualToLeft : bVisualToLeft;
1031
1032 if ( !bDone && pEditView->IsInsertMode() )
1033 {
1034 // Check if we are within a portion and don't have overwrite mode, then it's easy...
1035 sal_Int32 nPortionStart;
1036 sal_Int32 nTextPortion = pParaPortion->GetTextPortions().FindPortion( aPaM.GetIndex(), nPortionStart );
1037 const TextPortion& rTextPortion = pParaPortion->GetTextPortions()[nTextPortion];
1038
1039 bool bPortionBoundary = ( aPaM.GetIndex() == nPortionStart ) || ( aPaM.GetIndex() == (nPortionStart+rTextPortion.GetLen()) );
1040 sal_uInt16 nRTLLevel = rTextPortion.GetRightToLeftLevel();
1041
1042 // Portion boundary doesn't matter if both have same RTL level
1043 sal_Int32 nRTLLevelNextPortion = -1;
1044 if ( bPortionBoundary && aPaM.GetIndex() && ( aPaM.GetIndex() < aPaM.GetNode()->Len() ) )
1045 {
1046 sal_Int32 nTmp;
1047 sal_Int32 nNextTextPortion = pParaPortion->GetTextPortions().FindPortion( aPaM.GetIndex()+1, nTmp, !bLogicalBackward );
1048 const TextPortion& rNextTextPortion = pParaPortion->GetTextPortions()[nNextTextPortion];
1049 nRTLLevelNextPortion = rNextTextPortion.GetRightToLeftLevel();
1050 }
1051
1052 if ( !bPortionBoundary || ( nRTLLevel == nRTLLevelNextPortion ) )
1053 {
1054 if (bVisualToLeft != bool(nRTLLevel % 2))
1055 {
1056 aPaM = CursorLeft( aPaM, nCharacterIteratorMode );
1057 pEditView->pImpEditView->SetCursorBidiLevel( 1 );
1058 }
1059 else
1060 {
1061 aPaM = CursorRight( aPaM, nCharacterIteratorMode );
1062 pEditView->pImpEditView->SetCursorBidiLevel( 0 );
1063 }
1064 bDone = true;
1065 }
1066 }
1067
1068 if ( !bDone )
1069 {
1070 bool bGotoStartOfNextLine = false;
1071 bool bGotoEndOfPrevLine = false;
1072
1073 OUString aLine = aPaM.GetNode()->GetString().copy(rLine.GetStart(), rLine.GetEnd() - rLine.GetStart());
1074 const sal_Int32 nPosInLine = aPaM.GetIndex() - rLine.GetStart();
1075
1076 UErrorCode nError = U_ZERO_ERROR;
1077 UBiDi* pBidi = ubidi_openSizedubidi_openSized_67( aLine.getLength(), 0, &nError );
1078
1079 const UBiDiLevel nBidiLevel = IsRightToLeft( nPara ) ? 1 /*RTL*/ : 0 /*LTR*/;
1080 ubidi_setParaubidi_setPara_67( pBidi, reinterpret_cast<const UChar *>(aLine.getStr()), aLine.getLength(), nBidiLevel, nullptr, &nError );
1081
1082 if ( !pEditView->IsInsertMode() )
1083 {
1084 bool bEndOfLine = nPosInLine == aLine.getLength();
1085 sal_Int32 nVisPos = ubidi_getVisualIndexubidi_getVisualIndex_67( pBidi, !bEndOfLine ? nPosInLine : nPosInLine-1, &nError );
1086 if ( bVisualToLeft )
1087 {
1088 bGotoEndOfPrevLine = nVisPos == 0;
1089 if ( !bEndOfLine )
1090 nVisPos--;
1091 }
1092 else
1093 {
1094 bGotoStartOfNextLine = nVisPos == (aLine.getLength() - 1);
1095 if ( !bEndOfLine )
1096 nVisPos++;
1097 }
1098
1099 if ( !bGotoEndOfPrevLine && !bGotoStartOfNextLine )
1100 {
1101 aPaM.SetIndex( rLine.GetStart() + ubidi_getLogicalIndexubidi_getLogicalIndex_67( pBidi, nVisPos, &nError ) );
1102 pEditView->pImpEditView->SetCursorBidiLevel( 0 );
1103 }
1104 }
1105 else
1106 {
1107 bool bWasBehind = false;
1108 bool bBeforePortion = !nPosInLine || pEditView->pImpEditView->GetCursorBidiLevel() == 1;
1109 if ( nPosInLine && ( !bBeforePortion ) ) // before the next portion
1110 bWasBehind = true; // step one back, otherwise visual will be unusable when rtl portion follows.
1111
1112 sal_Int32 nPortionStart;
1113 sal_Int32 nTextPortion = pParaPortion->GetTextPortions().FindPortion( aPaM.GetIndex(), nPortionStart, bBeforePortion );
1114 const TextPortion& rTextPortion = pParaPortion->GetTextPortions()[nTextPortion];
1115 bool bRTLPortion = rTextPortion.IsRightToLeft();
1116
1117 // -1: We are 'behind' the character
1118 long nVisPos = static_cast<long>(ubidi_getVisualIndexubidi_getVisualIndex_67( pBidi, bWasBehind ? nPosInLine-1 : nPosInLine, &nError ));
1119 if ( bVisualToLeft )
1120 {
1121 if ( !bWasBehind || bRTLPortion )
1122 nVisPos--;
1123 }
1124 else
1125 {
1126 if ( bWasBehind || bRTLPortion || bBeforePortion )
1127 nVisPos++;
1128 }
1129
1130 bGotoEndOfPrevLine = nVisPos < 0;
1131 bGotoStartOfNextLine = nVisPos >= aLine.getLength();
1132
1133 if ( !bGotoEndOfPrevLine && !bGotoStartOfNextLine )
1134 {
1135 aPaM.SetIndex( rLine.GetStart() + ubidi_getLogicalIndexubidi_getLogicalIndex_67( pBidi, nVisPos, &nError ) );
1136
1137 // RTL portion, stay visually on the left side.
1138 sal_Int32 _nPortionStart;
1139 // sal_uInt16 nTextPortion = pParaPortion->GetTextPortions().FindPortion( aPaM.GetIndex(), nPortionStart, !bRTLPortion );
1140 sal_Int32 _nTextPortion = pParaPortion->GetTextPortions().FindPortion( aPaM.GetIndex(), _nPortionStart, true );
1141 const TextPortion& _rTextPortion = pParaPortion->GetTextPortions()[_nTextPortion];
1142 if ( bVisualToLeft && !bRTLPortion && _rTextPortion.IsRightToLeft() )
1143 aPaM.SetIndex( aPaM.GetIndex()+1 );
1144 else if ( !bVisualToLeft && bRTLPortion && ( bWasBehind || !_rTextPortion.IsRightToLeft() ) )
1145 aPaM.SetIndex( aPaM.GetIndex()+1 );
1146
1147 pEditView->pImpEditView->SetCursorBidiLevel( _nPortionStart );
1148 }
1149 }
1150
1151 ubidi_closeubidi_close_67( pBidi );
1152
1153 if ( bGotoEndOfPrevLine )
1154 {
1155 aPaM = CursorUp( aPaM, pEditView );
1156 if ( aPaM != rPaM )
1157 aPaM = CursorVisualStartEnd( pEditView, aPaM, false );
1158 }
1159 else if ( bGotoStartOfNextLine )
1160 {
1161 aPaM = CursorDown( aPaM, pEditView );
1162 if ( aPaM != rPaM )
1163 aPaM = CursorVisualStartEnd( pEditView, aPaM, true );
1164 }
1165 }
1166 return aPaM;
1167}
1168
1169
1170EditPaM ImpEditEngine::CursorLeft( const EditPaM& rPaM, sal_uInt16 nCharacterIteratorMode )
1171{
1172 EditPaM aCurPaM( rPaM );
1173 EditPaM aNewPaM( aCurPaM );
1174
1175 if ( aCurPaM.GetIndex() )
1176 {
1177 sal_Int32 nCount = 1;
1178 uno::Reference < i18n::XBreakIterator > _xBI( ImplGetBreakIterator() );
1179 aNewPaM.SetIndex(
1180 _xBI->previousCharacters(
1181 aNewPaM.GetNode()->GetString(), aNewPaM.GetIndex(), GetLocale( aNewPaM ), nCharacterIteratorMode, nCount, nCount));
1182 }
1183 else
1184 {
1185 ContentNode* pNode = aCurPaM.GetNode();
1186 pNode = GetPrevVisNode( pNode );
1187 if ( pNode )
1188 {
1189 aNewPaM.SetNode( pNode );
1190 aNewPaM.SetIndex( pNode->Len() );
1191 }
1192 }
1193
1194 return aNewPaM;
1195}
1196
1197EditPaM ImpEditEngine::CursorRight( const EditPaM& rPaM, sal_uInt16 nCharacterIteratorMode )
1198{
1199 EditPaM aCurPaM( rPaM );
1200 EditPaM aNewPaM( aCurPaM );
1201
1202 if ( aCurPaM.GetIndex() < aCurPaM.GetNode()->Len() )
1203 {
1204 uno::Reference < i18n::XBreakIterator > _xBI( ImplGetBreakIterator() );
1205 sal_Int32 nCount = 1;
1206 aNewPaM.SetIndex(
1207 _xBI->nextCharacters(
1208 aNewPaM.GetNode()->GetString(), aNewPaM.GetIndex(), GetLocale( aNewPaM ), nCharacterIteratorMode, nCount, nCount));
1209 }
1210 else
1211 {
1212 ContentNode* pNode = aCurPaM.GetNode();
1213 pNode = GetNextVisNode( pNode );
1214 if ( pNode )
1215 {
1216 aNewPaM.SetNode( pNode );
1217 aNewPaM.SetIndex( 0 );
1218 }
1219 }
1220
1221 return aNewPaM;
1222}
1223
1224EditPaM ImpEditEngine::CursorUp( const EditPaM& rPaM, EditView const * pView )
1225{
1226 assert(pView && "No View - No Cursor Movement!")(static_cast <bool> (pView && "No View - No Cursor Movement!"
) ? void (0) : __assert_fail ("pView && \"No View - No Cursor Movement!\""
, "/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
, 1226, __extension__ __PRETTY_FUNCTION__))
;
1227
1228 const ParaPortion* pPPortion = FindParaPortion( rPaM.GetNode() );
1229 OSL_ENSURE( pPPortion, "No matching portion found: CursorUp ")do { if (true && (!(pPPortion))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "1229" ": "), "%s", "No matching portion found: CursorUp "
); } } while (false)
;
1230 sal_Int32 nLine = pPPortion->GetLineNumber( rPaM.GetIndex() );
1231 const EditLine& rLine = pPPortion->GetLines()[nLine];
1232
1233 long nX;
1234 if ( pView->pImpEditView->nTravelXPos == TRAVEL_X_DONTKNOW0xFFFFFFFF )
1235 {
1236 nX = GetXPos( pPPortion, &rLine, rPaM.GetIndex() );
1237 pView->pImpEditView->nTravelXPos = nX+nOnePixelInRef;
1238 }
1239 else
1240 nX = pView->pImpEditView->nTravelXPos;
1241
1242 EditPaM aNewPaM( rPaM );
1243 if ( nLine ) // same paragraph
1244 {
1245 const EditLine& rPrevLine = pPPortion->GetLines()[nLine-1];
1246 aNewPaM.SetIndex( GetChar( pPPortion, &rPrevLine, nX ) );
1247 // If a previous automatically wrapped line, and one has to be exactly
1248 // at the end of this line, the cursor lands on the current line at the
1249 // beginning. See Problem: Last character of an automatically wrapped
1250 // Row = cursor
1251 if ( aNewPaM.GetIndex() && ( aNewPaM.GetIndex() == rLine.GetStart() ) )
1252 aNewPaM = CursorLeft( aNewPaM );
1253 }
1254 else // previous paragraph
1255 {
1256 const ParaPortion* pPrevPortion = GetPrevVisPortion( pPPortion );
1257 if ( pPrevPortion )
1258 {
1259 const EditLine& rLine2 = pPrevPortion->GetLines()[pPrevPortion->GetLines().Count()-1];
1260 aNewPaM.SetNode( pPrevPortion->GetNode() );
1261 aNewPaM.SetIndex( GetChar( pPrevPortion, &rLine2, nX+nOnePixelInRef ) );
1262 }
1263 }
1264
1265 return aNewPaM;
1266}
1267
1268EditPaM ImpEditEngine::CursorDown( const EditPaM& rPaM, EditView const * pView )
1269{
1270 OSL_ENSURE( pView, "No View - No Cursor Movement!" )do { if (true && (!(pView))) { sal_detail_logFormat((
SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "1270" ": "), "%s", "No View - No Cursor Movement!"); } }
while (false)
;
1271
1272 const ParaPortion* pPPortion = FindParaPortion( rPaM.GetNode() );
1273 OSL_ENSURE( pPPortion, "No matching portion found: CursorDown" )do { if (true && (!(pPPortion))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "1273" ": "), "%s", "No matching portion found: CursorDown"
); } } while (false)
;
1274 sal_Int32 nLine = pPPortion->GetLineNumber( rPaM.GetIndex() );
1275
1276 long nX;
1277 if ( pView->pImpEditView->nTravelXPos == TRAVEL_X_DONTKNOW0xFFFFFFFF )
1278 {
1279 const EditLine& rLine = pPPortion->GetLines()[nLine];
1280 nX = GetXPos( pPPortion, &rLine, rPaM.GetIndex() );
1281 pView->pImpEditView->nTravelXPos = nX+nOnePixelInRef;
1282 }
1283 else
1284 nX = pView->pImpEditView->nTravelXPos;
1285
1286 EditPaM aNewPaM( rPaM );
1287 if ( nLine < pPPortion->GetLines().Count()-1 )
1288 {
1289 const EditLine& rNextLine = pPPortion->GetLines()[nLine+1];
1290 aNewPaM.SetIndex( GetChar( pPPortion, &rNextLine, nX ) );
1291 // Special treatment, see CursorUp ...
1292 if ( ( aNewPaM.GetIndex() == rNextLine.GetEnd() ) && ( aNewPaM.GetIndex() > rNextLine.GetStart() ) && ( aNewPaM.GetIndex() < pPPortion->GetNode()->Len() ) )
1293 aNewPaM = CursorLeft( aNewPaM );
1294 }
1295 else // next paragraph
1296 {
1297 const ParaPortion* pNextPortion = GetNextVisPortion( pPPortion );
1298 if ( pNextPortion )
1299 {
1300 const EditLine& rLine = pNextPortion->GetLines()[0];
1301 aNewPaM.SetNode( pNextPortion->GetNode() );
1302 // Never at the very end when several lines, because then a line
1303 // below the cursor appears.
1304 aNewPaM.SetIndex( GetChar( pNextPortion, &rLine, nX+nOnePixelInRef ) );
1305 if ( ( aNewPaM.GetIndex() == rLine.GetEnd() ) && ( aNewPaM.GetIndex() > rLine.GetStart() ) && ( pNextPortion->GetLines().Count() > 1 ) )
1306 aNewPaM = CursorLeft( aNewPaM );
1307 }
1308 }
1309
1310 return aNewPaM;
1311}
1312
1313EditPaM ImpEditEngine::CursorStartOfLine( const EditPaM& rPaM )
1314{
1315 const ParaPortion* pCurPortion = FindParaPortion( rPaM.GetNode() );
1316 OSL_ENSURE( pCurPortion, "No Portion for the PaM ?" )do { if (true && (!(pCurPortion))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "1316" ": "), "%s", "No Portion for the PaM ?"); } } while
(false)
;
1317 sal_Int32 nLine = pCurPortion->GetLineNumber( rPaM.GetIndex() );
1318 const EditLine& rLine = pCurPortion->GetLines()[nLine];
1319
1320 EditPaM aNewPaM( rPaM );
1321 aNewPaM.SetIndex( rLine.GetStart() );
1322 return aNewPaM;
1323}
1324
1325EditPaM ImpEditEngine::CursorEndOfLine( const EditPaM& rPaM )
1326{
1327 const ParaPortion* pCurPortion = FindParaPortion( rPaM.GetNode() );
1328 OSL_ENSURE( pCurPortion, "No Portion for the PaM ?" )do { if (true && (!(pCurPortion))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "1328" ": "), "%s", "No Portion for the PaM ?"); } } while
(false)
;
1329 sal_Int32 nLine = pCurPortion->GetLineNumber( rPaM.GetIndex() );
1330 const EditLine& rLine = pCurPortion->GetLines()[nLine];
1331
1332 EditPaM aNewPaM( rPaM );
1333 aNewPaM.SetIndex( rLine.GetEnd() );
1334 if ( rLine.GetEnd() > rLine.GetStart() )
1335 {
1336 if ( aNewPaM.GetNode()->IsFeature( aNewPaM.GetIndex() - 1 ) )
1337 {
1338 // When a soft break, be in front of it!
1339 const EditCharAttrib* pNextFeature = aNewPaM.GetNode()->GetCharAttribs().FindFeature( aNewPaM.GetIndex()-1 );
1340 if ( pNextFeature && ( pNextFeature->GetItem()->Which() == EE_FEATURE_LINEBR ) )
1341 aNewPaM = CursorLeft( aNewPaM );
1342 }
1343 else if ( ( aNewPaM.GetNode()->GetChar( aNewPaM.GetIndex() - 1 ) == ' ' ) && ( aNewPaM.GetIndex() != aNewPaM.GetNode()->Len() ) )
1344 {
1345 // For a Blank in an auto wrapped line, it makes sense, to stand
1346 // in front of it, since the user wants to be after the word.
1347 // If this is changed, special treatment for Pos1 to End!
1348 aNewPaM = CursorLeft( aNewPaM );
1349 }
1350 }
1351 return aNewPaM;
1352}
1353
1354EditPaM ImpEditEngine::CursorStartOfParagraph( const EditPaM& rPaM )
1355{
1356 EditPaM aPaM(rPaM);
1357 aPaM.SetIndex(0);
1358 return aPaM;
1359}
1360
1361EditPaM ImpEditEngine::CursorEndOfParagraph( const EditPaM& rPaM )
1362{
1363 EditPaM aPaM(rPaM);
1364 aPaM.SetIndex(rPaM.GetNode()->Len());
1365 return aPaM;
1366}
1367
1368EditPaM ImpEditEngine::CursorStartOfDoc()
1369{
1370 EditPaM aPaM( aEditDoc.GetObject( 0 ), 0 );
1371 return aPaM;
1372}
1373
1374EditPaM ImpEditEngine::CursorEndOfDoc()
1375{
1376 ContentNode* pLastNode = aEditDoc.GetObject( aEditDoc.Count()-1 );
1377 ParaPortion* pLastPortion = GetParaPortions().SafeGetObject( aEditDoc.Count()-1 );
1378 OSL_ENSURE( pLastNode && pLastPortion, "CursorEndOfDoc: Node or Portion not found" )do { if (true && (!(pLastNode && pLastPortion
))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "1378" ": "), "%s", "CursorEndOfDoc: Node or Portion not found"
); } } while (false)
;
1379 if (!(pLastNode && pLastPortion))
1380 return EditPaM();
1381
1382 if ( !pLastPortion->IsVisible() )
1383 {
1384 pLastNode = GetPrevVisNode( pLastPortion->GetNode() );
1385 OSL_ENSURE( pLastNode, "No visible paragraph?" )do { if (true && (!(pLastNode))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "1385" ": "), "%s", "No visible paragraph?"); } } while (
false)
;
1386 if ( !pLastNode )
1387 pLastNode = aEditDoc.GetObject( aEditDoc.Count()-1 );
1388 }
1389
1390 EditPaM aPaM( pLastNode, pLastNode->Len() );
1391 return aPaM;
1392}
1393
1394EditPaM ImpEditEngine::PageUp( const EditPaM& rPaM, EditView const * pView )
1395{
1396 tools::Rectangle aRect = PaMtoEditCursor( rPaM );
1397 Point aTopLeft = aRect.TopLeft();
1398 aTopLeft.AdjustY( -(pView->GetVisArea().GetHeight() *9/10) );
1399 aTopLeft.AdjustX(nOnePixelInRef );
1400 if ( aTopLeft.Y() < 0 )
1401 {
1402 aTopLeft.setY( 0 );
1403 }
1404 return GetPaM( aTopLeft );
1405}
1406
1407EditPaM ImpEditEngine::PageDown( const EditPaM& rPaM, EditView const * pView )
1408{
1409 tools::Rectangle aRect = PaMtoEditCursor( rPaM );
1410 Point aBottomRight = aRect.BottomRight();
1411 aBottomRight.AdjustY(pView->GetVisArea().GetHeight() *9/10 );
1412 aBottomRight.AdjustX(nOnePixelInRef );
1413 long nHeight = GetTextHeight();
1414 if ( aBottomRight.Y() > nHeight )
1415 {
1416 aBottomRight.setY( nHeight-2 );
1417 }
1418 return GetPaM( aBottomRight );
1419}
1420
1421EditPaM ImpEditEngine::WordLeft( const EditPaM& rPaM )
1422{
1423 const sal_Int32 nCurrentPos = rPaM.GetIndex();
1424 EditPaM aNewPaM( rPaM );
1425 if ( nCurrentPos == 0 )
1426 {
1427 // Previous paragraph...
1428 sal_Int32 nCurPara = aEditDoc.GetPos( aNewPaM.GetNode() );
1429 ContentNode* pPrevNode = aEditDoc.GetObject( --nCurPara );
1430 if ( pPrevNode )
1431 {
1432 aNewPaM.SetNode( pPrevNode );
1433 aNewPaM.SetIndex( pPrevNode->Len() );
1434 }
1435 }
1436 else
1437 {
1438 // we need to increase the position by 1 when retrieving the locale
1439 // since the attribute for the char left to the cursor position is returned
1440 EditPaM aTmpPaM( aNewPaM );
1441 if ( aTmpPaM.GetIndex() < rPaM.GetNode()->Len() )
1442 aTmpPaM.SetIndex( aTmpPaM.GetIndex() + 1 );
1443 lang::Locale aLocale( GetLocale( aTmpPaM ) );
1444
1445 uno::Reference < i18n::XBreakIterator > _xBI( ImplGetBreakIterator() );
1446 i18n::Boundary aBoundary =
1447 _xBI->getWordBoundary(aNewPaM.GetNode()->GetString(), nCurrentPos, aLocale, css::i18n::WordType::ANYWORD_IGNOREWHITESPACES, true);
1448 if ( aBoundary.startPos >= nCurrentPos )
1449 aBoundary = _xBI->previousWord(
1450 aNewPaM.GetNode()->GetString(), nCurrentPos, aLocale, css::i18n::WordType::ANYWORD_IGNOREWHITESPACES);
1451 aNewPaM.SetIndex( ( aBoundary.startPos != -1 ) ? aBoundary.startPos : 0 );
1452 }
1453
1454 return aNewPaM;
1455}
1456
1457EditPaM ImpEditEngine::WordRight( const EditPaM& rPaM, sal_Int16 nWordType )
1458{
1459 const sal_Int32 nMax = rPaM.GetNode()->Len();
1460 EditPaM aNewPaM( rPaM );
1461 if ( aNewPaM.GetIndex() < nMax )
1462 {
1463 // we need to increase the position by 1 when retrieving the locale
1464 // since the attribute for the char left to the cursor position is returned
1465 EditPaM aTmpPaM( aNewPaM );
1466 aTmpPaM.SetIndex( aTmpPaM.GetIndex() + 1 );
1467 lang::Locale aLocale( GetLocale( aTmpPaM ) );
1468
1469 uno::Reference < i18n::XBreakIterator > _xBI( ImplGetBreakIterator() );
1470 i18n::Boundary aBoundary = _xBI->nextWord(
1471 aNewPaM.GetNode()->GetString(), aNewPaM.GetIndex(), aLocale, nWordType);
1472 aNewPaM.SetIndex( aBoundary.startPos );
1473 }
1474 // not 'else', maybe the index reached nMax now...
1475 if ( aNewPaM.GetIndex() >= nMax )
1476 {
1477 // Next paragraph ...
1478 sal_Int32 nCurPara = aEditDoc.GetPos( aNewPaM.GetNode() );
1479 ContentNode* pNextNode = aEditDoc.GetObject( ++nCurPara );
1480 if ( pNextNode )
1481 {
1482 aNewPaM.SetNode( pNextNode );
1483 aNewPaM.SetIndex( 0 );
1484 }
1485 }
1486 return aNewPaM;
1487}
1488
1489EditPaM ImpEditEngine::StartOfWord( const EditPaM& rPaM )
1490{
1491 EditPaM aNewPaM( rPaM );
1492
1493 // we need to increase the position by 1 when retrieving the locale
1494 // since the attribute for the char left to the cursor position is returned
1495 EditPaM aTmpPaM( aNewPaM );
1496 if ( aTmpPaM.GetIndex() < rPaM.GetNode()->Len() )
1497 aTmpPaM.SetIndex( aTmpPaM.GetIndex() + 1 );
1498 lang::Locale aLocale( GetLocale( aTmpPaM ) );
1499
1500 uno::Reference < i18n::XBreakIterator > _xBI( ImplGetBreakIterator() );
1501 i18n::Boundary aBoundary = _xBI->getWordBoundary(
1502 rPaM.GetNode()->GetString(), rPaM.GetIndex(), aLocale, css::i18n::WordType::ANYWORD_IGNOREWHITESPACES, true);
1503
1504 aNewPaM.SetIndex( aBoundary.startPos );
1505 return aNewPaM;
1506}
1507
1508EditPaM ImpEditEngine::EndOfWord( const EditPaM& rPaM )
1509{
1510 EditPaM aNewPaM( rPaM );
1511
1512 // we need to increase the position by 1 when retrieving the locale
1513 // since the attribute for the char left to the cursor position is returned
1514 EditPaM aTmpPaM( aNewPaM );
1515 if ( aTmpPaM.GetIndex() < rPaM.GetNode()->Len() )
1516 aTmpPaM.SetIndex( aTmpPaM.GetIndex() + 1 );
1517 lang::Locale aLocale( GetLocale( aTmpPaM ) );
1518
1519 uno::Reference < i18n::XBreakIterator > _xBI( ImplGetBreakIterator() );
1520 i18n::Boundary aBoundary = _xBI->getWordBoundary(
1521 rPaM.GetNode()->GetString(), rPaM.GetIndex(), aLocale, css::i18n::WordType::ANYWORD_IGNOREWHITESPACES, true);
1522
1523 aNewPaM.SetIndex( aBoundary.endPos );
1524 return aNewPaM;
1525}
1526
1527EditSelection ImpEditEngine::SelectWord( const EditSelection& rCurSel, sal_Int16 nWordType, bool bAcceptStartOfWord )
1528{
1529 EditSelection aNewSel( rCurSel );
1530 EditPaM aPaM( rCurSel.Max() );
1531
1532 // we need to increase the position by 1 when retrieving the locale
1533 // since the attribute for the char left to the cursor position is returned
1534 EditPaM aTmpPaM( aPaM );
1535 if ( aTmpPaM.GetIndex() < aPaM.GetNode()->Len() )
1536 aTmpPaM.SetIndex( aTmpPaM.GetIndex() + 1 );
1537 lang::Locale aLocale( GetLocale( aTmpPaM ) );
1538
1539 uno::Reference < i18n::XBreakIterator > _xBI( ImplGetBreakIterator() );
1540 sal_Int16 nType = _xBI->getWordType(
1541 aPaM.GetNode()->GetString(), aPaM.GetIndex(), aLocale);
1542
1543 if ( nType == i18n::WordType::ANY_WORD )
1544 {
1545 i18n::Boundary aBoundary = _xBI->getWordBoundary(
1546 aPaM.GetNode()->GetString(), aPaM.GetIndex(), aLocale, nWordType, true);
1547
1548 // don't select when cursor at end of word
1549 if ( ( aBoundary.endPos > aPaM.GetIndex() ) &&
1550 ( ( aBoundary.startPos < aPaM.GetIndex() ) || ( bAcceptStartOfWord && ( aBoundary.startPos == aPaM.GetIndex() ) ) ) )
1551 {
1552 aNewSel.Min().SetIndex( aBoundary.startPos );
1553 aNewSel.Max().SetIndex( aBoundary.endPos );
1554 }
1555 }
1556
1557 return aNewSel;
1558}
1559
1560EditSelection ImpEditEngine::SelectSentence( const EditSelection& rCurSel )
1561 const
1562{
1563 uno::Reference < i18n::XBreakIterator > _xBI( ImplGetBreakIterator() );
1564 const EditPaM& rPaM = rCurSel.Min();
1565 const ContentNode* pNode = rPaM.GetNode();
1566 // #i50710# line breaks are marked with 0x01 - the break iterator prefers 0x0a for that
1567 const OUString sParagraph = pNode->GetString().replaceAll("\x01", "\x0a");
1568 //return Null if search starts at the beginning of the string
1569 sal_Int32 nStart = rPaM.GetIndex() ? _xBI->beginOfSentence( sParagraph, rPaM.GetIndex(), GetLocale( rPaM ) ) : 0;
1570
1571 sal_Int32 nEnd = _xBI->endOfSentence(
1572 pNode->GetString(), rPaM.GetIndex(), GetLocale(rPaM));
1573
1574 EditSelection aNewSel( rCurSel );
1575 OSL_ENSURE(pNode->Len() ? (nStart < pNode->Len()) : (nStart == 0), "sentence start index out of range")do { if (true && (!(pNode->Len() ? (nStart < pNode
->Len()) : (nStart == 0)))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "1575" ": "), "%s", "sentence start index out of range")
; } } while (false)
;
1576 OSL_ENSURE(nEnd <= pNode->Len(), "sentence end index out of range")do { if (true && (!(nEnd <= pNode->Len()))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "1576" ": "), "%s", "sentence end index out of range"); }
} while (false)
;
1577 aNewSel.Min().SetIndex( nStart );
1578 aNewSel.Max().SetIndex( nEnd );
1579 return aNewSel;
1580}
1581
1582bool ImpEditEngine::IsInputSequenceCheckingRequired( sal_Unicode nChar, const EditSelection& rCurSel ) const
1583{
1584 uno::Reference < i18n::XBreakIterator > _xBI( ImplGetBreakIterator() );
1585 if (!pCTLOptions)
1586 pCTLOptions.reset( new SvtCTLOptions );
1587
1588 // get the index that really is first
1589 const sal_Int32 nFirstPos = std::min(rCurSel.Min().GetIndex(), rCurSel.Max().GetIndex());
1590
1591 bool bIsSequenceChecking =
1592 pCTLOptions->IsCTLFontEnabled() &&
1593 pCTLOptions->IsCTLSequenceChecking() &&
1594 nFirstPos != 0 && /* first char needs not to be checked */
1595 _xBI.is() && i18n::ScriptType::COMPLEX == _xBI->getScriptType( OUString( nChar ), 0 );
1596
1597 return bIsSequenceChecking;
1598}
1599
1600static bool lcl_HasStrongLTR ( const OUString& rTxt, sal_Int32 nStart, sal_Int32 nEnd )
1601 {
1602 for( sal_Int32 nCharIdx = nStart; nCharIdx < nEnd; ++nCharIdx )
1603 {
1604 const UCharDirection nCharDir = u_charDirectionu_charDirection_67 ( rTxt[ nCharIdx ] );
1605 if ( nCharDir == U_LEFT_TO_RIGHT ||
1606 nCharDir == U_LEFT_TO_RIGHT_EMBEDDING ||
1607 nCharDir == U_LEFT_TO_RIGHT_OVERRIDE )
1608 return true;
1609 }
1610 return false;
1611 }
1612
1613
1614void ImpEditEngine::InitScriptTypes( sal_Int32 nPara )
1615{
1616 ParaPortion* pParaPortion = GetParaPortions().SafeGetObject( nPara );
1617 if (!pParaPortion)
1618 return;
1619
1620 ScriptTypePosInfos& rTypes = pParaPortion->aScriptInfos;
1621 rTypes.clear();
1622
1623 ContentNode* pNode = pParaPortion->GetNode();
1624 if ( !pNode->Len() )
1625 return;
1626
1627 uno::Reference < i18n::XBreakIterator > _xBI( ImplGetBreakIterator() );
1628
1629 OUString aText = pNode->GetString();
1630
1631 // To handle fields put the character from the field in the string,
1632 // because endOfScript( ... ) will skip the CH_FEATURE, because this is WEAK
1633 const EditCharAttrib* pField = pNode->GetCharAttribs().FindNextAttrib( EE_FEATURE_FIELD, 0 );
1634 while ( pField )
1635 {
1636 const OUString aFldText = static_cast<const EditCharAttribField*>(pField)->GetFieldValue();
1637 if ( !aFldText.isEmpty() )
1638 {
1639 aText = aText.replaceAt( pField->GetStart(), 1, aFldText.copy(0,1) );
1640 short nFldScriptType = _xBI->getScriptType( aFldText, 0 );
1641
1642 for ( sal_Int32 nCharInField = 1; nCharInField < aFldText.getLength(); nCharInField++ )
1643 {
1644 short nTmpType = _xBI->getScriptType( aFldText, nCharInField );
1645
1646 // First char from field wins...
1647 if ( nFldScriptType == i18n::ScriptType::WEAK )
1648 {
1649 nFldScriptType = nTmpType;
1650 aText = aText.replaceAt( pField->GetStart(), 1, aFldText.copy(nCharInField,1) );
1651 }
1652
1653 // ... but if the first one is LATIN, and there are CJK or CTL chars too,
1654 // we prefer that ScriptType because we need another font.
1655 if ( ( nTmpType == i18n::ScriptType::ASIAN ) || ( nTmpType == i18n::ScriptType::COMPLEX ) )
1656 {
1657 aText = aText.replaceAt( pField->GetStart(), 1, aFldText.copy(nCharInField,1) );
1658 break;
1659 }
1660 }
1661 }
1662 // #112831# Last Field might go from 0xffff to 0x0000
1663 pField = pField->GetEnd() ? pNode->GetCharAttribs().FindNextAttrib( EE_FEATURE_FIELD, pField->GetEnd() ) : nullptr;
1664 }
1665
1666 sal_Int32 nTextLen = aText.getLength();
1667
1668 sal_Int32 nPos = 0;
1669 short nScriptType = _xBI->getScriptType( aText, nPos );
1670 rTypes.emplace_back( nScriptType, nPos, nTextLen );
1671 nPos = _xBI->endOfScript( aText, nPos, nScriptType );
1672 while ( ( nPos != -1 ) && ( nPos < nTextLen ) )
1673 {
1674 rTypes.back().nEndPos = nPos;
1675
1676 nScriptType = _xBI->getScriptType( aText, nPos );
1677 long nEndPos = _xBI->endOfScript( aText, nPos, nScriptType );
1678
1679 if ( ( nScriptType == i18n::ScriptType::WEAK ) || ( nScriptType == rTypes.back().nScriptType ) )
1680 {
1681 // Expand last ScriptTypePosInfo, don't create weak or unnecessary portions
1682 rTypes.back().nEndPos = nEndPos;
1683 }
1684 else
1685 {
1686 if ( _xBI->getScriptType( aText, nPos - 1 ) == i18n::ScriptType::WEAK )
1687 {
1688 switch ( u_charTypeu_charType_67(aText.iterateCodePoints(&nPos, 0) ) ) {
1689 case U_NON_SPACING_MARK:
1690 case U_ENCLOSING_MARK:
1691 case U_COMBINING_SPACING_MARK:
1692 --nPos;
1693 rTypes.back().nEndPos--;
1694 break;
1695 }
1696 }
1697 rTypes.emplace_back( nScriptType, nPos, nTextLen );
1698 }
1699
1700 nPos = nEndPos;
1701 }
1702
1703 if ( rTypes[0].nScriptType == i18n::ScriptType::WEAK )
1704 rTypes[0].nScriptType = ( rTypes.size() > 1 ) ? rTypes[1].nScriptType : SvtLanguageOptions::GetI18NScriptTypeOfLanguage( GetDefaultLanguage() );
1705
1706 // create writing direction information:
1707 if ( pParaPortion->aWritingDirectionInfos.empty() )
1708 InitWritingDirections( nPara );
1709
1710 // i89825: Use CTL font for numbers embedded into an RTL run:
1711 WritingDirectionInfos& rDirInfos = pParaPortion->aWritingDirectionInfos;
1712 for (const WritingDirectionInfo & rDirInfo : rDirInfos)
1713 {
1714 const sal_Int32 nStart = rDirInfo.nStartPos;
1715 const sal_Int32 nEnd = rDirInfo.nEndPos;
1716 const sal_uInt8 nCurrDirType = rDirInfo.nType;
1717
1718 if ( nCurrDirType % 2 == UBIDI_RTL || // text in RTL run
1719 ( nCurrDirType > UBIDI_LTR && !lcl_HasStrongLTR( aText, nStart, nEnd ) ) ) // non-strong text in embedded LTR run
1720 {
1721 size_t nIdx = 0;
1722
1723 // Skip entries in ScriptArray which are not inside the RTL run:
1724 while ( nIdx < rTypes.size() && rTypes[nIdx].nStartPos < nStart )
1725 ++nIdx;
1726
1727 // Remove any entries *inside* the current run:
1728 while (nIdx < rTypes.size() && rTypes[nIdx].nEndPos <= nEnd)
1729 {
1730 // coverity[use_iterator] - we're protected from a bad iterator by the above condition
1731 rTypes.erase(rTypes.begin() + nIdx);
1732 }
1733
1734 // special case:
1735 if(nIdx < rTypes.size() && rTypes[nIdx].nStartPos < nStart && rTypes[nIdx].nEndPos > nEnd)
1736 {
1737 rTypes.insert( rTypes.begin()+nIdx, ScriptTypePosInfo( rTypes[nIdx].nScriptType, nEnd, rTypes[nIdx].nEndPos ) );
1738 rTypes[nIdx].nEndPos = nStart;
1739 }
1740
1741 if( nIdx )
1742 rTypes[nIdx - 1].nEndPos = nStart;
1743
1744 rTypes.insert( rTypes.begin()+nIdx, ScriptTypePosInfo( i18n::ScriptType::COMPLEX, nStart, nEnd) );
1745 ++nIdx;
1746
1747 if( nIdx < rTypes.size() )
1748 rTypes[nIdx].nStartPos = nEnd;
1749 }
1750 }
1751}
1752
1753namespace {
1754
1755struct FindByPos
1756{
1757 explicit FindByPos(sal_Int32 nPos)
1758 : mnPos(nPos)
1759 {
1760 }
1761
1762 bool operator()(const ScriptTypePosInfos::value_type& rValue)
1763 {
1764 return rValue.nStartPos <= mnPos && rValue.nEndPos >= mnPos;
1765 }
1766
1767private:
1768 sal_Int32 mnPos;
1769};
1770
1771}
1772
1773sal_uInt16 ImpEditEngine::GetI18NScriptType( const EditPaM& rPaM, sal_Int32* pEndPos ) const
1774{
1775 sal_uInt16 nScriptType = 0;
1776
1777 if ( pEndPos )
1778 *pEndPos = rPaM.GetNode()->Len();
1779
1780 if ( rPaM.GetNode()->Len() )
1781 {
1782 sal_Int32 nPara = GetEditDoc().GetPos( rPaM.GetNode() );
1783 const ParaPortion* pParaPortion = GetParaPortions().SafeGetObject( nPara );
1784 if (pParaPortion)
1785 {
1786 if ( pParaPortion->aScriptInfos.empty() )
1787 const_cast<ImpEditEngine*>(this)->InitScriptTypes( nPara );
1788
1789 const ScriptTypePosInfos& rTypes = pParaPortion->aScriptInfos;
1790
1791 const sal_Int32 nPos = rPaM.GetIndex();
1792 ScriptTypePosInfos::const_iterator itr = std::find_if(rTypes.begin(), rTypes.end(), FindByPos(nPos));
1793 if(itr != rTypes.end())
1794 {
1795 nScriptType = itr->nScriptType;
1796 if( pEndPos )
1797 *pEndPos = itr->nEndPos;
1798 }
1799 }
1800 }
1801 return nScriptType ? nScriptType : SvtLanguageOptions::GetI18NScriptTypeOfLanguage( GetDefaultLanguage() );
1802}
1803
1804SvtScriptType ImpEditEngine::GetItemScriptType( const EditSelection& rSel ) const
1805{
1806 EditSelection aSel( rSel );
1807 aSel.Adjust( aEditDoc );
1808
1809 SvtScriptType nScriptType = SvtScriptType::NONE;
1810
1811 sal_Int32 nStartPara = GetEditDoc().GetPos( aSel.Min().GetNode() );
1812 sal_Int32 nEndPara = GetEditDoc().GetPos( aSel.Max().GetNode() );
1813
1814 for ( sal_Int32 nPara = nStartPara; nPara <= nEndPara; nPara++ )
1815 {
1816 const ParaPortion* pParaPortion = GetParaPortions().SafeGetObject( nPara );
1817 if (!pParaPortion)
1818 continue;
1819
1820 if ( pParaPortion->aScriptInfos.empty() )
1821 const_cast<ImpEditEngine*>(this)->InitScriptTypes( nPara );
1822
1823 const ScriptTypePosInfos& rTypes = pParaPortion->aScriptInfos;
1824
1825 // find all the scripts of this range
1826 sal_Int32 nS = ( nPara == nStartPara ) ? aSel.Min().GetIndex() : 0;
1827 sal_Int32 nE = ( nPara == nEndPara ) ? aSel.Max().GetIndex() : pParaPortion->GetNode()->Len();
1828
1829 //no selection, just bare cursor
1830 if (nStartPara == nEndPara && nS == nE)
1831 {
1832 //If we are not at the start of the paragraph we want the properties of the
1833 //preceding character. Otherwise get the properties of the next (or what the
1834 //next would have if it existed)
1835 if (nS != 0)
1836 --nS;
1837 else
1838 ++nE;
1839 }
1840
1841 for (const ScriptTypePosInfo & rType : rTypes)
1842 {
1843 bool bStartInRange = rType.nStartPos <= nS && nS < rType.nEndPos;
1844 bool bEndInRange = rType.nStartPos < nE && nE <= rType.nEndPos;
1845
1846 if (bStartInRange || bEndInRange)
1847 {
1848 if ( rType.nScriptType != i18n::ScriptType::WEAK )
1849 nScriptType |= SvtLanguageOptions::FromI18NToSvtScriptType( rType.nScriptType );
1850 }
1851 }
1852 }
1853 return bool(nScriptType) ? nScriptType : SvtLanguageOptions::GetScriptTypeOfLanguage( GetDefaultLanguage() );
1854}
1855
1856bool ImpEditEngine::IsScriptChange( const EditPaM& rPaM ) const
1857{
1858 bool bScriptChange = false;
1859
1860 if ( rPaM.GetNode()->Len() )
1861 {
1862 sal_Int32 nPara = GetEditDoc().GetPos( rPaM.GetNode() );
1863 const ParaPortion* pParaPortion = GetParaPortions().SafeGetObject( nPara );
1864 if (pParaPortion)
1865 {
1866 if ( pParaPortion->aScriptInfos.empty() )
1867 const_cast<ImpEditEngine*>(this)->InitScriptTypes( nPara );
1868
1869 const ScriptTypePosInfos& rTypes = pParaPortion->aScriptInfos;
1870 const sal_Int32 nPos = rPaM.GetIndex();
1871 for (const ScriptTypePosInfo & rType : rTypes)
1872 {
1873 if ( rType.nStartPos == nPos )
1874 {
1875 bScriptChange = true;
1876 break;
1877 }
1878 }
1879 }
1880 }
1881 return bScriptChange;
1882}
1883
1884bool ImpEditEngine::HasScriptType( sal_Int32 nPara, sal_uInt16 nType ) const
1885{
1886 bool bTypeFound = false;
1887
1888 const ParaPortion* pParaPortion = GetParaPortions().SafeGetObject( nPara );
1889 if (pParaPortion)
1890 {
1891 if ( pParaPortion->aScriptInfos.empty() )
1892 const_cast<ImpEditEngine*>(this)->InitScriptTypes( nPara );
1893
1894 const ScriptTypePosInfos& rTypes = pParaPortion->aScriptInfos;
1895 for ( size_t n = rTypes.size(); n && !bTypeFound; )
1896 {
1897 if ( rTypes[--n].nScriptType == nType )
1898 bTypeFound = true;
1899 }
1900 }
1901 return bTypeFound;
1902}
1903
1904void ImpEditEngine::InitWritingDirections( sal_Int32 nPara )
1905{
1906 ParaPortion* pParaPortion = GetParaPortions().SafeGetObject( nPara );
1907 if (!pParaPortion)
1908 return;
1909
1910 WritingDirectionInfos& rInfos = pParaPortion->aWritingDirectionInfos;
1911 rInfos.clear();
1912
1913 if (pParaPortion->GetNode()->Len())
1914 {
1915 const OUString aText = pParaPortion->GetNode()->GetString();
1916
1917 // Bidi functions from icu 2.0
1918
1919 UErrorCode nError = U_ZERO_ERROR;
1920 UBiDi* pBidi = ubidi_openSizedubidi_openSized_67( aText.getLength(), 0, &nError );
1921 nError = U_ZERO_ERROR;
1922
1923 const UBiDiLevel nBidiLevel = IsRightToLeft(nPara) ? 1 /*RTL*/ : 0 /*LTR*/;
1924 ubidi_setParaubidi_setPara_67( pBidi, reinterpret_cast<const UChar *>(aText.getStr()), aText.getLength(), nBidiLevel, nullptr, &nError );
1925 nError = U_ZERO_ERROR;
1926
1927 int32_t nCount = ubidi_countRunsubidi_countRuns_67( pBidi, &nError );
1928
1929 /* ubidi_countRuns can return -1 in case of error */
1930 if (nCount > 0)
1931 {
1932 int32_t nStart = 0;
1933 int32_t nEnd;
1934 UBiDiLevel nCurrDir;
1935
1936 for (int32_t nIdx = 0; nIdx < nCount; ++nIdx)
1937 {
1938 ubidi_getLogicalRunubidi_getLogicalRun_67( pBidi, nStart, &nEnd, &nCurrDir );
1939 rInfos.emplace_back( nCurrDir, nStart, nEnd );
1940 nStart = nEnd;
1941 }
1942 }
1943
1944 ubidi_closeubidi_close_67( pBidi );
1945 }
1946
1947 // No infos mean ubidi error, default to LTR
1948 if ( rInfos.empty() )
1949 rInfos.emplace_back( 0, 0, pParaPortion->GetNode()->Len() );
1950
1951}
1952
1953bool ImpEditEngine::IsRightToLeft( sal_Int32 nPara ) const
1954{
1955 bool bR2L = false;
1956 const SvxFrameDirectionItem* pFrameDirItem = nullptr;
1957
1958 if ( !IsVertical() )
1959 {
1960 bR2L = GetDefaultHorizontalTextDirection() == EEHorizontalTextDirection::R2L;
1961 pFrameDirItem = &GetParaAttrib( nPara, EE_PARA_WRITINGDIR );
1962 if ( pFrameDirItem->GetValue() == SvxFrameDirection::Environment )
1963 {
1964 // #103045# if DefaultHorizontalTextDirection is set, use that value, otherwise pool default.
1965 if ( GetDefaultHorizontalTextDirection() != EEHorizontalTextDirection::Default )
1966 {
1967 pFrameDirItem = nullptr; // bR2L already set to default horizontal text direction
1968 }
1969 else
1970 {
1971 // Use pool default
1972 pFrameDirItem = &GetEmptyItemSet().Get(EE_PARA_WRITINGDIR);
1973 }
1974 }
1975 }
1976
1977 if ( pFrameDirItem )
1978 bR2L = pFrameDirItem->GetValue() == SvxFrameDirection::Horizontal_RL_TB;
1979
1980 return bR2L;
1981}
1982
1983bool ImpEditEngine::HasDifferentRTLLevels( const ContentNode* pNode )
1984{
1985 bool bHasDifferentRTLLevels = false;
1986
1987 sal_Int32 nPara = GetEditDoc().GetPos( pNode );
1988 ParaPortion* pParaPortion = GetParaPortions().SafeGetObject( nPara );
1989 if (pParaPortion)
1990 {
1991 sal_uInt16 nRTLLevel = IsRightToLeft( nPara ) ? 1 : 0;
1992 for ( sal_Int32 n = 0; n < pParaPortion->GetTextPortions().Count(); n++ )
1993 {
1994 const TextPortion& rTextPortion = pParaPortion->GetTextPortions()[n];
1995 if ( rTextPortion.GetRightToLeftLevel() != nRTLLevel )
1996 {
1997 bHasDifferentRTLLevels = true;
1998 break;
1999 }
2000 }
2001 }
2002 return bHasDifferentRTLLevels;
2003}
2004
2005
2006sal_uInt8 ImpEditEngine::GetRightToLeft( sal_Int32 nPara, sal_Int32 nPos, sal_Int32* pStart, sal_Int32* pEnd )
2007{
2008 sal_uInt8 nRightToLeft = 0;
2009
2010 ContentNode* pNode = aEditDoc.GetObject( nPara );
2011 if ( pNode && pNode->Len() )
2012 {
2013 ParaPortion* pParaPortion = GetParaPortions().SafeGetObject( nPara );
2014 if (pParaPortion)
2015 {
2016 if ( pParaPortion->aWritingDirectionInfos.empty() )
2017 InitWritingDirections( nPara );
2018
2019 WritingDirectionInfos& rDirInfos = pParaPortion->aWritingDirectionInfos;
2020 for (const WritingDirectionInfo & rDirInfo : rDirInfos)
2021 {
2022 if ( ( rDirInfo.nStartPos <= nPos ) && ( rDirInfo.nEndPos >= nPos ) )
2023 {
2024 nRightToLeft = rDirInfo.nType;
2025 if ( pStart )
2026 *pStart = rDirInfo.nStartPos;
2027 if ( pEnd )
2028 *pEnd = rDirInfo.nEndPos;
2029 break;
2030 }
2031 }
2032 }
2033 }
2034 return nRightToLeft;
2035}
2036
2037SvxAdjust ImpEditEngine::GetJustification( sal_Int32 nPara ) const
2038{
2039 SvxAdjust eJustification = SvxAdjust::Left;
2040
2041 if ( !aStatus.IsOutliner() )
2042 {
2043 eJustification = GetParaAttrib( nPara, EE_PARA_JUST ).GetAdjust();
2044
2045 if ( IsRightToLeft( nPara ) )
2046 {
2047 if ( eJustification == SvxAdjust::Left )
2048 eJustification = SvxAdjust::Right;
2049 else if ( eJustification == SvxAdjust::Right )
2050 eJustification = SvxAdjust::Left;
2051 }
2052 }
2053 return eJustification;
2054}
2055
2056SvxCellJustifyMethod ImpEditEngine::GetJustifyMethod( sal_Int32 nPara ) const
2057{
2058 const SvxJustifyMethodItem& rItem = GetParaAttrib(nPara, EE_PARA_JUST_METHOD);
2059 return static_cast<SvxCellJustifyMethod>(rItem.GetEnumValue());
2060}
2061
2062SvxCellVerJustify ImpEditEngine::GetVerJustification( sal_Int32 nPara ) const
2063{
2064 const SvxVerJustifyItem& rItem = GetParaAttrib(nPara, EE_PARA_VER_JUST);
2065 return static_cast<SvxCellVerJustify>(rItem.GetEnumValue());
2066}
2067
2068// Text changes
2069void ImpEditEngine::ImpRemoveChars( const EditPaM& rPaM, sal_Int32 nChars )
2070{
2071 if ( IsUndoEnabled() && !IsInUndo() )
2072 {
2073 const OUString aStr( rPaM.GetNode()->Copy( rPaM.GetIndex(), nChars ) );
2074
2075 // Check whether attributes are deleted or changed:
2076 const sal_Int32 nStart = rPaM.GetIndex();
2077 const sal_Int32 nEnd = nStart + nChars;
2078 const CharAttribList::AttribsType& rAttribs = rPaM.GetNode()->GetCharAttribs().GetAttribs();
2079 for (const auto & rAttrib : rAttribs)
2080 {
2081 const EditCharAttrib& rAttr = *rAttrib;
2082 if (rAttr.GetEnd() >= nStart && rAttr.GetStart() < nEnd)
2083 {
2084 EditSelection aSel( rPaM );
2085 aSel.Max().SetIndex( aSel.Max().GetIndex() + nChars );
2086 InsertUndo( CreateAttribUndo( aSel, GetEmptyItemSet() ) );
2087 break; // for
2088 }
2089 }
2090 InsertUndo(std::make_unique<EditUndoRemoveChars>(pEditEngine, CreateEPaM(rPaM), aStr));
2091 }
2092
2093 aEditDoc.RemoveChars( rPaM, nChars );
2094}
2095
2096EditSelection ImpEditEngine::ImpMoveParagraphs( Range aOldPositions, sal_Int32 nNewPos )
2097{
2098 aOldPositions.Justify();
2099 bool bValidAction = ( static_cast<long>(nNewPos) < aOldPositions.Min() ) || ( static_cast<long>(nNewPos) > aOldPositions.Max() );
2100 OSL_ENSURE( bValidAction, "Move in itself?" )do { if (true && (!(bValidAction))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "2100" ": "), "%s", "Move in itself?"); } } while (false
)
;
2101 OSL_ENSURE( aOldPositions.Max() <= static_cast<long>(GetParaPortions().Count()), "totally over it: MoveParagraphs" )do { if (true && (!(aOldPositions.Max() <= static_cast
<long>(GetParaPortions().Count())))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "2101" ": "), "%s", "totally over it: MoveParagraphs"); }
} while (false)
;
2102
2103 EditSelection aSelection;
2104
2105 if ( !bValidAction )
2106 {
2107 aSelection = aEditDoc.GetStartPaM();
2108 return aSelection;
2109 }
2110
2111 sal_Int32 nParaCount = GetParaPortions().Count();
2112
2113 if ( nNewPos >= nParaCount )
2114 nNewPos = nParaCount;
2115
2116 // Height may change when moving first or last Paragraph
2117 ParaPortion* pRecalc1 = nullptr;
2118 ParaPortion* pRecalc2 = nullptr;
2119 ParaPortion* pRecalc3 = nullptr;
2120 ParaPortion* pRecalc4 = nullptr;
2121
2122 if ( nNewPos == 0 ) // Move to Start
2123 {
2124 pRecalc1 = GetParaPortions()[0];
2125 pRecalc2 = GetParaPortions()[aOldPositions.Min()];
2126
2127 }
2128 else if ( nNewPos == nParaCount )
2129 {
2130 pRecalc1 = GetParaPortions()[nParaCount-1];
2131 pRecalc2 = GetParaPortions()[aOldPositions.Max()];
2132 }
2133
2134 if ( aOldPositions.Min() == 0 ) // Move from Start
2135 {
2136 pRecalc3 = GetParaPortions()[0];
2137 pRecalc4 = GetParaPortions()[aOldPositions.Max()+1];
2138 }
2139 else if ( aOldPositions.Max() == (nParaCount-1) )
2140 {
2141 pRecalc3 = GetParaPortions()[aOldPositions.Max()];
2142 pRecalc4 = GetParaPortions()[aOldPositions.Min()-1];
2143 }
2144
2145 MoveParagraphsInfo aMoveParagraphsInfo( aOldPositions.Min(), aOldPositions.Max(), nNewPos );
2146 aBeginMovingParagraphsHdl.Call( aMoveParagraphsInfo );
2147
2148 if ( IsUndoEnabled() && !IsInUndo())
2149 InsertUndo(std::make_unique<EditUndoMoveParagraphs>(pEditEngine, aOldPositions, nNewPos));
2150
2151 // do not lose sight of the Position !
2152 ParaPortion* pDestPortion = GetParaPortions().SafeGetObject( nNewPos );
2153
2154 ParaPortionList aTmpPortionList;
2155 for (long i = aOldPositions.Min(); i <= aOldPositions.Max(); i++ )
2156 {
2157 // always aOldPositions.Min(), since Remove().
2158 std::unique_ptr<ParaPortion> pTmpPortion = GetParaPortions().Release(aOldPositions.Min());
2159 aEditDoc.Release( aOldPositions.Min() );
2160 aTmpPortionList.Append(std::move(pTmpPortion));
2161 }
2162
2163 sal_Int32 nRealNewPos = pDestPortion ? GetParaPortions().GetPos( pDestPortion ) : GetParaPortions().Count();
2164 OSL_ENSURE( nRealNewPos != EE_PARA_NOT_FOUND, "ImpMoveParagraphs: Invalid Position!" )do { if (true && (!(nRealNewPos != ((sal_Int32) 0x7FFFFFFF
)))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "2164" ": "), "%s", "ImpMoveParagraphs: Invalid Position!"
); } } while (false)
;
2165
2166 sal_Int32 i = 0;
2167 while( aTmpPortionList.Count() > 0 )
2168 {
2169 std::unique_ptr<ParaPortion> pTmpPortion = aTmpPortionList.Release(0);
2170 if ( i == 0 )
2171 aSelection.Min().SetNode( pTmpPortion->GetNode() );
2172
2173 aSelection.Max().SetNode( pTmpPortion->GetNode() );
2174 aSelection.Max().SetIndex( pTmpPortion->GetNode()->Len() );
2175
2176 ContentNode* pN = pTmpPortion->GetNode();
2177 aEditDoc.Insert(nRealNewPos+i, pN);
2178
2179 GetParaPortions().Insert(nRealNewPos+i, std::move(pTmpPortion));
2180 ++i;
2181 }
2182
2183 aEndMovingParagraphsHdl.Call( aMoveParagraphsInfo );
2184
2185 if ( GetNotifyHdl().IsSet() )
2186 {
2187 EENotify aNotify( EE_NOTIFY_PARAGRAPHSMOVED );
2188 aNotify.nParagraph = nNewPos;
2189 aNotify.nParam1 = aOldPositions.Min();
2190 aNotify.nParam2 = aOldPositions.Max();
2191 GetNotifyHdl().Call( aNotify );
2192 }
2193
2194 aEditDoc.SetModified( true );
2195
2196 if ( pRecalc1 )
2197 CalcHeight( pRecalc1 );
2198 if ( pRecalc2 )
2199 CalcHeight( pRecalc2 );
2200 if ( pRecalc3 )
2201 CalcHeight( pRecalc3 );
2202 if ( pRecalc4 )
2203 CalcHeight( pRecalc4 );
2204
2205#if OSL_DEBUG_LEVEL1 > 0 && !defined NDEBUG
2206 ParaPortionList::DbgCheck(GetParaPortions(), aEditDoc);
2207#endif
2208 return aSelection;
2209}
2210
2211
2212EditPaM ImpEditEngine::ImpConnectParagraphs( ContentNode* pLeft, ContentNode* pRight, bool bBackward )
2213{
2214 OSL_ENSURE( pLeft != pRight, "Join together the same paragraph ?" )do { if (true && (!(pLeft != pRight))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "2214" ": "), "%s", "Join together the same paragraph ?"
); } } while (false)
;
2215 OSL_ENSURE( aEditDoc.GetPos( pLeft ) != EE_PARA_NOT_FOUND, "Inserted node not found (1)" )do { if (true && (!(aEditDoc.GetPos( pLeft ) != ((sal_Int32
) 0x7FFFFFFF)))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "2215" ": "), "%s", "Inserted node not found (1)"); } } while
(false)
;
2216 OSL_ENSURE( aEditDoc.GetPos( pRight ) != EE_PARA_NOT_FOUND, "Inserted node not found (2)" )do { if (true && (!(aEditDoc.GetPos( pRight ) != ((sal_Int32
) 0x7FFFFFFF)))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "2216" ": "), "%s", "Inserted node not found (2)"); } } while
(false)
;
2217
2218 // #i120020# it is possible that left and right are *not* in the desired order (left/right)
2219 // so correct it. This correction is needed, else an invalid SfxLinkUndoAction will be
2220 // created from ConnectParagraphs below. Assert this situation, it should be corrected by the
2221 // caller.
2222 if(aEditDoc.GetPos( pLeft ) > aEditDoc.GetPos( pRight ))
2223 {
2224 OSL_ENSURE(false, "ImpConnectParagraphs with wrong order of pLeft/pRight nodes (!)")do { if (true && (!(false))) { sal_detail_logFormat((
SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "2224" ": "), "%s", "ImpConnectParagraphs with wrong order of pLeft/pRight nodes (!)"
); } } while (false)
;
2225 std::swap(pLeft, pRight);
2226 }
2227
2228 sal_Int32 nParagraphTobeDeleted = aEditDoc.GetPos( pRight );
2229 aDeletedNodes.push_back(std::make_unique<DeletedNodeInfo>( pRight, nParagraphTobeDeleted ));
2230
2231 GetEditEnginePtr()->ParagraphConnected( aEditDoc.GetPos( pLeft ), aEditDoc.GetPos( pRight ) );
2232
2233 if ( IsUndoEnabled() && !IsInUndo() )
2234 {
2235 InsertUndo( std::make_unique<EditUndoConnectParas>(pEditEngine,
2236 aEditDoc.GetPos( pLeft ), pLeft->Len(),
2237 pLeft->GetContentAttribs().GetItems(), pRight->GetContentAttribs().GetItems(),
2238 pLeft->GetStyleSheet(), pRight->GetStyleSheet(), bBackward ) );
2239 }
2240
2241 if ( bBackward )
2242 {
2243 pLeft->SetStyleSheet( pRight->GetStyleSheet() );
2244 // it feels wrong to set pLeft's attribs if pRight is empty, tdf#128046
2245 if ( pRight->Len() )
2246 pLeft->GetContentAttribs().GetItems().Set( pRight->GetContentAttribs().GetItems() );
2247 pLeft->GetCharAttribs().GetDefFont() = pRight->GetCharAttribs().GetDefFont();
2248 }
2249
2250 ParaAttribsChanged( pLeft, true );
2251
2252 // First search for Portions since pRight is gone after ConnectParagraphs.
2253 ParaPortion* pLeftPortion = FindParaPortion( pLeft );
2254 OSL_ENSURE( pLeftPortion, "Blind Portion in ImpConnectParagraphs(1)" )do { if (true && (!(pLeftPortion))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "2254" ": "), "%s", "Blind Portion in ImpConnectParagraphs(1)"
); } } while (false)
;
2255
2256 if ( GetStatus().DoOnlineSpelling() )
2257 {
2258 sal_Int32 nEnd = pLeft->Len();
2259 sal_Int32 nInv = nEnd ? nEnd-1 : nEnd;
2260 pLeft->GetWrongList()->ClearWrongs( nInv, static_cast<size_t>(-1), pLeft ); // Possibly remove one
2261 pLeft->GetWrongList()->SetInvalidRange(nInv, nEnd+1);
2262 // Take over misspelled words
2263 WrongList* pRWrongs = pRight->GetWrongList();
2264 for (auto & elem : *pRWrongs)
2265 {
2266 if (elem.mnStart != 0) // Not a subsequent
2267 {
2268 elem.mnStart = elem.mnStart + nEnd;
2269 elem.mnEnd = elem.mnEnd + nEnd;
2270 pLeft->GetWrongList()->push_back(elem);
2271 }
2272 }
2273 }
2274
2275 if ( IsCallParaInsertedOrDeleted() )
2276 GetEditEnginePtr()->ParagraphDeleted( nParagraphTobeDeleted );
2277
2278 EditPaM aPaM = aEditDoc.ConnectParagraphs( pLeft, pRight );
2279 GetParaPortions().Remove( nParagraphTobeDeleted );
2280
2281 pLeftPortion->MarkSelectionInvalid( aPaM.GetIndex() );
2282
2283 // the right node is deleted by EditDoc:ConnectParagraphs().
2284 if ( GetTextRanger() )
2285 {
2286 // By joining together the two, the left is although reformatted,
2287 // however if its height does not change then the formatting receives
2288 // the change of the total text height too late...
2289 for ( sal_Int32 n = nParagraphTobeDeleted; n < GetParaPortions().Count(); n++ )
2290 {
2291 ParaPortion* pPP = GetParaPortions()[n];
2292 pPP->MarkSelectionInvalid( 0 );
2293 pPP->GetLines().Reset();
2294 }
2295 }
2296
2297 TextModified();
2298
2299 return aPaM;
2300}
2301
2302EditPaM ImpEditEngine::DeleteLeftOrRight( const EditSelection& rSel, sal_uInt8 nMode, DeleteMode nDelMode )
2303{
2304 OSL_ENSURE( !rSel.DbgIsBuggy( aEditDoc ), "Index out of range in DeleteLeftOrRight" )do { if (true && (!(!rSel.DbgIsBuggy( aEditDoc )))) {
sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "2304" ": "), "%s", "Index out of range in DeleteLeftOrRight"
); } } while (false)
;
2305
2306 if ( rSel.HasRange() ) // only then Delete Selection
2307 return ImpDeleteSelection( rSel );
2308
2309 EditPaM aCurPos( rSel.Max() );
2310 EditPaM aDelStart( aCurPos );
2311 EditPaM aDelEnd( aCurPos );
2312 if ( nMode == DEL_LEFT1 )
2313 {
2314 if ( nDelMode == DeleteMode::Simple )
2315 {
2316 sal_uInt16 nCharMode = i18n::CharacterIteratorMode::SKIPCHARACTER;
2317 // Check if we are deleting a CJK ideograph variance sequence (IVS).
2318 sal_Int32 nIndex = aCurPos.GetIndex();
2319 if (nIndex > 0)
2320 {
2321 const OUString& rString = aCurPos.GetNode()->GetString();
2322 sal_Int32 nCode = rString.iterateCodePoints(&nIndex, -1);
2323 if (unicode::isIVSSelector(nCode) && nIndex > 0 &&
2324 unicode::isCJKIVSCharacter(rString.iterateCodePoints(&nIndex, -1)))
2325 {
2326 nCharMode = i18n::CharacterIteratorMode::SKIPCELL;
2327 }
2328 }
2329 aDelStart = CursorLeft(aCurPos, nCharMode);
2330 }
2331 else if ( nDelMode == DeleteMode::RestOfWord )
2332 {
2333 aDelStart = StartOfWord( aCurPos );
2334 if ( aDelStart.GetIndex() == aCurPos.GetIndex() )
2335 aDelStart = WordLeft( aCurPos );
2336 }
2337 else // DELMODE_RESTOFCONTENT
2338 {
2339 aDelStart.SetIndex( 0 );
2340 if ( aDelStart == aCurPos )
2341 {
2342 // Complete paragraph previous
2343 ContentNode* pPrev = GetPrevVisNode( aCurPos.GetNode() );
2344 if ( pPrev )
2345 aDelStart = EditPaM( pPrev, 0 );
2346 }
2347 }
2348 }
2349 else
2350 {
2351 if ( nDelMode == DeleteMode::Simple )
2352 {
2353 aDelEnd = CursorRight( aCurPos );
2354 }
2355 else if ( nDelMode == DeleteMode::RestOfWord )
2356 {
2357 aDelEnd = EndOfWord( aCurPos );
2358
2359 if (aDelEnd.GetIndex() == aCurPos.GetIndex())
2360 {
2361 const sal_Int32 nLen(aCurPos.GetNode()->Len());
2362
2363 // #i120020# when 0 == nLen, aDelStart needs to be adapted, not
2364 // aDelEnd. This would (and did) lead to a wrong order in the
2365 // ImpConnectParagraphs call later.
2366 if(nLen)
2367 {
2368 // end of para?
2369 if (aDelEnd.GetIndex() == nLen)
2370 {
2371 aDelEnd = WordLeft( aCurPos );
2372 }
2373 else // there's still sth to delete on the right
2374 {
2375 aDelEnd = EndOfWord( WordRight( aCurPos ) );
2376 // if there'n no next word...
2377 if (aDelEnd.GetIndex() == nLen )
2378 {
2379 aDelEnd.SetIndex( nLen );
2380 }
2381 }
2382 }
2383 else
2384 {
2385 aDelStart = WordLeft(aCurPos);
2386 }
2387 }
2388 }
2389 else // DELMODE_RESTOFCONTENT
2390 {
2391 aDelEnd.SetIndex( aCurPos.GetNode()->Len() );
2392 if ( aDelEnd == aCurPos )
2393 {
2394 // Complete paragraph next
2395 ContentNode* pNext = GetNextVisNode( aCurPos.GetNode() );
2396 if ( pNext )
2397 aDelEnd = EditPaM( pNext, pNext->Len() );
2398 }
2399 }
2400 }
2401
2402 // ConnectParagraphs not enough for different Nodes when
2403 // DeleteMode::RestOfContent.
2404 if ( ( nDelMode == DeleteMode::RestOfContent ) || ( aDelStart.GetNode() == aDelEnd.GetNode() ) )
2405 return ImpDeleteSelection( EditSelection( aDelStart, aDelEnd ) );
2406
2407 return ImpConnectParagraphs(aDelStart.GetNode(), aDelEnd.GetNode());
2408}
2409
2410EditPaM ImpEditEngine::ImpDeleteSelection(const EditSelection& rCurSel)
2411{
2412 if ( !rCurSel.HasRange() )
2413 return rCurSel.Min();
2414
2415 EditSelection aCurSel(rCurSel);
2416 aCurSel.Adjust( aEditDoc );
2417 EditPaM aStartPaM(aCurSel.Min());
2418 EditPaM aEndPaM(aCurSel.Max());
2419
2420 CursorMoved( aStartPaM.GetNode() ); // only so that newly set Attributes disappear...
2421 CursorMoved( aEndPaM.GetNode() ); // only so that newly set Attributes disappear...
2422
2423 OSL_ENSURE( aStartPaM.GetIndex() <= aStartPaM.GetNode()->Len(), "Index out of range in ImpDeleteSelection" )do { if (true && (!(aStartPaM.GetIndex() <= aStartPaM
.GetNode()->Len()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "2423" ": "), "%s", "Index out of range in ImpDeleteSelection"
); } } while (false)
;
2424 OSL_ENSURE( aEndPaM.GetIndex() <= aEndPaM.GetNode()->Len(), "Index out of range in ImpDeleteSelection" )do { if (true && (!(aEndPaM.GetIndex() <= aEndPaM.
GetNode()->Len()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "2424" ": "), "%s", "Index out of range in ImpDeleteSelection"
); } } while (false)
;
2425
2426 sal_Int32 nStartNode = aEditDoc.GetPos( aStartPaM.GetNode() );
2427 sal_Int32 nEndNode = aEditDoc.GetPos( aEndPaM.GetNode() );
2428
2429 OSL_ENSURE( nEndNode != EE_PARA_NOT_FOUND, "Start > End ?!" )do { if (true && (!(nEndNode != ((sal_Int32) 0x7FFFFFFF
)))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "2429" ": "), "%s", "Start > End ?!"); } } while (false
)
;
2430 OSL_ENSURE( nStartNode <= nEndNode, "Start > End ?!" )do { if (true && (!(nStartNode <= nEndNode))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "2430" ": "), "%s", "Start > End ?!"); } } while (false
)
;
2431
2432 // Remove all nodes in between...
2433 for ( sal_Int32 z = nStartNode+1; z < nEndNode; z++ )
2434 {
2435 // Always nStartNode+1, due to Remove()!
2436 ImpRemoveParagraph( nStartNode+1 );
2437 }
2438
2439 if ( aStartPaM.GetNode() != aEndPaM.GetNode() )
2440 {
2441 // The Rest of the StartNodes...
2442 ImpRemoveChars( aStartPaM, aStartPaM.GetNode()->Len() - aStartPaM.GetIndex() );
2443 ParaPortion* pPortion = FindParaPortion( aStartPaM.GetNode() );
2444 OSL_ENSURE( pPortion, "Blind Portion in ImpDeleteSelection(3)" )do { if (true && (!(pPortion))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "2444" ": "), "%s", "Blind Portion in ImpDeleteSelection(3)"
); } } while (false)
;
2445 pPortion->MarkSelectionInvalid( aStartPaM.GetIndex() );
2446
2447 // The beginning of the EndNodes...
2448 const sal_Int32 nChars = aEndPaM.GetIndex();
2449 aEndPaM.SetIndex( 0 );
2450 ImpRemoveChars( aEndPaM, nChars );
2451 pPortion = FindParaPortion( aEndPaM.GetNode() );
2452 OSL_ENSURE( pPortion, "Blind Portion in ImpDeleteSelection(4)" )do { if (true && (!(pPortion))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "2452" ": "), "%s", "Blind Portion in ImpDeleteSelection(4)"
); } } while (false)
;
2453 pPortion->MarkSelectionInvalid( 0 );
2454 // Join together...
2455 aStartPaM = ImpConnectParagraphs( aStartPaM.GetNode(), aEndPaM.GetNode() );
2456 }
2457 else
2458 {
2459 ImpRemoveChars( aStartPaM, aEndPaM.GetIndex() - aStartPaM.GetIndex() );
2460 ParaPortion* pPortion = FindParaPortion( aStartPaM.GetNode() );
2461 OSL_ENSURE( pPortion, "Blind Portion in ImpDeleteSelection(5)" )do { if (true && (!(pPortion))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "2461" ": "), "%s", "Blind Portion in ImpDeleteSelection(5)"
); } } while (false)
;
2462 pPortion->MarkInvalid( aEndPaM.GetIndex(), aStartPaM.GetIndex() - aEndPaM.GetIndex() );
2463 }
2464
2465 UpdateSelections();
2466 TextModified();
2467 return aStartPaM;
2468}
2469
2470void ImpEditEngine::ImpRemoveParagraph( sal_Int32 nPara )
2471{
2472 ContentNode* pNode = aEditDoc.GetObject( nPara );
2473 ContentNode* pNextNode = aEditDoc.GetObject( nPara+1 );
2474
2475 OSL_ENSURE( pNode, "Blind Node in ImpRemoveParagraph" )do { if (true && (!(pNode))) { sal_detail_logFormat((
SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "2475" ": "), "%s", "Blind Node in ImpRemoveParagraph");
} } while (false)
;
2476
2477 aDeletedNodes.push_back(std::make_unique<DeletedNodeInfo>( pNode, nPara ));
2478
2479 // The node is managed by the undo and possibly destroyed!
2480 aEditDoc.Release( nPara );
2481 GetParaPortions().Remove( nPara );
2482
2483 if ( IsCallParaInsertedOrDeleted() )
2484 {
2485 GetEditEnginePtr()->ParagraphDeleted( nPara );
2486 }
2487
2488 // Extra-Space may be determined again in the following. For
2489 // ParaAttribsChanged the paragraph is unfortunately formatted again,
2490 // however this method should not be time critical!
2491 if ( pNextNode )
2492 ParaAttribsChanged( pNextNode );
2493
2494 if ( IsUndoEnabled() && !IsInUndo() )
2495 InsertUndo(std::make_unique<EditUndoDelContent>(pEditEngine, pNode, nPara));
2496 else
2497 {
2498 aEditDoc.RemoveItemsFromPool(*pNode);
2499 if ( pNode->GetStyleSheet() )
2500 EndListening( *pNode->GetStyleSheet() );
2501 delete pNode;
2502 }
2503}
2504
2505EditPaM ImpEditEngine::AutoCorrect( const EditSelection& rCurSel, sal_Unicode c,
2506 bool bOverwrite, vcl::Window const * pFrameWin )
2507{
2508 // i.e. Calc has special needs regarding a leading single quotation mark
2509 // when starting cell input.
2510 if (c == '\'' && !IsReplaceLeadingSingleQuotationMark() &&
2511 rCurSel.Min() == rCurSel.Max() && rCurSel.Max().GetIndex() == 0)
2512 {
2513 return InsertTextUserInput( rCurSel, c, bOverwrite );
2514 }
2515
2516 EditSelection aSel( rCurSel );
2517 SvxAutoCorrect* pAutoCorrect = SvxAutoCorrCfg::Get().GetAutoCorrect();
2518 if ( pAutoCorrect )
2519 {
2520 if ( aSel.HasRange() )
2521 aSel = ImpDeleteSelection( rCurSel );
2522
2523 // #i78661 allow application to turn off capitalization of
2524 // start sentence explicitly.
2525 // (This is done by setting IsFirstWordCapitalization to sal_False.)
2526 bool bOldCapitalStartSentence = pAutoCorrect->IsAutoCorrFlag( ACFlags::CapitalStartSentence );
2527 if (!IsFirstWordCapitalization())
2528 {
2529 ESelection aESel( CreateESel(aSel) );
2530 EditSelection aFirstWordSel;
2531 EditSelection aSecondWordSel;
2532 if (aESel.nEndPara == 0) // is this the first para?
2533 {
2534 // select first word...
2535 // start by checking if para starts with word.
2536 aFirstWordSel = SelectWord( CreateSel(ESelection()) );
2537 if (aFirstWordSel.Min().GetIndex() == 0 && aFirstWordSel.Max().GetIndex() == 0)
2538 {
2539 // para does not start with word -> select next/first word
2540 EditPaM aRightWord( WordRight( aFirstWordSel.Max() ) );
2541 aFirstWordSel = SelectWord( EditSelection( aRightWord ) );
2542 }
2543
2544 // select second word
2545 // (sometimes aSel might not point to the end of the first word
2546 // but to some following char like '.'. ':', ...
2547 // In those cases we need aSecondWordSel to see if aSel
2548 // will actually effect the first word.)
2549 EditPaM aRight2Word( WordRight( aFirstWordSel.Max() ) );
2550 aSecondWordSel = SelectWord( EditSelection( aRight2Word ) );
2551 }
2552 bool bIsFirstWordInFirstPara = aESel.nEndPara == 0 &&
2553 aFirstWordSel.Max().GetIndex() <= aSel.Max().GetIndex() &&
2554 aSel.Max().GetIndex() <= aSecondWordSel.Min().GetIndex();
2555
2556 if (bIsFirstWordInFirstPara)
2557 pAutoCorrect->SetAutoCorrFlag( ACFlags::CapitalStartSentence, IsFirstWordCapitalization() );
2558 }
2559
2560 ContentNode* pNode = aSel.Max().GetNode();
2561 const sal_Int32 nIndex = aSel.Max().GetIndex();
2562 EdtAutoCorrDoc aAuto(pEditEngine, pNode, nIndex, c);
2563 // FIXME: this _must_ be called with reference to the actual node text!
2564 OUString const& rNodeString(pNode->GetString());
2565 pAutoCorrect->DoAutoCorrect(
2566 aAuto, rNodeString, nIndex, c, !bOverwrite, mbNbspRunNext, pFrameWin );
2567 aSel.Max().SetIndex( aAuto.GetCursor() );
2568
2569 // #i78661 since the SvxAutoCorrect object used here is
2570 // shared we need to reset the value to its original state.
2571 pAutoCorrect->SetAutoCorrFlag( ACFlags::CapitalStartSentence, bOldCapitalStartSentence );
2572 }
2573 return aSel.Max();
2574}
2575
2576
2577EditPaM ImpEditEngine::InsertTextUserInput( const EditSelection& rCurSel,
2578 sal_Unicode c, bool bOverwrite )
2579{
2580 OSL_ENSURE( c != '\t', "Tab for InsertText ?" )do { if (true && (!(c != '\t'))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "2580" ": "), "%s", "Tab for InsertText ?"); } } while (
false)
;
2581 OSL_ENSURE( c != '\n', "Word wrapping for InsertText ?")do { if (true && (!(c != '\n'))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "2581" ": "), "%s", "Word wrapping for InsertText ?"); }
} while (false)
;
2582
2583 EditPaM aPaM( rCurSel.Min() );
2584
2585 bool bDoOverwrite = bOverwrite &&
2586 ( aPaM.GetIndex() < aPaM.GetNode()->Len() );
2587
2588 bool bUndoAction = ( rCurSel.HasRange() || bDoOverwrite );
2589
2590 if ( bUndoAction )
2591 UndoActionStart( EDITUNDO_INSERT111 );
2592
2593 if ( rCurSel.HasRange() )
2594 {
2595 aPaM = ImpDeleteSelection( rCurSel );
2596 }
2597 else if ( bDoOverwrite )
2598 {
2599 // If selected, then do not also overwrite a character!
2600 EditSelection aTmpSel( aPaM );
2601 aTmpSel.Max().SetIndex( aTmpSel.Max().GetIndex()+1 );
2602 OSL_ENSURE( !aTmpSel.DbgIsBuggy( aEditDoc ), "Overwrite: Wrong selection! ")do { if (true && (!(!aTmpSel.DbgIsBuggy( aEditDoc )))
) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "2602" ": "), "%s", "Overwrite: Wrong selection! "); } }
while (false)
;
2603 ImpDeleteSelection( aTmpSel );
2604 }
2605
2606 if ( aPaM.GetNode()->Len() < MAXCHARSINPARA0x3FFF-16 )
2607 {
2608 if (IsInputSequenceCheckingRequired( c, rCurSel ))
2609 {
2610 uno::Reference < i18n::XExtendedInputSequenceChecker > _xISC( ImplGetInputSequenceChecker() );
2611 if (!pCTLOptions)
2612 pCTLOptions.reset( new SvtCTLOptions );
2613
2614 if (_xISC)
2615 {
2616 const sal_Int32 nTmpPos = aPaM.GetIndex();
2617 sal_Int16 nCheckMode = pCTLOptions->IsCTLSequenceCheckingRestricted() ?
2618 i18n::InputSequenceCheckMode::STRICT : i18n::InputSequenceCheckMode::BASIC;
2619
2620 // the text that needs to be checked is only the one
2621 // before the current cursor position
2622 const OUString aOldText( aPaM.GetNode()->Copy(0, nTmpPos) );
2623 OUString aNewText( aOldText );
2624 if (pCTLOptions->IsCTLSequenceCheckingTypeAndReplace())
2625 {
2626 _xISC->correctInputSequence(aNewText, nTmpPos - 1, c, nCheckMode);
2627
2628 // find position of first character that has changed
2629 sal_Int32 nOldLen = aOldText.getLength();
2630 sal_Int32 nNewLen = aNewText.getLength();
2631 const sal_Unicode *pOldTxt = aOldText.getStr();
2632 const sal_Unicode *pNewTxt = aNewText.getStr();
2633 sal_Int32 nChgPos = 0;
2634 while ( nChgPos < nOldLen && nChgPos < nNewLen &&
2635 pOldTxt[nChgPos] == pNewTxt[nChgPos] )
2636 ++nChgPos;
2637
2638 const OUString aChgText( aNewText.copy( nChgPos ) );
2639
2640 // select text from first pos to be changed to current pos
2641 EditSelection aSel( EditPaM( aPaM.GetNode(), nChgPos ), aPaM );
2642
2643 if (!aChgText.isEmpty())
2644 return InsertText( aSel, aChgText ); // implicitly handles undo
2645 else
2646 return aPaM;
2647 }
2648 else
2649 {
2650 // should the character be ignored (i.e. not get inserted) ?
2651 if (!_xISC->checkInputSequence( aOldText, nTmpPos - 1, c, nCheckMode ))
2652 return aPaM; // nothing to be done -> no need for undo
2653 }
2654 }
2655
2656 // at this point now we will insert the character 'normally' some lines below...
2657 }
2658
2659 if ( IsUndoEnabled() && !IsInUndo() )
2660 {
2661 std::unique_ptr<EditUndoInsertChars> pNewUndo(new EditUndoInsertChars(pEditEngine, CreateEPaM(aPaM), OUString(c)));
2662 bool bTryMerge = !bDoOverwrite && ( c != ' ' );
2663 InsertUndo( std::move(pNewUndo), bTryMerge );
2664 }
2665
2666 aEditDoc.InsertText( aPaM, OUString(c) );
2667 ParaPortion* pPortion = FindParaPortion( aPaM.GetNode() );
2668 OSL_ENSURE( pPortion, "Blind Portion in InsertText" )do { if (true && (!(pPortion))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "2668" ": "), "%s", "Blind Portion in InsertText"); } } while
(false)
;
2669 pPortion->MarkInvalid( aPaM.GetIndex(), 1 );
2670 aPaM.SetIndex( aPaM.GetIndex()+1 ); // does not do EditDoc-Method anymore
2671 }
2672
2673 TextModified();
2674
2675 if ( bUndoAction )
2676 UndoActionEnd();
2677
2678 return aPaM;
2679}
2680
2681EditPaM ImpEditEngine::ImpInsertText(const EditSelection& aCurSel, const OUString& rStr)
2682{
2683 UndoActionStart( EDITUNDO_INSERT111 );
2684
2685 EditPaM aPaM;
2686 if ( aCurSel.HasRange() )
2687 aPaM = ImpDeleteSelection( aCurSel );
2688 else
2689 aPaM = aCurSel.Max();
2690
2691 EditPaM aCurPaM( aPaM ); // for the Invalidate
2692
2693 // get word boundaries in order to clear possible WrongList entries
2694 // and invalidate all the necessary text (everything after and including the
2695 // start of the word)
2696 // #i107201# do the expensive SelectWord call only if online spelling is active
2697 EditSelection aCurWord;
2698 if ( GetStatus().DoOnlineSpelling() )
2699 aCurWord = SelectWord( aCurPaM, i18n::WordType::DICTIONARY_WORD );
2700
2701 OUString aText(convertLineEnd(rStr, LINEEND_LF));
2702 if (utl::ConfigManager::IsFuzzing()) //tab expansion performance in editeng is appalling
2703 aText = aText.replaceAll("\t","-");
2704 SfxVoidItem aTabItem( EE_FEATURE_TAB );
2705
2706 // Converts to linesep = \n
2707 // Token LINE_SEP query,
2708 // since the MAC-Compiler makes something else from \n !
2709
2710 sal_Int32 nStart = 0;
2711 while ( nStart < aText.getLength() )
2712 {
2713 sal_Int32 nEnd = aText.indexOf( LINE_SEP'\x0A', nStart );
2714 if ( nEnd == -1 )
2715 nEnd = aText.getLength(); // not dereference!
2716
2717 // Start == End => empty line
2718 if ( nEnd > nStart )
2719 {
2720 OUString aLine = aText.copy( nStart, nEnd-nStart );
2721 sal_Int32 nExistingChars = aPaM.GetNode()->Len();
2722 sal_Int32 nChars = nExistingChars + aLine.getLength();
2723 if (nChars > MAXCHARSINPARA0x3FFF-16)
2724 {
2725 sal_Int32 nMaxNewChars = std::max<sal_Int32>(0, MAXCHARSINPARA0x3FFF-16 - nExistingChars);
2726 nEnd -= ( aLine.getLength() - nMaxNewChars ); // Then the characters end up in the next paragraph.
2727 aLine = aLine.copy( 0, nMaxNewChars ); // Delete the Rest...
2728 }
2729 if ( IsUndoEnabled() && !IsInUndo() )
2730 InsertUndo(std::make_unique<EditUndoInsertChars>(pEditEngine, CreateEPaM(aPaM), aLine));
2731 // Tabs ?
2732 if ( aLine.indexOf( '\t' ) == -1 )
2733 aPaM = aEditDoc.InsertText( aPaM, aLine );
2734 else
2735 {
2736 sal_Int32 nStart2 = 0;
2737 while ( nStart2 < aLine.getLength() )
2738 {
2739 sal_Int32 nEnd2 = aLine.indexOf( "\t", nStart2 );
2740 if ( nEnd2 == -1 )
2741 nEnd2 = aLine.getLength(); // not dereference!
2742
2743 if ( nEnd2 > nStart2 )
2744 aPaM = aEditDoc.InsertText( aPaM, aLine.copy( nStart2, nEnd2-nStart2 ) );
2745 if ( nEnd2 < aLine.getLength() )
2746 {
2747 aPaM = aEditDoc.InsertFeature( aPaM, aTabItem );
2748 }
2749 nStart2 = nEnd2+1;
2750 }
2751 }
2752 ParaPortion* pPortion = FindParaPortion( aPaM.GetNode() );
2753 OSL_ENSURE( pPortion, "Blind Portion in InsertText" )do { if (true && (!(pPortion))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "2753" ": "), "%s", "Blind Portion in InsertText"); } } while
(false)
;
2754
2755 if ( GetStatus().DoOnlineSpelling() )
2756 {
2757 // now remove the Wrongs (red spell check marks) from both words...
2758 WrongList *pWrongs = aCurPaM.GetNode()->GetWrongList();
2759 if (pWrongs && !pWrongs->empty())
2760 pWrongs->ClearWrongs( aCurWord.Min().GetIndex(), aPaM.GetIndex(), aPaM.GetNode() );
2761 // ... and mark both words as 'to be checked again'
2762 pPortion->MarkInvalid( aCurWord.Min().GetIndex(), aLine.getLength() );
2763 }
2764 else
2765 pPortion->MarkInvalid( aCurPaM.GetIndex(), aLine.getLength() );
2766 }
2767 if ( nEnd < aText.getLength() )
2768 aPaM = ImpInsertParaBreak( aPaM );
2769
2770 nStart = nEnd+1;
2771 }
2772
2773 UndoActionEnd();
2774
2775 TextModified();
2776 return aPaM;
2777}
2778
2779EditPaM ImpEditEngine::ImpFastInsertText( EditPaM aPaM, const OUString& rStr )
2780{
2781 OSL_ENSURE( rStr.indexOf( 0x0A ) == -1, "FastInsertText: Newline not allowed! ")do { if (true && (!(rStr.indexOf( 0x0A ) == -1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "2781" ": "), "%s", "FastInsertText: Newline not allowed! "
); } } while (false)
;
2782 OSL_ENSURE( rStr.indexOf( 0x0D ) == -1, "FastInsertText: Newline not allowed! ")do { if (true && (!(rStr.indexOf( 0x0D ) == -1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "2782" ": "), "%s", "FastInsertText: Newline not allowed! "
); } } while (false)
;
2783 OSL_ENSURE( rStr.indexOf( '\t' ) == -1, "FastInsertText: Newline not allowed! ")do { if (true && (!(rStr.indexOf( '\t' ) == -1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "2783" ": "), "%s", "FastInsertText: Newline not allowed! "
); } } while (false)
;
2784
2785 if ( ( aPaM.GetNode()->Len() + rStr.getLength() ) < MAXCHARSINPARA0x3FFF-16 )
2786 {
2787 if ( IsUndoEnabled() && !IsInUndo() )
2788 InsertUndo(std::make_unique<EditUndoInsertChars>(pEditEngine, CreateEPaM(aPaM), rStr));
2789
2790 aPaM = aEditDoc.InsertText( aPaM, rStr );
2791 TextModified();
2792 }
2793 else
2794 {
2795 aPaM = ImpInsertText( aPaM, rStr );
2796 }
2797
2798 return aPaM;
2799}
2800
2801EditPaM ImpEditEngine::ImpInsertFeature(const EditSelection& rCurSel, const SfxPoolItem& rItem)
2802{
2803 EditPaM aPaM;
2804 if ( rCurSel.HasRange() )
2805 aPaM = ImpDeleteSelection( rCurSel );
2806 else
2807 aPaM = rCurSel.Max();
2808
2809 if ( aPaM.GetIndex() >= SAL_MAX_INT32((sal_Int32) 0x7FFFFFFF)-1 )
2810 return aPaM;
2811
2812 if ( IsUndoEnabled() && !IsInUndo() )
2813 InsertUndo(std::make_unique<EditUndoInsertFeature>(pEditEngine, CreateEPaM(aPaM), rItem));
2814 aPaM = aEditDoc.InsertFeature( aPaM, rItem );
2815 UpdateFields();
2816
2817 ParaPortion* pPortion = FindParaPortion( aPaM.GetNode() );
2818 OSL_ENSURE( pPortion, "Blind Portion in InsertFeature" )do { if (true && (!(pPortion))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "2818" ": "), "%s", "Blind Portion in InsertFeature"); }
} while (false)
;
2819 pPortion->MarkInvalid( aPaM.GetIndex()-1, 1 );
2820
2821 TextModified();
2822
2823 return aPaM;
2824}
2825
2826EditPaM ImpEditEngine::ImpInsertParaBreak( const EditSelection& rCurSel )
2827{
2828 EditPaM aPaM;
2829 if ( rCurSel.HasRange() )
2830 aPaM = ImpDeleteSelection( rCurSel );
2831 else
2832 aPaM = rCurSel.Max();
2833
2834 return ImpInsertParaBreak( aPaM );
2835}
2836
2837EditPaM ImpEditEngine::ImpInsertParaBreak( EditPaM& rPaM, bool bKeepEndingAttribs )
2838{
2839 if ( aEditDoc.Count() >= EE_PARA_MAX_COUNT((sal_Int32) 0x7FFFFFFF) )
2840 {
2841 SAL_WARN( "editeng", "ImpEditEngine::ImpInsertParaBreak - can't process more than "do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "editeng")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case
SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "ImpEditEngine::ImpInsertParaBreak - can't process more than "
<< ((sal_Int32) 0x7FFFFFFF) << " paragraphs!") ==
1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("editeng"
), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "2842" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "ImpEditEngine::ImpInsertParaBreak - can't process more than "
<< ((sal_Int32) 0x7FFFFFFF) << " paragraphs!"), 0
); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "ImpEditEngine::ImpInsertParaBreak - can't process more than "
<< ((sal_Int32) 0x7FFFFFFF) << " paragraphs!"; ::
sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("editeng"),
("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "2842" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "ImpEditEngine::ImpInsertParaBreak - can't process more than "
<< ((sal_Int32) 0x7FFFFFFF) << " paragraphs!") ==
1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("editeng"
), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "2842" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "ImpEditEngine::ImpInsertParaBreak - can't process more than "
<< ((sal_Int32) 0x7FFFFFFF) << " paragraphs!"), 0
); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "ImpEditEngine::ImpInsertParaBreak - can't process more than "
<< ((sal_Int32) 0x7FFFFFFF) << " paragraphs!"; ::
sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("editeng"),
("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "2842" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
2842 << EE_PARA_MAX_COUNT << " paragraphs!")do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "editeng")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case
SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "ImpEditEngine::ImpInsertParaBreak - can't process more than "
<< ((sal_Int32) 0x7FFFFFFF) << " paragraphs!") ==
1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("editeng"
), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "2842" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "ImpEditEngine::ImpInsertParaBreak - can't process more than "
<< ((sal_Int32) 0x7FFFFFFF) << " paragraphs!"), 0
); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "ImpEditEngine::ImpInsertParaBreak - can't process more than "
<< ((sal_Int32) 0x7FFFFFFF) << " paragraphs!"; ::
sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("editeng"),
("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "2842" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "ImpEditEngine::ImpInsertParaBreak - can't process more than "
<< ((sal_Int32) 0x7FFFFFFF) << " paragraphs!") ==
1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("editeng"
), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "2842" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "ImpEditEngine::ImpInsertParaBreak - can't process more than "
<< ((sal_Int32) 0x7FFFFFFF) << " paragraphs!"), 0
); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "ImpEditEngine::ImpInsertParaBreak - can't process more than "
<< ((sal_Int32) 0x7FFFFFFF) << " paragraphs!"; ::
sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("editeng"),
("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "2842" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
2843 return rPaM;
2844 }
2845
2846 if ( IsUndoEnabled() && !IsInUndo() )
2847 InsertUndo(std::make_unique<EditUndoSplitPara>(pEditEngine, aEditDoc.GetPos(rPaM.GetNode()), rPaM.GetIndex()));
2848
2849 EditPaM aPaM( aEditDoc.InsertParaBreak( rPaM, bKeepEndingAttribs ) );
2850
2851 if ( GetStatus().DoOnlineSpelling() )
2852 {
2853 sal_Int32 nEnd = rPaM.GetNode()->Len();
2854 aPaM.GetNode()->CreateWrongList();
2855 WrongList* pLWrongs = rPaM.GetNode()->GetWrongList();
2856 WrongList* pRWrongs = aPaM.GetNode()->GetWrongList();
2857 // take over misspelled words:
2858 for (auto & elem : *pLWrongs)
2859 {
2860 // Correct only if really a word gets overlapped in the process of
2861 // Spell checking
2862 if (elem.mnStart > o3tl::make_unsigned(nEnd))
2863 {
2864 pRWrongs->push_back(elem);
2865 editeng::MisspellRange& rRWrong = pRWrongs->back();
2866 rRWrong.mnStart = rRWrong.mnStart - nEnd;
2867 rRWrong.mnEnd = rRWrong.mnEnd - nEnd;
2868 }
2869 else if (elem.mnStart < o3tl::make_unsigned(nEnd) && elem.mnEnd > o3tl::make_unsigned(nEnd))
2870 elem.mnEnd = nEnd;
2871 }
2872 sal_Int32 nInv = nEnd ? nEnd-1 : nEnd;
2873 if ( nEnd )
2874 pLWrongs->SetInvalidRange(nInv, nEnd);
2875 else
2876 pLWrongs->SetValid();
2877 pRWrongs->SetValid();
2878 pRWrongs->SetInvalidRange(0, 1); // Only test the first word
2879 }
2880
2881 ParaPortion* pPortion = FindParaPortion( rPaM.GetNode() );
2882 OSL_ENSURE( pPortion, "Blind Portion in ImpInsertParaBreak" )do { if (true && (!(pPortion))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "2882" ": "), "%s", "Blind Portion in ImpInsertParaBreak"
); } } while (false)
;
2883 pPortion->MarkInvalid( rPaM.GetIndex(), 0 );
2884
2885 // Optimization: Do not place unnecessarily many getPos to Listen!
2886 // Here, as in undo, but also in all other methods.
2887 sal_Int32 nPos = GetParaPortions().GetPos( pPortion );
2888 ParaPortion* pNewPortion = new ParaPortion( aPaM.GetNode() );
2889 GetParaPortions().Insert(nPos+1, std::unique_ptr<ParaPortion>(pNewPortion));
2890 ParaAttribsChanged( pNewPortion->GetNode() );
2891 if ( IsCallParaInsertedOrDeleted() )
2892 GetEditEnginePtr()->ParagraphInserted( nPos+1 );
2893
2894 CursorMoved( rPaM.GetNode() ); // if empty Attributes have emerged.
2895 TextModified();
2896 return aPaM;
2897}
2898
2899EditPaM ImpEditEngine::ImpFastInsertParagraph( sal_Int32 nPara )
2900{
2901 if ( IsUndoEnabled() && !IsInUndo() )
2902 {
2903 if ( nPara )
2904 {
2905 OSL_ENSURE( aEditDoc.GetObject( nPara-1 ), "FastInsertParagraph: Prev does not exist" )do { if (true && (!(aEditDoc.GetObject( nPara-1 )))) {
sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "2905" ": "), "%s", "FastInsertParagraph: Prev does not exist"
); } } while (false)
;
2906 InsertUndo(std::make_unique<EditUndoSplitPara>(pEditEngine, nPara-1, aEditDoc.GetObject( nPara-1 )->Len()));
2907 }
2908 else
2909 InsertUndo(std::make_unique<EditUndoSplitPara>(pEditEngine, 0, 0));
2910 }
2911
2912 ContentNode* pNode = new ContentNode( aEditDoc.GetItemPool() );
2913 // If flat mode, then later no Font is set:
2914 pNode->GetCharAttribs().GetDefFont() = aEditDoc.GetDefFont();
2915
2916 if ( GetStatus().DoOnlineSpelling() )
2917 pNode->CreateWrongList();
2918
2919 aEditDoc.Insert(nPara, pNode);
2920
2921 GetParaPortions().Insert(nPara, std::make_unique<ParaPortion>( pNode ));
2922 if ( IsCallParaInsertedOrDeleted() )
2923 GetEditEnginePtr()->ParagraphInserted( nPara );
2924
2925 return EditPaM( pNode, 0 );
2926}
2927
2928EditPaM ImpEditEngine::InsertParaBreak(const EditSelection& rCurSel)
2929{
2930 EditPaM aPaM(ImpInsertParaBreak(rCurSel));
2931 if ( aStatus.DoAutoIndenting() )
2932 {
2933 sal_Int32 nPara = aEditDoc.GetPos( aPaM.GetNode() );
2934 OSL_ENSURE( nPara > 0, "AutoIndenting: Error!" )do { if (true && (!(nPara > 0))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "2934" ": "), "%s", "AutoIndenting: Error!"); } } while (
false)
;
2935 const OUString aPrevParaText( GetEditDoc().GetParaAsString( nPara-1 ) );
2936 sal_Int32 n = 0;
2937 while ( ( n < aPrevParaText.getLength() ) &&
2938 ( ( aPrevParaText[n] == ' ' ) || ( aPrevParaText[n] == '\t' ) ) )
2939 {
2940 if ( aPrevParaText[n] == '\t' )
2941 aPaM = ImpInsertFeature( aPaM, SfxVoidItem( EE_FEATURE_TAB ) );
2942 else
2943 aPaM = ImpInsertText( aPaM, OUString(aPrevParaText[n]) );
2944 n++;
2945 }
2946
2947 }
2948 return aPaM;
2949}
2950
2951EditPaM ImpEditEngine::InsertTab(const EditSelection& rCurSel)
2952{
2953 EditPaM aPaM( ImpInsertFeature(rCurSel, SfxVoidItem(EE_FEATURE_TAB )));
2954 return aPaM;
2955}
2956
2957EditPaM ImpEditEngine::InsertField(const EditSelection& rCurSel, const SvxFieldItem& rFld)
2958{
2959 return ImpInsertFeature(rCurSel, rFld);
2960}
2961
2962bool ImpEditEngine::UpdateFields()
2963{
2964 bool bChanges = false;
2965 sal_Int32 nParas = GetEditDoc().Count();
2966 for ( sal_Int32 nPara = 0; nPara < nParas; nPara++ )
2967 {
2968 bool bChangesInPara = false;
2969 ContentNode* pNode = GetEditDoc().GetObject( nPara );
2970 OSL_ENSURE( pNode, "NULL-Pointer in Doc" )do { if (true && (!(pNode))) { sal_detail_logFormat((
SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "2970" ": "), "%s", "NULL-Pointer in Doc"); } } while (false
)
;
2971 CharAttribList::AttribsType& rAttribs = pNode->GetCharAttribs().GetAttribs();
2972 for (std::unique_ptr<EditCharAttrib> & rAttrib : rAttribs)
2973 {
2974 EditCharAttrib& rAttr = *rAttrib;
2975 if (rAttr.Which() == EE_FEATURE_FIELD)
2976 {
2977 EditCharAttribField& rField = static_cast<EditCharAttribField&>(rAttr);
2978 std::unique_ptr<EditCharAttribField> pCurrent(new EditCharAttribField(rField));
2979 rField.Reset();
2980
2981 if (!aStatus.MarkNonUrlFields() && !aStatus.MarkUrlFields())
2982 ; // nothing marked
2983 else if (aStatus.MarkNonUrlFields() && aStatus.MarkUrlFields())
2984 rField.GetFieldColor() = GetColorConfig().GetColorValue( svtools::WRITERFIELDSHADINGS ).nColor;
2985 else
2986 {
2987 bool bURL = false;
2988 if (const SvxFieldItem* pFieldItem = dynamic_cast<const SvxFieldItem*>(rField.GetItem()))
2989 {
2990 if (const SvxFieldData* pFieldData = pFieldItem->GetField())
2991 bURL = (dynamic_cast<const SvxURLField* >(pFieldData) != nullptr);
2992 }
2993 if ((bURL && aStatus.MarkUrlFields()) || (!bURL && aStatus.MarkNonUrlFields()))
2994 rField.GetFieldColor() = GetColorConfig().GetColorValue( svtools::WRITERFIELDSHADINGS ).nColor;
2995 }
2996
2997 const OUString aFldValue =
2998 GetEditEnginePtr()->CalcFieldValue(
2999 static_cast<const SvxFieldItem&>(*rField.GetItem()),
3000 nPara, rField.GetStart(), rField.GetTextColor(), rField.GetFieldColor());
3001
3002 rField.SetFieldValue(aFldValue);
3003 if (rField != *pCurrent)
3004 {
3005 bChanges = true;
3006 bChangesInPara = true;
3007 }
3008 }
3009 }
3010 if ( bChangesInPara )
3011 {
3012 // If possible be more precise when invalidate.
3013 ParaPortion* pPortion = GetParaPortions()[nPara];
3014 OSL_ENSURE( pPortion, "NULL-Pointer in Doc" )do { if (true && (!(pPortion))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "3014" ": "), "%s", "NULL-Pointer in Doc"); } } while (false
)
;
3015 pPortion->MarkSelectionInvalid( 0 );
3016 }
3017 }
3018 return bChanges;
3019}
3020
3021EditPaM ImpEditEngine::InsertLineBreak(const EditSelection& aCurSel)
3022{
3023 EditPaM aPaM( ImpInsertFeature( aCurSel, SfxVoidItem( EE_FEATURE_LINEBR ) ) );
3024 return aPaM;
3025}
3026
3027
3028// Helper functions
3029
3030tools::Rectangle ImpEditEngine::PaMtoEditCursor( EditPaM aPaM, GetCursorFlags nFlags )
3031{
3032 OSL_ENSURE( GetUpdateMode(), "Must not be reached when Update=FALSE: PaMtoEditCursor" )do { if (true && (!(GetUpdateMode()))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "3032" ": "), "%s", "Must not be reached when Update=FALSE: PaMtoEditCursor"
); } } while (false)
;
3033
3034 tools::Rectangle aEditCursor;
3035 long nY = 0;
3036 for ( sal_Int32 nPortion = 0; nPortion < GetParaPortions().Count(); nPortion++ )
3037 {
3038 ParaPortion* pPortion = GetParaPortions()[nPortion];
3039 ContentNode* pNode = pPortion->GetNode();
3040 OSL_ENSURE( pNode, "Invalid Node in Portion!" )do { if (true && (!(pNode))) { sal_detail_logFormat((
SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "3040" ": "), "%s", "Invalid Node in Portion!"); } } while
(false)
;
3041 if ( pNode != aPaM.GetNode() )
3042 {
3043 nY += pPortion->GetHeight();
3044 }
3045 else
3046 {
3047 aEditCursor = GetEditCursor( pPortion, aPaM.GetIndex(), nFlags );
3048 aEditCursor.AdjustTop(nY );
3049 aEditCursor.AdjustBottom(nY );
3050 return aEditCursor;
3051 }
3052 }
3053 OSL_FAIL( "Portion not found!" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "3053" ": "), "%s", "Portion not found!"); } } while (false
)
;
3054 return aEditCursor;
3055}
3056
3057EditPaM ImpEditEngine::GetPaM( Point aDocPos, bool bSmart )
3058{
3059 OSL_ENSURE( GetUpdateMode(), "Must not be reached when Update=FALSE: GetPaM" )do { if (true && (!(GetUpdateMode()))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "3059" ": "), "%s", "Must not be reached when Update=FALSE: GetPaM"
); } } while (false)
;
3060
3061 long nY = 0;
3062 EditPaM aPaM;
3063 sal_Int32 nPortion;
3064 for ( nPortion = 0; nPortion < GetParaPortions().Count(); nPortion++ )
3065 {
3066 ParaPortion* pPortion = GetParaPortions()[nPortion];
3067 const long nTmpHeight = pPortion->GetHeight(); // should also be correct for !bVisible!
3068 nY += nTmpHeight;
3069 if ( nY > aDocPos.Y() )
3070 {
3071 nY -= nTmpHeight;
3072 aDocPos.AdjustY( -nY );
3073 // Skip invisible Portions:
3074 while ( pPortion && !pPortion->IsVisible() )
3075 {
3076 nPortion++;
3077 pPortion = GetParaPortions().SafeGetObject( nPortion );
3078 }
3079 SAL_WARN_IF(!pPortion, "editeng", "worrying lack of any visible paragraph")do { if (true && (!pPortion)) { switch (sal_detail_log_report
(::SAL_DETAIL_LOG_LEVEL_WARN, "editeng")) { case SAL_DETAIL_LOG_ACTION_IGNORE
: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail
::getResult( ::sal::detail::StreamStart() << "worrying lack of any visible paragraph"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("editeng"
), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "3079" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "worrying lack of any visible paragraph"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "worrying lack of any visible paragraph"; ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("editeng"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "3079" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "worrying lack of any visible paragraph") == 1) {
::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("editeng")
, ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "3079" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "worrying lack of any visible paragraph"
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "worrying lack of any visible paragraph"; ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("editeng"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "3079" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
3080 if (!pPortion)
3081 return aPaM;
3082 return GetPaM(pPortion, aDocPos, bSmart);
3083
3084 }
3085 }
3086 // Then search for the last visible:
3087 nPortion = GetParaPortions().Count()-1;
3088 while ( nPortion && !GetParaPortions()[nPortion]->IsVisible() )
3089 nPortion--;
3090
3091 OSL_ENSURE( GetParaPortions()[nPortion]->IsVisible(), "No visible paragraph found: GetPaM" )do { if (true && (!(GetParaPortions()[nPortion]->IsVisible
()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "3091" ": "), "%s", "No visible paragraph found: GetPaM"
); } } while (false)
;
3092 aPaM.SetNode( GetParaPortions()[nPortion]->GetNode() );
3093 aPaM.SetIndex( GetParaPortions()[nPortion]->GetNode()->Len() );
3094 return aPaM;
3095}
3096
3097sal_uInt32 ImpEditEngine::GetTextHeight() const
3098{
3099 OSL_ENSURE( GetUpdateMode(), "Should not be used for Update=FALSE: GetTextHeight" )do { if (true && (!(GetUpdateMode()))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "3099" ": "), "%s", "Should not be used for Update=FALSE: GetTextHeight"
); } } while (false)
;
3100 OSL_ENSURE( IsFormatted() || IsFormatting(), "GetTextHeight: Not formatted" )do { if (true && (!(IsFormatted() || IsFormatting()))
) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "3100" ": "), "%s", "GetTextHeight: Not formatted"); } }
while (false)
;
3101 return nCurTextHeight;
3102}
3103
3104sal_uInt32 ImpEditEngine::CalcTextWidth( bool bIgnoreExtraSpace )
3105{
3106 // If still not formatted and not in the process.
3107 // Will be brought in the formatting for AutoPageSize.
3108 if ( !IsFormatted() && !IsFormatting() )
3109 FormatDoc();
3110
3111 sal_uInt32 nMaxWidth = 0;
3112
3113 // Over all the paragraphs ...
3114
3115 sal_Int32 nParas = GetParaPortions().Count();
3116 for ( sal_Int32 nPara = 0; nPara < nParas; nPara++ )
3117 {
3118 nMaxWidth = std::max(nMaxWidth, CalcParaWidth(nPara, bIgnoreExtraSpace));
3119 }
3120
3121 return nMaxWidth;
3122}
3123
3124sal_uInt32 ImpEditEngine::CalcParaWidth( sal_Int32 nPara, bool bIgnoreExtraSpace )
3125{
3126 // If still not formatted and not in the process.
3127 // Will be brought in the formatting for AutoPageSize.
3128 if ( !IsFormatted() && !IsFormatting() )
3129 FormatDoc();
3130
3131 long nMaxWidth = 0;
3132
3133 // Over all the paragraphs ...
3134
3135 OSL_ENSURE( 0 <= nPara && nPara < GetParaPortions().Count(), "CalcParaWidth: Out of range" )do { if (true && (!(0 <= nPara && nPara <
GetParaPortions().Count()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "3135" ": "), "%s", "CalcParaWidth: Out of range"); } } while
(false)
;
3136 ParaPortion* pPortion = GetParaPortions()[nPara];
3137 if ( pPortion && pPortion->IsVisible() )
3138 {
3139 const SvxLRSpaceItem& rLRItem = GetLRSpaceItem( pPortion->GetNode() );
3140 sal_Int32 nSpaceBeforeAndMinLabelWidth = GetSpaceBeforeAndMinLabelWidth( pPortion->GetNode() );
3141
3142
3143 // On the lines of the paragraph ...
3144
3145 sal_Int32 nLines = pPortion->GetLines().Count();
3146 for ( sal_Int32 nLine = 0; nLine < nLines; nLine++ )
3147 {
3148 EditLine& rLine = pPortion->GetLines()[nLine];
3149 // nCurWidth = pLine->GetStartPosX();
3150 // For Center- or Right- alignment it depends on the paper
3151 // width, here not preferred. I general, it is best not leave it
3152 // to StartPosX, also the right indents have to be taken into
3153 // account!
3154 long nCurWidth = GetXValue( rLRItem.GetTextLeft() + nSpaceBeforeAndMinLabelWidth );
3155 if ( nLine == 0 )
3156 {
3157 long nFI = GetXValue( rLRItem.GetTextFirstLineOffset() );
3158 nCurWidth -= nFI;
3159 if ( pPortion->GetBulletX() > nCurWidth )
3160 {
3161 nCurWidth += nFI; // LI?
3162 if ( pPortion->GetBulletX() > nCurWidth )
3163 nCurWidth = pPortion->GetBulletX();
3164 }
3165 }
3166 nCurWidth += GetXValue( rLRItem.GetRight() );
3167 nCurWidth += CalcLineWidth( pPortion, &rLine, bIgnoreExtraSpace );
3168 if ( nCurWidth > nMaxWidth )
3169 {
3170 nMaxWidth = nCurWidth;
3171 }
3172 }
3173 }
3174
3175 nMaxWidth++; // widen it, because in CreateLines for >= is wrapped.
3176 return static_cast<sal_uInt32>(nMaxWidth);
3177}
3178
3179sal_uInt32 ImpEditEngine::CalcLineWidth( ParaPortion* pPortion, EditLine* pLine, bool bIgnoreExtraSpace )
3180{
3181 sal_Int32 nPara = GetEditDoc().GetPos( pPortion->GetNode() );
3182
3183 // #114278# Saving both layout mode and language (since I'm
3184 // potentially changing both)
3185 GetRefDevice()->Push( PushFlags::TEXTLAYOUTMODE|PushFlags::TEXTLANGUAGE );
3186
3187 ImplInitLayoutMode( GetRefDevice(), nPara, -1 );
3188
3189 SvxAdjust eJustification = GetJustification( nPara );
3190
3191 // Calculation of the width without the Indents ...
3192 sal_uInt32 nWidth = 0;
3193 sal_Int32 nPos = pLine->GetStart();
3194 for ( sal_Int32 nTP = pLine->GetStartPortion(); nTP <= pLine->GetEndPortion(); nTP++ )
3195 {
3196 const TextPortion& rTextPortion = pPortion->GetTextPortions()[nTP];
3197 switch ( rTextPortion.GetKind() )
3198 {
3199 case PortionKind::FIELD:
3200 case PortionKind::HYPHENATOR:
3201 case PortionKind::TAB:
3202 {
3203 nWidth += rTextPortion.GetSize().Width();
3204 }
3205 break;
3206 case PortionKind::TEXT:
3207 {
3208 if ( ( eJustification != SvxAdjust::Block ) || ( !bIgnoreExtraSpace ) )
3209 {
3210 nWidth += rTextPortion.GetSize().Width();
3211 }
3212 else
3213 {
3214 SvxFont aTmpFont( pPortion->GetNode()->GetCharAttribs().GetDefFont() );
3215 SeekCursor( pPortion->GetNode(), nPos+1, aTmpFont );
3216 aTmpFont.SetPhysFont( GetRefDevice() );
3217 ImplInitDigitMode(GetRefDevice(), aTmpFont.GetLanguage());
3218 nWidth += aTmpFont.QuickGetTextSize( GetRefDevice(), pPortion->GetNode()->GetString(), nPos, rTextPortion.GetLen() ).Width();
3219 }
3220 }
3221 break;
3222 case PortionKind::LINEBREAK: break;
3223 }
3224 nPos = nPos + rTextPortion.GetLen();
3225 }
3226
3227 GetRefDevice()->Pop();
3228
3229 return nWidth;
3230}
3231
3232sal_uInt32 ImpEditEngine::GetTextHeightNTP() const
3233{
3234 DBG_ASSERT( GetUpdateMode(), "Should not be used for Update=FALSE: GetTextHeight" )do { if (true && (!(GetUpdateMode()))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "3234" ": "), "%s", "Should not be used for Update=FALSE: GetTextHeight"
); } } while (false)
;
3235 DBG_ASSERT( IsFormatted() || IsFormatting(), "GetTextHeight: Not formatted" )do { if (true && (!(IsFormatted() || IsFormatting()))
) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"
), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "3235" ": "), "%s", "GetTextHeight: Not formatted"); } }
while (false)
;
3236 return nCurTextHeightNTP;
3237}
3238
3239sal_uInt32 ImpEditEngine::CalcTextHeight( sal_uInt32* pHeightNTP )
3240{
3241 OSL_ENSURE( GetUpdateMode(), "Should not be used when Update=FALSE: CalcTextHeight" )do { if (true && (!(GetUpdateMode()))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "3241" ": "), "%s", "Should not be used when Update=FALSE: CalcTextHeight"
); } } while (false)
;
3242 sal_uInt32 nY = 0;
3243 sal_uInt32 nPH;
3244 sal_uInt32 nEmptyHeight = 0;
3245 for ( sal_Int32 nPortion = 0; nPortion < GetParaPortions().Count(); nPortion++ ) {
3246 ParaPortion* pPortion = GetParaPortions()[nPortion];
3247 nPH = pPortion->GetHeight();
3248 nY += nPH;
3249 if( pHeightNTP ) {
3250 if ( pPortion->IsEmpty() )
3251 nEmptyHeight += nPH;
3252 else
3253 nEmptyHeight = 0;
3254 }
3255 }
3256
3257 if ( pHeightNTP )
3258 *pHeightNTP = nY - nEmptyHeight;
3259
3260 return nY;
3261}
3262
3263sal_Int32 ImpEditEngine::GetLineCount( sal_Int32 nParagraph ) const
3264{
3265 OSL_ENSURE( 0 <= nParagraph && nParagraph < GetParaPortions().Count(), "GetLineCount: Out of range" )do { if (true && (!(0 <= nParagraph && nParagraph
< GetParaPortions().Count()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "3265" ": "), "%s", "GetLineCount: Out of range"); } } while
(false)
;
3266 const ParaPortion* pPPortion = GetParaPortions().SafeGetObject( nParagraph );
3267 OSL_ENSURE( pPPortion, "Paragraph not found: GetLineCount" )do { if (true && (!(pPPortion))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "3267" ": "), "%s", "Paragraph not found: GetLineCount")
; } } while (false)
;
3268 if ( pPPortion )
3269 return pPPortion->GetLines().Count();
3270
3271 return -1;
3272}
3273
3274sal_Int32 ImpEditEngine::GetLineLen( sal_Int32 nParagraph, sal_Int32 nLine ) const
3275{
3276 OSL_ENSURE( 0 <= nParagraph && nParagraph < GetParaPortions().Count(), "GetLineLen: Out of range" )do { if (true && (!(0 <= nParagraph && nParagraph
< GetParaPortions().Count()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "3276" ": "), "%s", "GetLineLen: Out of range"); } } while
(false)
;
3277 const ParaPortion* pPPortion = GetParaPortions().SafeGetObject( nParagraph );
3278 OSL_ENSURE( pPPortion, "Paragraph not found: GetLineLen" )do { if (true && (!(pPPortion))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "3278" ": "), "%s", "Paragraph not found: GetLineLen"); }
} while (false)
;
3279 if ( pPPortion && ( nLine < pPPortion->GetLines().Count() ) )
3280 {
3281 const EditLine& rLine = pPPortion->GetLines()[nLine];
3282 return rLine.GetLen();
3283 }
3284
3285 return -1;
3286}
3287
3288void ImpEditEngine::GetLineBoundaries( /*out*/sal_Int32 &rStart, /*out*/sal_Int32 &rEnd, sal_Int32 nParagraph, sal_Int32 nLine ) const
3289{
3290 OSL_ENSURE( 0 <= nParagraph && nParagraph < GetParaPortions().Count(), "GetLineCount: Out of range" )do { if (true && (!(0 <= nParagraph && nParagraph
< GetParaPortions().Count()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "3290" ": "), "%s", "GetLineCount: Out of range"); } } while
(false)
;
3291 const ParaPortion* pPPortion = GetParaPortions().SafeGetObject( nParagraph );
3292 OSL_ENSURE( pPPortion, "Paragraph not found: GetLineBoundaries" )do { if (true && (!(pPPortion))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "3292" ": "), "%s", "Paragraph not found: GetLineBoundaries"
); } } while (false)
;
3293 rStart = rEnd = -1; // default values in case of error
3294 if ( pPPortion && ( nLine < pPPortion->GetLines().Count() ) )
3295 {
3296 const EditLine& rLine = pPPortion->GetLines()[nLine];
3297 rStart = rLine.GetStart();
3298 rEnd = rLine.GetEnd();
3299 }
3300}
3301
3302sal_Int32 ImpEditEngine::GetLineNumberAtIndex( sal_Int32 nPara, sal_Int32 nIndex ) const
3303{
3304 sal_Int32 nLineNo = -1;
3305 const ContentNode* pNode = GetEditDoc().GetObject( nPara );
3306 OSL_ENSURE( pNode, "GetLineNumberAtIndex: invalid paragraph index" )do { if (true && (!(pNode))) { sal_detail_logFormat((
SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "3306" ": "), "%s", "GetLineNumberAtIndex: invalid paragraph index"
); } } while (false)
;
3307 if (pNode)
3308 {
3309 // we explicitly allow for the index to point at the character right behind the text
3310 const bool bValidIndex = /*0 <= nIndex &&*/ nIndex <= pNode->Len();
3311 OSL_ENSURE( bValidIndex, "GetLineNumberAtIndex: invalid index" )do { if (true && (!(bValidIndex))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "3311" ": "), "%s", "GetLineNumberAtIndex: invalid index"
); } } while (false)
;
3312 const sal_Int32 nLineCount = GetLineCount( nPara );
3313 if (nIndex == pNode->Len())
3314 nLineNo = nLineCount > 0 ? nLineCount - 1 : 0;
3315 else if (bValidIndex) // nIndex < pNode->Len()
3316 {
3317 sal_Int32 nStart = -1, nEnd = -1;
3318 for (sal_Int32 i = 0; i < nLineCount && nLineNo == -1; ++i)
3319 {
3320 GetLineBoundaries( nStart, nEnd, nPara, i );
3321 if (nStart >= 0 && nStart <= nIndex && nEnd >= 0 && nIndex < nEnd)
3322 nLineNo = i;
3323 }
3324 }
3325 }
3326 return nLineNo;
3327}
3328
3329sal_uInt16 ImpEditEngine::GetLineHeight( sal_Int32 nParagraph, sal_Int32 nLine )
3330{
3331 OSL_ENSURE( 0 <= nParagraph && nParagraph < GetParaPortions().Count(), "GetLineCount: Out of range" )do { if (true && (!(0 <= nParagraph && nParagraph
< GetParaPortions().Count()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "3331" ": "), "%s", "GetLineCount: Out of range"); } } while
(false)
;
3332 ParaPortion* pPPortion = GetParaPortions().SafeGetObject( nParagraph );
3333 OSL_ENSURE( pPPortion, "Paragraph not found: GetLineHeight" )do { if (true && (!(pPPortion))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "3333" ": "), "%s", "Paragraph not found: GetLineHeight"
); } } while (false)
;
3334 if ( pPPortion && ( nLine < pPPortion->GetLines().Count() ) )
3335 {
3336 const EditLine& rLine = pPPortion->GetLines()[nLine];
3337 return rLine.GetHeight();
3338 }
3339
3340 return 0xFFFF;
3341}
3342
3343sal_uInt32 ImpEditEngine::GetParaHeight( sal_Int32 nParagraph )
3344{
3345 sal_uInt32 nHeight = 0;
3346
3347 ParaPortion* pPPortion = GetParaPortions().SafeGetObject( nParagraph );
3348 OSL_ENSURE( pPPortion, "Paragraph not found: GetParaHeight" )do { if (true && (!(pPPortion))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "3348" ": "), "%s", "Paragraph not found: GetParaHeight"
); } } while (false)
;
3349
3350 if ( pPPortion )
3351 nHeight = pPPortion->GetHeight();
3352
3353 return nHeight;
3354}
3355
3356void ImpEditEngine::UpdateSelections()
3357{
3358 // Check whether one of the selections is at a deleted node...
3359 // If the node is valid, the index has yet to be examined!
3360 for (EditView* pView : aEditViews)
3361 {
3362 EditSelection aCurSel( pView->pImpEditView->GetEditSelection() );
3363 bool bChanged = false;
3364 for (const std::unique_ptr<DeletedNodeInfo> & aDeletedNode : aDeletedNodes)
3365 {
3366 const DeletedNodeInfo& rInf = *aDeletedNode;
3367 if ( ( aCurSel.Min().GetNode() == rInf.GetNode() ) ||
3368 ( aCurSel.Max().GetNode() == rInf.GetNode() ) )
3369 {
3370 // Use ParaPortions, as now also hidden paragraphs have to be
3371 // taken into account!
3372 sal_Int32 nPara = rInf.GetPosition();
3373 if (!GetParaPortions().SafeGetObject(nPara)) // Last paragraph
3374 {
3375 nPara = GetParaPortions().Count()-1;
3376 }
3377 assert(GetParaPortions()[nPara] && "Empty Document in UpdateSelections ?")(static_cast <bool> (GetParaPortions()[nPara] &&
"Empty Document in UpdateSelections ?") ? void (0) : __assert_fail
("GetParaPortions()[nPara] && \"Empty Document in UpdateSelections ?\""
, "/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
, 3377, __extension__ __PRETTY_FUNCTION__))
;
3378 // Do not end up from a hidden paragraph:
3379 sal_Int32 nCurPara = nPara;
3380 sal_Int32 nLastPara = GetParaPortions().Count()-1;
3381 while ( nPara <= nLastPara && !GetParaPortions()[nPara]->IsVisible() )
3382 nPara++;
3383 if ( nPara > nLastPara ) // then also backwards ...
3384 {
3385 nPara = nCurPara;
3386 while ( nPara && !GetParaPortions()[nPara]->IsVisible() )
3387 nPara--;
3388 }
3389 OSL_ENSURE( GetParaPortions()[nPara]->IsVisible(), "No visible paragraph found: UpdateSelections" )do { if (true && (!(GetParaPortions()[nPara]->IsVisible
()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "3389" ": "), "%s", "No visible paragraph found: UpdateSelections"
); } } while (false)
;
3390
3391 ParaPortion* pParaPortion = GetParaPortions()[nPara];
3392 EditSelection aTmpSelection( EditPaM( pParaPortion->GetNode(), 0 ) );
3393 pView->pImpEditView->SetEditSelection( aTmpSelection );
3394 bChanged=true;
3395 break; // for loop
3396 }
3397 }
3398 if ( !bChanged )
3399 {
3400 // Check Index if node shrunk.
3401 if ( aCurSel.Min().GetIndex() > aCurSel.Min().GetNode()->Len() )
3402 {
3403 aCurSel.Min().SetIndex( aCurSel.Min().GetNode()->Len() );
3404 pView->pImpEditView->SetEditSelection( aCurSel );
3405 }
3406 if ( aCurSel.Max().GetIndex() > aCurSel.Max().GetNode()->Len() )
3407 {
3408 aCurSel.Max().SetIndex( aCurSel.Max().GetNode()->Len() );
3409 pView->pImpEditView->SetEditSelection( aCurSel );
3410 }
3411 }
3412 }
3413 aDeletedNodes.clear();
3414}
3415
3416EditSelection ImpEditEngine::ConvertSelection(
3417 sal_Int32 nStartPara, sal_Int32 nStartPos, sal_Int32 nEndPara, sal_Int32 nEndPos )
3418{
3419 EditSelection aNewSelection;
3420
3421 // Start...
3422 ContentNode* pNode = aEditDoc.GetObject( nStartPara );
3423 sal_Int32 nIndex = nStartPos;
3424 if ( !pNode )
3425 {
3426 pNode = aEditDoc[ aEditDoc.Count()-1 ];
3427 nIndex = pNode->Len();
3428 }
3429 else if ( nIndex > pNode->Len() )
3430 nIndex = pNode->Len();
3431
3432 aNewSelection.Min().SetNode( pNode );
3433 aNewSelection.Min().SetIndex( nIndex );
3434
3435 // End...
3436 pNode = aEditDoc.GetObject( nEndPara );
3437 nIndex = nEndPos;
3438 if ( !pNode )
3439 {
3440 pNode = aEditDoc[ aEditDoc.Count()-1 ];
3441 nIndex = pNode->Len();
3442 }
3443 else if ( nIndex > pNode->Len() )
3444 nIndex = pNode->Len();
3445
3446 aNewSelection.Max().SetNode( pNode );
3447 aNewSelection.Max().SetIndex( nIndex );
3448
3449 return aNewSelection;
3450}
3451
3452void ImpEditEngine::SetActiveView( EditView* pView )
3453{
3454 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
3455 // Actually, now bHasVisSel and HideSelection would be necessary !!!
3456
3457 if ( pView == pActiveView )
3458 return;
3459
3460 if ( pActiveView && pActiveView->HasSelection() )
3461 pActiveView->pImpEditView->DrawSelectionXOR();
3462
3463 pActiveView = pView;
3464
3465 if ( pActiveView && pActiveView->HasSelection() )
3466 pActiveView->pImpEditView->DrawSelectionXOR();
3467
3468 // NN: Quick fix for #78668#:
3469 // When editing of a cell in Calc is ended, the edit engine is not deleted,
3470 // only the edit views are removed. If mpIMEInfos is still set in that case,
3471 // mpIMEInfos->aPos points to an invalid selection.
3472 // -> reset mpIMEInfos now
3473 // (probably something like this is necessary whenever the content is modified
3474 // from the outside)
3475
3476 if ( !pView && mpIMEInfos )
3477 {
3478 mpIMEInfos.reset();
3479 }
3480}
3481
3482uno::Reference< datatransfer::XTransferable > ImpEditEngine::CreateTransferable( const EditSelection& rSelection )
3483{
3484 EditSelection aSelection( rSelection );
3485 aSelection.Adjust( GetEditDoc() );
3486
3487 EditDataObject* pDataObj = new EditDataObject;
3488 uno::Reference< datatransfer::XTransferable > xDataObj = pDataObj;
3489
3490 pDataObj->GetString() = convertLineEnd(GetSelected(aSelection), GetSystemLineEnd()); // System specific
3491
3492 WriteRTF( pDataObj->GetRTFStream(), aSelection );
3493 pDataObj->GetRTFStream().Seek( 0 );
3494
3495 WriteXML( pDataObj->GetODFStream(), aSelection );
3496 pDataObj->GetODFStream().Seek( 0 );
3497
3498 //Dumping the ODFStream to a XML file for testing purpose
3499 /*
3500 std::filebuf afilebuf;
3501 afilebuf.open ("gsoc17_clipboard_test.xml",std::ios::out);
3502 std::ostream os(&afilebuf);
3503 os.write((const char*)(pDataObj->GetODFStream().GetData()), pDataObj->GetODFStream().remainingSize());
3504 afilebuf.close();
3505 */
3506 //dumping ends
3507
3508 if ( ( aSelection.Min().GetNode() == aSelection.Max().GetNode() )
3509 && ( aSelection.Max().GetIndex() == (aSelection.Min().GetIndex()+1) ) )
3510 {
3511 const EditCharAttrib* pAttr = aSelection.Min().GetNode()->GetCharAttribs().
3512 FindFeature( aSelection.Min().GetIndex() );
3513 if ( pAttr &&
3514 ( pAttr->GetStart() == aSelection.Min().GetIndex() ) &&
3515 ( pAttr->Which() == EE_FEATURE_FIELD ) )
3516 {
3517 const SvxFieldItem* pField = static_cast<const SvxFieldItem*>(pAttr->GetItem());
3518 const SvxFieldData* pFld = pField->GetField();
3519 if ( auto pUrlField = dynamic_cast<const SvxURLField* >(pFld) )
3520 {
3521 // Office-Bookmark
3522 pDataObj->GetURL() = pUrlField->GetURL();
3523 }
3524 }
3525 }
3526
3527 return xDataObj;
3528}
3529
3530EditSelection ImpEditEngine::PasteText( uno::Reference< datatransfer::XTransferable > const & rxDataObj, const OUString& rBaseURL, const EditPaM& rPaM, bool bUseSpecial )
3531{
3532 EditSelection aNewSelection( rPaM );
3533
3534 if ( !rxDataObj.is() )
3535 return aNewSelection;
3536
3537 datatransfer::DataFlavor aFlavor;
3538 bool bDone = false;
3539
3540 if ( bUseSpecial )
3541 {
3542 // XML
3543 SotExchange::GetFormatDataFlavor( SotClipboardFormatId::EDITENGINE_ODF_TEXT_FLAT, aFlavor );
3544 if ( rxDataObj->isDataFlavorSupported( aFlavor ) )
3545 {
3546 try
3547 {
3548 uno::Any aData = rxDataObj->getTransferData( aFlavor );
3549 uno::Sequence< sal_Int8 > aSeq;
3550 aData >>= aSeq;
3551 {
3552 SvMemoryStream aODFStream( aSeq.getArray(), aSeq.getLength(), StreamMode::READ );
3553 aNewSelection = Read( aODFStream, rBaseURL, EETextFormat::Xml, rPaM );
3554 }
3555 bDone = true;
3556 }
3557 catch( const css::uno::Exception&)
3558 {
3559 TOOLS_WARN_EXCEPTION( "editeng", "Unable to paste EDITENGINE_ODF_TEXT_FLAT" )do { css::uno::Any tools_warn_exception( DbgGetCaughtException
() ); do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "editeng")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case
SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "Unable to paste EDITENGINE_ODF_TEXT_FLAT"
<< " " << exceptionToString(tools_warn_exception
)) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), (
"editeng"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "3559" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "Unable to paste EDITENGINE_ODF_TEXT_FLAT"
<< " " << exceptionToString(tools_warn_exception
)), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Unable to paste EDITENGINE_ODF_TEXT_FLAT" <<
" " << exceptionToString(tools_warn_exception); ::sal::
detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("editeng"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "3559" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "Unable to paste EDITENGINE_ODF_TEXT_FLAT" <<
" " << exceptionToString(tools_warn_exception)) == 1) {
::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("editeng")
, ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "3559" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "Unable to paste EDITENGINE_ODF_TEXT_FLAT"
<< " " << exceptionToString(tools_warn_exception
)), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Unable to paste EDITENGINE_ODF_TEXT_FLAT" <<
" " << exceptionToString(tools_warn_exception); ::sal::
detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("editeng"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "3559" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false); } while (false)
;
3560 }
3561 }
3562
3563 if ( !bDone )
3564 {
3565 // RTF
3566 SotExchange::GetFormatDataFlavor( SotClipboardFormatId::RTF, aFlavor );
3567 // RICHTEXT
3568 datatransfer::DataFlavor aFlavorRichtext;
3569 SotExchange::GetFormatDataFlavor( SotClipboardFormatId::RICHTEXT, aFlavorRichtext );
3570 bool bRtfSupported = rxDataObj->isDataFlavorSupported( aFlavor );
3571 bool bRichtextSupported = rxDataObj->isDataFlavorSupported( aFlavorRichtext );
3572 if ( bRtfSupported || bRichtextSupported )
3573 {
3574 if(bRichtextSupported)
3575 {
3576 aFlavor = aFlavorRichtext;
3577 }
3578 try
3579 {
3580 uno::Any aData = rxDataObj->getTransferData( aFlavor );
3581 uno::Sequence< sal_Int8 > aSeq;
3582 aData >>= aSeq;
3583 {
3584 SvMemoryStream aRTFStream( aSeq.getArray(), aSeq.getLength(), StreamMode::READ );
3585 aNewSelection = Read( aRTFStream, rBaseURL, EETextFormat::Rtf, rPaM );
3586 }
3587 bDone = true;
3588 }
3589 catch( const css::uno::Exception& )
3590 {
3591 }
3592 }
3593 }
3594 }
3595 if ( !bDone )
3596 {
3597 SotExchange::GetFormatDataFlavor( SotClipboardFormatId::STRING, aFlavor );
3598 if ( rxDataObj->isDataFlavorSupported( aFlavor ) )
3599 {
3600 try
3601 {
3602 uno::Any aData = rxDataObj->getTransferData( aFlavor );
3603 OUString aText;
3604 aData >>= aText;
3605 aNewSelection = ImpInsertText( rPaM, aText );
3606 }
3607 catch( ... )
3608 {
3609 ; // #i9286# can happen, even if isDataFlavorSupported returns true...
3610 }
3611 }
3612 }
3613
3614 return aNewSelection;
3615}
3616
3617Range ImpEditEngine::GetInvalidYOffsets( ParaPortion* pPortion )
3618{
3619 Range aRange( 0, 0 );
3620
3621 if ( pPortion->IsVisible() )
3622 {
3623 const SvxULSpaceItem& rULSpace = pPortion->GetNode()->GetContentAttribs().GetItem( EE_PARA_ULSPACE );
3624 const SvxLineSpacingItem& rLSItem = pPortion->GetNode()->GetContentAttribs().GetItem( EE_PARA_SBL );
3625 sal_uInt16 nSBL = ( rLSItem.GetInterLineSpaceRule() == SvxInterLineSpaceRule::Fix )
3626 ? GetYValue( rLSItem.GetInterLineSpace() ) : 0;
3627
3628 // only from the top ...
3629 sal_Int32 nFirstInvalid = -1;
3630 sal_Int32 nLine;
3631 for ( nLine = 0; nLine < pPortion->GetLines().Count(); nLine++ )
3632 {
3633 const EditLine& rL = pPortion->GetLines()[nLine];
3634 if ( rL.IsInvalid() )
3635 {
3636 nFirstInvalid = nLine;
3637 break;
3638 }
3639 if ( nLine && !aStatus.IsOutliner() ) // not the first line
3640 aRange.Min() += nSBL;
3641 aRange.Min() += rL.GetHeight();
3642 }
3643 OSL_ENSURE( nFirstInvalid != -1, "No invalid line found in GetInvalidYOffset(1)" )do { if (true && (!(nFirstInvalid != -1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "3643" ": "), "%s", "No invalid line found in GetInvalidYOffset(1)"
); } } while (false)
;
3644
3645
3646 // Syndicate and more ...
3647 aRange.Max() = aRange.Min();
3648 aRange.Max() += pPortion->GetFirstLineOffset();
3649 if (nFirstInvalid >= 0) // Only if the first line is invalid
3650 aRange.Min() = aRange.Max();
3651
3652 sal_Int32 nLastInvalid = pPortion->GetLines().Count()-1;
3653 if (nFirstInvalid >= 0)
3654 {
3655 for ( nLine = nFirstInvalid; nLine < pPortion->GetLines().Count(); nLine++ )
3656 {
3657 const EditLine& rL = pPortion->GetLines()[nLine];
3658 if ( rL.IsValid() )
3659 {
3660 nLastInvalid = nLine;
3661 break;
3662 }
3663 if ( nLine && !aStatus.IsOutliner() )
3664 aRange.Max() += nSBL;
3665 aRange.Max() += rL.GetHeight();
3666 }
3667
3668 sal_uInt16 nPropLineSpace = rLSItem.GetPropLineSpace();
3669 if ( ( rLSItem.GetInterLineSpaceRule() == SvxInterLineSpaceRule::Prop )
3670 && nPropLineSpace && ( nPropLineSpace < 100 ) )
3671 {
3672 const EditLine& rL = pPortion->GetLines()[nFirstInvalid];
3673 auto n = rL.GetTxtHeight() * ( 100 - nPropLineSpace );
3674 n /= 100;
3675 aRange.Min() -= n;
3676 aRange.Max() += n;
3677 }
3678
3679 if ( ( nLastInvalid == pPortion->GetLines().Count()-1 ) && ( !aStatus.IsOutliner() ) )
3680 aRange.Max() += GetYValue( rULSpace.GetLower() );
3681 }
3682 }
3683 return aRange;
3684}
3685
3686EditPaM ImpEditEngine::GetPaM( ParaPortion* pPortion, Point aDocPos, bool bSmart )
3687{
3688 OSL_ENSURE( pPortion->IsVisible(), "Why GetPaM() for an invisible paragraph?" )do { if (true && (!(pPortion->IsVisible()))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "3688" ": "), "%s", "Why GetPaM() for an invisible paragraph?"
); } } while (false)
;
3689 OSL_ENSURE( IsFormatted(), "GetPaM: Not formatted" )do { if (true && (!(IsFormatted()))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "3689" ": "), "%s", "GetPaM: Not formatted"); } } while (
false)
;
3690
3691 sal_Int32 nCurIndex = 0;
3692 EditPaM aPaM;
3693 aPaM.SetNode( pPortion->GetNode() );
3694
3695 const SvxLineSpacingItem& rLSItem = pPortion->GetNode()->GetContentAttribs().GetItem( EE_PARA_SBL );
3696 sal_uInt16 nSBL = ( rLSItem.GetInterLineSpaceRule() == SvxInterLineSpaceRule::Fix )
3697 ? GetYValue( rLSItem.GetInterLineSpace() ) : 0;
3698
3699 long nY = pPortion->GetFirstLineOffset();
3700
3701 OSL_ENSURE( pPortion->GetLines().Count(), "Empty ParaPortion in GetPaM!" )do { if (true && (!(pPortion->GetLines().Count()))
) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "3701" ": "), "%s", "Empty ParaPortion in GetPaM!"); } }
while (false)
;
3702
3703 const EditLine* pLine = nullptr;
3704 for ( sal_Int32 nLine = 0; nLine < pPortion->GetLines().Count(); nLine++ )
3705 {
3706 const EditLine& rTmpLine = pPortion->GetLines()[nLine];
3707 nY += rTmpLine.GetHeight();
3708 if ( !aStatus.IsOutliner() )
3709 nY += nSBL;
3710 if ( nY > aDocPos.Y() )
3711 {
3712 pLine = &rTmpLine;
3713 break; // correct Y-position is not of interest
3714 }
3715
3716 nCurIndex = nCurIndex + rTmpLine.GetLen();
3717 }
3718
3719 if ( !pLine ) // may happen only in the range of SA!
3720 {
3721#if OSL_DEBUG_LEVEL1 > 0
3722 const SvxULSpaceItem& rULSpace = pPortion->GetNode()->GetContentAttribs().GetItem( EE_PARA_ULSPACE );
3723 OSL_ENSURE( nY+GetYValue( rULSpace.GetLower() ) >= aDocPos.Y() , "Index in no line, GetPaM ?" )do { if (true && (!(nY+GetYValue( rULSpace.GetLower()
) >= aDocPos.Y()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "3723" ": "), "%s", "Index in no line, GetPaM ?"); } } while
(false)
;
3724#endif
3725 aPaM.SetIndex( pPortion->GetNode()->Len() );
3726 return aPaM;
3727 }
3728
3729 // If no line found, only just X-Position => Index
3730 nCurIndex = GetChar( pPortion, pLine, aDocPos.X(), bSmart );
3731 aPaM.SetIndex( nCurIndex );
3732
3733 if ( nCurIndex && ( nCurIndex == pLine->GetEnd() ) &&
3734 ( pLine != &pPortion->GetLines()[pPortion->GetLines().Count()-1] ) )
3735 {
3736 aPaM = CursorLeft( aPaM );
3737 }
3738
3739 return aPaM;
3740}
3741
3742sal_Int32 ImpEditEngine::GetChar(
3743 const ParaPortion* pParaPortion, const EditLine* pLine, long nXPos, bool bSmart)
3744{
3745 OSL_ENSURE( pLine, "No line received: GetChar" )do { if (true && (!(pLine))) { sal_detail_logFormat((
SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "3745" ": "), "%s", "No line received: GetChar"); } } while
(false)
;
3746
3747 sal_Int32 nChar = -1;
3748 sal_Int32 nCurIndex = pLine->GetStart();
3749
3750
3751 // Search best matching portion with GetPortionXOffset()
3752 for ( sal_Int32 i = pLine->GetStartPortion(); i <= pLine->GetEndPortion(); i++ )
3753 {
3754 const TextPortion& rPortion = pParaPortion->GetTextPortions()[i];
3755 long nXLeft = GetPortionXOffset( pParaPortion, pLine, i );
3756 long nXRight = nXLeft + rPortion.GetSize().Width();
3757 if ( ( nXLeft <= nXPos ) && ( nXRight >= nXPos ) )
3758 {
3759 nChar = nCurIndex;
3760
3761 // Search within Portion...
3762
3763 // Don't search within special portions...
3764 if ( rPortion.GetKind() != PortionKind::TEXT )
3765 {
3766 // ...but check on which side
3767 if ( bSmart )
3768 {
3769 long nLeftDiff = nXPos-nXLeft;
3770 long nRightDiff = nXRight-nXPos;
3771 if ( nRightDiff < nLeftDiff )
3772 nChar++;
3773 }
3774 }
3775 else
3776 {
3777 sal_Int32 nMax = rPortion.GetLen();
3778 sal_Int32 nOffset = -1;
3779 sal_Int32 nTmpCurIndex = nChar - pLine->GetStart();
3780
3781 long nXInPortion = nXPos - nXLeft;
3782 if ( rPortion.IsRightToLeft() )
3783 nXInPortion = nXRight - nXPos;
3784
3785 // Search in Array...
3786 for ( sal_Int32 x = 0; x < nMax; x++ )
3787 {
3788 long nTmpPosMax = pLine->GetCharPosArray()[nTmpCurIndex+x];
3789 if ( nTmpPosMax > nXInPortion )
3790 {
3791 // Check whether this or the previous...
3792 long nTmpPosMin = x ? pLine->GetCharPosArray()[nTmpCurIndex+x-1] : 0;
3793 long nDiffLeft = nXInPortion - nTmpPosMin;
3794 long nDiffRight = nTmpPosMax - nXInPortion;
3795 OSL_ENSURE( nDiffLeft >= 0, "DiffLeft negative" )do { if (true && (!(nDiffLeft >= 0))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "3795" ": "), "%s", "DiffLeft negative"); } } while (false
)
;
3796 OSL_ENSURE( nDiffRight >= 0, "DiffRight negative" )do { if (true && (!(nDiffRight >= 0))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "3796" ": "), "%s", "DiffRight negative"); } } while (false
)
;
3797 nOffset = ( bSmart && ( nDiffRight < nDiffLeft ) ) ? x+1 : x;
3798 // I18N: If there are character position with the length of 0,
3799 // they belong to the same character, we can not use this position as an index.
3800 // Skip all 0-positions, cheaper than using XBreakIterator:
3801 if ( nOffset < nMax )
3802 {
3803 const long nX = pLine->GetCharPosArray()[nOffset];
3804 while ( ( (nOffset+1) < nMax ) && ( pLine->GetCharPosArray()[nOffset+1] == nX ) )
3805 nOffset++;
3806 }
3807 break;
3808 }
3809 }
3810
3811 // There should not be any inaccuracies when using the
3812 // CharPosArray! Maybe for kerning?
3813 // 0xFFF happens for example for Outline-Font when at the very end.
3814 if ( nOffset < 0 )
3815 nOffset = nMax;
3816
3817 OSL_ENSURE( nOffset <= nMax, "nOffset > nMax" )do { if (true && (!(nOffset <= nMax))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "3817" ": "), "%s", "nOffset > nMax"); } } while (false
)
;
3818
3819 nChar = nChar + nOffset;
3820
3821 // Check if index is within a cell:
3822 if ( nChar && ( nChar < pParaPortion->GetNode()->Len() ) )
3823 {
3824 EditPaM aPaM( pParaPortion->GetNode(), nChar+1 );
3825 sal_uInt16 nScriptType = GetI18NScriptType( aPaM );
3826 if ( nScriptType == i18n::ScriptType::COMPLEX )
3827 {
3828 uno::Reference < i18n::XBreakIterator > _xBI( ImplGetBreakIterator() );
3829 sal_Int32 nCount = 1;
3830 lang::Locale aLocale = GetLocale( aPaM );
3831 sal_Int32 nRight = _xBI->nextCharacters(
3832 pParaPortion->GetNode()->GetString(), nChar, aLocale, css::i18n::CharacterIteratorMode::SKIPCELL, nCount, nCount );
3833 sal_Int32 nLeft = _xBI->previousCharacters(
3834 pParaPortion->GetNode()->GetString(), nRight, aLocale, css::i18n::CharacterIteratorMode::SKIPCELL, nCount, nCount );
3835 if ( ( nLeft != nChar ) && ( nRight != nChar ) )
3836 {
3837 nChar = ( std::abs( nRight - nChar ) < std::abs( nLeft - nChar ) ) ? nRight : nLeft;
3838 }
3839 }
3840 else
3841 {
3842 OUString aStr(pParaPortion->GetNode()->GetString());
3843 // tdf#102625: don't select middle of a pair of surrogates with mouse cursor
3844 if (rtl::isSurrogate(aStr[nChar]))
3845 --nChar;
3846 }
3847 }
3848 }
3849 }
3850
3851 nCurIndex = nCurIndex + rPortion.GetLen();
3852 }
3853
3854 if ( nChar == -1 )
3855 {
3856 nChar = ( nXPos <= pLine->GetStartPosX() ) ? pLine->GetStart() : pLine->GetEnd();
3857 }
3858
3859 return nChar;
3860}
3861
3862Range ImpEditEngine::GetLineXPosStartEnd( const ParaPortion* pParaPortion, const EditLine* pLine ) const
3863{
3864 Range aLineXPosStartEnd;
3865
3866 sal_Int32 nPara = GetEditDoc().GetPos( pParaPortion->GetNode() );
3867 if ( !IsRightToLeft( nPara ) )
3868 {
3869 aLineXPosStartEnd.Min() = pLine->GetStartPosX();
3870 aLineXPosStartEnd.Max() = pLine->GetStartPosX() + pLine->GetTextWidth();
3871 }
3872 else
3873 {
3874 aLineXPosStartEnd.Min() = GetPaperSize().Width() - ( pLine->GetStartPosX() + pLine->GetTextWidth() );
3875 aLineXPosStartEnd.Max() = GetPaperSize().Width() - pLine->GetStartPosX();
3876 }
3877
3878
3879 return aLineXPosStartEnd;
3880}
3881
3882long ImpEditEngine::GetPortionXOffset(
3883 const ParaPortion* pParaPortion, const EditLine* pLine, sal_Int32 nTextPortion) const
3884{
3885 long nX = pLine->GetStartPosX();
3886
3887 for ( sal_Int32 i = pLine->GetStartPortion(); i < nTextPortion; i++ )
3888 {
3889 const TextPortion& rPortion = pParaPortion->GetTextPortions()[i];
3890 switch ( rPortion.GetKind() )
3891 {
3892 case PortionKind::FIELD:
3893 case PortionKind::TEXT:
3894 case PortionKind::HYPHENATOR:
3895 case PortionKind::TAB:
3896 {
3897 nX += rPortion.GetSize().Width();
3898 }
3899 break;
3900 case PortionKind::LINEBREAK: break;
3901 }
3902 }
3903
3904 sal_Int32 nPara = GetEditDoc().GetPos( pParaPortion->GetNode() );
3905 bool bR2LPara = IsRightToLeft( nPara );
3906
3907 const TextPortion& rDestPortion = pParaPortion->GetTextPortions()[nTextPortion];
3908 if ( rDestPortion.GetKind() != PortionKind::TAB )
3909 {
3910 if ( !bR2LPara && rDestPortion.GetRightToLeftLevel() )
3911 {
3912 // Portions behind must be added, visual before this portion
3913 sal_Int32 nTmpPortion = nTextPortion+1;
3914 while ( nTmpPortion <= pLine->GetEndPortion() )
3915 {
3916 const TextPortion& rNextTextPortion = pParaPortion->GetTextPortions()[nTmpPortion];
3917 if ( rNextTextPortion.GetRightToLeftLevel() && ( rNextTextPortion.GetKind() != PortionKind::TAB ) )
3918 nX += rNextTextPortion.GetSize().Width();
3919 else
3920 break;
3921 nTmpPortion++;
3922 }
3923 // Portions before must be removed, visual behind this portion
3924 nTmpPortion = nTextPortion;
3925 while ( nTmpPortion > pLine->GetStartPortion() )
3926 {
3927 --nTmpPortion;
3928 const TextPortion& rPrevTextPortion = pParaPortion->GetTextPortions()[nTmpPortion];
3929 if ( rPrevTextPortion.GetRightToLeftLevel() && ( rPrevTextPortion.GetKind() != PortionKind::TAB ) )
3930 nX -= rPrevTextPortion.GetSize().Width();
3931 else
3932 break;
3933 }
3934 }
3935 else if ( bR2LPara && !rDestPortion.IsRightToLeft() )
3936 {
3937 // Portions behind must be removed, visual behind this portion
3938 sal_Int32 nTmpPortion = nTextPortion+1;
3939 while ( nTmpPortion <= pLine->GetEndPortion() )
3940 {
3941 const TextPortion& rNextTextPortion = pParaPortion->GetTextPortions()[nTmpPortion];
3942 if ( !rNextTextPortion.IsRightToLeft() && ( rNextTextPortion.GetKind() != PortionKind::TAB ) )
3943 nX += rNextTextPortion.GetSize().Width();
3944 else
3945 break;
3946 nTmpPortion++;
3947 }
3948 // Portions before must be added, visual before this portion
3949 nTmpPortion = nTextPortion;
3950 while ( nTmpPortion > pLine->GetStartPortion() )
3951 {
3952 --nTmpPortion;
3953 const TextPortion& rPrevTextPortion = pParaPortion->GetTextPortions()[nTmpPortion];
3954 if ( !rPrevTextPortion.IsRightToLeft() && ( rPrevTextPortion.GetKind() != PortionKind::TAB ) )
3955 nX -= rPrevTextPortion.GetSize().Width();
3956 else
3957 break;
3958 }
3959 }
3960 }
3961 if ( bR2LPara )
3962 {
3963 // Switch X positions...
3964 OSL_ENSURE( GetTextRanger() || GetPaperSize().Width(), "GetPortionXOffset - paper size?!" )do { if (true && (!(GetTextRanger() || GetPaperSize()
.Width()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "3964" ": "), "%s", "GetPortionXOffset - paper size?!");
} } while (false)
;
3965 OSL_ENSURE( GetTextRanger() || (nX <= GetPaperSize().Width()), "GetPortionXOffset - position out of paper size!" )do { if (true && (!(GetTextRanger() || (nX <= GetPaperSize
().Width())))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "3965" ": "), "%s", "GetPortionXOffset - position out of paper size!"
); } } while (false)
;
3966 nX = GetPaperSize().Width() - nX;
3967 nX -= rDestPortion.GetSize().Width();
3968 }
3969
3970 return nX;
3971}
3972
3973long ImpEditEngine::GetXPos(
3974 const ParaPortion* pParaPortion, const EditLine* pLine, sal_Int32 nIndex, bool bPreferPortionStart) const
3975{
3976 OSL_ENSURE( pLine, "No line received: GetXPos" )do { if (true && (!(pLine))) { sal_detail_logFormat((
SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "3976" ": "), "%s", "No line received: GetXPos"); } } while
(false)
;
3977 OSL_ENSURE( ( nIndex >= pLine->GetStart() ) && ( nIndex <= pLine->GetEnd() ) , "GetXPos has to be called properly!" )do { if (true && (!(( nIndex >= pLine->GetStart
() ) && ( nIndex <= pLine->GetEnd() )))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "3977" ": "), "%s", "GetXPos has to be called properly!"
); } } while (false)
;
3978
3979 bool bDoPreferPortionStart = bPreferPortionStart;
3980 // Assure that the portion belongs to this line:
3981 if ( nIndex == pLine->GetStart() )
3982 bDoPreferPortionStart = true;
3983 else if ( nIndex == pLine->GetEnd() )
3984 bDoPreferPortionStart = false;
3985
3986 sal_Int32 nTextPortionStart = 0;
3987 sal_Int32 nTextPortion = pParaPortion->GetTextPortions().FindPortion( nIndex, nTextPortionStart, bDoPreferPortionStart );
3988
3989 OSL_ENSURE( ( nTextPortion >= pLine->GetStartPortion() ) && ( nTextPortion <= pLine->GetEndPortion() ), "GetXPos: Portion not in current line! " )do { if (true && (!(( nTextPortion >= pLine->GetStartPortion
() ) && ( nTextPortion <= pLine->GetEndPortion(
) )))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "3989" ": "), "%s", "GetXPos: Portion not in current line! "
); } } while (false)
;
3990
3991 const TextPortion& rPortion = pParaPortion->GetTextPortions()[nTextPortion];
3992
3993 long nX = GetPortionXOffset( pParaPortion, pLine, nTextPortion );
3994
3995 // calc text width, portion size may include CJK/CTL spacing...
3996 // But the array might not be init yet, if using text ranger this method is called within CreateLines()...
3997 long nPortionTextWidth = rPortion.GetSize().Width();
3998 if ( ( rPortion.GetKind() == PortionKind::TEXT ) && rPortion.GetLen() && !GetTextRanger() )
3999 nPortionTextWidth = pLine->GetCharPosArray()[nTextPortionStart + rPortion.GetLen() - 1 - pLine->GetStart()];
4000
4001 if ( nTextPortionStart != nIndex )
4002 {
4003 // Search within portion...
4004 if ( nIndex == ( nTextPortionStart + rPortion.GetLen() ) )
4005 {
4006 // End of Portion
4007 if ( rPortion.GetKind() == PortionKind::TAB )
4008 {
4009 if ( nTextPortion+1 < pParaPortion->GetTextPortions().Count() )
4010 {
4011 const TextPortion& rNextPortion = pParaPortion->GetTextPortions()[nTextPortion+1];
4012 if ( rNextPortion.GetKind() != PortionKind::TAB )
4013 {
4014 if ( !bPreferPortionStart )
4015 nX = GetXPos( pParaPortion, pLine, nIndex, true );
4016 else if ( !IsRightToLeft( GetEditDoc().GetPos( pParaPortion->GetNode() ) ) )
4017 nX += nPortionTextWidth;
4018 }
4019 }
4020 else if ( !IsRightToLeft( GetEditDoc().GetPos( pParaPortion->GetNode() ) ) )
4021 {
4022 nX += nPortionTextWidth;
4023 }
4024 }
4025 else if ( !rPortion.IsRightToLeft() )
4026 {
4027 nX += nPortionTextWidth;
4028 }
4029 }
4030 else if ( rPortion.GetKind() == PortionKind::TEXT )
4031 {
4032 OSL_ENSURE( nIndex != pLine->GetStart(), "Strange behavior in new GetXPos()" )do { if (true && (!(nIndex != pLine->GetStart())))
{ sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "4032" ": "), "%s", "Strange behavior in new GetXPos()")
; } } while (false)
;
4033 OSL_ENSURE( pLine && !pLine->GetCharPosArray().empty(), "svx::ImpEditEngine::GetXPos(), portion in an empty line?" )do { if (true && (!(pLine && !pLine->GetCharPosArray
().empty()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "4033" ": "), "%s", "svx::ImpEditEngine::GetXPos(), portion in an empty line?"
); } } while (false)
;
4034
4035 if( !pLine->GetCharPosArray().empty() )
4036 {
4037 sal_Int32 nPos = nIndex - 1 - pLine->GetStart();
4038 if (nPos < 0 || nPos >= static_cast<sal_Int32>(pLine->GetCharPosArray().size()))
4039 {
4040 nPos = pLine->GetCharPosArray().size()-1;
4041 OSL_FAIL("svx::ImpEditEngine::GetXPos(), index out of range!")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "4041" ": "), "%s", "svx::ImpEditEngine::GetXPos(), index out of range!"
); } } while (false)
;
4042 }
4043
4044 // old code restored see #i112788 (which leaves #i74188 unfixed again)
4045 long nPosInPortion = pLine->GetCharPosArray()[nPos];
4046
4047 if ( !rPortion.IsRightToLeft() )
4048 {
4049 nX += nPosInPortion;
4050 }
4051 else
4052 {
4053 nX += nPortionTextWidth - nPosInPortion;
4054 }
4055
4056 if ( rPortion.GetExtraInfos() && rPortion.GetExtraInfos()->bCompressed )
4057 {
4058 nX += rPortion.GetExtraInfos()->nPortionOffsetX;
4059 if ( rPortion.GetExtraInfos()->nAsianCompressionTypes & AsianCompressionFlags::PunctuationRight )
4060 {
4061 AsianCompressionFlags nType = GetCharTypeForCompression( pParaPortion->GetNode()->GetChar( nIndex ) );
4062 if ( nType == AsianCompressionFlags::PunctuationRight && !pLine->GetCharPosArray().empty() )
4063 {
4064 sal_Int32 n = nIndex - nTextPortionStart;
4065 const long* pDXArray = pLine->GetCharPosArray().data()+( nTextPortionStart-pLine->GetStart() );
4066 sal_Int32 nCharWidth = ( ( (n+1) < rPortion.GetLen() ) ? pDXArray[n] : rPortion.GetSize().Width() )
4067 - ( n ? pDXArray[n-1] : 0 );
4068 if ( (n+1) < rPortion.GetLen() )
4069 {
4070 // smaller, when char behind is AsianCompressionFlags::PunctuationRight also
4071 nType = GetCharTypeForCompression( pParaPortion->GetNode()->GetChar( nIndex+1 ) );
4072 if ( nType == AsianCompressionFlags::PunctuationRight )
4073 {
4074 sal_Int32 nNextCharWidth = ( ( (n+2) < rPortion.GetLen() ) ? pDXArray[n+1] : rPortion.GetSize().Width() )
4075 - pDXArray[n];
4076 sal_Int32 nCompressed = nNextCharWidth/2;
4077 nCompressed *= rPortion.GetExtraInfos()->nMaxCompression100thPercent;
4078 nCompressed /= 10000;
4079 nCharWidth += nCompressed;
4080 }
4081 }
4082 else
4083 {
4084 nCharWidth *= 2; // last char pos to portion end is only compressed size
4085 }
4086 nX += nCharWidth/2; // 50% compression
4087 }
4088 }
4089 }
4090 }
4091 }
4092 }
4093 else // if ( nIndex == pLine->GetStart() )
4094 {
4095 if ( rPortion.IsRightToLeft() )
4096 {
4097 nX += nPortionTextWidth;
4098 }
4099 }
4100
4101 return nX;
4102}
4103
4104void ImpEditEngine::CalcHeight( ParaPortion* pPortion )
4105{
4106 pPortion->nHeight = 0;
4107 pPortion->nFirstLineOffset = 0;
4108
4109 if ( !pPortion->IsVisible() )
4110 return;
4111
4112 OSL_ENSURE( pPortion->GetLines().Count(), "Paragraph with no lines in ParaPortion::CalcHeight" )do { if (true && (!(pPortion->GetLines().Count()))
) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "4112" ": "), "%s", "Paragraph with no lines in ParaPortion::CalcHeight"
); } } while (false)
;
4113 for (sal_Int32 nLine = 0; nLine < pPortion->GetLines().Count(); ++nLine)
4114 pPortion->nHeight += pPortion->GetLines()[nLine].GetHeight();
4115
4116 if ( aStatus.IsOutliner() )
4117 return;
4118
4119 const SvxULSpaceItem& rULItem = pPortion->GetNode()->GetContentAttribs().GetItem( EE_PARA_ULSPACE );
4120 const SvxLineSpacingItem& rLSItem = pPortion->GetNode()->GetContentAttribs().GetItem( EE_PARA_SBL );
4121 sal_Int32 nSBL = ( rLSItem.GetInterLineSpaceRule() == SvxInterLineSpaceRule::Fix ) ? GetYValue( rLSItem.GetInterLineSpace() ) : 0;
4122
4123 if ( nSBL )
4124 {
4125 if ( pPortion->GetLines().Count() > 1 )
4126 pPortion->nHeight += ( pPortion->GetLines().Count() - 1 ) * nSBL;
4127 if ( aStatus.ULSpaceSummation() )
4128 pPortion->nHeight += nSBL;
4129 }
4130
4131 sal_Int32 nPortion = GetParaPortions().GetPos( pPortion );
4132 if ( nPortion )
4133 {
4134 sal_uInt16 nUpper = GetYValue( rULItem.GetUpper() );
4135 pPortion->nHeight += nUpper;
4136 pPortion->nFirstLineOffset = nUpper;
4137 }
4138
4139 if ( nPortion != (GetParaPortions().Count()-1) )
4140 {
4141 pPortion->nHeight += GetYValue( rULItem.GetLower() ); // not in the last
4142 }
4143
4144
4145 if ( !nPortion || aStatus.ULSpaceSummation() )
4146 return;
4147
4148 ParaPortion* pPrev = GetParaPortions().SafeGetObject( nPortion-1 );
4149 if (!pPrev)
4150 return;
4151
4152 const SvxULSpaceItem& rPrevULItem = pPrev->GetNode()->GetContentAttribs().GetItem( EE_PARA_ULSPACE );
4153 const SvxLineSpacingItem& rPrevLSItem = pPrev->GetNode()->GetContentAttribs().GetItem( EE_PARA_SBL );
4154
4155 // In relation between WinWord6/Writer3:
4156 // With a proportional line spacing the paragraph spacing is
4157 // also manipulated.
4158 // Only Writer3: Do not add up, but minimum distance.
4159
4160 // check if distance by LineSpacing > Upper:
4161 sal_uInt16 nExtraSpace = GetYValue( lcl_CalcExtraSpace( rLSItem ) );
4162 if ( nExtraSpace > pPortion->nFirstLineOffset )
4163 {
4164 // Paragraph becomes 'bigger':
4165 pPortion->nHeight += ( nExtraSpace - pPortion->nFirstLineOffset );
4166 pPortion->nFirstLineOffset = nExtraSpace;
4167 }
4168
4169 // Determine nFirstLineOffset now f(pNode) => now f(pNode, pPrev):
4170 sal_uInt16 nPrevLower = GetYValue( rPrevULItem.GetLower() );
4171
4172 // This PrevLower is still in the height of PrevPortion ...
4173 if ( nPrevLower > pPortion->nFirstLineOffset )
4174 {
4175 // Paragraph is 'small':
4176 pPortion->nHeight -= pPortion->nFirstLineOffset;
4177 pPortion->nFirstLineOffset = 0;
4178 }
4179 else if ( nPrevLower )
4180 {
4181 // Paragraph becomes 'somewhat smaller':
4182 pPortion->nHeight -= nPrevLower;
4183 pPortion->nFirstLineOffset =
4184 pPortion->nFirstLineOffset - nPrevLower;
4185 }
4186 // I find it not so good, but Writer3 feature:
4187 // Check if distance by LineSpacing > Lower: this value is not
4188 // stuck in the height of PrevPortion.
4189 if ( pPrev->IsInvalid() )
4190 return;
4191
4192 nExtraSpace = GetYValue( lcl_CalcExtraSpace( rPrevLSItem ) );
4193 if ( nExtraSpace > nPrevLower )
4194 {
4195 sal_uInt16 nMoreLower = nExtraSpace - nPrevLower;
4196 // Paragraph becomes 'bigger', 'grows' downwards:
4197 if ( nMoreLower > pPortion->nFirstLineOffset )
4198 {
4199 pPortion->nHeight += ( nMoreLower - pPortion->nFirstLineOffset );
4200 pPortion->nFirstLineOffset = nMoreLower;
4201 }
4202 }
4203}
4204
4205tools::Rectangle ImpEditEngine::GetEditCursor( ParaPortion* pPortion, sal_Int32 nIndex, GetCursorFlags nFlags )
4206{
4207 OSL_ENSURE( pPortion->IsVisible(), "Why GetEditCursor() for an invisible paragraph?" )do { if (true && (!(pPortion->IsVisible()))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "4207" ": "), "%s", "Why GetEditCursor() for an invisible paragraph?"
); } } while (false)
;
4208 OSL_ENSURE( IsFormatted() || GetTextRanger(), "GetEditCursor: Not formatted" )do { if (true && (!(IsFormatted() || GetTextRanger())
)) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "4208" ": "), "%s", "GetEditCursor: Not formatted"); } }
while (false)
;
4209
4210 /*
4211 GetCursorFlags::EndOfLine: If after the last character of a wrapped line, remaining
4212 at the end of the line, not the beginning of the next one.
4213 Purpose: - END => really after the last character
4214 - Selection...
4215 */
4216
4217 long nY = pPortion->GetFirstLineOffset();
4218
4219 const SvxLineSpacingItem& rLSItem = pPortion->GetNode()->GetContentAttribs().GetItem( EE_PARA_SBL );
4220 sal_uInt16 nSBL = ( rLSItem.GetInterLineSpaceRule() == SvxInterLineSpaceRule::Fix )
4221 ? GetYValue( rLSItem.GetInterLineSpace() ) : 0;
4222
4223 sal_Int32 nCurIndex = 0;
4224 sal_Int32 nLineCount = pPortion->GetLines().Count();
4225 OSL_ENSURE( nLineCount, "Empty ParaPortion in GetEditCursor!" )do { if (true && (!(nLineCount))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "4225" ": "), "%s", "Empty ParaPortion in GetEditCursor!"
); } } while (false)
;
4226 if (nLineCount == 0)
4227 return tools::Rectangle();
4228 const EditLine* pLine = nullptr;
4229 bool bEOL( nFlags & GetCursorFlags::EndOfLine );
4230 for (sal_Int32 nLine = 0; nLine < nLineCount; ++nLine)
4231 {
4232 const EditLine& rTmpLine = pPortion->GetLines()[nLine];
4233 if ( ( rTmpLine.GetStart() == nIndex ) || ( rTmpLine.IsIn( nIndex, bEOL ) ) )
4234 {
4235 pLine = &rTmpLine;
4236 break;
4237 }
4238
4239 nCurIndex = nCurIndex + rTmpLine.GetLen();
4240 nY += rTmpLine.GetHeight();
4241 if ( !aStatus.IsOutliner() )
4242 nY += nSBL;
4243 }
4244 if ( !pLine )
4245 {
4246 // Cursor at the End of the paragraph.
4247 OSL_ENSURE( nIndex == nCurIndex, "Index dead wrong in GetEditCursor!" )do { if (true && (!(nIndex == nCurIndex))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx"
":" "4247" ": "), "%s", "Index dead wrong in GetEditCursor!"
); } } while (false)
;
4248
4249 pLine = &pPortion->GetLines()[nLineCount-1];
4250 nY -= pLine->GetHeight();
4251 if ( !aStatus.IsOutliner() )
4252 nY -= nSBL;
4253 }
4254
4255 tools::Rectangle aEditCursor;
4256
4257 aEditCursor.SetTop( nY );
4258 nY += pLine->GetHeight();
4259 aEditCursor.SetBottom( nY-1 );
4260
4261 // Search within the line...
4262 long nX;
4263
4264 if ( ( nIndex == pLine->GetStart() ) && ( nFlags & GetCursorFlags::StartOfLine ) )
4265 {
4266 Range aXRange = GetLineXPosStartEnd( pPortion, pLine );
4267 nX = !IsRightToLeft( GetEditDoc().GetPos( pPortion->GetNode() ) ) ? aXRange.Min() : aXRange.Max();
4268 }
4269 else if ( ( nIndex == pLine->GetEnd() ) && ( nFlags & GetCursorFlags::EndOfLine ) )
4270 {
4271 Range aXRange = GetLineXPosStartEnd( pPortion, pLine );
4272 nX = !IsRightToLeft( GetEditDoc().GetPos( pPortion->GetNode() ) ) ? aXRange.Max() : aXRange.Min();
4273 }
4274 else
4275 {
4276 nX = GetXPos( pPortion, pLine, nIndex, bool( nFlags & GetCursorFlags::PreferPortionStart ) );
4277 }
4278
4279 aEditCursor.SetLeft(nX);
4280 aEditCursor.SetRight(nX);
4281
4282 if ( nFlags & GetCursorFlags::TextOnly )
4283 aEditCursor.SetTop( aEditCursor.Bottom() - pLine->GetTxtHeight() + 1 );
4284 else
4285 aEditCursor.SetTop( aEditCursor.Bottom() - std::min( pLine->GetTxtHeight(), pLine->GetHeight() ) + 1 );
4286
4287 return aEditCursor;
4288}
4289
4290void ImpEditEngine::SetValidPaperSize( const Size& rNewSz )
4291{
4292 aPaperSize = rNewSz;
4293
4294 long nMinWidth = aStatus.AutoPageWidth() ? aMinAutoPaperSize.Width() : 0;
4295 long nMaxWidth = aStatus.AutoPageWidth() ? aMaxAutoPaperSize.Width() : 0x7FFFFFFF;
4296 long nMinHeight = aStatus.AutoPageHeight() ? aMinAutoPaperSize.Height() : 0;
4297 long nMaxHeight = aStatus.AutoPageHeight() ? aMaxAutoPaperSize.Height() : 0x7FFFFFFF;
4298
4299 // Minimum/Maximum width:
4300 if ( aPaperSize.Width() < nMinWidth )
4301 aPaperSize.setWidth( nMinWidth );
4302 else if ( aPaperSize.Width() > nMaxWidth )
4303 aPaperSize.setWidth( nMaxWidth );
4304
4305 // Minimum/Maximum height:
4306 if ( aPaperSize.Height() < nMinHeight )
4307 aPaperSize.setHeight( nMinHeight );
4308 else if ( aPaperSize.Height() > nMaxHeight )
4309 aPaperSize.setHeight( nMaxHeight );
4310}
4311
4312std::shared_ptr<SvxForbiddenCharactersTable> const & ImpEditEngine::GetForbiddenCharsTable()
4313{
4314 return EditDLL::Get().GetGlobalData()->GetForbiddenCharsTable();
4315}
4316
4317void ImpEditEngine::SetForbiddenCharsTable(const std::shared_ptr<SvxForbiddenCharactersTable>& xForbiddenChars)
4318{
4319 EditDLL::Get().GetGlobalData()->SetForbiddenCharsTable( xForbiddenChars );
4320}
4321
4322bool ImpEditEngine::IsVisualCursorTravelingEnabled()
4323{
4324 bool bVisualCursorTravaling = false;
4325
4326 if( !pCTLOptions )
4327 pCTLOptions.reset( new SvtCTLOptions );
4328
4329 if ( pCTLOptions->IsCTLFontEnabled() && ( pCTLOptions->GetCTLCursorMovement() == SvtCTLOptions::MOVEMENT_VISUAL ) )
4330 {
4331 bVisualCursorTravaling = true;
4332 }
4333
4334 return bVisualCursorTravaling;
4335
4336}
4337
4338bool ImpEditEngine::DoVisualCursorTraveling()
4339{
4340 // Don't check if it's necessary, because we also need it when leaving the paragraph
4341 return IsVisualCursorTravelingEnabled();
4342}
4343
4344IMPL_LINK_NOARG(ImpEditEngine, DocModified, LinkParamNone*, void)void ImpEditEngine::LinkStubDocModified(void * instance, LinkParamNone
* data) { return static_cast<ImpEditEngine *>(instance)
->DocModified(data); } void ImpEditEngine::DocModified(__attribute__
((unused)) LinkParamNone*)
4345{
4346 aModifyHdl.Call( nullptr /*GetEditEnginePtr()*/ ); // NULL, because also used for Outliner
4347}
4348
4349/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx

1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20#ifndef INCLUDED_VCL_PTR_HXX
21#define INCLUDED_VCL_PTR_HXX
22
23#include <sal/config.h>
24
25#include <rtl/ref.hxx>
26
27#include <utility>
28#include <type_traits>
29
30#ifdef DBG_UTIL
31#ifndef _WIN32
32#include <vcl/vclmain.hxx>
33#endif
34#endif
35
36class VclReferenceBase;
37
38namespace vcl::detail {
39
40template<typename>
41constexpr bool isIncompleteOrDerivedFromVclReferenceBase(...) { return true; }
42
43template<typename T> constexpr bool isIncompleteOrDerivedFromVclReferenceBase(
44 int (*)[sizeof(T)])
45{ return std::is_base_of<VclReferenceBase, T>::value; }
46
47} // namespace vcl::detail
48
49/**
50 * A thin wrapper around rtl::Reference to implement the acquire and dispose semantics we want for references to vcl::Window subclasses.
51 *
52 * For more details on the design please see vcl/README.lifecycle
53 *
54 * @param reference_type must be a subclass of vcl::Window
55 */
56template <class reference_type>
57class VclPtr
58{
59 static_assert(
60 vcl::detail::isIncompleteOrDerivedFromVclReferenceBase<reference_type>(
61 nullptr),
62 "template argument type must be derived from VclReferenceBase");
63
64 ::rtl::Reference<reference_type> m_rInnerRef;
65
66public:
67 /** Constructor...
68 */
69 VclPtr()
70 : m_rInnerRef()
71 {}
72
73 /** Constructor...
74 */
75 VclPtr (reference_type * pBody)
76 : m_rInnerRef(pBody)
77 {}
78
79 /** Constructor... that doesn't take a ref.
80 */
81 VclPtr (reference_type * pBody, __sal_NoAcquire)
82 : m_rInnerRef(pBody, SAL_NO_ACQUIRE)
83 {}
84
85 /** Up-casting conversion constructor: Copies interface reference.
86
87 Does not work for up-casts to ambiguous bases. For the special case of
88 up-casting to Reference< XInterface >, see the corresponding conversion
89 operator.
90
91 @param rRef another reference
92 */
93 template< class derived_type >
94 VclPtr(
95 const VclPtr< derived_type > & rRef,
96 typename std::enable_if<
97 std::is_base_of<reference_type, derived_type>::value, int>::type
98 = 0 )
99 : m_rInnerRef( static_cast<reference_type*>(rRef) )
100 {
101 }
102
103#if defined(DBG_UTIL) && !defined(_WIN32)
104 virtual ~VclPtr()
105 {
106 assert(m_rInnerRef.get() == nullptr || vclmain::isAlive())(static_cast <bool> (m_rInnerRef.get() == nullptr || vclmain
::isAlive()) ? void (0) : __assert_fail ("m_rInnerRef.get() == nullptr || vclmain::isAlive()"
, "/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx"
, 106, __extension__ __PRETTY_FUNCTION__))
;
107 // We can be one of the intermediate counts, but if we are the last
108 // VclPtr keeping this object alive, then something forgot to call dispose().
109 assert((!m_rInnerRef.get() || m_rInnerRef->isDisposed() || m_rInnerRef->getRefCount() > 1)(static_cast <bool> ((!m_rInnerRef.get() || m_rInnerRef
->isDisposed() || m_rInnerRef->getRefCount() > 1) &&
"someone forgot to call dispose()") ? void (0) : __assert_fail
("(!m_rInnerRef.get() || m_rInnerRef->isDisposed() || m_rInnerRef->getRefCount() > 1) && \"someone forgot to call dispose()\""
, "/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx"
, 110, __extension__ __PRETTY_FUNCTION__))
110 && "someone forgot to call dispose()")(static_cast <bool> ((!m_rInnerRef.get() || m_rInnerRef
->isDisposed() || m_rInnerRef->getRefCount() > 1) &&
"someone forgot to call dispose()") ? void (0) : __assert_fail
("(!m_rInnerRef.get() || m_rInnerRef->isDisposed() || m_rInnerRef->getRefCount() > 1) && \"someone forgot to call dispose()\""
, "/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx"
, 110, __extension__ __PRETTY_FUNCTION__))
;
111 }
112 VclPtr(VclPtr const &) = default;
113 VclPtr(VclPtr &&) = default;
114 VclPtr & operator =(VclPtr const &) = default;
115 VclPtr & operator =(VclPtr &&) = default;
116#endif
117
118 /**
119 * A construction helper for VclPtr. Since VclPtr types are created
120 * with a reference-count of one - to help fit into the existing
121 * code-flow; this helps us to construct them easily.
122 *
123 * For more details on the design please see vcl/README.lifecycle
124 *
125 * @tparam reference_type must be a subclass of vcl::Window
126 */
127 template<typename... Arg> [[nodiscard]] static VclPtr< reference_type > Create(Arg &&... arg)
128 {
129 return VclPtr< reference_type >( new reference_type(std::forward<Arg>(arg)...), SAL_NO_ACQUIRE );
130 }
131
132 /** Probably most common used: handle->someBodyOp().
133 */
134 reference_type * operator->() const
135 {
136 return m_rInnerRef.get();
137 }
138
139 /** Get the body. Can be used instead of operator->().
140 I.e. handle->someBodyOp() and handle.get()->someBodyOp()
141 are the same.
142 */
143 reference_type * get() const
144 {
145 return m_rInnerRef.get();
146 }
147
148 void set(reference_type *pBody)
149 {
150 m_rInnerRef.set(pBody);
151 }
152
153 void reset(reference_type *pBody)
154 {
155 m_rInnerRef.set(pBody);
156 }
157
158 /** Up-casting copy assignment operator.
159
160 Does not work for up-casts to ambiguous bases.
161
162 @param rRef another reference
163 */
164 template<typename derived_type>
165 typename std::enable_if<
166 std::is_base_of<reference_type, derived_type>::value,
167 VclPtr &>::type
168 operator =(VclPtr<derived_type> const & rRef)
169 {
170 m_rInnerRef.set(rRef.get());
171 return *this;
172 }
173
174 VclPtr & operator =(reference_type * pBody)
175 {
176 m_rInnerRef.set(pBody);
177 return *this;
178 }
179
180 operator reference_type * () const
181 {
182 return m_rInnerRef.get();
183 }
184
185 explicit operator bool () const
186 {
187 return m_rInnerRef.get() != nullptr;
188 }
189
190 void clear()
191 {
192 m_rInnerRef.clear();
193 }
194
195 void reset()
196 {
197 m_rInnerRef.clear();
198 }
199
200 void disposeAndClear()
201 {
202 // hold it alive for the lifetime of this method
203 ::rtl::Reference<reference_type> aTmp(m_rInnerRef);
4
Calling copy constructor for 'Reference<VirtualDevice>'
7
Returning from copy constructor for 'Reference<VirtualDevice>'
204 m_rInnerRef.clear(); // we should use some 'swap' method ideally ;-)
8
Calling 'Reference::clear'
15
Returning; memory was released
205 if (aTmp.get()) {
16
Calling 'Reference::get'
206 aTmp->disposeOnce();
207 }
208 }
209
210 /** Needed to place VclPtr's into STL collection.
211 */
212 bool operator< (const VclPtr<reference_type> & handle) const
213 {
214 return (m_rInnerRef < handle.m_rInnerRef);
215 }
216}; // class VclPtr
217
218template<typename T1, typename T2>
219inline bool operator ==(VclPtr<T1> const & p1, VclPtr<T2> const & p2) {
220 return p1.get() == p2.get();
221}
222
223template<typename T> inline bool operator ==(VclPtr<T> const & p1, T const * p2)
224{
225 return p1.get() == p2;
226}
227
228template<typename T> inline bool operator ==(VclPtr<T> const & p1, T * p2) {
229 return p1.get() == p2;
230}
231
232template<typename T> inline bool operator ==(T const * p1, VclPtr<T> const & p2)
233{
234 return p1 == p2.get();
235}
236
237template<typename T> inline bool operator ==(T * p1, VclPtr<T> const & p2) {
238 return p1 == p2.get();
239}
240
241template<typename T1, typename T2>
242inline bool operator !=(VclPtr<T1> const & p1, VclPtr<T2> const & p2) {
243 return !(p1 == p2);
244}
245
246template<typename T> inline bool operator !=(VclPtr<T> const & p1, T const * p2)
247{
248 return !(p1 == p2);
249}
250
251template<typename T> inline bool operator !=(VclPtr<T> const & p1, T * p2) {
252 return !(p1 == p2);
253}
254
255template<typename T> inline bool operator !=(T const * p1, VclPtr<T> const & p2)
256{
257 return !(p1 == p2);
258}
259
260template<typename T> inline bool operator !=(T * p1, VclPtr<T> const & p2) {
261 return !(p1 == p2);
262}
263
264/**
265 * A construction helper for a temporary VclPtr. Since VclPtr types
266 * are created with a reference-count of one - to help fit into
267 * the existing code-flow; this helps us to construct them easily.
268 * see also VclPtr::Create and ScopedVclPtr
269 *
270 * For more details on the design please see vcl/README.lifecycle
271 *
272 * @param reference_type must be a subclass of vcl::Window
273 */
274template <class reference_type>
275class SAL_WARN_UNUSED__attribute__((warn_unused)) VclPtrInstance final : public VclPtr<reference_type>
276{
277public:
278 template<typename... Arg> VclPtrInstance(Arg &&... arg)
279 : VclPtr<reference_type>( new reference_type(std::forward<Arg>(arg)...), SAL_NO_ACQUIRE )
280 {
281 }
282
283 /**
284 * Override and disallow this, to prevent people accidentally calling it and actually
285 * getting VclPtr::Create and getting a naked VclPtr<> instance
286 */
287 template<typename... Arg> static VclPtrInstance< reference_type > Create(Arg &&... ) = delete;
288};
289
290template <class reference_type>
291class ScopedVclPtr : public VclPtr<reference_type>
292{
293public:
294 /** Constructor...
295 */
296 ScopedVclPtr()
297 : VclPtr<reference_type>()
298 {}
299
300 /** Constructor
301 */
302 ScopedVclPtr (reference_type * pBody)
303 : VclPtr<reference_type>(pBody)
304 {}
305
306 /** Copy constructor...
307 */
308 ScopedVclPtr (const VclPtr<reference_type> & handle)
309 : VclPtr<reference_type>(handle)
310 {}
311
312 /**
313 Assignment that releases the last reference.
314 */
315 void disposeAndReset(reference_type *pBody)
316 {
317 if (pBody != this->get()) {
318 VclPtr<reference_type>::disposeAndClear();
319 VclPtr<reference_type>::set(pBody);
320 }
321 }
322
323 /**
324 Assignment that releases the last reference.
325 */
326 ScopedVclPtr<reference_type>& operator = (reference_type * pBody)
327 {
328 disposeAndReset(pBody);
329 return *this;
330 }
331
332 /** Up-casting conversion constructor: Copies interface reference.
333
334 Does not work for up-casts to ambiguous bases. For the special case of
335 up-casting to Reference< XInterface >, see the corresponding conversion
336 operator.
337
338 @param rRef another reference
339 */
340 template< class derived_type >
341 ScopedVclPtr(
342 const VclPtr< derived_type > & rRef,
343 typename std::enable_if<
344 std::is_base_of<reference_type, derived_type>::value, int>::type
345 = 0 )
346 : VclPtr<reference_type>( rRef )
347 {
348 }
349
350 /** Up-casting assignment operator.
351
352 Does not work for up-casts to ambiguous bases.
353
354 @param rRef another VclPtr
355 */
356 template<typename derived_type>
357 typename std::enable_if<
358 std::is_base_of<reference_type, derived_type>::value,
359 ScopedVclPtr &>::type
360 operator =(VclPtr<derived_type> const & rRef)
361 {
362 disposeAndReset(rRef.get());
363 return *this;
364 }
365
366 /**
367 * Override and disallow this, to prevent people accidentally calling it and actually
368 * getting VclPtr::Create and getting a naked VclPtr<> instance
369 */
370 template<typename... Arg> static ScopedVclPtr< reference_type > Create(Arg &&... ) = delete;
371
372 ~ScopedVclPtr()
373 {
374 VclPtr<reference_type>::disposeAndClear();
375 assert(VclPtr<reference_type>::get() == nullptr)(static_cast <bool> (VclPtr<reference_type>::get(
) == nullptr) ? void (0) : __assert_fail ("VclPtr<reference_type>::get() == nullptr"
, "/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx"
, 375, __extension__ __PRETTY_FUNCTION__))
; // make sure there are no lingering references
376 }
377
378private:
379 // Most likely we don't want this default copy-constructor.
380 ScopedVclPtr (const ScopedVclPtr<reference_type> &) = delete;
381 // And certainly we don't want a default assignment operator.
382 ScopedVclPtr<reference_type>& operator = (const ScopedVclPtr<reference_type> &) = delete;
383 // And disallow reset as that doesn't call disposeAndClear on the original reference
384 void reset() = delete;
385 void reset(reference_type *pBody) = delete;
386
387protected:
388 ScopedVclPtr (reference_type * pBody, __sal_NoAcquire)
389 : VclPtr<reference_type>(pBody, SAL_NO_ACQUIRE)
390 {}
391};
392
393/**
394 * A construction helper for ScopedVclPtr. Since VclPtr types are created
395 * with a reference-count of one - to help fit into the existing
396 * code-flow; this helps us to construct them easily.
397 *
398 * For more details on the design please see vcl/README.lifecycle
399 *
400 * @param reference_type must be a subclass of vcl::Window
401 */
402#if defined _MSC_VER
403#pragma warning(push)
404#pragma warning(disable: 4521) // " multiple copy constructors specified"
405#endif
406template <class reference_type>
407class SAL_WARN_UNUSED__attribute__((warn_unused)) ScopedVclPtrInstance final : public ScopedVclPtr<reference_type>
408{
409public:
410 template<typename... Arg> ScopedVclPtrInstance(Arg &&... arg)
411 : ScopedVclPtr<reference_type>( new reference_type(std::forward<Arg>(arg)...), SAL_NO_ACQUIRE )
412 {
413 }
414
415 /**
416 * Override and disallow this, to prevent people accidentally calling it and actually
417 * getting VclPtr::Create and getting a naked VclPtr<> instance
418 */
419 template<typename... Arg> static ScopedVclPtrInstance< reference_type > Create(Arg &&...) = delete;
420
421private:
422 // Prevent the above perfect forwarding ctor from hijacking (accidental)
423 // attempts at ScopedVclPtrInstance copy construction (where the hijacking
424 // would typically lead to somewhat obscure error messages); both non-const
425 // and const variants are needed here, as the ScopedVclPtr base class has a
426 // const--variant copy ctor, so the implicitly declared copy ctor for
427 // ScopedVclPtrInstance would also be the const variant, so non-const copy
428 // construction attempts would be hijacked by the perfect forwarding ctor;
429 // but if we only declared a non-const variant here, the const variant would
430 // no longer be implicitly declared (as there would already be an explicitly
431 // declared copy ctor), so const copy construction attempts would then be
432 // hijacked by the perfect forwarding ctor:
433 ScopedVclPtrInstance(ScopedVclPtrInstance &) = delete;
434 ScopedVclPtrInstance(ScopedVclPtrInstance const &) = delete;
435};
436#if defined _MSC_VER
437#pragma warning(pop)
438#endif
439
440#endif // INCLUDED_VCL_PTR_HXX
441
442/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

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

1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20#ifndef INCLUDED_RTL_REF_HXX
21#define INCLUDED_RTL_REF_HXX
22
23#include "sal/config.h"
24
25#include <cassert>
26#include <cstddef>
27#include <functional>
28#ifdef LIBO_INTERNAL_ONLY1
29#include <type_traits>
30#endif
31
32#include "sal/types.h"
33
34namespace rtl
35{
36
37/** Template reference class for reference type.
38*/
39template <class reference_type>
40class Reference
41{
42 /** The <b>reference_type</b> body pointer.
43 */
44 reference_type * m_pBody;
45
46
47public:
48 /** Constructor...
49 */
50 Reference()
51 : m_pBody (NULL__null)
52 {}
53
54
55 /** Constructor...
56 */
57 Reference (reference_type * pBody, __sal_NoAcquire)
58 : m_pBody (pBody)
59 {
60 }
61
62 /** Constructor...
63 */
64 Reference (reference_type * pBody)
65 : m_pBody (pBody)
66 {
67 if (m_pBody)
68 m_pBody->acquire();
69 }
70
71 /** Copy constructor...
72 */
73 Reference (const Reference<reference_type> & handle)
74 : m_pBody (handle.m_pBody)
75 {
76 if (m_pBody)
5
Assuming field 'm_pBody' is non-null
6
Taking true branch
77 m_pBody->acquire();
78 }
79
80#ifdef LIBO_INTERNAL_ONLY1
81 /** Move constructor...
82 */
83 Reference (Reference<reference_type> && handle) noexcept
84 : m_pBody (handle.m_pBody)
85 {
86 handle.m_pBody = nullptr;
87 }
88#endif
89
90#if defined LIBO_INTERNAL_ONLY1
91 /** Up-casting conversion constructor: Copies interface reference.
92
93 Does not work for up-casts to ambiguous bases.
94
95 @param rRef another reference
96 */
97 template< class derived_type >
98 inline Reference(
99 const Reference< derived_type > & rRef,
100 std::enable_if_t<std::is_base_of_v<reference_type, derived_type>, int> = 0 )
101 : m_pBody (rRef.get())
102 {
103 if (m_pBody)
104 m_pBody->acquire();
105 }
106#endif
107
108 /** Destructor...
109 */
110 ~Reference() COVERITY_NOEXCEPT_FALSE
111 {
112 if (m_pBody)
113 m_pBody->release();
114 }
115
116 /** Set...
117 Similar to assignment.
118 */
119 Reference<reference_type> &
120 SAL_CALL set (reference_type * pBody)
121 {
122 if (pBody)
123 pBody->acquire();
124 reference_type * const pOld = m_pBody;
125 m_pBody = pBody;
126 if (pOld)
127 pOld->release();
128 return *this;
129 }
130
131 /** Assignment.
132 Unbinds this instance from its body (if bound) and
133 bind it to the body represented by the handle.
134 */
135 Reference<reference_type> &
136 SAL_CALL operator= (const Reference<reference_type> & handle)
137 {
138 return set( handle.m_pBody );
139 }
140
141#ifdef LIBO_INTERNAL_ONLY1
142 /** Assignment.
143 * Unbinds this instance from its body (if bound),
144 * bind it to the body represented by the handle, and
145 * set the body represented by the handle to nullptr.
146 */
147 Reference<reference_type> &
148 operator= (Reference<reference_type> && handle)
149 {
150 // self-movement guts ourself
151 if (m_pBody)
152 m_pBody->release();
153 m_pBody = handle.m_pBody;
154 handle.m_pBody = nullptr;
155 return *this;
156 }
157#endif
158
159 /** Assignment...
160 */
161 Reference<reference_type> &
162 SAL_CALL operator= (reference_type * pBody)
163 {
164 return set( pBody );
165 }
166
167 /** Unbind the body from this handle.
168 Note that for a handle representing a large body,
169 "handle.clear().set(new body());" _might_
170 perform a little bit better than "handle.set(new body());",
171 since in the second case two large objects exist in memory
172 (the old body and the new body).
173 */
174 Reference<reference_type> & SAL_CALL clear()
175 {
176 if (m_pBody
8.1
Field 'm_pBody' is non-null
8.1
Field 'm_pBody' is non-null
8.1
Field 'm_pBody' is non-null
8.1
Field 'm_pBody' is non-null
)
9
Taking true branch
177 {
178 reference_type * const pOld = m_pBody;
179 m_pBody = NULL__null;
180 pOld->release();
10
Calling 'VclReferenceBase::release'
14
Returning; memory was released
181 }
182 return *this;
183 }
184
185
186 /** Get the body. Can be used instead of operator->().
187 I.e. handle->someBodyOp() and handle.get()->someBodyOp()
188 are the same.
189 */
190 reference_type * SAL_CALL get() const
191 {
192 return m_pBody;
17
Use of memory after it is freed
193 }
194
195
196 /** Probably most common used: handle->someBodyOp().
197 */
198 reference_type * SAL_CALL operator->() const
199 {
200 assert(m_pBody != NULL)(static_cast <bool> (m_pBody != __null) ? void (0) : __assert_fail
("m_pBody != NULL", "/home/maarten/src/libreoffice/core/include/rtl/ref.hxx"
, 200, __extension__ __PRETTY_FUNCTION__))
;
201 return m_pBody;
202 }
203
204
205 /** Allows (*handle).someBodyOp().
206 */
207 reference_type & SAL_CALL operator*() const
208 {
209 assert(m_pBody != NULL)(static_cast <bool> (m_pBody != __null) ? void (0) : __assert_fail
("m_pBody != NULL", "/home/maarten/src/libreoffice/core/include/rtl/ref.hxx"
, 209, __extension__ __PRETTY_FUNCTION__))
;
210 return *m_pBody;
211 }
212
213
214 /** Returns True if the handle does point to a valid body.
215 */
216 bool SAL_CALL is() const
217 {
218 return (m_pBody != NULL__null);
219 }
220
221#if defined LIBO_INTERNAL_ONLY1
222 /** Returns True if the handle does point to a valid body.
223 */
224 explicit operator bool() const
225 {
226 return is();
227 }
228#endif
229
230 /** Returns True if this points to pBody.
231 */
232 bool SAL_CALL operator== (const reference_type * pBody) const
233 {
234 return (m_pBody == pBody);
235 }
236
237
238 /** Returns True if handle points to the same body.
239 */
240 bool
241 SAL_CALL operator== (const Reference<reference_type> & handle) const
242 {
243 return (m_pBody == handle.m_pBody);
244 }
245
246
247 /** Needed to place References into STL collection.
248 */
249 bool
250 SAL_CALL operator!= (const Reference<reference_type> & handle) const
251 {
252 return (m_pBody != handle.m_pBody);
253 }
254
255
256 /** Needed to place References into STL collection.
257 */
258 bool
259 SAL_CALL operator< (const Reference<reference_type> & handle) const
260 {
261 return (m_pBody < handle.m_pBody);
262 }
263
264
265 /** Needed to place References into STL collection.
266 */
267 bool
268 SAL_CALL operator> (const Reference<reference_type> & handle) const
269 {
270 return (m_pBody > handle.m_pBody);
271 }
272};
273
274} // namespace rtl
275
276#if defined LIBO_INTERNAL_ONLY1
277namespace std
278{
279
280/// @cond INTERNAL
281/**
282 Make rtl::Reference hashable by default for use in STL containers.
283
284 @since LibreOffice 6.3
285*/
286template<typename T>
287struct hash<::rtl::Reference<T>>
288{
289 std::size_t operator()(::rtl::Reference<T> const & s) const
290 { return std::size_t(s.get()); }
291};
292/// @endcond
293
294}
295
296#endif
297
298#endif /* ! INCLUDED_RTL_REF_HXX */
299
300/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

/home/maarten/src/libreoffice/core/include/vcl/vclreferencebase.hxx

1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19#ifndef INCLUDED_VCL_Reference_HXX
20#define INCLUDED_VCL_Reference_HXX
21
22#include <vcl/dllapi.h>
23#include <osl/interlck.h>
24
25class VCL_DLLPUBLIC__attribute__ ((visibility("default"))) VclReferenceBase
26{
27 mutable oslInterlockedCount mnRefCnt;
28
29 template<typename T> friend class VclPtr;
30
31public:
32 void acquire() const
33 {
34 osl_atomic_increment(&mnRefCnt)__sync_add_and_fetch((&mnRefCnt), 1);
35 }
36
37 void release() const
38 {
39 if (osl_atomic_decrement(&mnRefCnt)__sync_sub_and_fetch((&mnRefCnt), 1) == 0)
11
Assuming the condition is true
12
Taking true branch
40 delete this;
13
Memory is released
41 }
42#ifdef DBG_UTIL
43#ifndef _WIN32
44 sal_Int32 getRefCount() const { return mnRefCnt; }
45#endif
46#endif
47
48
49private:
50 VclReferenceBase(const VclReferenceBase&) = delete;
51 VclReferenceBase& operator=(const VclReferenceBase&) = delete;
52
53 bool mbDisposed : 1;
54
55protected:
56 VclReferenceBase();
57protected:
58 virtual ~VclReferenceBase();
59
60protected:
61 virtual void dispose();
62
63public:
64 void disposeOnce();
65 bool isDisposed() const { return mbDisposed; }
66
67};
68#endif