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 impedit.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/impedit.cxx

/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit.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 "impedit.hxx"
21#include <sal/log.hxx>
22#include <editeng/editeng.hxx>
23#include <editeng/editview.hxx>
24#include <editeng/outliner.hxx>
25#include <tools/poly.hxx>
26#include <editeng/unolingu.hxx>
27#include <com/sun/star/linguistic2/XDictionary.hpp>
28#include <com/sun/star/datatransfer/dnd/DNDConstants.hpp>
29#include <com/sun/star/datatransfer/dnd/XDragGestureRecognizer.hpp>
30#include <com/sun/star/datatransfer/dnd/XDropTarget.hpp>
31#include <com/sun/star/datatransfer/clipboard/XFlushableClipboard.hpp>
32#include <comphelper/lok.hxx>
33#include <editeng/flditem.hxx>
34#include <svl/intitem.hxx>
35#include <vcl/inputctx.hxx>
36#include <vcl/transfer.hxx>
37#include <vcl/svapp.hxx>
38#include <sot/exchange.hxx>
39#include <sot/formats.hxx>
40#include <LibreOfficeKit/LibreOfficeKitEnums.h>
41#include <comphelper/string.hxx>
42#include <sfx2/viewsh.hxx>
43#include <sfx2/lokhelper.hxx>
44#include <boost/property_tree/json_parser.hpp>
45
46using namespace ::com::sun::star;
47using namespace ::com::sun::star::uno;
48using namespace ::com::sun::star::linguistic2;
49
50#define SCRLRANGE20 20 // Scroll 1/20 of the width/height, when in QueryDrop
51
52static void lcl_AllignToPixel( Point& rPoint, OutputDevice const * pOutDev, short nDiffX, short nDiffY )
53{
54 rPoint = pOutDev->LogicToPixel( rPoint );
55
56 if ( nDiffX )
57 rPoint.AdjustX(nDiffX );
58 if ( nDiffY )
59 rPoint.AdjustY(nDiffY );
60
61 rPoint = pOutDev->PixelToLogic( rPoint );
62}
63
64LOKSpecialPositioning::LOKSpecialPositioning(const ImpEditView& rImpEditView, MapUnit eUnit,
65 const tools::Rectangle& rOutputArea,
66 const Point& rVisDocStartPos) :
67 mrImpEditView(rImpEditView),
68 maOutArea(rOutputArea),
69 maVisDocStartPos(rVisDocStartPos),
70 meUnit(eUnit)
71{
72}
73
74void LOKSpecialPositioning::ReInit(MapUnit eUnit, const tools::Rectangle& rOutputArea, const Point& rVisDocStartPos)
75{
76 meUnit = eUnit;
77 maOutArea = rOutputArea;
78 maVisDocStartPos = rVisDocStartPos;
79}
80
81void LOKSpecialPositioning::SetOutputArea(const tools::Rectangle& rOutputArea)
82{
83 maOutArea = rOutputArea;
84}
85
86const tools::Rectangle& LOKSpecialPositioning::GetOutputArea() const
87{
88 return maOutArea;
89}
90
91void LOKSpecialPositioning::SetVisDocStartPos(const Point& rVisDocStartPos)
92{
93 maVisDocStartPos = rVisDocStartPos;
94}
95
96tools::Rectangle LOKSpecialPositioning::GetVisDocArea() const
97{
98 return tools::Rectangle(GetVisDocLeft(), GetVisDocTop(), GetVisDocRight(), GetVisDocBottom());
99}
100
101bool LOKSpecialPositioning::IsVertical() const
102{
103 return mrImpEditView.IsVertical();
104}
105
106bool LOKSpecialPositioning::IsTopToBottom() const
107{
108 return mrImpEditView.IsTopToBottom();
109}
110
111Point LOKSpecialPositioning::GetWindowPos(const Point& rDocPos, MapUnit eDocPosUnit) const
112{
113 const Point aDocPos = convertUnit(rDocPos, eDocPosUnit);
114 Point aPoint;
115 if ( !IsVertical() )
116 {
117 aPoint.setX(aDocPos.X() + maOutArea.Left() - GetVisDocLeft());
118 aPoint.setY(aDocPos.Y() + maOutArea.Top() - GetVisDocTop());
119 }
120 else
121 {
122 if (IsTopToBottom())
123 {
124 aPoint.setX(maOutArea.Right() - aDocPos.Y() + GetVisDocTop());
125 aPoint.setY(aDocPos.X() + maOutArea.Top() - GetVisDocLeft());
126 }
127 else
128 {
129 aPoint.setX(maOutArea.Left() + aDocPos.Y() - GetVisDocTop());
130 aPoint.setY(maOutArea.Bottom() - aDocPos.X() + GetVisDocLeft());
131 }
132 }
133
134 return aPoint;
135}
136
137tools::Rectangle LOKSpecialPositioning::GetWindowPos(const tools::Rectangle& rDocRect, MapUnit eDocRectUnit) const
138{
139 const tools::Rectangle aDocRect = convertUnit(rDocRect, eDocRectUnit);
140 Point aPos(GetWindowPos(aDocRect.TopLeft(), meUnit));
141 Size aSz = aDocRect.GetSize();
142 tools::Rectangle aRect;
143 if (!IsVertical())
144 {
145 aRect = tools::Rectangle(aPos, aSz);
146 }
147 else
148 {
149 Point aNewPos(aPos.X() - aSz.Height(), aPos.Y());
150 // coverity[swapped_arguments : FALSE] - this is in the correct order
151 aRect = tools::Rectangle(aNewPos, Size(aSz.Height(), aSz.Width()));
152 }
153 return aRect;
154}
155
156Point LOKSpecialPositioning::convertUnit(const Point& rPos, MapUnit ePosUnit) const
157{
158 if (ePosUnit == meUnit)
159 return rPos;
160
161 return OutputDevice::LogicToLogic(rPos, MapMode(ePosUnit), MapMode(meUnit));
162}
163
164tools::Rectangle LOKSpecialPositioning::convertUnit(const tools::Rectangle& rRect, MapUnit eRectUnit) const
165{
166 if (eRectUnit == meUnit)
167 return rRect;
168
169 return OutputDevice::LogicToLogic(rRect, MapMode(eRectUnit), MapMode(meUnit));
170}
171
172Point LOKSpecialPositioning::GetRefPoint() const
173{
174 return maOutArea.TopLeft();
175}
176
177// class ImpEditView
178
179ImpEditView::ImpEditView( EditView* pView, EditEngine* pEng, vcl::Window* pWindow ) :
180 pEditView(pView),
181 mpViewShell(nullptr),
182 mpOtherShell(nullptr),
183 pEditEngine(pEng),
184 pOutWin(pWindow),
185 nInvMore(1),
186 nControl(EVControlBits::AUTOSCROLL | EVControlBits::ENABLEPASTE),
187 nTravelXPos(TRAVEL_X_DONTKNOW0xFFFFFFFF),
188 nExtraCursorFlags(GetCursorFlags::NONE),
189 nCursorBidiLevel(CURSOR_BIDILEVEL_DONTKNOW0xFFFF),
190 nScrollDiffX(0),
191 bReadOnly(false),
192 bClickedInSelection(false),
193 bActiveDragAndDropListener(false),
194 aOutArea( Point(), pEng->GetPaperSize() ),
195 eSelectionMode(EESelectionMode::Std),
196 eAnchorMode(EEAnchorMode::TopLeft),
197 mpEditViewCallbacks(nullptr),
198 mbBroadcastLOKViewCursor(comphelper::LibreOfficeKit::isActive()),
199 mbSuppressLOKMessages(false)
200{
201 aEditSelection.Min() = pEng->GetEditDoc().GetStartPaM();
202 aEditSelection.Max() = pEng->GetEditDoc().GetEndPaM();
203
204 SelectionChanged();
205}
206
207ImpEditView::~ImpEditView()
208{
209 RemoveDragAndDropListeners();
210
211 if ( pOutWin && ( pOutWin->GetCursor() == pCursor.get() ) )
212 pOutWin->SetCursor( nullptr );
213}
1
Calling '~unique_ptr'
214
215void ImpEditView::SetBackgroundColor( const Color& rColor )
216{
217 pBackgroundColor.reset( new Color( rColor ) );
218}
219
220void ImpEditView::RegisterViewShell(OutlinerViewShell* pViewShell)
221{
222 mpViewShell = pViewShell;
223}
224
225void ImpEditView::RegisterOtherShell(OutlinerViewShell* pOtherShell)
226{
227 mpOtherShell = pOtherShell;
228}
229
230const OutlinerViewShell* ImpEditView::GetViewShell() const
231{
232 return mpViewShell;
233}
234
235void ImpEditView::SetEditSelection( const EditSelection& rEditSelection )
236{
237 // set state before notification
238 aEditSelection = rEditSelection;
239
240 SelectionChanged();
241
242 if (comphelper::LibreOfficeKit::isActive())
243 // Tiled rendering: selections are only painted when we are in selection mode.
244 pEditEngine->SetInSelectionMode(aEditSelection.HasRange());
245
246 if ( pEditEngine->pImpEditEngine->GetNotifyHdl().IsSet() )
247 {
248 const EditDoc& rDoc = pEditEngine->GetEditDoc();
249 const EditPaM pmEnd = rDoc.GetEndPaM();
250 EENotifyType eNotifyType;
251 if (rDoc.Count() > 1 &&
252 pmEnd == rEditSelection.Min() &&
253 pmEnd == rEditSelection.Max())//if move cursor to the last para.
254 {
255 eNotifyType = EE_NOTIFY_TEXTVIEWSELECTIONCHANGED_ENDD_PARA;
256 }
257 else
258 {
259 eNotifyType = EE_NOTIFY_TEXTVIEWSELECTIONCHANGED;
260 }
261 EENotify aNotify( eNotifyType );
262 pEditEngine->pImpEditEngine->GetNotifyHdl().Call( aNotify );
263 }
264 if(pEditEngine->pImpEditEngine->IsFormatted())
265 {
266 EENotify aNotify(EE_NOTIFY_PROCESSNOTIFICATIONS);
267 pEditEngine->pImpEditEngine->GetNotifyHdl().Call(aNotify);
268 }
269}
270
271/// Translate absolute <-> relative twips: LOK wants absolute coordinates as output and gives absolute coordinates as input.
272static void lcl_translateTwips(vcl::Window const & rParent, vcl::Window& rChild)
273{
274 // Don't translate if we already have a non-zero origin.
275 // This prevents multiple translate calls that negate
276 // one another.
277 const Point aOrigin = rChild.GetMapMode().GetOrigin();
278 if (aOrigin.getX() != 0 || aOrigin.getY() != 0)
279 return;
280
281 // Set map mode, so that callback payloads will contain absolute coordinates instead of relative ones.
282 Point aOffset(rChild.GetOutOffXPixel() - rParent.GetOutOffXPixel(), rChild.GetOutOffYPixel() - rParent.GetOutOffYPixel());
283 if (!rChild.IsMapModeEnabled())
284 {
285 MapMode aMapMode(rChild.GetMapMode());
286 aMapMode.SetMapUnit(MapUnit::MapTwip);
287 aMapMode.SetScaleX(rParent.GetMapMode().GetScaleX());
288 aMapMode.SetScaleY(rParent.GetMapMode().GetScaleY());
289 rChild.SetMapMode(aMapMode);
290 rChild.EnableMapMode();
291 }
292 aOffset = rChild.PixelToLogic(aOffset);
293 MapMode aMapMode(rChild.GetMapMode());
294 aMapMode.SetOrigin(aOffset);
295 aMapMode.SetMapUnit(rParent.GetMapMode().GetMapUnit());
296 rChild.SetMapMode(aMapMode);
297 rChild.EnableMapMode(false);
298}
299
300// EditView never had a central/secure place to react on SelectionChange since
301// Selection was changed in many places, often by not using SetEditSelection()
302// but (mis)using GetEditSelection() and manipulating this non-const return
303// value. Sorted this out now to have such a place, this is needed for safely
304// change/update the Selection visualization for enhanced mechanisms
305void ImpEditView::SelectionChanged()
306{
307 if (EditViewCallbacks* pCallbacks = getEditViewCallbacks())
308 {
309 // use callback to tell about change in selection visualisation
310 pCallbacks->EditViewSelectionChange();
311 }
312}
313
314// This function is also called when a text's font || size is changed. Because its highlight rectangle must be updated.
315void ImpEditView::lokSelectionCallback(const std::unique_ptr<tools::PolyPolygon> &pPolyPoly, bool bStartHandleVisible, bool bEndHandleVisible) {
316 VclPtr<vcl::Window> pParent = pOutWin->GetParentWithLOKNotifier();
317 vcl::Region aRegion( *pPolyPoly );
318
319 if (pParent && pParent->GetLOKWindowId() != 0)
320 {
321 const long nX = pOutWin->GetOutOffXPixel() - pParent->GetOutOffXPixel();
322 const long nY = pOutWin->GetOutOffYPixel() - pParent->GetOutOffYPixel();
323
324 std::vector<tools::Rectangle> aRectangles;
325 aRegion.GetRegionRectangles(aRectangles);
326
327 std::vector<OString> v;
328 for (tools::Rectangle & rRectangle : aRectangles)
329 {
330 rRectangle = pOutWin->LogicToPixel(rRectangle);
331 rRectangle.Move(nX, nY);
332 v.emplace_back(rRectangle.toString().getStr());
333 }
334 OString sRectangle = comphelper::string::join("; ", v);
335
336 const vcl::ILibreOfficeKitNotifier* pNotifier = pParent->GetLOKNotifier();
337 std::vector<vcl::LOKPayloadItem> aItems;
338 aItems.emplace_back("rectangles", sRectangle);
339 aItems.emplace_back("startHandleVisible", OString::boolean(bStartHandleVisible));
340 aItems.emplace_back("endHandleVisible", OString::boolean(bEndHandleVisible));
341 pNotifier->notifyWindow(pParent->GetLOKWindowId(), "text_selection", aItems);
342 }
343 else
344 {
345 pOutWin->Push(PushFlags::MAPMODE);
346 if (pOutWin->GetMapMode().GetMapUnit() == MapUnit::MapTwip)
347 {
348 // Find the parent that is not right
349 // on top of us to use its offset.
350 vcl::Window* parent = pOutWin->GetParent();
351 while (parent &&
352 parent->GetOutOffXPixel() == pOutWin->GetOutOffXPixel() &&
353 parent->GetOutOffYPixel() == pOutWin->GetOutOffYPixel())
354 {
355 parent = parent->GetParent();
356 }
357
358 if (parent)
359 {
360 lcl_translateTwips(*parent, *pOutWin);
361 }
362 }
363
364 bool bMm100ToTwip = !mpLOKSpecialPositioning &&
365 (pOutWin->GetMapMode().GetMapUnit() == MapUnit::Map100thMM);
366
367 Point aOrigin;
368 if (pOutWin->GetMapMode().GetMapUnit() == MapUnit::MapTwip)
369 // Writer comments: they use editeng, but are separate widgets.
370 aOrigin = pOutWin->GetMapMode().GetOrigin();
371
372 OString sRectangle;
373 OString sRefPoint;
374 if (mpLOKSpecialPositioning)
375 sRefPoint = mpLOKSpecialPositioning->GetRefPoint().toString();
376
377 std::vector<tools::Rectangle> aRectangles;
378 aRegion.GetRegionRectangles(aRectangles);
379
380 if (!aRectangles.empty())
381 {
382 if (pOutWin->IsChart())
383 {
384 const vcl::Window* pViewShellWindow = mpViewShell->GetEditWindowForActiveOLEObj();
385 if (pViewShellWindow && pViewShellWindow->IsAncestorOf(*pOutWin))
386 {
387 Point aOffsetPx = pOutWin->GetOffsetPixelFrom(*pViewShellWindow);
388 Point aLogicOffset = pOutWin->PixelToLogic(aOffsetPx);
389 for (tools::Rectangle& rRect : aRectangles)
390 rRect.Move(aLogicOffset.getX(), aLogicOffset.getY());
391 }
392 }
393
394 std::vector<OString> v;
395 for (tools::Rectangle & rRectangle : aRectangles)
396 {
397 if (bMm100ToTwip)
398 rRectangle = OutputDevice::LogicToLogic(rRectangle, MapMode(MapUnit::Map100thMM), MapMode(MapUnit::MapTwip));
399 rRectangle.Move(aOrigin.getX(), aOrigin.getY());
400 v.emplace_back(rRectangle.toString().getStr());
401 }
402 sRectangle = comphelper::string::join("; ", v);
403
404 if (mpLOKSpecialPositioning && !sRectangle.isEmpty())
405 sRectangle += ":: " + sRefPoint;
406
407 tools::Rectangle& rStart = aRectangles.front();
408 tools::Rectangle aStart(rStart.Left(), rStart.Top(), rStart.Left() + 1, rStart.Bottom());
409
410 OString aPayload = aStart.toString();
411 if (mpLOKSpecialPositioning)
412 aPayload += ":: " + sRefPoint;
413
414 mpViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_TEXT_SELECTION_START, aPayload.getStr());
415
416 tools::Rectangle& rEnd = aRectangles.back();
417 tools::Rectangle aEnd(rEnd.Right() - 1, rEnd.Top(), rEnd.Right(), rEnd.Bottom());
418
419 aPayload = aEnd.toString();
420 if (mpLOKSpecialPositioning)
421 aPayload += ":: " + sRefPoint;
422
423 mpViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_TEXT_SELECTION_END, aPayload.getStr());
424 }
425
426 if (mpOtherShell)
427 {
428 // Another shell wants to know about our existing selection.
429 if (mpViewShell != mpOtherShell)
430 mpViewShell->NotifyOtherView(mpOtherShell, LOK_CALLBACK_TEXT_VIEW_SELECTION, "selection", sRectangle);
431 }
432 else
433 {
434 mpViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_TEXT_SELECTION, sRectangle.getStr());
435 mpViewShell->NotifyOtherViews(LOK_CALLBACK_TEXT_VIEW_SELECTION, "selection", sRectangle);
436 }
437
438 pOutWin->Pop();
439 }
440}
441
442// renamed from DrawSelection to DrawSelectionXOR to better reflect what this
443// method was used for: Paint Selection in XOR, change it and again paint it in XOR.
444// This can be safely assumed due to the EditView only being capable of painting the
445// selection in XOR until today.
446// This also means that all places calling DrawSelectionXOR are thoroughly weighted
447// and chosen to make this fragile XOR-paint water-proof and thus contain some
448// information in this sense.
449// Someone thankfully expanded it to collect the SelectionRectangles when called with
450// the Region*, see GetSelectionRectangles below.
451void ImpEditView::DrawSelectionXOR( EditSelection aTmpSel, vcl::Region* pRegion, OutputDevice* pTargetDevice )
452{
453 if (getEditViewCallbacks() && !pRegion && !comphelper::LibreOfficeKit::isActive())
454 {
455 // we are done, do *not* visualize self
456 // CAUTION: do not use when comphelper::LibreOfficeKit::isActive()
457 // due to event stuff triggered below. That *should* probably be moved
458 // to SelectionChanged() which exists now, but I do not know enough about
459 // that stuff to do it
460 return;
461 }
462
463 if ( eSelectionMode == EESelectionMode::Hidden )
464 return;
465
466 // It must be ensured before rendering the selection, that the contents of
467 // the window is completely valid! Must be here so that in any case if
468 // empty, then later on two-Paint Events! Must be done even before the
469 // query from bUpdate, if after Invalidate paints still in the queue,
470 // but someone switches the update mode!
471
472 // pRegion: When not NULL, then only calculate Region.
473
474 OutputDevice* pTarget;
475 if (pTargetDevice)
476 pTarget = pTargetDevice;
477 else
478 pTarget = getEditViewCallbacks() ? &getEditViewCallbacks()->EditViewOutputDevice() : pOutWin;
479 bool bClipRegion = pTarget->IsClipRegion();
480 vcl::Region aOldRegion = pTarget->GetClipRegion();
481
482 std::unique_ptr<tools::PolyPolygon> pPolyPoly;
483
484 if ( !pRegion && !comphelper::LibreOfficeKit::isActive())
485 {
486 if ( !pEditEngine->pImpEditEngine->GetUpdateMode() )
487 return;
488 if ( pEditEngine->pImpEditEngine->IsInUndo() )
489 return;
490
491 if ( !aTmpSel.HasRange() )
492 return;
493
494 // aTmpOutArea: if OutputArea > Paper width and
495 // Text > Paper width ( over large fields )
496 tools::Rectangle aTmpOutArea( aOutArea );
497 if ( aTmpOutArea.GetWidth() > pEditEngine->pImpEditEngine->GetPaperSize().Width() )
498 aTmpOutArea.SetRight( aTmpOutArea.Left() + pEditEngine->pImpEditEngine->GetPaperSize().Width() );
499 pTarget->IntersectClipRegion( aTmpOutArea );
500
501 if (pOutWin && pOutWin->GetCursor())
502 pOutWin->GetCursor()->Hide();
503 }
504
505 if (comphelper::LibreOfficeKit::isActive() || pRegion)
506 pPolyPoly.reset(new tools::PolyPolygon);
507
508 DBG_ASSERT( !pEditEngine->IsIdleFormatterActive(), "DrawSelectionXOR: Not formatted!" )do { if (true && (!(!pEditEngine->IsIdleFormatterActive
()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"
), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit.cxx"
":" "508" ": "), "%s", "DrawSelectionXOR: Not formatted!"); }
} while (false)
;
509 aTmpSel.Adjust( pEditEngine->GetEditDoc() );
510
511 ContentNode* pStartNode = aTmpSel.Min().GetNode();
512 ContentNode* pEndNode = aTmpSel.Max().GetNode();
513 const sal_Int32 nStartPara = pEditEngine->GetEditDoc().GetPos(pStartNode);
514 const sal_Int32 nEndPara = pEditEngine->GetEditDoc().GetPos(pEndNode);
515 if (nStartPara == EE_PARA_NOT_FOUND((sal_Int32) 0x7FFFFFFF) || nEndPara == EE_PARA_NOT_FOUND((sal_Int32) 0x7FFFFFFF))
516 return;
517
518 bool bStartHandleVisible = false;
519 bool bEndHandleVisible = false;
520
521 for ( sal_Int32 nPara = nStartPara; nPara <= nEndPara; nPara++ )
522 {
523 ParaPortion* pTmpPortion = pEditEngine->GetParaPortions().SafeGetObject( nPara );
524 if (!pTmpPortion)
525 {
526 SAL_WARN( "editeng", "Portion in Selection not found!" )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() << "Portion in Selection not found!"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("editeng"
), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit.cxx"
":" "526" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "Portion in Selection not found!"), 0)
; } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Portion in Selection not found!"; ::sal::detail::log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("editeng"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit.cxx"
":" "526" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "Portion in Selection not found!") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("editeng"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit.cxx"
":" "526" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "Portion in Selection not found!"), 0)
; } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "Portion in Selection not found!"; ::sal::detail::log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("editeng"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit.cxx"
":" "526" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
527 continue;
528 }
529
530 DBG_ASSERT( !pTmpPortion->IsInvalid(), "Portion in Selection not formatted!" )do { if (true && (!(!pTmpPortion->IsInvalid()))) {
sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"
), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit.cxx"
":" "530" ": "), "%s", "Portion in Selection not formatted!"
); } } while (false)
;
531
532 if ( !pTmpPortion->IsVisible() || pTmpPortion->IsInvalid() )
533 continue;
534
535 long nParaStart = pEditEngine->GetParaPortions().GetYOffset( pTmpPortion );
536 if ( ( nParaStart + pTmpPortion->GetHeight() ) < GetVisDocTop() )
537 continue;
538 if ( nParaStart > GetVisDocBottom() )
539 break;
540
541 sal_uInt16 nStartLine = 0;
542 sal_uInt16 nEndLine = pTmpPortion->GetLines().Count() -1;
543 if ( nPara == nStartPara )
544 nStartLine = pTmpPortion->GetLines().FindLine( aTmpSel.Min().GetIndex(), false );
545 if ( nPara == nEndPara )
546 nEndLine = pTmpPortion->GetLines().FindLine( aTmpSel.Max().GetIndex(), true );
547
548 for ( sal_uInt16 nLine = nStartLine; nLine <= nEndLine; nLine++ )
549 {
550 const EditLine& rLine = pTmpPortion->GetLines()[nLine];
551
552 bool bPartOfLine = false;
553 sal_Int32 nStartIndex = rLine.GetStart();
554 sal_Int32 nEndIndex = rLine.GetEnd();
555 if ( ( nPara == nStartPara ) && ( nLine == nStartLine ) && ( nStartIndex != aTmpSel.Min().GetIndex() ) )
556 {
557 nStartIndex = aTmpSel.Min().GetIndex();
558 bPartOfLine = true;
559 }
560 if ( ( nPara == nEndPara ) && ( nLine == nEndLine ) && ( nEndIndex != aTmpSel.Max().GetIndex() ) )
561 {
562 nEndIndex = aTmpSel.Max().GetIndex();
563 bPartOfLine = true;
564 }
565
566 // Can happen if at the beginning of a wrapped line.
567 if ( nEndIndex < nStartIndex )
568 nEndIndex = nStartIndex;
569
570 tools::Rectangle aTmpRect( pEditEngine->pImpEditEngine->GetEditCursor( pTmpPortion, nStartIndex ) );
571 Point aTopLeft( aTmpRect.TopLeft() );
572 Point aBottomRight( aTmpRect.BottomRight() );
573
574 aTopLeft.AdjustY(nParaStart );
575 aBottomRight.AdjustY(nParaStart );
576
577 // Only paint if in the visible range ...
578 if ( aTopLeft.Y() > GetVisDocBottom() )
579 break;
580
581 if ( aBottomRight.Y() < GetVisDocTop() )
582 continue;
583
584 if ( ( nPara == nStartPara ) && ( nLine == nStartLine ) )
585 bStartHandleVisible = true;
586 if ( ( nPara == nEndPara ) && ( nLine == nEndLine ) )
587 bEndHandleVisible = true;
588
589 // Now that we have Bidi, the first/last index doesn't have to be the 'most outside' position
590 if ( !bPartOfLine )
591 {
592 Range aLineXPosStartEnd = pEditEngine->GetLineXPosStartEnd(pTmpPortion, &rLine);
593 aTopLeft.setX( aLineXPosStartEnd.Min() );
594 aBottomRight.setX( aLineXPosStartEnd.Max() );
595 ImplDrawHighlightRect( pTarget, aTopLeft, aBottomRight, pPolyPoly.get() );
596 }
597 else
598 {
599 sal_Int32 nTmpStartIndex = nStartIndex;
600 sal_Int32 nWritingDirStart, nTmpEndIndex;
601
602 while ( nTmpStartIndex < nEndIndex )
603 {
604 pEditEngine->pImpEditEngine->GetRightToLeft( nPara, nTmpStartIndex+1, &nWritingDirStart, &nTmpEndIndex );
605 if ( nTmpEndIndex > nEndIndex )
606 nTmpEndIndex = nEndIndex;
607
608 DBG_ASSERT( nTmpEndIndex > nTmpStartIndex, "DrawSelectionXOR, Start >= End?" )do { if (true && (!(nTmpEndIndex > nTmpStartIndex)
)) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"
), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit.cxx"
":" "608" ": "), "%s", "DrawSelectionXOR, Start >= End?")
; } } while (false)
;
609
610 long nX1 = pEditEngine->GetXPos(pTmpPortion, &rLine, nTmpStartIndex, true);
611 long nX2 = pEditEngine->GetXPos(pTmpPortion, &rLine, nTmpEndIndex);
612
613 Point aPt1( std::min( nX1, nX2 ), aTopLeft.Y() );
614 Point aPt2( std::max( nX1, nX2 ), aBottomRight.Y() );
615
616 ImplDrawHighlightRect( pTarget, aPt1, aPt2, pPolyPoly.get() );
617 nTmpStartIndex = nTmpEndIndex;
618 }
619 }
620 }
621 }
622
623 if (comphelper::LibreOfficeKit::isActive() && mpViewShell && pOutWin)
624 lokSelectionCallback(pPolyPoly, bStartHandleVisible, bEndHandleVisible);
625
626 if (pRegion || comphelper::LibreOfficeKit::isActive())
627 {
628 if (pRegion)
629 *pRegion = vcl::Region( *pPolyPoly );
630 pPolyPoly.reset();
631 }
632 else
633 {
634 if (pOutWin && pOutWin->GetCursor())
635 pOutWin->GetCursor()->Show();
636
637 if ( bClipRegion )
638 pTarget->SetClipRegion( aOldRegion );
639 else
640 pTarget->SetClipRegion();
641 }
642}
643
644void ImpEditView::GetSelectionRectangles(EditSelection aTmpSel, std::vector<tools::Rectangle>& rLogicRects)
645{
646 vcl::Region aRegion;
647 DrawSelectionXOR(aTmpSel, &aRegion);
648 aRegion.GetRegionRectangles(rLogicRects);
649}
650
651void ImpEditView::ImplDrawHighlightRect( OutputDevice* _pTarget, const Point& rDocPosTopLeft, const Point& rDocPosBottomRight, tools::PolyPolygon* pPolyPoly )
652{
653 if ( rDocPosTopLeft.X() == rDocPosBottomRight.X() )
654 return;
655
656 if (mpLOKSpecialPositioning && pPolyPoly)
657 {
658 MapUnit eDevUnit = _pTarget->GetMapMode().GetMapUnit();
659 tools::Rectangle aSelRect(rDocPosTopLeft, rDocPosBottomRight);
660 aSelRect = mpLOKSpecialPositioning->GetWindowPos(aSelRect, eDevUnit);
661 const Point aRefPoint = mpLOKSpecialPositioning->GetRefPoint();
662 aSelRect.Move(-aRefPoint.X(), -aRefPoint.Y());
663
664 tools::Polygon aTmpPoly(4);
665 aTmpPoly[0] = aSelRect.TopLeft();
666 aTmpPoly[1] = aSelRect.TopRight();
667 aTmpPoly[2] = aSelRect.BottomRight();
668 aTmpPoly[3] = aSelRect.BottomLeft();
669 pPolyPoly->Insert(aTmpPoly);
670 return;
671 }
672
673 bool bPixelMode = _pTarget->GetMapMode().GetMapUnit() == MapUnit::MapPixel;
674
675 Point aPnt1( GetWindowPos( rDocPosTopLeft ) );
676 Point aPnt2( GetWindowPos( rDocPosBottomRight ) );
677
678 if ( !IsVertical() )
679 {
680 lcl_AllignToPixel( aPnt1, _pTarget, +1, 0 );
681 lcl_AllignToPixel( aPnt2, _pTarget, 0, ( bPixelMode ? 0 : -1 ) );
682 }
683 else
684 {
685 lcl_AllignToPixel( aPnt1, _pTarget, 0, +1 );
686 lcl_AllignToPixel( aPnt2, _pTarget, ( bPixelMode ? 0 : +1 ), 0 );
687 }
688
689 tools::Rectangle aRect( aPnt1, aPnt2 );
690 if ( pPolyPoly )
691 {
692 tools::Polygon aTmpPoly( 4 );
693 aTmpPoly[0] = aRect.TopLeft();
694 aTmpPoly[1] = aRect.TopRight();
695 aTmpPoly[2] = aRect.BottomRight();
696 aTmpPoly[3] = aRect.BottomLeft();
697 pPolyPoly->Insert( aTmpPoly );
698 }
699 else
700 {
701 vcl::Window* pWindow = dynamic_cast< vcl::Window* >(_pTarget);
702
703 if(pWindow)
704 {
705 pWindow->Invert( aRect );
706 }
707 else
708 {
709 _pTarget->Push(PushFlags::LINECOLOR|PushFlags::FILLCOLOR|PushFlags::RASTEROP);
710 _pTarget->SetLineColor();
711 _pTarget->SetFillColor(COL_BLACK);
712 _pTarget->SetRasterOp(RasterOp::Invert);
713 _pTarget->DrawRect(aRect);
714 _pTarget->Pop();
715 }
716 }
717}
718
719
720bool ImpEditView::IsVertical() const
721{
722 return pEditEngine->pImpEditEngine->IsVertical();
723}
724
725bool ImpEditView::IsTopToBottom() const
726{
727 return pEditEngine->pImpEditEngine->IsTopToBottom();
728}
729
730tools::Rectangle ImpEditView::GetVisDocArea() const
731{
732 return tools::Rectangle( GetVisDocLeft(), GetVisDocTop(), GetVisDocRight(), GetVisDocBottom() );
733}
734
735Point ImpEditView::GetDocPos( const Point& rWindowPos ) const
736{
737 // Window Position => Position Document
738 Point aPoint;
739
740 if ( !pEditEngine->pImpEditEngine->IsVertical() )
741 {
742 aPoint.setX( rWindowPos.X() - aOutArea.Left() + GetVisDocLeft() );
743 aPoint.setY( rWindowPos.Y() - aOutArea.Top() + GetVisDocTop() );
744 }
745 else
746 {
747 if (pEditEngine->pImpEditEngine->IsTopToBottom())
748 {
749 aPoint.setX( rWindowPos.Y() - aOutArea.Top() + GetVisDocLeft() );
750 aPoint.setY( aOutArea.Right() - rWindowPos.X() + GetVisDocTop() );
751 }
752 else
753 {
754 aPoint.setX( aOutArea.Bottom() - rWindowPos.Y() + GetVisDocLeft() );
755 aPoint.setY( rWindowPos.X() - aOutArea.Left() + GetVisDocTop() );
756 }
757 }
758
759 return aPoint;
760}
761
762Point ImpEditView::GetWindowPos( const Point& rDocPos ) const
763{
764 // Document position => window position
765 Point aPoint;
766
767 if ( !pEditEngine->pImpEditEngine->IsVertical() )
768 {
769 aPoint.setX( rDocPos.X() + aOutArea.Left() - GetVisDocLeft() );
770 aPoint.setY( rDocPos.Y() + aOutArea.Top() - GetVisDocTop() );
771 }
772 else
773 {
774 if (pEditEngine->pImpEditEngine->IsTopToBottom())
775 {
776 aPoint.setX( aOutArea.Right() - rDocPos.Y() + GetVisDocTop() );
777 aPoint.setY( rDocPos.X() + aOutArea.Top() - GetVisDocLeft() );
778 }
779 else
780 {
781 aPoint.setX( aOutArea.Left() + rDocPos.Y() - GetVisDocTop() );
782 aPoint.setY( aOutArea.Bottom() - rDocPos.X() + GetVisDocLeft() );
783 }
784 }
785
786 return aPoint;
787}
788
789tools::Rectangle ImpEditView::GetWindowPos( const tools::Rectangle& rDocRect ) const
790{
791 // Document position => window position
792 Point aPos( GetWindowPos( rDocRect.TopLeft() ) );
793 Size aSz = rDocRect.GetSize();
794 tools::Rectangle aRect;
795 if ( !pEditEngine->pImpEditEngine->IsVertical() )
796 {
797 aRect = tools::Rectangle( aPos, aSz );
798 }
799 else
800 {
801 Point aNewPos( aPos.X()-aSz.Height(), aPos.Y() );
802 // coverity[swapped_arguments : FALSE] - this is in the correct order
803 aRect = tools::Rectangle( aNewPos, Size( aSz.Height(), aSz.Width() ) );
804 }
805 return aRect;
806}
807
808void ImpEditView::SetSelectionMode( EESelectionMode eNewMode )
809{
810 if ( eSelectionMode != eNewMode )
811 {
812 DrawSelectionXOR();
813 eSelectionMode = eNewMode;
814 DrawSelectionXOR(); // redraw
815 }
816}
817
818void ImpEditView::SetOutputArea( const tools::Rectangle& rRect )
819{
820 const OutputDevice& rOutDev = getEditViewCallbacks() ? getEditViewCallbacks()->EditViewOutputDevice() : *pOutWin;
821 // should be better be aligned on pixels!
822 tools::Rectangle aNewRect(rOutDev.LogicToPixel(rRect));
823 aNewRect = rOutDev.PixelToLogic(aNewRect);
824 aOutArea = aNewRect;
825 if ( !aOutArea.IsWidthEmpty() && aOutArea.Right() < aOutArea.Left() )
826 aOutArea.SetRight( aOutArea.Left() );
827 if ( !aOutArea.IsHeightEmpty() && aOutArea.Bottom() < aOutArea.Top() )
828 aOutArea.SetBottom( aOutArea.Top() );
829
830 SetScrollDiffX( static_cast<sal_uInt16>(aOutArea.GetWidth()) * 2 / 10 );
831}
832
833void ImpEditView::InvalidateAtWindow(const tools::Rectangle& rRect)
834{
835 if (EditViewCallbacks* pCallbacks = getEditViewCallbacks())
836 {
837 // do not invalidate and trigger a global repaint, but forward
838 // the need for change to the applied EditViewCallback, can e.g.
839 // be used to visualize the active edit text in an OverlayObject
840 pCallbacks->EditViewInvalidate(rRect);
841 }
842 else
843 {
844 // classic mode: invalidate and trigger full repaint
845 // of the changed area
846 GetWindow()->Invalidate(rRect);
847 }
848}
849
850void ImpEditView::ResetOutputArea( const tools::Rectangle& rRect )
851{
852 // remember old out area
853 const tools::Rectangle aOldArea(aOutArea);
854
855 // apply new one
856 SetOutputArea(rRect);
857
858 // invalidate surrounding areas if update is true
859 if(aOldArea.IsEmpty() || !pEditEngine->pImpEditEngine->GetUpdateMode())
860 return;
861
862 // #i119885# use grown area if needed; do when getting bigger OR smaller
863 const sal_Int32 nMore(DoInvalidateMore() ? GetWindow()->PixelToLogic(Size(nInvMore, 0)).Width() : 0);
864
865 if(aOldArea.Left() > aOutArea.Left())
866 {
867 const tools::Rectangle aRect(aOutArea.Left() - nMore, aOldArea.Top() - nMore, aOldArea.Left(), aOldArea.Bottom() + nMore);
868 InvalidateAtWindow(aRect);
869 }
870 else if(aOldArea.Left() < aOutArea.Left())
871 {
872 const tools::Rectangle aRect(aOldArea.Left() - nMore, aOldArea.Top() - nMore, aOutArea.Left(), aOldArea.Bottom() + nMore);
873 InvalidateAtWindow(aRect);
874 }
875
876 if(aOldArea.Right() > aOutArea.Right())
877 {
878 const tools::Rectangle aRect(aOutArea.Right(), aOldArea.Top() - nMore, aOldArea.Right() + nMore, aOldArea.Bottom() + nMore);
879 InvalidateAtWindow(aRect);
880 }
881 else if(aOldArea.Right() < aOutArea.Right())
882 {
883 const tools::Rectangle aRect(aOldArea.Right(), aOldArea.Top() - nMore, aOutArea.Right() + nMore, aOldArea.Bottom() + nMore);
884 InvalidateAtWindow(aRect);
885 }
886
887 if(aOldArea.Top() > aOutArea.Top())
888 {
889 const tools::Rectangle aRect(aOldArea.Left() - nMore, aOutArea.Top() - nMore, aOldArea.Right() + nMore, aOldArea.Top());
890 InvalidateAtWindow(aRect);
891 }
892 else if(aOldArea.Top() < aOutArea.Top())
893 {
894 const tools::Rectangle aRect(aOldArea.Left() - nMore, aOldArea.Top() - nMore, aOldArea.Right() + nMore, aOutArea.Top());
895 InvalidateAtWindow(aRect);
896 }
897
898 if(aOldArea.Bottom() > aOutArea.Bottom())
899 {
900 const tools::Rectangle aRect(aOldArea.Left() - nMore, aOutArea.Bottom(), aOldArea.Right() + nMore, aOldArea.Bottom() + nMore);
901 InvalidateAtWindow(aRect);
902 }
903 else if(aOldArea.Bottom() < aOutArea.Bottom())
904 {
905 const tools::Rectangle aRect(aOldArea.Left() - nMore, aOldArea.Bottom(), aOldArea.Right() + nMore, aOutArea.Bottom() + nMore);
906 InvalidateAtWindow(aRect);
907 }
908}
909
910void ImpEditView::RecalcOutputArea()
911{
912 Point aNewTopLeft( aOutArea.TopLeft() );
913 Size aNewSz( aOutArea.GetSize() );
914
915 // X:
916 if ( DoAutoWidth() )
917 {
918 if ( pEditEngine->pImpEditEngine->GetStatus().AutoPageWidth() )
919 aNewSz.setWidth( pEditEngine->pImpEditEngine->GetPaperSize().Width() );
920 switch ( eAnchorMode )
921 {
922 case EEAnchorMode::TopLeft:
923 case EEAnchorMode::VCenterLeft:
924 case EEAnchorMode::BottomLeft:
925 {
926 aNewTopLeft.setX( aAnchorPoint.X() );
927 }
928 break;
929 case EEAnchorMode::TopHCenter:
930 case EEAnchorMode::VCenterHCenter:
931 case EEAnchorMode::BottomHCenter:
932 {
933 aNewTopLeft.setX( aAnchorPoint.X() - aNewSz.Width() / 2 );
934 }
935 break;
936 case EEAnchorMode::TopRight:
937 case EEAnchorMode::VCenterRight:
938 case EEAnchorMode::BottomRight:
939 {
940 aNewTopLeft.setX( aAnchorPoint.X() - aNewSz.Width() - 1 );
941 }
942 break;
943 }
944 }
945
946 // Y:
947 if ( DoAutoHeight() )
948 {
949 if ( pEditEngine->pImpEditEngine->GetStatus().AutoPageHeight() )
950 aNewSz.setHeight( pEditEngine->pImpEditEngine->GetPaperSize().Height() );
951 switch ( eAnchorMode )
952 {
953 case EEAnchorMode::TopLeft:
954 case EEAnchorMode::TopHCenter:
955 case EEAnchorMode::TopRight:
956 {
957 aNewTopLeft.setY( aAnchorPoint.Y() );
958 }
959 break;
960 case EEAnchorMode::VCenterLeft:
961 case EEAnchorMode::VCenterHCenter:
962 case EEAnchorMode::VCenterRight:
963 {
964 aNewTopLeft.setY( aAnchorPoint.Y() - aNewSz.Height() / 2 );
965 }
966 break;
967 case EEAnchorMode::BottomLeft:
968 case EEAnchorMode::BottomHCenter:
969 case EEAnchorMode::BottomRight:
970 {
971 aNewTopLeft.setY( aAnchorPoint.Y() - aNewSz.Height() - 1 );
972 }
973 break;
974 }
975 }
976 ResetOutputArea( tools::Rectangle( aNewTopLeft, aNewSz ) );
977}
978
979void ImpEditView::SetAnchorMode( EEAnchorMode eMode )
980{
981 eAnchorMode = eMode;
982 CalcAnchorPoint();
983}
984
985void ImpEditView::CalcAnchorPoint()
986{
987 // GetHeight() and GetWidth() -1, because rectangle calculation not preferred.
988
989 // X:
990 switch ( eAnchorMode )
991 {
992 case EEAnchorMode::TopLeft:
993 case EEAnchorMode::VCenterLeft:
994 case EEAnchorMode::BottomLeft:
995 {
996 aAnchorPoint.setX( aOutArea.Left() );
997 }
998 break;
999 case EEAnchorMode::TopHCenter:
1000 case EEAnchorMode::VCenterHCenter:
1001 case EEAnchorMode::BottomHCenter:
1002 {
1003 aAnchorPoint.setX( aOutArea.Left() + (aOutArea.GetWidth()-1) / 2 );
1004 }
1005 break;
1006 case EEAnchorMode::TopRight:
1007 case EEAnchorMode::VCenterRight:
1008 case EEAnchorMode::BottomRight:
1009 {
1010 aAnchorPoint.setX( aOutArea.Right() );
1011 }
1012 break;
1013 }
1014
1015 // Y:
1016 switch ( eAnchorMode )
1017 {
1018 case EEAnchorMode::TopLeft:
1019 case EEAnchorMode::TopHCenter:
1020 case EEAnchorMode::TopRight:
1021 {
1022 aAnchorPoint.setY( aOutArea.Top() );
1023 }
1024 break;
1025 case EEAnchorMode::VCenterLeft:
1026 case EEAnchorMode::VCenterHCenter:
1027 case EEAnchorMode::VCenterRight:
1028 {
1029 aAnchorPoint.setY( aOutArea.Top() + (aOutArea.GetHeight()-1) / 2 );
1030 }
1031 break;
1032 case EEAnchorMode::BottomLeft:
1033 case EEAnchorMode::BottomHCenter:
1034 case EEAnchorMode::BottomRight:
1035 {
1036 aAnchorPoint.setY( aOutArea.Bottom() - 1 );
1037 }
1038 break;
1039 }
1040}
1041
1042namespace
1043{
1044
1045// For building JSON message to be sent to Online
1046boost::property_tree::ptree getHyperlinkPropTree(const OUString& sText, const OUString& sLink)
1047{
1048 boost::property_tree::ptree aTree;
1049 aTree.put("text", sText);
1050 aTree.put("link", sLink);
1051 return aTree;
1052}
1053
1054} // End of anon namespace
1055
1056tools::Rectangle ImpEditView::ImplGetEditCursor(EditPaM& aPaM, GetCursorFlags nShowCursorFlags, sal_Int32& nTextPortionStart,
1057 const ParaPortion* pParaPortion) const
1058{
1059 tools::Rectangle aEditCursor = pEditEngine->pImpEditEngine->PaMtoEditCursor( aPaM, nShowCursorFlags );
1060 if ( !IsInsertMode() && !aEditSelection.HasRange() )
1061 {
1062 if ( aPaM.GetNode()->Len() && ( aPaM.GetIndex() < aPaM.GetNode()->Len() ) )
1063 {
1064 // If we are behind a portion, and the next portion has other direction, we must change position...
1065 aEditCursor.SetLeft( pEditEngine->pImpEditEngine->PaMtoEditCursor( aPaM, GetCursorFlags::TextOnly|GetCursorFlags::PreferPortionStart ).Left() );
1066 aEditCursor.SetRight( aEditCursor.Left() );
1067
1068 sal_Int32 nTextPortion = pParaPortion->GetTextPortions().FindPortion( aPaM.GetIndex(), nTextPortionStart, true );
1069 const TextPortion& rTextPortion = pParaPortion->GetTextPortions()[nTextPortion];
1070 if ( rTextPortion.GetKind() == PortionKind::TAB )
1071 {
1072 aEditCursor.AdjustRight(rTextPortion.GetSize().Width() );
1073 }
1074 else
1075 {
1076 EditPaM aNext = pEditEngine->CursorRight( aPaM );
1077 tools::Rectangle aTmpRect = pEditEngine->pImpEditEngine->PaMtoEditCursor( aNext, GetCursorFlags::TextOnly );
1078 if ( aTmpRect.Top() != aEditCursor.Top() )
1079 aTmpRect = pEditEngine->pImpEditEngine->PaMtoEditCursor( aNext, GetCursorFlags::TextOnly|GetCursorFlags::EndOfLine );
1080 aEditCursor.SetRight( aTmpRect.Left() );
1081 }
1082 }
1083 }
1084
1085 long nMaxHeight = !IsVertical() ? aOutArea.GetHeight() : aOutArea.GetWidth();
1086 if ( aEditCursor.GetHeight() > nMaxHeight )
1087 {
1088 aEditCursor.SetBottom( aEditCursor.Top() + nMaxHeight - 1 );
1089 }
1090
1091 return aEditCursor;
1092}
1093
1094tools::Rectangle ImpEditView::GetEditCursor() const
1095{
1096 EditPaM aPaM( aEditSelection.Max() );
1097
1098 sal_Int32 nTextPortionStart = 0;
1099 sal_Int32 nPara = pEditEngine->GetEditDoc().GetPos( aPaM.GetNode() );
1100 if (nPara == EE_PARA_NOT_FOUND((sal_Int32) 0x7FFFFFFF)) // #i94322
1101 return tools::Rectangle();
1102
1103 const ParaPortion* pParaPortion = pEditEngine->GetParaPortions()[nPara];
1104
1105 GetCursorFlags nShowCursorFlags = nExtraCursorFlags | GetCursorFlags::TextOnly;
1106
1107 // Use CursorBidiLevel 0/1 in meaning of
1108 // 0: prefer portion end, normal mode
1109 // 1: prefer portion start
1110
1111 if ( ( GetCursorBidiLevel() != CURSOR_BIDILEVEL_DONTKNOW0xFFFF ) && GetCursorBidiLevel() )
1112 {
1113 nShowCursorFlags |= GetCursorFlags::PreferPortionStart;
1114 }
1115
1116 return ImplGetEditCursor(aPaM, nShowCursorFlags, nTextPortionStart, pParaPortion);
1117}
1118
1119void ImpEditView::ShowCursor( bool bGotoCursor, bool bForceVisCursor )
1120{
1121 // No ShowCursor in an empty View ...
1122 if (aOutArea.IsEmpty())
1123 return;
1124 if ( ( aOutArea.Left() >= aOutArea.Right() ) && ( aOutArea.Top() >= aOutArea.Bottom() ) )
1125 return;
1126
1127 pEditEngine->CheckIdleFormatter();
1128 if (!pEditEngine->IsFormatted())
1129 pEditEngine->pImpEditEngine->FormatDoc();
1130
1131 // For some reasons I end up here during the formatting, if the Outliner
1132 // is initialized in Paint, because no SetPool();
1133 if ( pEditEngine->pImpEditEngine->IsFormatting() )
1134 return;
1135 if ( !pEditEngine->pImpEditEngine->GetUpdateMode() )
1136 return;
1137 if ( pEditEngine->pImpEditEngine->IsInUndo() )
1138 return;
1139
1140 if (pOutWin && pOutWin->GetCursor() != GetCursor())
1141 pOutWin->SetCursor(GetCursor());
1142
1143 EditPaM aPaM( aEditSelection.Max() );
1144
1145 sal_Int32 nTextPortionStart = 0;
1146 sal_Int32 nPara = pEditEngine->GetEditDoc().GetPos( aPaM.GetNode() );
1147 if (nPara == EE_PARA_NOT_FOUND((sal_Int32) 0x7FFFFFFF)) // #i94322
1148 return;
1149
1150 const ParaPortion* pParaPortion = pEditEngine->GetParaPortions()[nPara];
1151
1152 GetCursorFlags nShowCursorFlags = nExtraCursorFlags | GetCursorFlags::TextOnly;
1153
1154 // Use CursorBidiLevel 0/1 in meaning of
1155 // 0: prefer portion end, normal mode
1156 // 1: prefer portion start
1157
1158 if ( ( GetCursorBidiLevel() != CURSOR_BIDILEVEL_DONTKNOW0xFFFF ) && GetCursorBidiLevel() )
1159 {
1160 nShowCursorFlags |= GetCursorFlags::PreferPortionStart;
1161 }
1162
1163 tools::Rectangle aEditCursor = ImplGetEditCursor(aPaM, nShowCursorFlags, nTextPortionStart, pParaPortion);
1164
1165 if ( bGotoCursor ) // && (!pEditEngine->pImpEditEngine->GetStatus().AutoPageSize() ) )
1166 {
1167 // check if scrolling is necessary...
1168 // if scrolling, then update () and Scroll ()!
1169 long nDocDiffX = 0;
1170 long nDocDiffY = 0;
1171
1172 tools::Rectangle aTmpVisArea( GetVisDocArea() );
1173 // aTmpOutArea: if OutputArea > Paper width and
1174 // Text > Paper width ( over large fields )
1175 long nMaxTextWidth = !IsVertical() ? pEditEngine->pImpEditEngine->GetPaperSize().Width() : pEditEngine->pImpEditEngine->GetPaperSize().Height();
1176 if ( aTmpVisArea.GetWidth() > nMaxTextWidth )
1177 aTmpVisArea.SetRight( aTmpVisArea.Left() + nMaxTextWidth );
1178
1179 if ( aEditCursor.Bottom() > aTmpVisArea.Bottom() )
1180 { // Scroll up, here positive
1181 nDocDiffY = aEditCursor.Bottom() - aTmpVisArea.Bottom();
1182 }
1183 else if ( aEditCursor.Top() < aTmpVisArea.Top() )
1184 { // Scroll down, here negative
1185 nDocDiffY = aEditCursor.Top() - aTmpVisArea.Top();
1186 }
1187
1188 if ( aEditCursor.Right() > aTmpVisArea.Right() )
1189 {
1190 // Scroll left, positive
1191 nDocDiffX = aEditCursor.Right() - aTmpVisArea.Right();
1192 // Can it be a little more?
1193 if ( aEditCursor.Right() < ( nMaxTextWidth - GetScrollDiffX() ) )
1194 nDocDiffX += GetScrollDiffX();
1195 else
1196 {
1197 long n = nMaxTextWidth - aEditCursor.Right();
1198 // If MapMode != RefMapMode then the EditCursor can go beyond
1199 // the paper width!
1200 nDocDiffX += ( n > 0 ? n : -n );
1201 }
1202 }
1203 else if ( aEditCursor.Left() < aTmpVisArea.Left() )
1204 {
1205 // Scroll right, negative:
1206 nDocDiffX = aEditCursor.Left() - aTmpVisArea.Left();
1207 // Can it be a little more?
1208 if ( aEditCursor.Left() > ( - static_cast<long>(GetScrollDiffX()) ) )
1209 nDocDiffX -= GetScrollDiffX();
1210 else
1211 nDocDiffX -= aEditCursor.Left();
1212 }
1213 if ( aPaM.GetIndex() == 0 ) // Olli needed for the Outliner
1214 {
1215 // But make sure that the cursor is not leaving visible area
1216 // because of this!
1217 if ( aEditCursor.Left() < aTmpVisArea.GetWidth() )
1218 {
1219 nDocDiffX = -aTmpVisArea.Left();
1220 }
1221 }
1222
1223 if ( nDocDiffX | nDocDiffY )
1224 {
1225 long nDiffX = !IsVertical() ? nDocDiffX : (IsTopToBottom() ? -nDocDiffY : nDocDiffY);
1226 long nDiffY = !IsVertical() ? nDocDiffY : (IsTopToBottom() ? nDocDiffX : -nDocDiffX);
1227
1228 if ( nDiffX )
1229 pEditEngine->GetInternalEditStatus().GetStatusWord() = pEditEngine->GetInternalEditStatus().GetStatusWord() | EditStatusFlags::HSCROLL;
1230 if ( nDiffY )
1231 pEditEngine->GetInternalEditStatus().GetStatusWord() = pEditEngine->GetInternalEditStatus().GetStatusWord() | EditStatusFlags::VSCROLL;
1232 Scroll( -nDiffX, -nDiffY );
1233 pEditEngine->pImpEditEngine->DelayedCallStatusHdl();
1234 }
1235 }
1236
1237 // Cursor may trim a little ...
1238 if ( ( aEditCursor.Bottom() > GetVisDocTop() ) &&
1239 ( aEditCursor.Top() < GetVisDocBottom() ) )
1240 {
1241 if ( aEditCursor.Bottom() > GetVisDocBottom() )
1242 aEditCursor.SetBottom( GetVisDocBottom() );
1243 if ( aEditCursor.Top() < GetVisDocTop() )
1244 aEditCursor.SetTop( GetVisDocTop() );
1245 }
1246
1247 const OutputDevice& rOutDev = getEditViewCallbacks() ? getEditViewCallbacks()->EditViewOutputDevice() : *pOutWin;
1248
1249 long nOnePixel = rOutDev.PixelToLogic( Size( 1, 0 ) ).Width();
1250
1251 if ( ( aEditCursor.Top() + nOnePixel >= GetVisDocTop() ) &&
1252 ( aEditCursor.Bottom() - nOnePixel <= GetVisDocBottom() ) &&
1253 ( aEditCursor.Left() + nOnePixel >= GetVisDocLeft() ) &&
1254 ( aEditCursor.Right() - nOnePixel <= GetVisDocRight() ) )
1255 {
1256 tools::Rectangle aCursorRect = GetWindowPos( aEditCursor );
1257 GetCursor()->SetPos( aCursorRect.TopLeft() );
1258 Size aCursorSz( aCursorRect.GetSize() );
1259 // Rectangle is inclusive
1260 aCursorSz.AdjustWidth( -1 );
1261 aCursorSz.AdjustHeight( -1 );
1262 if ( !aCursorSz.Width() || !aCursorSz.Height() )
1263 {
1264 long nCursorSz = rOutDev.GetSettings().GetStyleSettings().GetCursorSize();
1265 nCursorSz = rOutDev.PixelToLogic( Size( nCursorSz, 0 ) ).Width();
1266 if ( !aCursorSz.Width() )
1267 aCursorSz.setWidth( nCursorSz );
1268 if ( !aCursorSz.Height() )
1269 aCursorSz.setHeight( nCursorSz );
1270 }
1271 // #111036# Let VCL do orientation for cursor, otherwise problem when cursor has direction flag
1272 if ( IsVertical() )
1273 {
1274 Size aOldSz( aCursorSz );
1275 aCursorSz.setWidth( aOldSz.Height() );
1276 aCursorSz.setHeight( aOldSz.Width() );
1277 GetCursor()->SetPos( aCursorRect.TopRight() );
1278 GetCursor()->SetOrientation( IsTopToBottom() ? 2700 : 900 );
1279 }
1280 else
1281 // #i32593# Reset correct orientation in horizontal layout
1282 GetCursor()->SetOrientation();
1283
1284 GetCursor()->SetSize( aCursorSz );
1285
1286 if (comphelper::LibreOfficeKit::isActive() && mpViewShell && !mbSuppressLOKMessages)
1287 {
1288 Point aPos = GetCursor()->GetPos();
1289 boost::property_tree::ptree aMessageParams;
1290 if (mpLOKSpecialPositioning)
1291 {
1292 // Sending the absolute (pure) logical coordinates of the cursor to the client is not
1293 // enough for it to accurately reconstruct the corresponding tile-twips coordinates of the cursor.
1294 // This is because the editeng(doc) positioning is not pixel aligned for each cell involved in the output-area
1295 // (it better not be!). A simple solution is to send the coordinates of a point ('refpoint') in the output-area
1296 // along with the relative position of the cursor w.r.t this chosen 'refpoint'.
1297
1298 MapUnit eDevUnit = rOutDev.GetMapMode().GetMapUnit();
1299 tools::Rectangle aCursorRectPureLogical(aEditCursor.TopLeft(), GetCursor()->GetSize());
1300 // Get rectangle in window-coordinates from editeng(doc) coordinates.
1301 aCursorRectPureLogical = mpLOKSpecialPositioning->GetWindowPos(aCursorRectPureLogical, eDevUnit);
1302 const Point aRefPoint = mpLOKSpecialPositioning->GetRefPoint();
1303 // Get the relative coordinates w.r.t rRefPoint.
1304 aCursorRectPureLogical.Move(-aRefPoint.X(), -aRefPoint.Y());
1305 aMessageParams.put("relrect", aCursorRectPureLogical.toString());
1306 aMessageParams.put("refpoint", aRefPoint.toString());
1307 }
1308
1309 if (pOutWin && pOutWin->IsChart())
1310 {
1311 const vcl::Window* pViewShellWindow = mpViewShell->GetEditWindowForActiveOLEObj();
1312 if (pViewShellWindow && pViewShellWindow->IsAncestorOf(*pOutWin))
1313 {
1314 Point aOffsetPx = pOutWin->GetOffsetPixelFrom(*pViewShellWindow);
1315 Point aLogicOffset = pOutWin->PixelToLogic(aOffsetPx);
1316 aPos.Move(aLogicOffset.getX(), aLogicOffset.getY());
1317 }
1318 }
1319
1320 tools::Rectangle aRect(aPos.getX(), aPos.getY(), aPos.getX() + GetCursor()->GetWidth(), aPos.getY() + GetCursor()->GetHeight());
1321
1322 // LOK output is always in twips, convert from mm100 if necessary.
1323 if (rOutDev.GetMapMode().GetMapUnit() == MapUnit::Map100thMM)
1324 aRect = OutputDevice::LogicToLogic(aRect, MapMode(MapUnit::Map100thMM), MapMode(MapUnit::MapTwip));
1325 else if (rOutDev.GetMapMode().GetMapUnit() == MapUnit::MapTwip)
1326 {
1327 // Writer comments: they use editeng, but are separate widgets.
1328 Point aOrigin = rOutDev.GetMapMode().GetOrigin();
1329 // Move the rectangle, so that we output absolute twips.
1330 aRect.Move(aOrigin.getX(), aOrigin.getY());
1331 }
1332 // Let the LOK client decide the cursor width.
1333 aRect.setWidth(0);
1334
1335 OString sRect = aRect.toString();
1336 aMessageParams.put("rectangle", sRect);
1337
1338 SfxViewShell* pThisShell = dynamic_cast<SfxViewShell*>(mpViewShell);
1339 SfxViewShell* pOtherShell = dynamic_cast<SfxViewShell*>(mpOtherShell);
1340 assert(pThisShell)(static_cast <bool> (pThisShell) ? void (0) : __assert_fail
("pThisShell", "/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit.cxx"
, 1340, __extension__ __PRETTY_FUNCTION__))
;
1341
1342 if (pOtherShell && pThisShell != pOtherShell)
1343 {
1344 // Another shell wants to know about our existing cursor.
1345 SfxLokHelper::notifyOtherView(pThisShell, pOtherShell,
1346 LOK_CALLBACK_INVALIDATE_VIEW_CURSOR, aMessageParams);
1347 }
1348 else
1349 {
1350 // is cursor at a misspelled word ?
1351 Reference< linguistic2::XSpellChecker1 > xSpeller( pEditEngine->pImpEditEngine->GetSpeller() );
1352 bool bIsWrong = xSpeller.is() && IsWrongSpelledWord(aPaM, /*bMarkIfWrong*/ false);
1353
1354 boost::property_tree::ptree aHyperlinkTree;
1355 if (const SvxFieldItem* pFld = GetField(aPos, nullptr, nullptr))
1356 {
1357 if (auto pUrlField = dynamic_cast<const SvxURLField*>(pFld->GetField()))
1358 {
1359 aHyperlinkTree = getHyperlinkPropTree(pUrlField->GetRepresentation(), pUrlField->GetURL());
1360 }
1361 }
1362 else if (GetEditSelection().HasRange())
1363 {
1364 EditView* pActiveView = GetEditViewPtr();
1365
1366 if (pActiveView)
1367 {
1368 const SvxFieldItem* pFieldItem = pActiveView->GetFieldAtSelection();
1369 if (pFieldItem)
1370 {
1371 const SvxFieldData* pField = pFieldItem->GetField();
1372 if ( auto pUrlField = dynamic_cast<const SvxURLField*>( pField) )
1373 {
1374 aHyperlinkTree = getHyperlinkPropTree(pUrlField->GetRepresentation(), pUrlField->GetURL());
1375 }
1376 }
1377 }
1378 }
1379
1380 if (mbBroadcastLOKViewCursor)
1381 SfxLokHelper::notifyOtherViews(pThisShell,
1382 LOK_CALLBACK_INVALIDATE_VIEW_CURSOR, aMessageParams);
1383
1384 aMessageParams.put("mispelledWord", bIsWrong ? 1 : 0);
1385 aMessageParams.add_child("hyperlink", aHyperlinkTree);
1386
1387 if (comphelper::LibreOfficeKit::isViewIdForVisCursorInvalidation())
1388 SfxLokHelper::notifyOtherView(pThisShell, pThisShell,
1389 LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR, aMessageParams);
1390 else
1391 pThisShell->libreOfficeKitViewCallback(LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR,
1392 aMessageParams.get<std::string>("rectangle").c_str());
1393 }
1394 }
1395
1396 CursorDirection nCursorDir = CursorDirection::NONE;
1397 if ( IsInsertMode() && !aEditSelection.HasRange() && ( pEditEngine->pImpEditEngine->HasDifferentRTLLevels( aPaM.GetNode() ) ) )
1398 {
1399 sal_uInt16 nTextPortion = pParaPortion->GetTextPortions().FindPortion( aPaM.GetIndex(), nTextPortionStart, bool(nShowCursorFlags & GetCursorFlags::PreferPortionStart) );
1400 const TextPortion& rTextPortion = pParaPortion->GetTextPortions()[nTextPortion];
1401 if (rTextPortion.IsRightToLeft())
1402 nCursorDir = CursorDirection::RTL;
1403 else
1404 nCursorDir = CursorDirection::LTR;
1405
1406 }
1407 GetCursor()->SetDirection( nCursorDir );
1408
1409 if ( bForceVisCursor )
1410 GetCursor()->Show();
1411 {
1412 SvxFont aFont;
1413 pEditEngine->SeekCursor( aPaM.GetNode(), aPaM.GetIndex()+1, aFont );
1414
1415 InputContext aInputContext(aFont, InputContextFlags::Text | InputContextFlags::ExtText);
1416 if (EditViewCallbacks* pCallbacks = getEditViewCallbacks())
1417 pCallbacks->EditViewInputContext(aInputContext);
1418 else if (auto xWindow = GetWindow())
1419 xWindow->SetInputContext(aInputContext);
1420 }
1421 }
1422 else
1423 {
1424 pEditEngine->pImpEditEngine->GetStatus().GetStatusWord() = pEditEngine->pImpEditEngine->GetStatus().GetStatusWord() | EditStatusFlags::CURSOROUT;
1425 GetCursor()->Hide();
1426 GetCursor()->SetPos( Point( -1, -1 ) );
1427 GetCursor()->SetSize( Size( 0, 0 ) );
1428 }
1429}
1430
1431Pair ImpEditView::Scroll( long ndX, long ndY, ScrollRangeCheck nRangeCheck )
1432{
1433 DBG_ASSERT( pEditEngine->pImpEditEngine->IsFormatted(), "Scroll: Not formatted!" )do { if (true && (!(pEditEngine->pImpEditEngine->
IsFormatted()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit.cxx"
":" "1433" ": "), "%s", "Scroll: Not formatted!"); } } while
(false)
;
1434 if ( !ndX && !ndY )
1435 return Pair( 0, 0 );
1436
1437 const OutputDevice& rOutDev = getEditViewCallbacks() ? getEditViewCallbacks()->EditViewOutputDevice() : *GetWindow();
1438
1439#ifdef DBG_UTIL
1440 tools::Rectangle aR( aOutArea );
1441 aR = rOutDev.LogicToPixel( aR );
1442 aR = rOutDev.PixelToLogic( aR );
1443 SAL_WARN_IF( aR != aOutArea, "editeng", "OutArea before Scroll not aligned" )do { if (true && (aR != aOutArea)) { 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() << "OutArea before Scroll not aligned"
) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("editeng"
), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit.cxx"
":" "1443" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "OutArea before Scroll not aligned")
, 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "OutArea before Scroll not aligned"; ::sal::detail::
log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("editeng"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit.cxx"
":" "1443" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "OutArea before Scroll not aligned") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("editeng"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit.cxx"
":" "1443" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "OutArea before Scroll not aligned")
, 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "OutArea before Scroll not aligned"; ::sal::detail::
log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("editeng"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit.cxx"
":" "1443" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
1444#endif
1445
1446 tools::Rectangle aNewVisArea( GetVisDocArea() );
1447
1448 // Vertical:
1449 if ( !IsVertical() )
1450 {
1451 aNewVisArea.AdjustTop( -ndY );
1452 aNewVisArea.AdjustBottom( -ndY );
1453 }
1454 else
1455 {
1456 if( IsTopToBottom() )
1457 {
1458 aNewVisArea.AdjustTop(ndX );
1459 aNewVisArea.AdjustBottom(ndX );
1460 }
1461 else
1462 {
1463 aNewVisArea.AdjustTop( -ndX );
1464 aNewVisArea.AdjustBottom( -ndX );
1465 }
1466 }
1467 if ( ( nRangeCheck == ScrollRangeCheck::PaperWidthTextSize ) && ( aNewVisArea.Bottom() > static_cast<long>(pEditEngine->pImpEditEngine->GetTextHeight()) ) )
1468 {
1469 // GetTextHeight still optimizing!
1470 long nDiff = pEditEngine->pImpEditEngine->GetTextHeight() - aNewVisArea.Bottom(); // negative
1471 aNewVisArea.Move( 0, nDiff ); // could end up in the negative area...
1472 }
1473 if ( aNewVisArea.Top() < 0 )
1474 aNewVisArea.Move( 0, -aNewVisArea.Top() );
1475
1476 // Horizontal:
1477 if ( !IsVertical() )
1478 {
1479 aNewVisArea.AdjustLeft( -ndX );
1480 aNewVisArea.AdjustRight( -ndX );
1481 }
1482 else
1483 {
1484 if (IsTopToBottom())
1485 {
1486 aNewVisArea.AdjustLeft( -ndY );
1487 aNewVisArea.AdjustRight( -ndY );
1488 }
1489 else
1490 {
1491 aNewVisArea.AdjustLeft(ndY );
1492 aNewVisArea.AdjustRight(ndY );
1493 }
1494 }
1495 if ( ( nRangeCheck == ScrollRangeCheck::PaperWidthTextSize ) && ( aNewVisArea.Right() > static_cast<long>(pEditEngine->pImpEditEngine->CalcTextWidth( false )) ) )
1496 {
1497 long nDiff = pEditEngine->pImpEditEngine->CalcTextWidth( false ) - aNewVisArea.Right(); // negative
1498 aNewVisArea.Move( nDiff, 0 ); // could end up in the negative area...
1499 }
1500 if ( aNewVisArea.Left() < 0 )
1501 aNewVisArea.Move( -aNewVisArea.Left(), 0 );
1502
1503 // The difference must be alignt on pixel (due to scroll!)
1504 long nDiffX = !IsVertical() ? ( GetVisDocLeft() - aNewVisArea.Left() ) : (IsTopToBottom() ? -( GetVisDocTop() - aNewVisArea.Top() ) : (GetVisDocTop() - aNewVisArea.Top()));
1505 long nDiffY = !IsVertical() ? ( GetVisDocTop() - aNewVisArea.Top() ) : (IsTopToBottom() ? (GetVisDocLeft() - aNewVisArea.Left()) : -(GetVisDocTop() - aNewVisArea.Top()));
1506
1507 Size aDiffs( nDiffX, nDiffY );
1508 aDiffs = rOutDev.LogicToPixel( aDiffs );
1509 aDiffs = rOutDev.PixelToLogic( aDiffs );
1510
1511 long nRealDiffX = aDiffs.Width();
1512 long nRealDiffY = aDiffs.Height();
1513
1514
1515 if ( nRealDiffX || nRealDiffY )
1516 {
1517 vcl::Cursor* pCrsr = GetCursor();
1518 bool bVisCursor = pCrsr->IsVisible();
1519 pCrsr->Hide();
1520 if (pOutWin)
1521 pOutWin->PaintImmediately();
1522 if ( !IsVertical() )
1523 aVisDocStartPos.Move( -nRealDiffX, -nRealDiffY );
1524 else
1525 {
1526 if (IsTopToBottom())
1527 aVisDocStartPos.Move(-nRealDiffY, nRealDiffX);
1528 else
1529 aVisDocStartPos.Move(nRealDiffY, -nRealDiffX);
1530 }
1531 // Move by aligned value does not necessarily result in aligned
1532 // rectangle ...
1533 aVisDocStartPos = rOutDev.LogicToPixel( aVisDocStartPos );
1534 aVisDocStartPos = rOutDev.PixelToLogic( aVisDocStartPos );
1535 tools::Rectangle aRect( aOutArea );
1536
1537 if (pOutWin)
1538 {
1539 pOutWin->Scroll( nRealDiffX, nRealDiffY, aRect, ScrollFlags::Clip );
1540 }
1541
1542 if (comphelper::LibreOfficeKit::isActive() || getEditViewCallbacks())
1543 {
1544 // Need to invalidate the window, otherwise no tile will be re-painted.
1545 pEditView->Invalidate();
1546 }
1547
1548 if (pOutWin)
1549 pOutWin->PaintImmediately();
1550 pCrsr->SetPos( pCrsr->GetPos() + Point( nRealDiffX, nRealDiffY ) );
1551 if ( bVisCursor )
1552 {
1553 tools::Rectangle aCursorRect( pCrsr->GetPos(), pCrsr->GetSize() );
1554 if ( aOutArea.IsInside( aCursorRect ) )
1555 pCrsr->Show();
1556 }
1557
1558 if ( pEditEngine->pImpEditEngine->GetNotifyHdl().IsSet() )
1559 {
1560 EENotify aNotify( EE_NOTIFY_TEXTVIEWSCROLLED );
1561 pEditEngine->pImpEditEngine->GetNotifyHdl().Call( aNotify );
1562 }
1563
1564 if (comphelper::LibreOfficeKit::isActive())
1565 {
1566 DrawSelectionXOR();
1567 }
1568 }
1569
1570 return Pair( nRealDiffX, nRealDiffY );
1571}
1572
1573Reference<css::datatransfer::clipboard::XClipboard> ImpEditView::GetClipboard() const
1574{
1575 if (vcl::Window* pWindow = GetWindow())
1576 return pWindow->GetClipboard();
1577 return GetSystemClipboard();
1578}
1579
1580Reference<css::datatransfer::clipboard::XClipboard> ImpEditView::GetSelection() const
1581{
1582 if (vcl::Window* pWindow = GetWindow())
1583 return pWindow->GetPrimarySelection();
1584 return GetSystemPrimarySelection();
1585}
1586
1587bool ImpEditView::PostKeyEvent( const KeyEvent& rKeyEvent, vcl::Window const * pFrameWin )
1588{
1589 bool bDone = false;
1590
1591 KeyFuncType eFunc = rKeyEvent.GetKeyCode().GetFunction();
1592 if ( eFunc != KeyFuncType::DONTKNOW )
1593 {
1594 switch ( eFunc )
1595 {
1596 case KeyFuncType::CUT:
1597 {
1598 if ( !bReadOnly )
1599 {
1600 Reference<css::datatransfer::clipboard::XClipboard> aClipBoard(GetClipboard());
1601 CutCopy( aClipBoard, true );
1602 bDone = true;
1603 }
1604 }
1605 break;
1606 case KeyFuncType::COPY:
1607 {
1608 Reference<css::datatransfer::clipboard::XClipboard> aClipBoard(GetClipboard());
1609 CutCopy( aClipBoard, false );
1610 bDone = true;
1611 }
1612 break;
1613 case KeyFuncType::PASTE:
1614 {
1615 if ( !bReadOnly && IsPasteEnabled() )
1616 {
1617 pEditEngine->pImpEditEngine->UndoActionStart( EDITUNDO_PASTE110 );
1618 Reference<css::datatransfer::clipboard::XClipboard> aClipBoard(GetClipboard());
1619 Paste( aClipBoard, pEditEngine->pImpEditEngine->GetStatus().AllowPasteSpecial() );
1620 pEditEngine->pImpEditEngine->UndoActionEnd();
1621 bDone = true;
1622 }
1623 }
1624 break;
1625 default:
1626 break;
1627 }
1628 }
1629
1630 if( !bDone )
1631 bDone = pEditEngine->PostKeyEvent( rKeyEvent, GetEditViewPtr(), pFrameWin );
1632
1633 return bDone;
1634}
1635
1636bool ImpEditView::MouseButtonUp( const MouseEvent& rMouseEvent )
1637{
1638 nTravelXPos = TRAVEL_X_DONTKNOW0xFFFFFFFF;
1639 nCursorBidiLevel = CURSOR_BIDILEVEL_DONTKNOW0xFFFF;
1640 nExtraCursorFlags = GetCursorFlags::NONE;
1641 bClickedInSelection = false;
1642
1643 if (vcl::Window* pWindow = GetWindow())
1644 {
1645 if ( rMouseEvent.IsMiddle() && !bReadOnly &&
1646 ( pWindow->GetSettings().GetMouseSettings().GetMiddleButtonAction() == MouseMiddleButtonAction::PasteSelection ) )
1647 {
1648 Reference<css::datatransfer::clipboard::XClipboard> aClipBoard(GetSelection());
1649 Paste( aClipBoard );
1650 }
1651 else if ( rMouseEvent.IsLeft() && GetEditSelection().HasRange() )
1652 {
1653 Reference<css::datatransfer::clipboard::XClipboard> aClipBoard(GetSelection());
1654 CutCopy( aClipBoard, false );
1655 }
1656 }
1657
1658 return pEditEngine->pImpEditEngine->MouseButtonUp( rMouseEvent, GetEditViewPtr() );
1659}
1660
1661void ImpEditView::ReleaseMouse()
1662{
1663 pEditEngine->pImpEditEngine->ReleaseMouse();
1664}
1665
1666bool ImpEditView::MouseButtonDown( const MouseEvent& rMouseEvent )
1667{
1668 pEditEngine->CheckIdleFormatter(); // If fast typing and mouse button downs
1669 nTravelXPos = TRAVEL_X_DONTKNOW0xFFFFFFFF;
1670 nExtraCursorFlags = GetCursorFlags::NONE;
1671 nCursorBidiLevel = CURSOR_BIDILEVEL_DONTKNOW0xFFFF;
1672 bClickedInSelection = IsSelectionAtPoint( rMouseEvent.GetPosPixel() );
1673 return pEditEngine->pImpEditEngine->MouseButtonDown( rMouseEvent, GetEditViewPtr() );
1674}
1675
1676bool ImpEditView::MouseMove( const MouseEvent& rMouseEvent )
1677{
1678 return pEditEngine->pImpEditEngine->MouseMove( rMouseEvent, GetEditViewPtr() );
1679}
1680
1681void ImpEditView::Command( const CommandEvent& rCEvt )
1682{
1683 pEditEngine->CheckIdleFormatter(); // If fast typing and mouse button down
1684 pEditEngine->pImpEditEngine->Command( rCEvt, GetEditViewPtr() );
1685}
1686
1687
1688void ImpEditView::SetInsertMode( bool bInsert )
1689{
1690 if ( bInsert != IsInsertMode() )
1691 {
1692 SetFlags( nControl, EVControlBits::OVERWRITE, !bInsert );
1693 ShowCursor( DoAutoScroll(), false );
1694 }
1695}
1696
1697bool ImpEditView::IsWrongSpelledWord( const EditPaM& rPaM, bool bMarkIfWrong )
1698{
1699 bool bIsWrong = false;
1700 if ( rPaM.GetNode()->GetWrongList() )
1701 {
1702 EditSelection aSel = pEditEngine->SelectWord( rPaM, css::i18n::WordType::DICTIONARY_WORD );
1703 bIsWrong = rPaM.GetNode()->GetWrongList()->HasWrong( aSel.Min().GetIndex(), aSel.Max().GetIndex() );
1704 if ( bIsWrong && bMarkIfWrong )
1705 {
1706 DrawSelectionXOR();
1707 SetEditSelection( aSel );
1708 DrawSelectionXOR();
1709 }
1710 }
1711 return bIsWrong;
1712}
1713
1714OUString ImpEditView::SpellIgnoreWord()
1715{
1716 OUString aWord;
1717 if ( pEditEngine->pImpEditEngine->GetSpeller().is() )
1718 {
1719 EditPaM aPaM = GetEditSelection().Max();
1720 if ( !HasSelection() )
1721 {
1722 EditSelection aSel = pEditEngine->SelectWord(aPaM);
1723 aWord = pEditEngine->pImpEditEngine->GetSelected( aSel );
1724 }
1725 else
1726 {
1727 aWord = pEditEngine->pImpEditEngine->GetSelected( GetEditSelection() );
1728 // And deselect
1729 DrawSelectionXOR();
1730 SetEditSelection( EditSelection( aPaM, aPaM ) );
1731 DrawSelectionXOR();
1732 }
1733
1734 if ( !aWord.isEmpty() )
1735 {
1736 Reference< XDictionary > xDic = LinguMgr::GetIgnoreAllList();
1737 if (xDic.is())
1738 xDic->add( aWord, false, OUString() );
1739 EditDoc& rDoc = pEditEngine->GetEditDoc();
1740 sal_Int32 nNodes = rDoc.Count();
1741 for ( sal_Int32 n = 0; n < nNodes; n++ )
1742 {
1743 ContentNode* pNode = rDoc.GetObject( n );
1744 pNode->GetWrongList()->MarkWrongsInvalid();
1745 }
1746 pEditEngine->pImpEditEngine->DoOnlineSpelling( aPaM.GetNode() );
1747 pEditEngine->pImpEditEngine->StartOnlineSpellTimer();
1748 }
1749 }
1750 return aWord;
1751}
1752
1753void ImpEditView::DeleteSelected()
1754{
1755 DrawSelectionXOR();
1756
1757 pEditEngine->pImpEditEngine->UndoActionStart( EDITUNDO_DELETE108 );
1758
1759 EditPaM aPaM = pEditEngine->pImpEditEngine->DeleteSelected( GetEditSelection() );
1760
1761 pEditEngine->pImpEditEngine->UndoActionEnd();
1762
1763 SetEditSelection( EditSelection( aPaM, aPaM ) );
1764
1765 DrawSelectionXOR();
1766
1767 pEditEngine->pImpEditEngine->FormatAndUpdate( GetEditViewPtr() );
1768 ShowCursor( DoAutoScroll(), true );
1769}
1770
1771const SvxFieldItem* ImpEditView::GetField( const Point& rPos, sal_Int32* pPara, sal_Int32* pPos ) const
1772{
1773 if( !GetOutputArea().IsInside( rPos ) )
1774 return nullptr;
1775
1776 Point aDocPos( GetDocPos( rPos ) );
1777 EditPaM aPaM = pEditEngine->GetPaM(aDocPos, false);
1778
1779 if ( aPaM.GetIndex() == aPaM.GetNode()->Len() )
1780 {
1781 // Otherwise, whenever the Field at the very end and mouse under the text
1782 return nullptr;
1783 }
1784
1785 const CharAttribList::AttribsType& rAttrs = aPaM.GetNode()->GetCharAttribs().GetAttribs();
1786 const sal_Int32 nXPos = aPaM.GetIndex();
1787 for (size_t nAttr = rAttrs.size(); nAttr; )
1788 {
1789 const EditCharAttrib& rAttr = *rAttrs[--nAttr];
1790 if (rAttr.GetStart() == nXPos)
1791 {
1792 if (rAttr.Which() == EE_FEATURE_FIELD)
1793 {
1794 DBG_ASSERT(dynamic_cast<const SvxFieldItem*>(rAttr.GetItem()), "No FieldItem...")do { if (true && (!(dynamic_cast<const SvxFieldItem
*>(rAttr.GetItem())))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit.cxx"
":" "1794" ": "), "%s", "No FieldItem..."); } } while (false
)
;
1795 if ( pPara )
1796 *pPara = pEditEngine->GetEditDoc().GetPos( aPaM.GetNode() );
1797 if ( pPos )
1798 *pPos = rAttr.GetStart();
1799 return static_cast<const SvxFieldItem*>(rAttr.GetItem());
1800 }
1801 }
1802 }
1803 return nullptr;
1804}
1805
1806bool ImpEditView::IsBulletArea( const Point& rPos, sal_Int32* pPara )
1807{
1808 if ( pPara )
1809 *pPara = EE_PARA_NOT_FOUND((sal_Int32) 0x7FFFFFFF);
1810
1811 if( !GetOutputArea().IsInside( rPos ) )
1812 return false;
1813
1814 Point aDocPos( GetDocPos( rPos ) );
1815 EditPaM aPaM = pEditEngine->GetPaM(aDocPos, false);
1816
1817 if ( aPaM.GetIndex() == 0 )
1818 {
1819 sal_Int32 nPara = pEditEngine->GetEditDoc().GetPos( aPaM.GetNode() );
1820 tools::Rectangle aBulletArea = pEditEngine->GetBulletArea( nPara );
1821 long nY = pEditEngine->GetDocPosTopLeft( nPara ).Y();
1822 const ParaPortion* pParaPortion = pEditEngine->GetParaPortions()[nPara];
1823 nY += pParaPortion->GetFirstLineOffset();
1824 if ( ( aDocPos.Y() > ( nY + aBulletArea.Top() ) ) &&
1825 ( aDocPos.Y() < ( nY + aBulletArea.Bottom() ) ) &&
1826 ( aDocPos.X() > ( aBulletArea.Left() ) ) &&
1827 ( aDocPos.X() < ( aBulletArea.Right() ) ) )
1828 {
1829 if ( pPara )
1830 *pPara = nPara;
1831 return true;
1832 }
1833 }
1834
1835 return false;
1836}
1837
1838void ImpEditView::CutCopy( css::uno::Reference< css::datatransfer::clipboard::XClipboard > const & rxClipboard, bool bCut )
1839{
1840 if ( !(rxClipboard.is() && HasSelection()) )
1841 return;
1842
1843 uno::Reference<datatransfer::XTransferable> xData = pEditEngine->CreateTransferable( GetEditSelection() );
1844
1845 {
1846 SolarMutexReleaser aReleaser;
1847
1848 try
1849 {
1850 rxClipboard->setContents( xData, nullptr );
1851
1852 // #87756# FlushClipboard, but it would be better to become a TerminateListener to the Desktop and flush on demand...
1853 uno::Reference< datatransfer::clipboard::XFlushableClipboard > xFlushableClipboard( rxClipboard, uno::UNO_QUERY );
1854 if( xFlushableClipboard.is() )
1855 xFlushableClipboard->flushClipboard();
1856 }
1857 catch( const css::uno::Exception& )
1858 {
1859 }
1860
1861 }
1862
1863 if (bCut)
1864 {
1865 pEditEngine->pImpEditEngine->UndoActionStart(EDITUNDO_CUT109);
1866 DeleteSelected();
1867 pEditEngine->pImpEditEngine->UndoActionEnd();
1868 }
1869}
1870
1871void ImpEditView::Paste( css::uno::Reference< css::datatransfer::clipboard::XClipboard > const & rxClipboard, bool bUseSpecial )
1872{
1873 if ( !rxClipboard.is() )
1874 return;
1875
1876 uno::Reference< datatransfer::XTransferable > xDataObj;
1877
1878 try
1879 {
1880 SolarMutexReleaser aReleaser;
1881 xDataObj = rxClipboard->getContents();
1882 }
1883 catch( const css::uno::Exception& )
1884 {
1885 }
1886
1887 if ( !xDataObj.is() || !EditEngine::HasValidData( xDataObj ) )
1888 return;
1889
1890 pEditEngine->pImpEditEngine->UndoActionStart( EDITUNDO_PASTE110 );
1891
1892 EditSelection aSel( GetEditSelection() );
1893 if ( aSel.HasRange() )
1894 {
1895 DrawSelectionXOR();
1896 aSel = pEditEngine->DeleteSelection(aSel);
1897 }
1898
1899 PasteOrDropInfos aPasteOrDropInfos;
1900 aPasteOrDropInfos.nStartPara = pEditEngine->GetEditDoc().GetPos( aSel.Min().GetNode() );
1901 pEditEngine->HandleBeginPasteOrDrop(aPasteOrDropInfos);
1902
1903 if ( DoSingleLinePaste() )
1904 {
1905 datatransfer::DataFlavor aFlavor;
1906 SotExchange::GetFormatDataFlavor( SotClipboardFormatId::STRING, aFlavor );
1907 if ( xDataObj->isDataFlavorSupported( aFlavor ) )
1908 {
1909 try
1910 {
1911 uno::Any aData = xDataObj->getTransferData( aFlavor );
1912 OUString aTmpText;
1913 aData >>= aTmpText;
1914 OUString aText(convertLineEnd(aTmpText, LINEEND_LF));
1915 aText = aText.replaceAll( OUStringChar(LINE_SEP'\x0A'), " " );
1916 aSel = pEditEngine->InsertText(aSel, aText);
1917 }
1918 catch( ... )
1919 {
1920 ; // #i9286# can happen, even if isDataFlavorSupported returns true...
1921 }
1922 }
1923 }
1924 else
1925 {
1926 // Prevent notifications of paragraph inserts et al that would trigger
1927 // a11y to format content in a half-ready state when obtaining
1928 // paragraphs. Collect and broadcast when done instead.
1929 aSel = pEditEngine->InsertText(
1930 xDataObj, OUString(), aSel.Min(),
1931 bUseSpecial && pEditEngine->GetInternalEditStatus().AllowPasteSpecial());
1932 }
1933
1934 aPasteOrDropInfos.nEndPara = pEditEngine->GetEditDoc().GetPos( aSel.Max().GetNode() );
1935 pEditEngine->HandleEndPasteOrDrop(aPasteOrDropInfos);
1936
1937 pEditEngine->pImpEditEngine->UndoActionEnd();
1938 SetEditSelection( aSel );
1939 pEditEngine->pImpEditEngine->UpdateSelections();
1940 pEditEngine->pImpEditEngine->FormatAndUpdate( GetEditViewPtr() );
1941 ShowCursor( DoAutoScroll(), true );
1942}
1943
1944
1945bool ImpEditView::IsInSelection( const EditPaM& rPaM )
1946{
1947 EditSelection aSel = GetEditSelection();
1948 if ( !aSel.HasRange() )
1949 return false;
1950
1951 aSel.Adjust( pEditEngine->GetEditDoc() );
1952
1953 sal_Int32 nStartNode = pEditEngine->GetEditDoc().GetPos( aSel.Min().GetNode() );
1954 sal_Int32 nEndNode = pEditEngine->GetEditDoc().GetPos( aSel.Max().GetNode() );
1955 sal_Int32 nCurNode = pEditEngine->GetEditDoc().GetPos( rPaM.GetNode() );
1956
1957 if ( ( nCurNode > nStartNode ) && ( nCurNode < nEndNode ) )
1958 return true;
1959
1960 if ( nStartNode == nEndNode )
1961 {
1962 if ( nCurNode == nStartNode )
1963 if ( ( rPaM.GetIndex() >= aSel.Min().GetIndex() ) && ( rPaM.GetIndex() < aSel.Max().GetIndex() ) )
1964 return true;
1965 }
1966 else if ( ( nCurNode == nStartNode ) && ( rPaM.GetIndex() >= aSel.Min().GetIndex() ) )
1967 return true;
1968 else if ( ( nCurNode == nEndNode ) && ( rPaM.GetIndex() < aSel.Max().GetIndex() ) )
1969 return true;
1970
1971 return false;
1972}
1973
1974void ImpEditView::CreateAnchor()
1975{
1976 pEditEngine->SetInSelectionMode(true);
1977 EditSelection aNewSelection(GetEditSelection());
1978 aNewSelection.Min() = aNewSelection.Max();
1979 SetEditSelection(aNewSelection);
1980 // const_cast<EditPaM&>(GetEditSelection().Min()) = GetEditSelection().Max();
1981}
1982
1983void ImpEditView::DeselectAll()
1984{
1985 pEditEngine->SetInSelectionMode(false);
1986 DrawSelectionXOR();
1987 EditSelection aNewSelection(GetEditSelection());
1988 aNewSelection.Min() = aNewSelection.Max();
1989 SetEditSelection(aNewSelection);
1990 // const_cast<EditPaM&>(GetEditSelection().Min()) = GetEditSelection().Max();
1991
1992 if (comphelper::LibreOfficeKit::isActive() && mpViewShell)
1993 {
1994 VclPtr<vcl::Window> pParent = pOutWin->GetParentWithLOKNotifier();
1995 if (pParent && pParent->GetLOKWindowId())
1996 {
1997 const vcl::ILibreOfficeKitNotifier* pNotifier = pParent->GetLOKNotifier();
1998 std::vector<vcl::LOKPayloadItem> aItems;
1999 aItems.emplace_back("rectangles", "");
2000 pNotifier->notifyWindow(pParent->GetLOKWindowId(), "text_selection", aItems);
2001 }
2002 }
2003}
2004
2005bool ImpEditView::IsSelectionAtPoint( const Point& rPosPixel )
2006{
2007 if ( pDragAndDropInfo && pDragAndDropInfo->pField )
2008 return true;
2009
2010 // Logical units ...
2011 const OutputDevice& rOutDev = getEditViewCallbacks() ? getEditViewCallbacks()->EditViewOutputDevice() : *GetWindow();
2012 Point aMousePos = rOutDev.PixelToLogic(rPosPixel);
2013
2014 if ( ( !GetOutputArea().IsInside( aMousePos ) ) && !pEditEngine->pImpEditEngine->IsInSelectionMode() )
2015 {
2016 return false;
2017 }
2018
2019 Point aDocPos( GetDocPos( aMousePos ) );
2020 EditPaM aPaM = pEditEngine->GetPaM(aDocPos, false);
2021 return IsInSelection( aPaM );
2022}
2023
2024bool ImpEditView::SetCursorAtPoint( const Point& rPointPixel )
2025{
2026 pEditEngine->CheckIdleFormatter();
2027
2028 Point aMousePos( rPointPixel );
2029
2030 // Logical units ...
2031 const OutputDevice& rOutDev = getEditViewCallbacks() ? getEditViewCallbacks()->EditViewOutputDevice() : *GetWindow();
2032 aMousePos = rOutDev.PixelToLogic( aMousePos );
2033
2034 if ( ( !GetOutputArea().IsInside( aMousePos ) ) && !pEditEngine->pImpEditEngine->IsInSelectionMode() )
2035 {
2036 return false;
2037 }
2038
2039 Point aDocPos( GetDocPos( aMousePos ) );
2040
2041 // Can be optimized: first go through the lines within a paragraph for PAM,
2042 // then again with the PaM for the Rect, even though the line is already
2043 // known... This must not be, though!
2044 EditPaM aPaM = pEditEngine->GetPaM(aDocPos);
2045 bool bGotoCursor = DoAutoScroll();
2046
2047 // aTmpNewSel: Diff between old and new, not the new selection, unless for tiled rendering
2048 EditSelection aTmpNewSel( comphelper::LibreOfficeKit::isActive() ? GetEditSelection().Min() : GetEditSelection().Max(), aPaM );
2049
2050 // #i27299#
2051 // work on copy of current selection and set new selection, if it has changed.
2052 EditSelection aNewEditSelection( GetEditSelection() );
2053
2054 aNewEditSelection.Max() = aPaM;
2055 if (!pEditEngine->GetSelectionEngine().HasAnchor())
2056 {
2057 if ( aNewEditSelection.Min() != aPaM )
2058 pEditEngine->CursorMoved(aNewEditSelection.Min().GetNode());
2059 aNewEditSelection.Min() = aPaM;
2060 }
2061 else
2062 {
2063 DrawSelectionXOR( aTmpNewSel );
2064 }
2065
2066 // set changed text selection
2067 if ( GetEditSelection() != aNewEditSelection )
2068 {
2069 SetEditSelection( aNewEditSelection );
2070 }
2071
2072 bool bForceCursor = pDragAndDropInfo == nullptr && !pEditEngine->pImpEditEngine->IsInSelectionMode();
2073 ShowCursor( bGotoCursor, bForceCursor );
2074 return true;
2075}
2076
2077void ImpEditView::HideDDCursor()
2078{
2079 if ( pDragAndDropInfo && pDragAndDropInfo->bVisCursor )
2080 {
2081 OutputDevice& rOutDev = getEditViewCallbacks() ? getEditViewCallbacks()->EditViewOutputDevice() : *GetWindow();
2082 rOutDev.DrawOutDev( pDragAndDropInfo->aCurSavedCursor.TopLeft(), pDragAndDropInfo->aCurSavedCursor.GetSize(),
2083 Point(0,0), pDragAndDropInfo->aCurSavedCursor.GetSize(),*pDragAndDropInfo->pBackground );
2084 pDragAndDropInfo->bVisCursor = false;
2085 }
2086}
2087
2088void ImpEditView::ShowDDCursor( const tools::Rectangle& rRect )
2089{
2090 if ( !pDragAndDropInfo || pDragAndDropInfo->bVisCursor )
2091 return;
2092
2093 if (pOutWin && pOutWin->GetCursor())
2094 pOutWin->GetCursor()->Hide();
2095
2096 OutputDevice& rOutDev = getEditViewCallbacks() ? getEditViewCallbacks()->EditViewOutputDevice() : *GetWindow();
2097 Color aOldFillColor = rOutDev.GetFillColor();
2098 rOutDev.SetFillColor( Color(4210752) ); // GRAY BRUSH_50, OLDSV, change to DDCursor!
2099
2100 // Save background ...
2101 tools::Rectangle aSaveRect( rOutDev.LogicToPixel( rRect ) );
2102 // prefer to save some more ...
2103 aSaveRect.AdjustRight(1 );
2104 aSaveRect.AdjustBottom(1 );
2105
2106#ifdef DBG_UTIL
2107 Size aNewSzPx( aSaveRect.GetSize() );
2108#endif
2109 if ( !pDragAndDropInfo->pBackground )
2110 {
2111 pDragAndDropInfo->pBackground = VclPtr<VirtualDevice>::Create(rOutDev);
2112 MapMode aMapMode( rOutDev.GetMapMode() );
2113 aMapMode.SetOrigin( Point( 0, 0 ) );
2114 pDragAndDropInfo->pBackground->SetMapMode( aMapMode );
2115
2116 }
2117
2118#ifdef DBG_UTIL
2119 Size aCurSzPx( pDragAndDropInfo->pBackground->GetOutputSizePixel() );
2120 if ( ( aCurSzPx.Width() < aNewSzPx.Width() ) ||( aCurSzPx.Height() < aNewSzPx.Height() ) )
2121 {
2122 bool bDone = pDragAndDropInfo->pBackground->SetOutputSizePixel( aNewSzPx );
2123 DBG_ASSERT( bDone, "Virtual Device broken?" )do { if (true && (!(bDone))) { sal_detail_logFormat((
SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit.cxx"
":" "2123" ": "), "%s", "Virtual Device broken?"); } } while
(false)
;
2124 }
2125#endif
2126
2127 aSaveRect = rOutDev.PixelToLogic( aSaveRect );
2128
2129 pDragAndDropInfo->pBackground->DrawOutDev( Point(0,0), aSaveRect.GetSize(),
2130 aSaveRect.TopLeft(), aSaveRect.GetSize(), rOutDev );
2131 pDragAndDropInfo->aCurSavedCursor = aSaveRect;
2132
2133 // Draw Cursor...
2134 rOutDev.DrawRect( rRect );
2135
2136 pDragAndDropInfo->bVisCursor = true;
2137 pDragAndDropInfo->aCurCursor = rRect;
2138
2139 rOutDev.SetFillColor( aOldFillColor );
2140}
2141
2142void ImpEditView::dragGestureRecognized(const css::datatransfer::dnd::DragGestureEvent& rDGE)
2143{
2144 DBG_ASSERT( !pDragAndDropInfo, "dragGestureRecognized - DragAndDropInfo exist!" )do { if (true && (!(!pDragAndDropInfo))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit.cxx"
":" "2144" ": "), "%s", "dragGestureRecognized - DragAndDropInfo exist!"
); } } while (false)
;
2145
2146 SolarMutexGuard aVclGuard;
2147
2148 pDragAndDropInfo.reset();
2149
2150 Point aMousePosPixel( rDGE.DragOriginX, rDGE.DragOriginY );
2151
2152 EditSelection aCopySel( GetEditSelection() );
2153 aCopySel.Adjust( pEditEngine->GetEditDoc() );
2154
2155 if ( HasSelection() && bClickedInSelection )
2156 {
2157 pDragAndDropInfo.reset(new DragAndDropInfo());
2158 }
2159 else
2160 {
2161 // Field?!
2162 sal_Int32 nPara;
2163 sal_Int32 nPos;
2164 Point aMousePos = GetWindow()->PixelToLogic( aMousePosPixel );
2165 const SvxFieldItem* pField = GetField( aMousePos, &nPara, &nPos );
2166 if ( pField )
2167 {
2168 pDragAndDropInfo.reset(new DragAndDropInfo());
2169 pDragAndDropInfo->pField = pField;
2170 ContentNode* pNode = pEditEngine->GetEditDoc().GetObject( nPara );
2171 aCopySel = EditSelection( EditPaM( pNode, nPos ), EditPaM( pNode, nPos+1 ) );
2172 SetEditSelection(aCopySel);
2173 DrawSelectionXOR();
2174 bool bGotoCursor = DoAutoScroll();
2175 ShowCursor( bGotoCursor, /*bForceCursor=*/false );
2176 }
2177 else if ( IsBulletArea( aMousePos, &nPara ) )
2178 {
2179 pDragAndDropInfo.reset(new DragAndDropInfo());
2180 pDragAndDropInfo->bOutlinerMode = true;
2181 EditPaM aStartPaM( pEditEngine->GetEditDoc().GetObject( nPara ), 0 );
2182 EditPaM aEndPaM( aStartPaM );
2183 const SfxInt16Item& rLevel = pEditEngine->GetParaAttrib( nPara, EE_PARA_OUTLLEVEL );
2184 for ( sal_Int32 n = nPara +1; n < pEditEngine->GetEditDoc().Count(); n++ )
2185 {
2186 const SfxInt16Item& rL = pEditEngine->GetParaAttrib( n, EE_PARA_OUTLLEVEL );
2187 if ( rL.GetValue() > rLevel.GetValue() )
2188 {
2189 aEndPaM.SetNode( pEditEngine->GetEditDoc().GetObject( n ) );
2190 }
2191 else
2192 {
2193 break;
2194 }
2195 }
2196 aEndPaM.SetIndex( aEndPaM.GetNode()->Len() );
2197 SetEditSelection( EditSelection( aStartPaM, aEndPaM ) );
2198 }
2199 }
2200
2201 if ( !pDragAndDropInfo )
2202 return;
2203
2204
2205 pDragAndDropInfo->bStarterOfDD = true;
2206
2207 // Sensitive area to be scrolled.
2208 Size aSz( 5, 0 );
2209 aSz = GetWindow()->PixelToLogic( aSz );
2210 pDragAndDropInfo->nSensibleRange = static_cast<sal_uInt16>(aSz.Width());
2211 pDragAndDropInfo->nCursorWidth = static_cast<sal_uInt16>(aSz.Width()) / 2;
2212 pDragAndDropInfo->aBeginDragSel = pEditEngine->pImpEditEngine->CreateESel( aCopySel );
2213
2214 uno::Reference<datatransfer::XTransferable> xData = pEditEngine->CreateTransferable(aCopySel);
2215
2216 sal_Int8 nActions = bReadOnly ? datatransfer::dnd::DNDConstants::ACTION_COPY : datatransfer::dnd::DNDConstants::ACTION_COPY_OR_MOVE;
2217
2218 rDGE.DragSource->startDrag( rDGE, nActions, 0 /*cursor*/, 0 /*image*/, xData, mxDnDListener );
2219 // If Drag&Move in an Engine, then Copy&Del has to be optional!
2220 GetCursor()->Hide();
2221}
2222
2223void ImpEditView::dragDropEnd( const css::datatransfer::dnd::DragSourceDropEvent& rDSDE )
2224{
2225 SolarMutexGuard aVclGuard;
2226
2227 DBG_ASSERT( pDragAndDropInfo, "ImpEditView::dragDropEnd: pDragAndDropInfo is NULL!" )do { if (true && (!(pDragAndDropInfo))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit.cxx"
":" "2227" ": "), "%s", "ImpEditView::dragDropEnd: pDragAndDropInfo is NULL!"
); } } while (false)
;
2228
2229 // #123688# Shouldn't happen, but seems to happen...
2230 if ( !pDragAndDropInfo )
2231 return;
2232
2233 if ( !bReadOnly && rDSDE.DropSuccess && !pDragAndDropInfo->bOutlinerMode && ( rDSDE.DropAction & datatransfer::dnd::DNDConstants::ACTION_MOVE ) )
2234 {
2235 if ( pDragAndDropInfo->bStarterOfDD && pDragAndDropInfo->bDroppedInMe )
2236 {
2237 // DropPos: Where was it dropped, irrespective of length.
2238 ESelection aDropPos( pDragAndDropInfo->aDropSel.nStartPara, pDragAndDropInfo->aDropSel.nStartPos, pDragAndDropInfo->aDropSel.nStartPara, pDragAndDropInfo->aDropSel.nStartPos );
2239 ESelection aToBeDelSel = pDragAndDropInfo->aBeginDragSel;
2240 ESelection aNewSel( pDragAndDropInfo->aDropSel.nEndPara, pDragAndDropInfo->aDropSel.nEndPos,
2241 pDragAndDropInfo->aDropSel.nEndPara, pDragAndDropInfo->aDropSel.nEndPos );
2242 bool bBeforeSelection = aDropPos < pDragAndDropInfo->aBeginDragSel;
2243 sal_Int32 nParaDiff = pDragAndDropInfo->aBeginDragSel.nEndPara - pDragAndDropInfo->aBeginDragSel.nStartPara;
2244 if ( bBeforeSelection )
2245 {
2246 // Adjust aToBeDelSel.
2247 DBG_ASSERT( pDragAndDropInfo->aBeginDragSel.nStartPara >= pDragAndDropInfo->aDropSel.nStartPara, "But not before? ")do { if (true && (!(pDragAndDropInfo->aBeginDragSel
.nStartPara >= pDragAndDropInfo->aDropSel.nStartPara)))
{ sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"
), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit.cxx"
":" "2247" ": "), "%s", "But not before? "); } } while (false
)
;
2248 aToBeDelSel.nStartPara = aToBeDelSel.nStartPara + nParaDiff;
2249 aToBeDelSel.nEndPara = aToBeDelSel.nEndPara + nParaDiff;
2250 // To correct the character?
2251 if ( aToBeDelSel.nStartPara == pDragAndDropInfo->aDropSel.nEndPara )
2252 {
2253 sal_uInt16 nMoreChars;
2254 if ( pDragAndDropInfo->aDropSel.nStartPara == pDragAndDropInfo->aDropSel.nEndPara )
2255 nMoreChars = pDragAndDropInfo->aDropSel.nEndPos - pDragAndDropInfo->aDropSel.nStartPos;
2256 else
2257 nMoreChars = pDragAndDropInfo->aDropSel.nEndPos;
2258 aToBeDelSel.nStartPos =
2259 aToBeDelSel.nStartPos + nMoreChars;
2260 if ( aToBeDelSel.nStartPara == aToBeDelSel.nEndPara )
2261 aToBeDelSel.nEndPos =
2262 aToBeDelSel.nEndPos + nMoreChars;
2263 }
2264 }
2265 else
2266 {
2267 // aToBeDelSel is ok, but the selection of the View
2268 // has to be adapted, if it was deleted before!
2269 DBG_ASSERT( pDragAndDropInfo->aBeginDragSel.nStartPara <= pDragAndDropInfo->aDropSel.nStartPara, "But not before? ")do { if (true && (!(pDragAndDropInfo->aBeginDragSel
.nStartPara <= pDragAndDropInfo->aDropSel.nStartPara)))
{ sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"
), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit.cxx"
":" "2269" ": "), "%s", "But not before? "); } } while (false
)
;
2270 aNewSel.nStartPara = aNewSel.nStartPara - nParaDiff;
2271 aNewSel.nEndPara = aNewSel.nEndPara - nParaDiff;
2272 // To correct the character?
2273 if ( pDragAndDropInfo->aBeginDragSel.nEndPara == pDragAndDropInfo->aDropSel.nStartPara )
2274 {
2275 sal_uInt16 nLessChars;
2276 if ( pDragAndDropInfo->aBeginDragSel.nStartPara == pDragAndDropInfo->aBeginDragSel.nEndPara )
2277 nLessChars = pDragAndDropInfo->aBeginDragSel.nEndPos - pDragAndDropInfo->aBeginDragSel.nStartPos;
2278 else
2279 nLessChars = pDragAndDropInfo->aBeginDragSel.nEndPos;
2280 aNewSel.nStartPos = aNewSel.nStartPos - nLessChars;
2281 if ( aNewSel.nStartPara == aNewSel.nEndPara )
2282 aNewSel.nEndPos = aNewSel.nEndPos - nLessChars;
2283 }
2284 }
2285
2286 DrawSelectionXOR();
2287 EditSelection aDelSel( pEditEngine->pImpEditEngine->CreateSel( aToBeDelSel ) );
2288 DBG_ASSERT( !aDelSel.DbgIsBuggy( pEditEngine->GetEditDoc() ), "ToBeDel is buggy!" )do { if (true && (!(!aDelSel.DbgIsBuggy( pEditEngine->
GetEditDoc() )))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit.cxx"
":" "2288" ": "), "%s", "ToBeDel is buggy!"); } } while (false
)
;
2289 pEditEngine->DeleteSelection(aDelSel);
2290 if ( !bBeforeSelection )
2291 {
2292 DBG_ASSERT( !pEditEngine->pImpEditEngine->CreateSel( aNewSel ).DbgIsBuggy(pEditEngine->GetEditDoc()), "Bad" )do { if (true && (!(!pEditEngine->pImpEditEngine->
CreateSel( aNewSel ).DbgIsBuggy(pEditEngine->GetEditDoc())
))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"
), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit.cxx"
":" "2292" ": "), "%s", "Bad"); } } while (false)
;
2293 SetEditSelection( pEditEngine->pImpEditEngine->CreateSel( aNewSel ) );
2294 }
2295 pEditEngine->pImpEditEngine->FormatAndUpdate( pEditEngine->pImpEditEngine->GetActiveView() );
2296 DrawSelectionXOR();
2297 }
2298 else
2299 {
2300 // other EditEngine ...
2301 if (pEditEngine->HasText()) // #88630# SC is removing the content when switching the task
2302 DeleteSelected();
2303 }
2304 }
2305
2306 if ( pDragAndDropInfo->bUndoAction )
2307 pEditEngine->pImpEditEngine->UndoActionEnd();
2308
2309 HideDDCursor();
2310 ShowCursor( DoAutoScroll(), true );
2311 pDragAndDropInfo.reset();
2312 pEditEngine->GetEndDropHdl().Call(GetEditViewPtr());
2313}
2314
2315void ImpEditView::drop( const css::datatransfer::dnd::DropTargetDropEvent& rDTDE )
2316{
2317 SolarMutexGuard aVclGuard;
2318
2319 DBG_ASSERT( pDragAndDropInfo, "Drop - No Drag&Drop info?!" )do { if (true && (!(pDragAndDropInfo))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit.cxx"
":" "2319" ": "), "%s", "Drop - No Drag&Drop info?!"); }
} while (false)
;
2320
2321 if ( !(pDragAndDropInfo && pDragAndDropInfo->bDragAccepted) )
2322 return;
2323
2324 pEditEngine->GetBeginDropHdl().Call(GetEditViewPtr());
2325 bool bChanges = false;
2326
2327 HideDDCursor();
2328
2329 if ( pDragAndDropInfo->bStarterOfDD )
2330 {
2331 pEditEngine->pImpEditEngine->UndoActionStart( EDITUNDO_DRAGANDDROP116 );
2332 pDragAndDropInfo->bUndoAction = true;
2333 }
2334
2335 if ( pDragAndDropInfo->bOutlinerMode )
2336 {
2337 bChanges = true;
2338 GetEditViewPtr()->MoveParagraphs( Range( pDragAndDropInfo->aBeginDragSel.nStartPara, pDragAndDropInfo->aBeginDragSel.nEndPara ), pDragAndDropInfo->nOutlinerDropDest );
2339 }
2340 else
2341 {
2342 uno::Reference< datatransfer::XTransferable > xDataObj = rDTDE.Transferable;
2343 if ( xDataObj.is() )
2344 {
2345 bChanges = true;
2346 // remove Selection ...
2347 DrawSelectionXOR();
2348 EditPaM aPaM( pDragAndDropInfo->aDropDest );
2349
2350 PasteOrDropInfos aPasteOrDropInfos;
2351 aPasteOrDropInfos.nStartPara = pEditEngine->GetEditDoc().GetPos( aPaM.GetNode() );
2352 pEditEngine->HandleBeginPasteOrDrop(aPasteOrDropInfos);
2353
2354 EditSelection aNewSel = pEditEngine->InsertText(
2355 xDataObj, OUString(), aPaM, pEditEngine->GetInternalEditStatus().AllowPasteSpecial());
2356
2357 aPasteOrDropInfos.nEndPara = pEditEngine->GetEditDoc().GetPos( aNewSel.Max().GetNode() );
2358 pEditEngine->HandleEndPasteOrDrop(aPasteOrDropInfos);
2359
2360 SetEditSelection( aNewSel );
2361 pEditEngine->pImpEditEngine->FormatAndUpdate( pEditEngine->pImpEditEngine->GetActiveView() );
2362 if ( pDragAndDropInfo->bStarterOfDD )
2363 {
2364 // Only set if the same engine!
2365 pDragAndDropInfo->aDropSel.nStartPara = pEditEngine->GetEditDoc().GetPos( aPaM.GetNode() );
2366 pDragAndDropInfo->aDropSel.nStartPos = aPaM.GetIndex();
2367 pDragAndDropInfo->aDropSel.nEndPara = pEditEngine->GetEditDoc().GetPos( aNewSel.Max().GetNode() );
2368 pDragAndDropInfo->aDropSel.nEndPos = aNewSel.Max().GetIndex();
2369 pDragAndDropInfo->bDroppedInMe = true;
2370 }
2371 }
2372 }
2373
2374 if ( bChanges )
2375 {
2376 rDTDE.Context->acceptDrop( rDTDE.DropAction );
2377 }
2378
2379 if ( !pDragAndDropInfo->bStarterOfDD )
2380 {
2381 pDragAndDropInfo.reset();
2382 }
2383
2384 rDTDE.Context->dropComplete( bChanges );
2385}
2386
2387void ImpEditView::dragEnter( const css::datatransfer::dnd::DropTargetDragEnterEvent& rDTDEE )
2388{
2389 SolarMutexGuard aVclGuard;
2390
2391 if ( !pDragAndDropInfo )
2392 pDragAndDropInfo.reset(new DragAndDropInfo());
2393
2394 pDragAndDropInfo->bHasValidData = false;
2395
2396 // Check for supported format...
2397 // Only check for text, will also be there if bin or rtf
2398 datatransfer::DataFlavor aTextFlavor;
2399 SotExchange::GetFormatDataFlavor( SotClipboardFormatId::STRING, aTextFlavor );
2400 const css::datatransfer::DataFlavor* pFlavors = rDTDEE.SupportedDataFlavors.getConstArray();
2401 int nFlavors = rDTDEE.SupportedDataFlavors.getLength();
2402 for ( int n = 0; n < nFlavors; n++ )
2403 {
2404 if( TransferableDataHelper::IsEqual( pFlavors[n], aTextFlavor ) )
2405 {
2406 pDragAndDropInfo->bHasValidData = true;
2407 break;
2408 }
2409 }
2410
2411 dragOver( rDTDEE );
2412}
2413
2414void ImpEditView::dragExit( const css::datatransfer::dnd::DropTargetEvent& )
2415{
2416 SolarMutexGuard aVclGuard;
2417
2418 HideDDCursor();
2419
2420 if ( pDragAndDropInfo && !pDragAndDropInfo->bStarterOfDD )
2421 {
2422 pDragAndDropInfo.reset();
2423 }
2424}
2425
2426void ImpEditView::dragOver(const css::datatransfer::dnd::DropTargetDragEvent& rDTDE)
2427{
2428 SolarMutexGuard aVclGuard;
2429
2430 const OutputDevice& rOutDev = getEditViewCallbacks() ? getEditViewCallbacks()->EditViewOutputDevice() : *GetWindow();
2431
2432 Point aMousePos( rDTDE.LocationX, rDTDE.LocationY );
2433 aMousePos = rOutDev.PixelToLogic( aMousePos );
2434
2435 bool bAccept = false;
2436
2437 if ( GetOutputArea().IsInside( aMousePos ) && !bReadOnly )
2438 {
2439 if ( pDragAndDropInfo && pDragAndDropInfo->bHasValidData )
2440 {
2441 bAccept = true;
2442
2443 bool bAllowScroll = DoAutoScroll();
2444 if ( bAllowScroll )
2445 {
2446 long nScrollX = 0;
2447 long nScrollY = 0;
2448 // Check if in the sensitive area
2449 if ( ( (aMousePos.X()-pDragAndDropInfo->nSensibleRange) < GetOutputArea().Left() ) && ( ( aMousePos.X() + pDragAndDropInfo->nSensibleRange ) > GetOutputArea().Left() ) )
2450 nScrollX = GetOutputArea().GetWidth() / SCRLRANGE20;
2451 else if ( ( (aMousePos.X()+pDragAndDropInfo->nSensibleRange) > GetOutputArea().Right() ) && ( ( aMousePos.X() - pDragAndDropInfo->nSensibleRange ) < GetOutputArea().Right() ) )
2452 nScrollX = -( GetOutputArea().GetWidth() / SCRLRANGE20 );
2453
2454 if ( ( (aMousePos.Y()-pDragAndDropInfo->nSensibleRange) < GetOutputArea().Top() ) && ( ( aMousePos.Y() + pDragAndDropInfo->nSensibleRange ) > GetOutputArea().Top() ) )
2455 nScrollY = GetOutputArea().GetHeight() / SCRLRANGE20;
2456 else if ( ( (aMousePos.Y()+pDragAndDropInfo->nSensibleRange) > GetOutputArea().Bottom() ) && ( ( aMousePos.Y() - pDragAndDropInfo->nSensibleRange ) < GetOutputArea().Bottom() ) )
2457 nScrollY = -( GetOutputArea().GetHeight() / SCRLRANGE20 );
2458
2459 if ( nScrollX || nScrollY )
2460 {
2461 HideDDCursor();
2462 Scroll( nScrollX, nScrollY, ScrollRangeCheck::PaperWidthTextSize );
2463 }
2464 }
2465
2466 Point aDocPos( GetDocPos( aMousePos ) );
2467 EditPaM aPaM = pEditEngine->GetPaM( aDocPos );
2468 pDragAndDropInfo->aDropDest = aPaM;
2469 if ( pDragAndDropInfo->bOutlinerMode )
2470 {
2471 sal_Int32 nPara = pEditEngine->GetEditDoc().GetPos( aPaM.GetNode() );
2472 ParaPortion* pPPortion = pEditEngine->GetParaPortions().SafeGetObject( nPara );
2473 if (pPPortion)
2474 {
2475 long nDestParaStartY = pEditEngine->GetParaPortions().GetYOffset( pPPortion );
2476 long nRel = aDocPos.Y() - nDestParaStartY;
2477 if ( nRel < ( pPPortion->GetHeight() / 2 ) )
2478 {
2479 pDragAndDropInfo->nOutlinerDropDest = nPara;
2480 }
2481 else
2482 {
2483 pDragAndDropInfo->nOutlinerDropDest = nPara+1;
2484 }
2485
2486 if( ( pDragAndDropInfo->nOutlinerDropDest >= pDragAndDropInfo->aBeginDragSel.nStartPara ) &&
2487 ( pDragAndDropInfo->nOutlinerDropDest <= (pDragAndDropInfo->aBeginDragSel.nEndPara+1) ) )
2488 {
2489 bAccept = false;
2490 }
2491 }
2492 }
2493 else if ( HasSelection() )
2494 {
2495 // it must not be dropped into a selection
2496 EPaM aP = pEditEngine->pImpEditEngine->CreateEPaM( aPaM );
2497 ESelection aDestSel( aP.nPara, aP.nIndex, aP.nPara, aP.nIndex);
2498 ESelection aCurSel = pEditEngine->pImpEditEngine->CreateESel( GetEditSelection() );
2499 aCurSel.Adjust();
2500 if ( !(aDestSel < aCurSel) && !(aDestSel > aCurSel) )
2501 {
2502 bAccept = false;
2503 }
2504 }
2505 if ( bAccept )
2506 {
2507 tools::Rectangle aEditCursor;
2508 if ( pDragAndDropInfo->bOutlinerMode )
2509 {
2510 long nDDYPos(0);
2511 if ( pDragAndDropInfo->nOutlinerDropDest < pEditEngine->GetEditDoc().Count() )
2512 {
2513 ParaPortion* pPPortion = pEditEngine->GetParaPortions().SafeGetObject( pDragAndDropInfo->nOutlinerDropDest );
2514 if (pPPortion)
2515 nDDYPos = pEditEngine->GetParaPortions().GetYOffset( pPPortion );
2516 }
2517 else
2518 {
2519 nDDYPos = pEditEngine->pImpEditEngine->GetTextHeight();
2520 }
2521 Point aStartPos( 0, nDDYPos );
2522 aStartPos = GetWindowPos( aStartPos );
2523 Point aEndPos( GetOutputArea().GetWidth(), nDDYPos );
2524 aEndPos = GetWindowPos( aEndPos );
2525 aEditCursor = rOutDev.LogicToPixel( tools::Rectangle( aStartPos, aEndPos ) );
2526 if ( !pEditEngine->IsVertical() )
2527 {
2528 aEditCursor.AdjustTop( -1 );
2529 aEditCursor.AdjustBottom( 1 );
2530 }
2531 else
2532 {
2533 if( IsTopToBottom() )
2534 {
2535 aEditCursor.AdjustLeft( -1 );
2536 aEditCursor.AdjustRight( 1 );
2537 }
2538 else
2539 {
2540 aEditCursor.AdjustLeft( 1 );
2541 aEditCursor.AdjustRight( -1 );
2542 }
2543 }
2544 aEditCursor = rOutDev.PixelToLogic( aEditCursor );
2545 }
2546 else
2547 {
2548 aEditCursor = pEditEngine->pImpEditEngine->PaMtoEditCursor( aPaM );
2549 Point aTopLeft( GetWindowPos( aEditCursor.TopLeft() ) );
2550 aEditCursor.SetPos( aTopLeft );
2551 aEditCursor.SetRight( aEditCursor.Left() + pDragAndDropInfo->nCursorWidth );
2552 aEditCursor = rOutDev.LogicToPixel( aEditCursor );
2553 aEditCursor = rOutDev.PixelToLogic( aEditCursor );
2554 }
2555
2556 bool bCursorChanged = !pDragAndDropInfo->bVisCursor || ( pDragAndDropInfo->aCurCursor != aEditCursor );
2557 if ( bCursorChanged )
2558 {
2559 HideDDCursor();
2560 ShowDDCursor(aEditCursor );
2561 }
2562 pDragAndDropInfo->bDragAccepted = true;
2563 rDTDE.Context->acceptDrag( rDTDE.DropAction );
2564 }
2565 }
2566 }
2567
2568 if ( !bAccept )
2569 {
2570 HideDDCursor();
2571 if (pDragAndDropInfo)
2572 pDragAndDropInfo->bDragAccepted = false;
2573 rDTDE.Context->rejectDrag();
2574 }
2575}
2576
2577void ImpEditView::AddDragAndDropListeners()
2578{
2579 if (bActiveDragAndDropListener)
2580 return;
2581
2582 css::uno::Reference<css::datatransfer::dnd::XDropTarget> xDropTarget;
2583 if (EditViewCallbacks* pCallbacks = getEditViewCallbacks())
2584 xDropTarget = pCallbacks->GetDropTarget();
2585 else if (GetWindow())
2586 xDropTarget = GetWindow()->GetDropTarget();
2587
2588 if (!xDropTarget.is())
2589 return;
2590
2591 vcl::unohelper::DragAndDropWrapper* pDnDWrapper = new vcl::unohelper::DragAndDropWrapper(this);
2592 mxDnDListener = pDnDWrapper;
2593
2594 css::uno::Reference<css::datatransfer::dnd::XDragGestureRecognizer> xDragGestureRecognizer(xDropTarget, uno::UNO_QUERY);
2595 if (xDragGestureRecognizer.is())
2596 {
2597 uno::Reference<datatransfer::dnd::XDragGestureListener> xDGL(mxDnDListener, uno::UNO_QUERY);
2598 xDragGestureRecognizer->addDragGestureListener(xDGL);
2599 }
2600
2601 uno::Reference<datatransfer::dnd::XDropTargetListener> xDTL(mxDnDListener, uno::UNO_QUERY);
2602 xDropTarget->addDropTargetListener(xDTL);
2603 xDropTarget->setActive(true);
2604 xDropTarget->setDefaultActions(datatransfer::dnd::DNDConstants::ACTION_COPY_OR_MOVE);
2605
2606 bActiveDragAndDropListener = true;
2607}
2608
2609void ImpEditView::RemoveDragAndDropListeners()
2610{
2611 if (!bActiveDragAndDropListener)
2612 return;
2613
2614 css::uno::Reference<css::datatransfer::dnd::XDropTarget> xDropTarget;
2615 if (EditViewCallbacks* pCallbacks = getEditViewCallbacks())
2616 xDropTarget = pCallbacks->GetDropTarget();
2617 else if (GetWindow())
2618 xDropTarget = GetWindow()->GetDropTarget();
2619
2620 if (!xDropTarget.is())
2621 return;
2622
2623 css::uno::Reference<css::datatransfer::dnd::XDragGestureRecognizer> xDragGestureRecognizer(xDropTarget, uno::UNO_QUERY);
2624 if (xDragGestureRecognizer.is())
2625 {
2626 uno::Reference<datatransfer::dnd::XDragGestureListener> xDGL(mxDnDListener, uno::UNO_QUERY);
2627 xDragGestureRecognizer->removeDragGestureListener(xDGL);
2628 }
2629
2630 uno::Reference<datatransfer::dnd::XDropTargetListener> xDTL(mxDnDListener, uno::UNO_QUERY);
2631 xDropTarget->removeDropTargetListener(xDTL);
2632
2633 if ( mxDnDListener.is() )
2634 {
2635 mxDnDListener->disposing( lang::EventObject() ); // #95154# Empty Source means it's the Client
2636 mxDnDListener.clear();
2637 }
2638
2639 bActiveDragAndDropListener = false;
2640}
2641
2642void ImpEditView::InitLOKSpecialPositioning(MapUnit eUnit,
2643 const tools::Rectangle& rOutputArea,
2644 const Point& rVisDocStartPos)
2645{
2646 if (!mpLOKSpecialPositioning)
2647 mpLOKSpecialPositioning.reset(new LOKSpecialPositioning(*this, eUnit, rOutputArea, rVisDocStartPos));
2648 else
2649 mpLOKSpecialPositioning->ReInit(eUnit, rOutputArea, rVisDocStartPos);
2650}
2651
2652void ImpEditView::SetLOKSpecialOutputArea(const tools::Rectangle& rOutputArea)
2653{
2654 assert(mpLOKSpecialPositioning)(static_cast <bool> (mpLOKSpecialPositioning) ? void (0
) : __assert_fail ("mpLOKSpecialPositioning", "/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit.cxx"
, 2654, __extension__ __PRETTY_FUNCTION__))
;
2655 mpLOKSpecialPositioning->SetOutputArea(rOutputArea);
2656}
2657
2658tools::Rectangle ImpEditView::GetLOKSpecialOutputArea() const
2659{
2660 assert(mpLOKSpecialPositioning)(static_cast <bool> (mpLOKSpecialPositioning) ? void (0
) : __assert_fail ("mpLOKSpecialPositioning", "/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit.cxx"
, 2660, __extension__ __PRETTY_FUNCTION__))
;
2661 return mpLOKSpecialPositioning->GetOutputArea();
2662}
2663
2664void ImpEditView::SetLOKSpecialVisArea(const tools::Rectangle& rVisArea)
2665{
2666 assert(mpLOKSpecialPositioning)(static_cast <bool> (mpLOKSpecialPositioning) ? void (0
) : __assert_fail ("mpLOKSpecialPositioning", "/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit.cxx"
, 2666, __extension__ __PRETTY_FUNCTION__))
;
2667 mpLOKSpecialPositioning->SetVisDocStartPos(rVisArea.TopLeft());
2668}
2669
2670tools::Rectangle ImpEditView::GetLOKSpecialVisArea() const
2671{
2672 assert(mpLOKSpecialPositioning)(static_cast <bool> (mpLOKSpecialPositioning) ? void (0
) : __assert_fail ("mpLOKSpecialPositioning", "/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit.cxx"
, 2672, __extension__ __PRETTY_FUNCTION__))
;
2673 return mpLOKSpecialPositioning->GetVisDocArea();
2674}
2675
2676bool ImpEditView::HasLOKSpecialPositioning() const
2677{
2678 return bool(mpLOKSpecialPositioning);
2679}
2680
2681/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

/usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/bits/unique_ptr.h

1// unique_ptr implementation -*- C++ -*-
2
3// Copyright (C) 2008-2020 Free Software Foundation, Inc.
4//
5// This file is part of the GNU ISO C++ Library. This library is free
6// software; you can redistribute it and/or modify it under the
7// terms of the GNU General Public License as published by the
8// Free Software Foundation; either version 3, or (at your option)
9// any later version.
10
11// This library is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
15
16// Under Section 7 of GPL version 3, you are granted additional
17// permissions described in the GCC Runtime Library Exception, version
18// 3.1, as published by the Free Software Foundation.
19
20// You should have received a copy of the GNU General Public License and
21// a copy of the GCC Runtime Library Exception along with this program;
22// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
23// <http://www.gnu.org/licenses/>.
24
25/** @file bits/unique_ptr.h
26 * This is an internal header file, included by other library headers.
27 * Do not attempt to use it directly. @headername{memory}
28 */
29
30#ifndef _UNIQUE_PTR_H1
31#define _UNIQUE_PTR_H1 1
32
33#include <bits/c++config.h>
34#include <debug/assertions.h>
35#include <type_traits>
36#include <utility>
37#include <tuple>
38#include <bits/stl_function.h>
39#include <bits/functional_hash.h>
40#if __cplusplus201703L > 201703L
41# include <compare>
42# include <ostream>
43#endif
44
45namespace std _GLIBCXX_VISIBILITY(default)__attribute__ ((__visibility__ ("default")))
46{
47_GLIBCXX_BEGIN_NAMESPACE_VERSION
48
49 /**
50 * @addtogroup pointer_abstractions
51 * @{
52 */
53
54#if _GLIBCXX_USE_DEPRECATED1
55#pragma GCC diagnostic push
56#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
57 template<typename> class auto_ptr;
58#pragma GCC diagnostic pop
59#endif
60
61 /// Primary template of default_delete, used by unique_ptr for single objects
62 template<typename _Tp>
63 struct default_delete
64 {
65 /// Default constructor
66 constexpr default_delete() noexcept = default;
67
68 /** @brief Converting constructor.
69 *
70 * Allows conversion from a deleter for objects of another type, `_Up`,
71 * only if `_Up*` is convertible to `_Tp*`.
72 */
73 template<typename _Up,
74 typename = _Require<is_convertible<_Up*, _Tp*>>>
75 default_delete(const default_delete<_Up>&) noexcept { }
76
77 /// Calls `delete __ptr`
78 void
79 operator()(_Tp* __ptr) const
80 {
81 static_assert(!is_void<_Tp>::value,
82 "can't delete pointer to incomplete type");
83 static_assert(sizeof(_Tp)>0,
84 "can't delete pointer to incomplete type");
85 delete __ptr;
5
Calling '~DragAndDropInfo'
86 }
87 };
88
89 // _GLIBCXX_RESOLVE_LIB_DEFECTS
90 // DR 740 - omit specialization for array objects with a compile time length
91
92 /// Specialization of default_delete for arrays, used by `unique_ptr<T[]>`
93 template<typename _Tp>
94 struct default_delete<_Tp[]>
95 {
96 public:
97 /// Default constructor
98 constexpr default_delete() noexcept = default;
99
100 /** @brief Converting constructor.
101 *
102 * Allows conversion from a deleter for arrays of another type, such as
103 * a const-qualified version of `_Tp`.
104 *
105 * Conversions from types derived from `_Tp` are not allowed because
106 * it is undefined to `delete[]` an array of derived types through a
107 * pointer to the base type.
108 */
109 template<typename _Up,
110 typename = _Require<is_convertible<_Up(*)[], _Tp(*)[]>>>
111 default_delete(const default_delete<_Up[]>&) noexcept { }
112
113 /// Calls `delete[] __ptr`
114 template<typename _Up>
115 typename enable_if<is_convertible<_Up(*)[], _Tp(*)[]>::value>::type
116 operator()(_Up* __ptr) const
117 {
118 static_assert(sizeof(_Tp)>0,
119 "can't delete pointer to incomplete type");
120 delete [] __ptr;
121 }
122 };
123
124 /// @cond undocumented
125
126 // Manages the pointer and deleter of a unique_ptr
127 template <typename _Tp, typename _Dp>
128 class __uniq_ptr_impl
129 {
130 template <typename _Up, typename _Ep, typename = void>
131 struct _Ptr
132 {
133 using type = _Up*;
134 };
135
136 template <typename _Up, typename _Ep>
137 struct
138 _Ptr<_Up, _Ep, __void_t<typename remove_reference<_Ep>::type::pointer>>
139 {
140 using type = typename remove_reference<_Ep>::type::pointer;
141 };
142
143 public:
144 using _DeleterConstraint = enable_if<
145 __and_<__not_<is_pointer<_Dp>>,
146 is_default_constructible<_Dp>>::value>;
147
148 using pointer = typename _Ptr<_Tp, _Dp>::type;
149
150 static_assert( !is_rvalue_reference<_Dp>::value,
151 "unique_ptr's deleter type must be a function object type"
152 " or an lvalue reference type" );
153
154 __uniq_ptr_impl() = default;
155 __uniq_ptr_impl(pointer __p) : _M_t() { _M_ptr() = __p; }
156
157 template<typename _Del>
158 __uniq_ptr_impl(pointer __p, _Del&& __d)
159 : _M_t(__p, std::forward<_Del>(__d)) { }
160
161 __uniq_ptr_impl(__uniq_ptr_impl&& __u) noexcept
162 : _M_t(std::move(__u._M_t))
163 { __u._M_ptr() = nullptr; }
164
165 __uniq_ptr_impl& operator=(__uniq_ptr_impl&& __u) noexcept
166 {
167 reset(__u.release());
168 _M_deleter() = std::forward<_Dp>(__u._M_deleter());
169 return *this;
170 }
171
172 pointer& _M_ptr() { return std::get<0>(_M_t); }
173 pointer _M_ptr() const { return std::get<0>(_M_t); }
174 _Dp& _M_deleter() { return std::get<1>(_M_t); }
175 const _Dp& _M_deleter() const { return std::get<1>(_M_t); }
176
177 void reset(pointer __p) noexcept
178 {
179 const pointer __old_p = _M_ptr();
180 _M_ptr() = __p;
181 if (__old_p)
182 _M_deleter()(__old_p);
183 }
184
185 pointer release() noexcept
186 {
187 pointer __p = _M_ptr();
188 _M_ptr() = nullptr;
189 return __p;
190 }
191
192 void
193 swap(__uniq_ptr_impl& __rhs) noexcept
194 {
195 using std::swap;
196 swap(this->_M_ptr(), __rhs._M_ptr());
197 swap(this->_M_deleter(), __rhs._M_deleter());
198 }
199
200 private:
201 tuple<pointer, _Dp> _M_t;
202 };
203
204 // Defines move construction + assignment as either defaulted or deleted.
205 template <typename _Tp, typename _Dp,
206 bool = is_move_constructible<_Dp>::value,
207 bool = is_move_assignable<_Dp>::value>
208 struct __uniq_ptr_data : __uniq_ptr_impl<_Tp, _Dp>
209 {
210 using __uniq_ptr_impl<_Tp, _Dp>::__uniq_ptr_impl;
211 __uniq_ptr_data(__uniq_ptr_data&&) = default;
212 __uniq_ptr_data& operator=(__uniq_ptr_data&&) = default;
213 };
214
215 template <typename _Tp, typename _Dp>
216 struct __uniq_ptr_data<_Tp, _Dp, true, false> : __uniq_ptr_impl<_Tp, _Dp>
217 {
218 using __uniq_ptr_impl<_Tp, _Dp>::__uniq_ptr_impl;
219 __uniq_ptr_data(__uniq_ptr_data&&) = default;
220 __uniq_ptr_data& operator=(__uniq_ptr_data&&) = delete;
221 };
222
223 template <typename _Tp, typename _Dp>
224 struct __uniq_ptr_data<_Tp, _Dp, false, true> : __uniq_ptr_impl<_Tp, _Dp>
225 {
226 using __uniq_ptr_impl<_Tp, _Dp>::__uniq_ptr_impl;
227 __uniq_ptr_data(__uniq_ptr_data&&) = delete;
228 __uniq_ptr_data& operator=(__uniq_ptr_data&&) = default;
229 };
230
231 template <typename _Tp, typename _Dp>
232 struct __uniq_ptr_data<_Tp, _Dp, false, false> : __uniq_ptr_impl<_Tp, _Dp>
233 {
234 using __uniq_ptr_impl<_Tp, _Dp>::__uniq_ptr_impl;
235 __uniq_ptr_data(__uniq_ptr_data&&) = delete;
236 __uniq_ptr_data& operator=(__uniq_ptr_data&&) = delete;
237 };
238 /// @endcond
239
240 /// 20.7.1.2 unique_ptr for single objects.
241 template <typename _Tp, typename _Dp = default_delete<_Tp>>
242 class unique_ptr
243 {
244 template <typename _Up>
245 using _DeleterConstraint =
246 typename __uniq_ptr_impl<_Tp, _Up>::_DeleterConstraint::type;
247
248 __uniq_ptr_data<_Tp, _Dp> _M_t;
249
250 public:
251 using pointer = typename __uniq_ptr_impl<_Tp, _Dp>::pointer;
252 using element_type = _Tp;
253 using deleter_type = _Dp;
254
255 private:
256 // helper template for detecting a safe conversion from another
257 // unique_ptr
258 template<typename _Up, typename _Ep>
259 using __safe_conversion_up = __and_<
260 is_convertible<typename unique_ptr<_Up, _Ep>::pointer, pointer>,
261 __not_<is_array<_Up>>
262 >;
263
264 public:
265 // Constructors.
266
267 /// Default constructor, creates a unique_ptr that owns nothing.
268 template<typename _Del = _Dp, typename = _DeleterConstraint<_Del>>
269 constexpr unique_ptr() noexcept
270 : _M_t()
271 { }
272
273 /** Takes ownership of a pointer.
274 *
275 * @param __p A pointer to an object of @c element_type
276 *
277 * The deleter will be value-initialized.
278 */
279 template<typename _Del = _Dp, typename = _DeleterConstraint<_Del>>
280 explicit
281 unique_ptr(pointer __p) noexcept
282 : _M_t(__p)
283 { }
284
285 /** Takes ownership of a pointer.
286 *
287 * @param __p A pointer to an object of @c element_type
288 * @param __d A reference to a deleter.
289 *
290 * The deleter will be initialized with @p __d
291 */
292 template<typename _Del = deleter_type,
293 typename = _Require<is_copy_constructible<_Del>>>
294 unique_ptr(pointer __p, const deleter_type& __d) noexcept
295 : _M_t(__p, __d) { }
296
297 /** Takes ownership of a pointer.
298 *
299 * @param __p A pointer to an object of @c element_type
300 * @param __d An rvalue reference to a (non-reference) deleter.
301 *
302 * The deleter will be initialized with @p std::move(__d)
303 */
304 template<typename _Del = deleter_type,
305 typename = _Require<is_move_constructible<_Del>>>
306 unique_ptr(pointer __p,
307 __enable_if_t<!is_lvalue_reference<_Del>::value,
308 _Del&&> __d) noexcept
309 : _M_t(__p, std::move(__d))
310 { }
311
312 template<typename _Del = deleter_type,
313 typename _DelUnref = typename remove_reference<_Del>::type>
314 unique_ptr(pointer,
315 __enable_if_t<is_lvalue_reference<_Del>::value,
316 _DelUnref&&>) = delete;
317
318 /// Creates a unique_ptr that owns nothing.
319 template<typename _Del = _Dp, typename = _DeleterConstraint<_Del>>
320 constexpr unique_ptr(nullptr_t) noexcept
321 : _M_t()
322 { }
323
324 // Move constructors.
325
326 /// Move constructor.
327 unique_ptr(unique_ptr&&) = default;
328
329 /** @brief Converting constructor from another type
330 *
331 * Requires that the pointer owned by @p __u is convertible to the
332 * type of pointer owned by this object, @p __u does not own an array,
333 * and @p __u has a compatible deleter type.
334 */
335 template<typename _Up, typename _Ep, typename = _Require<
336 __safe_conversion_up<_Up, _Ep>,
337 typename conditional<is_reference<_Dp>::value,
338 is_same<_Ep, _Dp>,
339 is_convertible<_Ep, _Dp>>::type>>
340 unique_ptr(unique_ptr<_Up, _Ep>&& __u) noexcept
341 : _M_t(__u.release(), std::forward<_Ep>(__u.get_deleter()))
342 { }
343
344#if _GLIBCXX_USE_DEPRECATED1
345#pragma GCC diagnostic push
346#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
347 /// Converting constructor from @c auto_ptr
348 template<typename _Up, typename = _Require<
349 is_convertible<_Up*, _Tp*>, is_same<_Dp, default_delete<_Tp>>>>
350 unique_ptr(auto_ptr<_Up>&& __u) noexcept;
351#pragma GCC diagnostic pop
352#endif
353
354 /// Destructor, invokes the deleter if the stored pointer is not null.
355 ~unique_ptr() noexcept
356 {
357 static_assert(__is_invocable<deleter_type&, pointer>::value,
358 "unique_ptr's deleter must be invocable with a pointer");
359 auto& __ptr = _M_t._M_ptr();
360 if (__ptr != nullptr)
2
Assuming the condition is true
3
Taking true branch
361 get_deleter()(std::move(__ptr));
4
Calling 'default_delete::operator()'
362 __ptr = pointer();
363 }
364
365 // Assignment.
366
367 /** @brief Move assignment operator.
368 *
369 * Invokes the deleter if this object owns a pointer.
370 */
371 unique_ptr& operator=(unique_ptr&&) = default;
372
373 /** @brief Assignment from another type.
374 *
375 * @param __u The object to transfer ownership from, which owns a
376 * convertible pointer to a non-array object.
377 *
378 * Invokes the deleter if this object owns a pointer.
379 */
380 template<typename _Up, typename _Ep>
381 typename enable_if< __and_<
382 __safe_conversion_up<_Up, _Ep>,
383 is_assignable<deleter_type&, _Ep&&>
384 >::value,
385 unique_ptr&>::type
386 operator=(unique_ptr<_Up, _Ep>&& __u) noexcept
387 {
388 reset(__u.release());
389 get_deleter() = std::forward<_Ep>(__u.get_deleter());
390 return *this;
391 }
392
393 /// Reset the %unique_ptr to empty, invoking the deleter if necessary.
394 unique_ptr&
395 operator=(nullptr_t) noexcept
396 {
397 reset();
398 return *this;
399 }
400
401 // Observers.
402
403 /// Dereference the stored pointer.
404 typename add_lvalue_reference<element_type>::type
405 operator*() const
406 {
407 __glibcxx_assert(get() != pointer());
408 return *get();
409 }
410
411 /// Return the stored pointer.
412 pointer
413 operator->() const noexcept
414 {
415 _GLIBCXX_DEBUG_PEDASSERT(get() != pointer());
416 return get();
417 }
418
419 /// Return the stored pointer.
420 pointer
421 get() const noexcept
422 { return _M_t._M_ptr(); }
423
424 /// Return a reference to the stored deleter.
425 deleter_type&
426 get_deleter() noexcept
427 { return _M_t._M_deleter(); }
428
429 /// Return a reference to the stored deleter.
430 const deleter_type&
431 get_deleter() const noexcept
432 { return _M_t._M_deleter(); }
433
434 /// Return @c true if the stored pointer is not null.
435 explicit operator bool() const noexcept
436 { return get() == pointer() ? false : true; }
437
438 // Modifiers.
439
440 /// Release ownership of any stored pointer.
441 pointer
442 release() noexcept
443 { return _M_t.release(); }
444
445 /** @brief Replace the stored pointer.
446 *
447 * @param __p The new pointer to store.
448 *
449 * The deleter will be invoked if a pointer is already owned.
450 */
451 void
452 reset(pointer __p = pointer()) noexcept
453 {
454 static_assert(__is_invocable<deleter_type&, pointer>::value,
455 "unique_ptr's deleter must be invocable with a pointer");
456 _M_t.reset(std::move(__p));
457 }
458
459 /// Exchange the pointer and deleter with another object.
460 void
461 swap(unique_ptr& __u) noexcept
462 {
463 static_assert(__is_swappable<_Dp>::value, "deleter must be swappable");
464 _M_t.swap(__u._M_t);
465 }
466
467 // Disable copy from lvalue.
468 unique_ptr(const unique_ptr&) = delete;
469 unique_ptr& operator=(const unique_ptr&) = delete;
470 };
471
472 /// 20.7.1.3 unique_ptr for array objects with a runtime length
473 // [unique.ptr.runtime]
474 // _GLIBCXX_RESOLVE_LIB_DEFECTS
475 // DR 740 - omit specialization for array objects with a compile time length
476 template<typename _Tp, typename _Dp>
477 class unique_ptr<_Tp[], _Dp>
478 {
479 template <typename _Up>
480 using _DeleterConstraint =
481 typename __uniq_ptr_impl<_Tp, _Up>::_DeleterConstraint::type;
482
483 __uniq_ptr_data<_Tp, _Dp> _M_t;
484
485 template<typename _Up>
486 using __remove_cv = typename remove_cv<_Up>::type;
487
488 // like is_base_of<_Tp, _Up> but false if unqualified types are the same
489 template<typename _Up>
490 using __is_derived_Tp
491 = __and_< is_base_of<_Tp, _Up>,
492 __not_<is_same<__remove_cv<_Tp>, __remove_cv<_Up>>> >;
493
494 public:
495 using pointer = typename __uniq_ptr_impl<_Tp, _Dp>::pointer;
496 using element_type = _Tp;
497 using deleter_type = _Dp;
498
499 // helper template for detecting a safe conversion from another
500 // unique_ptr
501 template<typename _Up, typename _Ep,
502 typename _UPtr = unique_ptr<_Up, _Ep>,
503 typename _UP_pointer = typename _UPtr::pointer,
504 typename _UP_element_type = typename _UPtr::element_type>
505 using __safe_conversion_up = __and_<
506 is_array<_Up>,
507 is_same<pointer, element_type*>,
508 is_same<_UP_pointer, _UP_element_type*>,
509 is_convertible<_UP_element_type(*)[], element_type(*)[]>
510 >;
511
512 // helper template for detecting a safe conversion from a raw pointer
513 template<typename _Up>
514 using __safe_conversion_raw = __and_<
515 __or_<__or_<is_same<_Up, pointer>,
516 is_same<_Up, nullptr_t>>,
517 __and_<is_pointer<_Up>,
518 is_same<pointer, element_type*>,
519 is_convertible<
520 typename remove_pointer<_Up>::type(*)[],
521 element_type(*)[]>
522 >
523 >
524 >;
525
526 // Constructors.
527
528 /// Default constructor, creates a unique_ptr that owns nothing.
529 template<typename _Del = _Dp, typename = _DeleterConstraint<_Del>>
530 constexpr unique_ptr() noexcept
531 : _M_t()
532 { }
533
534 /** Takes ownership of a pointer.
535 *
536 * @param __p A pointer to an array of a type safely convertible
537 * to an array of @c element_type
538 *
539 * The deleter will be value-initialized.
540 */
541 template<typename _Up,
542 typename _Vp = _Dp,
543 typename = _DeleterConstraint<_Vp>,
544 typename = typename enable_if<
545 __safe_conversion_raw<_Up>::value, bool>::type>
546 explicit
547 unique_ptr(_Up __p) noexcept
548 : _M_t(__p)
549 { }
550
551 /** Takes ownership of a pointer.
552 *
553 * @param __p A pointer to an array of a type safely convertible
554 * to an array of @c element_type
555 * @param __d A reference to a deleter.
556 *
557 * The deleter will be initialized with @p __d
558 */
559 template<typename _Up, typename _Del = deleter_type,
560 typename = _Require<__safe_conversion_raw<_Up>,
561 is_copy_constructible<_Del>>>
562 unique_ptr(_Up __p, const deleter_type& __d) noexcept
563 : _M_t(__p, __d) { }
564
565 /** Takes ownership of a pointer.
566 *
567 * @param __p A pointer to an array of a type safely convertible
568 * to an array of @c element_type
569 * @param __d A reference to a deleter.
570 *
571 * The deleter will be initialized with @p std::move(__d)
572 */
573 template<typename _Up, typename _Del = deleter_type,
574 typename = _Require<__safe_conversion_raw<_Up>,
575 is_move_constructible<_Del>>>
576 unique_ptr(_Up __p,
577 __enable_if_t<!is_lvalue_reference<_Del>::value,
578 _Del&&> __d) noexcept
579 : _M_t(std::move(__p), std::move(__d))
580 { }
581
582 template<typename _Up, typename _Del = deleter_type,
583 typename _DelUnref = typename remove_reference<_Del>::type,
584 typename = _Require<__safe_conversion_raw<_Up>>>
585 unique_ptr(_Up,
586 __enable_if_t<is_lvalue_reference<_Del>::value,
587 _DelUnref&&>) = delete;
588
589 /// Move constructor.
590 unique_ptr(unique_ptr&&) = default;
591
592 /// Creates a unique_ptr that owns nothing.
593 template<typename _Del = _Dp, typename = _DeleterConstraint<_Del>>
594 constexpr unique_ptr(nullptr_t) noexcept
595 : _M_t()
596 { }
597
598 template<typename _Up, typename _Ep, typename = _Require<
599 __safe_conversion_up<_Up, _Ep>,
600 typename conditional<is_reference<_Dp>::value,
601 is_same<_Ep, _Dp>,
602 is_convertible<_Ep, _Dp>>::type>>
603 unique_ptr(unique_ptr<_Up, _Ep>&& __u) noexcept
604 : _M_t(__u.release(), std::forward<_Ep>(__u.get_deleter()))
605 { }
606
607 /// Destructor, invokes the deleter if the stored pointer is not null.
608 ~unique_ptr()
609 {
610 auto& __ptr = _M_t._M_ptr();
611 if (__ptr != nullptr)
612 get_deleter()(__ptr);
613 __ptr = pointer();
614 }
615
616 // Assignment.
617
618 /** @brief Move assignment operator.
619 *
620 * Invokes the deleter if this object owns a pointer.
621 */
622 unique_ptr&
623 operator=(unique_ptr&&) = default;
624
625 /** @brief Assignment from another type.
626 *
627 * @param __u The object to transfer ownership from, which owns a
628 * convertible pointer to an array object.
629 *
630 * Invokes the deleter if this object owns a pointer.
631 */
632 template<typename _Up, typename _Ep>
633 typename
634 enable_if<__and_<__safe_conversion_up<_Up, _Ep>,
635 is_assignable<deleter_type&, _Ep&&>
636 >::value,
637 unique_ptr&>::type
638 operator=(unique_ptr<_Up, _Ep>&& __u) noexcept
639 {
640 reset(__u.release());
641 get_deleter() = std::forward<_Ep>(__u.get_deleter());
642 return *this;
643 }
644
645 /// Reset the %unique_ptr to empty, invoking the deleter if necessary.
646 unique_ptr&
647 operator=(nullptr_t) noexcept
648 {
649 reset();
650 return *this;
651 }
652
653 // Observers.
654
655 /// Access an element of owned array.
656 typename std::add_lvalue_reference<element_type>::type
657 operator[](size_t __i) const
658 {
659 __glibcxx_assert(get() != pointer());
660 return get()[__i];
661 }
662
663 /// Return the stored pointer.
664 pointer
665 get() const noexcept
666 { return _M_t._M_ptr(); }
667
668 /// Return a reference to the stored deleter.
669 deleter_type&
670 get_deleter() noexcept
671 { return _M_t._M_deleter(); }
672
673 /// Return a reference to the stored deleter.
674 const deleter_type&
675 get_deleter() const noexcept
676 { return _M_t._M_deleter(); }
677
678 /// Return @c true if the stored pointer is not null.
679 explicit operator bool() const noexcept
680 { return get() == pointer() ? false : true; }
681
682 // Modifiers.
683
684 /// Release ownership of any stored pointer.
685 pointer
686 release() noexcept
687 { return _M_t.release(); }
688
689 /** @brief Replace the stored pointer.
690 *
691 * @param __p The new pointer to store.
692 *
693 * The deleter will be invoked if a pointer is already owned.
694 */
695 template <typename _Up,
696 typename = _Require<
697 __or_<is_same<_Up, pointer>,
698 __and_<is_same<pointer, element_type*>,
699 is_pointer<_Up>,
700 is_convertible<
701 typename remove_pointer<_Up>::type(*)[],
702 element_type(*)[]
703 >
704 >
705 >
706 >>
707 void
708 reset(_Up __p) noexcept
709 { _M_t.reset(std::move(__p)); }
710
711 void reset(nullptr_t = nullptr) noexcept
712 { reset(pointer()); }
713
714 /// Exchange the pointer and deleter with another object.
715 void
716 swap(unique_ptr& __u) noexcept
717 {
718 static_assert(__is_swappable<_Dp>::value, "deleter must be swappable");
719 _M_t.swap(__u._M_t);
720 }
721
722 // Disable copy from lvalue.
723 unique_ptr(const unique_ptr&) = delete;
724 unique_ptr& operator=(const unique_ptr&) = delete;
725 };
726
727 /// @relates unique_ptr @{
728
729 /// Swap overload for unique_ptr
730 template<typename _Tp, typename _Dp>
731 inline
732#if __cplusplus201703L > 201402L || !defined(__STRICT_ANSI__1) // c++1z or gnu++11
733 // Constrained free swap overload, see p0185r1
734 typename enable_if<__is_swappable<_Dp>::value>::type
735#else
736 void
737#endif
738 swap(unique_ptr<_Tp, _Dp>& __x,
739 unique_ptr<_Tp, _Dp>& __y) noexcept
740 { __x.swap(__y); }
741
742#if __cplusplus201703L > 201402L || !defined(__STRICT_ANSI__1) // c++1z or gnu++11
743 template<typename _Tp, typename _Dp>
744 typename enable_if<!__is_swappable<_Dp>::value>::type
745 swap(unique_ptr<_Tp, _Dp>&,
746 unique_ptr<_Tp, _Dp>&) = delete;
747#endif
748
749 /// Equality operator for unique_ptr objects, compares the owned pointers
750 template<typename _Tp, typename _Dp,
751 typename _Up, typename _Ep>
752 _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool
753 operator==(const unique_ptr<_Tp, _Dp>& __x,
754 const unique_ptr<_Up, _Ep>& __y)
755 { return __x.get() == __y.get(); }
756
757 /// unique_ptr comparison with nullptr
758 template<typename _Tp, typename _Dp>
759 _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool
760 operator==(const unique_ptr<_Tp, _Dp>& __x, nullptr_t) noexcept
761 { return !__x; }
762
763#ifndef __cpp_lib_three_way_comparison
764 /// unique_ptr comparison with nullptr
765 template<typename _Tp, typename _Dp>
766 _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool
767 operator==(nullptr_t, const unique_ptr<_Tp, _Dp>& __x) noexcept
768 { return !__x; }
769
770 /// Inequality operator for unique_ptr objects, compares the owned pointers
771 template<typename _Tp, typename _Dp,
772 typename _Up, typename _Ep>
773 _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool
774 operator!=(const unique_ptr<_Tp, _Dp>& __x,
775 const unique_ptr<_Up, _Ep>& __y)
776 { return __x.get() != __y.get(); }
777
778 /// unique_ptr comparison with nullptr
779 template<typename _Tp, typename _Dp>
780 _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool
781 operator!=(const unique_ptr<_Tp, _Dp>& __x, nullptr_t) noexcept
782 { return (bool)__x; }
783
784 /// unique_ptr comparison with nullptr
785 template<typename _Tp, typename _Dp>
786 _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool
787 operator!=(nullptr_t, const unique_ptr<_Tp, _Dp>& __x) noexcept
788 { return (bool)__x; }
789#endif // three way comparison
790
791 /// Relational operator for unique_ptr objects, compares the owned pointers
792 template<typename _Tp, typename _Dp,
793 typename _Up, typename _Ep>
794 _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool
795 operator<(const unique_ptr<_Tp, _Dp>& __x,
796 const unique_ptr<_Up, _Ep>& __y)
797 {
798 typedef typename
799 std::common_type<typename unique_ptr<_Tp, _Dp>::pointer,
800 typename unique_ptr<_Up, _Ep>::pointer>::type _CT;
801 return std::less<_CT>()(__x.get(), __y.get());
802 }
803
804 /// unique_ptr comparison with nullptr
805 template<typename _Tp, typename _Dp>
806 _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool
807 operator<(const unique_ptr<_Tp, _Dp>& __x, nullptr_t)
808 {
809 return std::less<typename unique_ptr<_Tp, _Dp>::pointer>()(__x.get(),
810 nullptr);
811 }
812
813 /// unique_ptr comparison with nullptr
814 template<typename _Tp, typename _Dp>
815 _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool
816 operator<(nullptr_t, const unique_ptr<_Tp, _Dp>& __x)
817 {
818 return std::less<typename unique_ptr<_Tp, _Dp>::pointer>()(nullptr,
819 __x.get());
820 }
821
822 /// Relational operator for unique_ptr objects, compares the owned pointers
823 template<typename _Tp, typename _Dp,
824 typename _Up, typename _Ep>
825 _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool
826 operator<=(const unique_ptr<_Tp, _Dp>& __x,
827 const unique_ptr<_Up, _Ep>& __y)
828 { return !(__y < __x); }
829
830 /// unique_ptr comparison with nullptr
831 template<typename _Tp, typename _Dp>
832 _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool
833 operator<=(const unique_ptr<_Tp, _Dp>& __x, nullptr_t)
834 { return !(nullptr < __x); }
835
836 /// unique_ptr comparison with nullptr
837 template<typename _Tp, typename _Dp>
838 _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool
839 operator<=(nullptr_t, const unique_ptr<_Tp, _Dp>& __x)
840 { return !(__x < nullptr); }
841
842 /// Relational operator for unique_ptr objects, compares the owned pointers
843 template<typename _Tp, typename _Dp,
844 typename _Up, typename _Ep>
845 _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool
846 operator>(const unique_ptr<_Tp, _Dp>& __x,
847 const unique_ptr<_Up, _Ep>& __y)
848 { return (__y < __x); }
849
850 /// unique_ptr comparison with nullptr
851 template<typename _Tp, typename _Dp>
852 _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool
853 operator>(const unique_ptr<_Tp, _Dp>& __x, nullptr_t)
854 {
855 return std::less<typename unique_ptr<_Tp, _Dp>::pointer>()(nullptr,
856 __x.get());
857 }
858
859 /// unique_ptr comparison with nullptr
860 template<typename _Tp, typename _Dp>
861 _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool
862 operator>(nullptr_t, const unique_ptr<_Tp, _Dp>& __x)
863 {
864 return std::less<typename unique_ptr<_Tp, _Dp>::pointer>()(__x.get(),
865 nullptr);
866 }
867
868 /// Relational operator for unique_ptr objects, compares the owned pointers
869 template<typename _Tp, typename _Dp,
870 typename _Up, typename _Ep>
871 _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool
872 operator>=(const unique_ptr<_Tp, _Dp>& __x,
873 const unique_ptr<_Up, _Ep>& __y)
874 { return !(__x < __y); }
875
876 /// unique_ptr comparison with nullptr
877 template<typename _Tp, typename _Dp>
878 _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool
879 operator>=(const unique_ptr<_Tp, _Dp>& __x, nullptr_t)
880 { return !(__x < nullptr); }
881
882 /// unique_ptr comparison with nullptr
883 template<typename _Tp, typename _Dp>
884 _GLIBCXX_NODISCARD[[__nodiscard__]] inline bool
885 operator>=(nullptr_t, const unique_ptr<_Tp, _Dp>& __x)
886 { return !(nullptr < __x); }
887
888#ifdef __cpp_lib_three_way_comparison
889 template<typename _Tp, typename _Dp, typename _Up, typename _Ep>
890 requires three_way_comparable_with<typename unique_ptr<_Tp, _Dp>::pointer,
891 typename unique_ptr<_Up, _Ep>::pointer>
892 inline
893 compare_three_way_result_t<typename unique_ptr<_Tp, _Dp>::pointer,
894 typename unique_ptr<_Up, _Ep>::pointer>
895 operator<=>(const unique_ptr<_Tp, _Dp>& __x,
896 const unique_ptr<_Up, _Ep>& __y)
897 { return compare_three_way()(__x.get(), __y.get()); }
898
899 template<typename _Tp, typename _Dp>
900 requires three_way_comparable<typename unique_ptr<_Tp, _Dp>::pointer>
901 inline
902 compare_three_way_result_t<typename unique_ptr<_Tp, _Dp>::pointer>
903 operator<=>(const unique_ptr<_Tp, _Dp>& __x, nullptr_t)
904 {
905 using pointer = typename unique_ptr<_Tp, _Dp>::pointer;
906 return compare_three_way()(__x.get(), static_cast<pointer>(nullptr));
907 }
908#endif
909 // @} relates unique_ptr
910
911 /// @cond undocumented
912 template<typename _Up, typename _Ptr = typename _Up::pointer,
913 bool = __poison_hash<_Ptr>::__enable_hash_call>
914 struct __uniq_ptr_hash
915#if ! _GLIBCXX_INLINE_VERSION0
916 : private __poison_hash<_Ptr>
917#endif
918 {
919 size_t
920 operator()(const _Up& __u) const
921 noexcept(noexcept(std::declval<hash<_Ptr>>()(std::declval<_Ptr>())))
922 { return hash<_Ptr>()(__u.get()); }
923 };
924
925 template<typename _Up, typename _Ptr>
926 struct __uniq_ptr_hash<_Up, _Ptr, false>
927 : private __poison_hash<_Ptr>
928 { };
929 /// @endcond
930
931 /// std::hash specialization for unique_ptr.
932 template<typename _Tp, typename _Dp>
933 struct hash<unique_ptr<_Tp, _Dp>>
934 : public __hash_base<size_t, unique_ptr<_Tp, _Dp>>,
935 public __uniq_ptr_hash<unique_ptr<_Tp, _Dp>>
936 { };
937
938#if __cplusplus201703L >= 201402L
939 /// @relates unique_ptr @{
940#define __cpp_lib_make_unique201304 201304
941
942 /// @cond undocumented
943
944 template<typename _Tp>
945 struct _MakeUniq
946 { typedef unique_ptr<_Tp> __single_object; };
947
948 template<typename _Tp>
949 struct _MakeUniq<_Tp[]>
950 { typedef unique_ptr<_Tp[]> __array; };
951
952 template<typename _Tp, size_t _Bound>
953 struct _MakeUniq<_Tp[_Bound]>
954 { struct __invalid_type { }; };
955
956 /// @endcond
957
958 /// std::make_unique for single objects
959 template<typename _Tp, typename... _Args>
960 inline typename _MakeUniq<_Tp>::__single_object
961 make_unique(_Args&&... __args)
962 { return unique_ptr<_Tp>(new _Tp(std::forward<_Args>(__args)...)); }
963
964 /// std::make_unique for arrays of unknown bound
965 template<typename _Tp>
966 inline typename _MakeUniq<_Tp>::__array
967 make_unique(size_t __num)
968 { return unique_ptr<_Tp>(new remove_extent_t<_Tp>[__num]()); }
969
970 /// Disable std::make_unique for arrays of known bound
971 template<typename _Tp, typename... _Args>
972 inline typename _MakeUniq<_Tp>::__invalid_type
973 make_unique(_Args&&...) = delete;
974 // @} relates unique_ptr
975#endif // C++14
976
977#if __cplusplus201703L > 201703L && __cpp_concepts
978 // _GLIBCXX_RESOLVE_LIB_DEFECTS
979 // 2948. unique_ptr does not define operator<< for stream output
980 /// Stream output operator for unique_ptr
981 template<typename _CharT, typename _Traits, typename _Tp, typename _Dp>
982 inline basic_ostream<_CharT, _Traits>&
983 operator<<(basic_ostream<_CharT, _Traits>& __os,
984 const unique_ptr<_Tp, _Dp>& __p)
985 requires requires { __os << __p.get(); }
986 {
987 __os << __p.get();
988 return __os;
989 }
990#endif // C++20
991
992 // @} group pointer_abstractions
993
994#if __cplusplus201703L >= 201703L
995 namespace __detail::__variant
996 {
997 template<typename> struct _Never_valueless_alt; // see <variant>
998
999 // Provide the strong exception-safety guarantee when emplacing a
1000 // unique_ptr into a variant.
1001 template<typename _Tp, typename _Del>
1002 struct _Never_valueless_alt<std::unique_ptr<_Tp, _Del>>
1003 : std::true_type
1004 { };
1005 } // namespace __detail::__variant
1006#endif // C++17
1007
1008_GLIBCXX_END_NAMESPACE_VERSION
1009} // namespace
1010
1011#endif /* _UNIQUE_PTR_H */

/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit.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#pragma once
20
21#include <eerdll2.hxx>
22#include <editdoc.hxx>
23#include "editsel.hxx"
24#include "editundo.hxx"
25#include "editstt2.hxx"
26#include <editeng/editdata.hxx>
27#include <editeng/SpellPortions.hxx>
28#include <editeng/editeng.hxx>
29#include <editeng/editview.hxx>
30#include <svtools/colorcfg.hxx>
31#include <editeng/outliner.hxx>
32#include <vcl/virdev.hxx>
33#include <vcl/cursor.hxx>
34#include <vcl/vclptr.hxx>
35#include <tools/fract.hxx>
36#include <vcl/idle.hxx>
37#include <vcl/commandevent.hxx>
38#include <vcl/ptrstyle.hxx>
39
40#include <vcl/dndhelp.hxx>
41#include <svl/ondemand.hxx>
42#include <svl/languageoptions.hxx>
43#include <com/sun/star/linguistic2/XSpellAlternatives.hpp>
44#include <com/sun/star/linguistic2/XSpellChecker1.hpp>
45#include <com/sun/star/linguistic2/XHyphenator.hpp>
46#include <com/sun/star/lang/Locale.hpp>
47#include <com/sun/star/i18n/XBreakIterator.hpp>
48#include <com/sun/star/i18n/CharacterIteratorMode.hpp>
49#include <com/sun/star/i18n/WordType.hpp>
50#include <com/sun/star/i18n/XExtendedInputSequenceChecker.hpp>
51#include <com/sun/star/uno/Sequence.hxx>
52
53#include <i18nlangtag/lang.h>
54#include <o3tl/deleter.hxx>
55#include <o3tl/typed_flags_set.hxx>
56
57#include <optional>
58#include <memory>
59#include <vector>
60
61class EditView;
62class EditEngine;
63class OutlinerSearchable;
64
65class SvxSearchItem;
66class SvxLRSpaceItem;
67class TextRanger;
68class SvKeyValueIterator;
69class SvxForbiddenCharactersTable;
70class SvtCTLOptions;
71namespace vcl { class Window; }
72class SvxNumberFormat;
73namespace com::sun::star::datatransfer::clipboard {
74 class XClipboard;
75}
76
77namespace editeng {
78 struct MisspellRanges;
79}
80
81#define DEL_LEFT1 1
82#define DEL_RIGHT2 2
83#define TRAVEL_X_DONTKNOW0xFFFFFFFF 0xFFFFFFFF
84#define CURSOR_BIDILEVEL_DONTKNOW0xFFFF 0xFFFF
85#define MAXCHARSINPARA0x3FFF-16 0x3FFF-CHARPOSGROW16 // Max 16K, because WYSIWYG array
86#define LINE_SEP'\x0A' '\x0A'
87
88#define ATTRSPECIAL_WHOLEWORD1 1
89#define ATTRSPECIAL_EDGE2 2
90
91enum class GetCursorFlags {
92 NONE = 0x0000,
93 TextOnly = 0x0001,
94 StartOfLine = 0x0002,
95 EndOfLine = 0x0004,
96 PreferPortionStart = 0x0008,
97};
98namespace o3tl {
99 template<> struct typed_flags<GetCursorFlags> : is_typed_flags<GetCursorFlags, 0x0f> {};
100}
101
102
103struct DragAndDropInfo
104{
105 tools::Rectangle aCurCursor;
106 tools::Rectangle aCurSavedCursor;
107 sal_uInt16 nSensibleRange;
108 sal_uInt16 nCursorWidth;
109 ESelection aBeginDragSel;
110 EditPaM aDropDest;
111 sal_Int32 nOutlinerDropDest;
112 ESelection aDropSel;
113 VclPtr<VirtualDevice> pBackground;
114 const SvxFieldItem* pField;
115 bool bVisCursor : 1;
116 bool bDroppedInMe : 1;
117 bool bStarterOfDD : 1;
118 bool bHasValidData : 1;
119 bool bUndoAction : 1;
120 bool bOutlinerMode : 1;
121 bool bDragAccepted : 1;
122
123 DragAndDropInfo()
124 : nSensibleRange(0), nCursorWidth(0), nOutlinerDropDest(0), pBackground(nullptr),
125 pField(nullptr), bVisCursor(false), bDroppedInMe(false), bStarterOfDD(false),
126 bHasValidData(false), bUndoAction(false), bOutlinerMode(false), bDragAccepted(false)
127 {
128 }
129 ~DragAndDropInfo()
130 {
131 pBackground.disposeAndClear();
6
Calling 'VclPtr::disposeAndClear'
132 }
133};
134
135struct ImplIMEInfos
136{
137 OUString aOldTextAfterStartPos;
138 std::unique_ptr<ExtTextInputAttr[]> pAttribs;
139 EditPaM aPos;
140 sal_Int32 nLen;
141 bool bWasCursorOverwrite;
142
143 ImplIMEInfos( const EditPaM& rPos, const OUString& rOldTextAfterStartPos );
144 ~ImplIMEInfos();
145
146 void CopyAttribs( const ExtTextInputAttr* pA, sal_uInt16 nL );
147 void DestroyAttribs();
148};
149
150// #i18881# to be able to identify the positions of changed words
151// the positions of each portion need to be saved
152typedef std::vector<EditSelection> SpellContentSelections;
153
154struct SpellInfo
155{
156 EESpellState eState;
157 EPaM aSpellStart;
158 EPaM aSpellTo;
159 EditPaM aCurSentenceStart;
160 bool bSpellToEnd;
161 bool bMultipleDoc;
162 svx::SpellPortions aLastSpellPortions;
163 SpellContentSelections aLastSpellContentSelections;
164 SpellInfo() : eState(EESpellState::Ok), bSpellToEnd(true), bMultipleDoc(false)
165 { }
166};
167
168// used for text conversion
169struct ConvInfo
170{
171 EPaM aConvStart;
172 EPaM aConvTo;
173 EPaM aConvContinue; // position to start search for next text portion (word) with
174 bool bConvToEnd;
175 bool bMultipleDoc;
176
177 ConvInfo() : bConvToEnd(true), bMultipleDoc(false) {}
178};
179
180struct FormatterFontMetric
181{
182 sal_uInt16 nMaxAscent;
183 sal_uInt16 nMaxDescent;
184
185 FormatterFontMetric() : nMaxAscent(0), nMaxDescent(0) { /* nMinLeading = 0xFFFF; */ }
186 sal_uInt16 GetHeight() const { return nMaxAscent+nMaxDescent; }
187};
188
189class IdleFormattter : public Idle
190{
191private:
192 EditView* pView;
193 int nRestarts;
194
195public:
196 IdleFormattter();
197 virtual ~IdleFormattter() override;
198
199 void DoIdleFormat( EditView* pV );
200 void ForceTimeout();
201 void ResetRestarts() { nRestarts = 0; }
202 EditView* GetView() { return pView; }
203};
204
205class ImpEditView;
206/// This is meant just for Calc, where all positions in logical units (twips for LOK) are computed by
207/// doing independent pixel-alignment for each cell's size. LOKSpecialPositioning stores
208/// both 'output-area' and 'visible-doc-position' in pure logical unit (twips for LOK).
209/// This allows the cursor/selection messages to be in regular(print) twips unit like in Writer.
210class LOKSpecialPositioning
211{
212public:
213 LOKSpecialPositioning(const ImpEditView& rImpEditView, MapUnit eUnit, const tools::Rectangle& rOutputArea,
214 const Point& rVisDocStartPos);
215
216 void ReInit(MapUnit eUnit, const tools::Rectangle& rOutputArea, const Point& rVisDocStartPos);
217
218 void SetOutputArea(const tools::Rectangle& rOutputArea);
219 const tools::Rectangle& GetOutputArea() const;
220 void SetVisDocStartPos(const Point& rVisDocStartPos);
221
222 bool IsVertical() const;
223 bool IsTopToBottom() const;
224
225 long GetVisDocLeft() const { return maVisDocStartPos.X(); }
226 long GetVisDocTop() const { return maVisDocStartPos.Y(); }
227 long GetVisDocRight() const { return maVisDocStartPos.X() + (!IsVertical() ? maOutArea.GetWidth() : maOutArea.GetHeight()); }
228 long GetVisDocBottom() const { return maVisDocStartPos.Y() + (!IsVertical() ? maOutArea.GetHeight() : maOutArea.GetWidth()); }
229 tools::Rectangle GetVisDocArea() const;
230
231 Point GetWindowPos(const Point& rDocPos, MapUnit eDocPosUnit) const;
232 tools::Rectangle GetWindowPos(const tools::Rectangle& rDocRect, MapUnit eDocRectUnit) const;
233
234 Point GetRefPoint() const;
235
236private:
237 Point convertUnit(const Point& rPos, MapUnit ePosUnit) const;
238 tools::Rectangle convertUnit(const tools::Rectangle& rRect, MapUnit eRectUnit) const;
239
240 const ImpEditView& mrImpEditView;
241 tools::Rectangle maOutArea;
242 Point maVisDocStartPos;
243 MapUnit meUnit;
244};
245
246
247
248class ImpEditView : public vcl::unohelper::DragAndDropClient
249{
250 friend class EditView;
251 friend class EditEngine;
252 friend class ImpEditEngine;
253 using vcl::unohelper::DragAndDropClient::dragEnter;
254 using vcl::unohelper::DragAndDropClient::dragExit;
255 using vcl::unohelper::DragAndDropClient::dragOver;
256
257private:
258 EditView* pEditView;
259 std::unique_ptr<vcl::Cursor, o3tl::default_delete<vcl::Cursor>> pCursor;
260 std::unique_ptr<Color> pBackgroundColor;
261 /// Containing view shell, if any.
262 OutlinerViewShell* mpViewShell;
263 /// Another shell, just listening to our state, if any.
264 OutlinerViewShell* mpOtherShell;
265 EditEngine* pEditEngine;
266 VclPtr<vcl::Window> pOutWin;
267 EditView::OutWindowSet aOutWindowSet;
268 std::optional<PointerStyle> mxPointer;
269 std::unique_ptr<DragAndDropInfo> pDragAndDropInfo;
270
271 css::uno::Reference< css::datatransfer::dnd::XDragSourceListener > mxDnDListener;
272
273
274 long nInvMore;
275 EVControlBits nControl;
276 sal_uInt32 nTravelXPos;
277 GetCursorFlags nExtraCursorFlags;
278 sal_uInt16 nCursorBidiLevel;
279 sal_uInt16 nScrollDiffX;
280 bool bReadOnly;
281 bool bClickedInSelection;
282 bool bActiveDragAndDropListener;
283
284 Point aAnchorPoint;
285 tools::Rectangle aOutArea;
286 Point aVisDocStartPos;
287 EESelectionMode eSelectionMode;
288 EditSelection aEditSelection;
289 EEAnchorMode eAnchorMode;
290
291 /// mechanism to change from the classic refresh mode that simply
292 // invalidates the area where text was changed. When set, the invalidate
293 // and the direct repaint of the Window-plugged EditView will be suppressed.
294 // Instead, a consumer that has registered using an EditViewCallbacks
295 // incarnation has to handle that. Used e.g. to represent the edited text
296 // in Draw/Impress in an OverlayObject which avoids evtl. expensive full
297 // repaints of the EditView(s)
298 EditViewCallbacks* mpEditViewCallbacks;
299 std::unique_ptr<LOKSpecialPositioning> mpLOKSpecialPositioning;
300 bool mbBroadcastLOKViewCursor:1;
301 bool mbSuppressLOKMessages:1;
302
303 EditViewCallbacks* getEditViewCallbacks() const
304 {
305 return mpEditViewCallbacks;
306 }
307
308 void lokSelectionCallback(const std::unique_ptr<tools::PolyPolygon> &pPolyPoly, bool bStartHandleVisible, bool bEndHandleVisible);
309
310 void setEditViewCallbacks(EditViewCallbacks* pEditViewCallbacks)
311 {
312 mpEditViewCallbacks = pEditViewCallbacks;
313 }
314
315 void InvalidateAtWindow(const tools::Rectangle& rRect);
316
317 css::uno::Reference<css::datatransfer::clipboard::XClipboard> GetClipboard() const;
318 css::uno::Reference<css::datatransfer::clipboard::XClipboard> GetSelection() const;
319
320 void SetBroadcastLOKViewCursor(bool bSet)
321 {
322 mbBroadcastLOKViewCursor = bSet;
323 }
324
325protected:
326
327 // DragAndDropClient
328 void dragGestureRecognized(const css::datatransfer::dnd::DragGestureEvent& dge) override;
329 void dragDropEnd( const css::datatransfer::dnd::DragSourceDropEvent& dsde ) override;
330 void drop(const css::datatransfer::dnd::DropTargetDropEvent& dtde) override;
331 void dragEnter( const css::datatransfer::dnd::DropTargetDragEnterEvent& dtdee ) override;
332 void dragExit( const css::datatransfer::dnd::DropTargetEvent& dte ) override;
333 void dragOver(const css::datatransfer::dnd::DropTargetDragEvent& dtde) override;
334
335 void ShowDDCursor( const tools::Rectangle& rRect );
336 void HideDDCursor();
337
338 void ImplDrawHighlightRect( OutputDevice* _pTarget, const Point& rDocPosTopLeft, const Point& rDocPosBottomRight, tools::PolyPolygon* pPolyPoly );
339 tools::Rectangle ImplGetEditCursor(EditPaM& aPaM, GetCursorFlags nShowCursorFlags,
340 sal_Int32& nTextPortionStart, const ParaPortion* pParaPortion) const;
341
342public:
343 ImpEditView( EditView* pView, EditEngine* pEng, vcl::Window* pWindow );
344 virtual ~ImpEditView() override;
345
346 EditView* GetEditViewPtr() { return pEditView; }
347
348 sal_uInt16 GetScrollDiffX() const { return nScrollDiffX; }
349 void SetScrollDiffX( sal_uInt16 n ) { nScrollDiffX = n; }
350
351 sal_uInt16 GetCursorBidiLevel() const { return nCursorBidiLevel; }
352 void SetCursorBidiLevel( sal_uInt16 n ) { nCursorBidiLevel = n; }
353
354 Point GetDocPos( const Point& rWindowPos ) const;
355 Point GetWindowPos( const Point& rDocPos ) const;
356 tools::Rectangle GetWindowPos( const tools::Rectangle& rDocPos ) const;
357
358 void SetOutputArea( const tools::Rectangle& rRect );
359 void ResetOutputArea( const tools::Rectangle& rRect );
360 const tools::Rectangle& GetOutputArea() const { return aOutArea; }
361
362 bool IsVertical() const;
363 bool IsTopToBottom() const;
364
365 bool PostKeyEvent( const KeyEvent& rKeyEvent, vcl::Window const * pFrameWin );
366
367 bool MouseButtonUp( const MouseEvent& rMouseEvent );
368 bool MouseButtonDown( const MouseEvent& rMouseEvent );
369 void ReleaseMouse();
370 bool MouseMove( const MouseEvent& rMouseEvent );
371 void Command( const CommandEvent& rCEvt );
372
373 void CutCopy( css::uno::Reference< css::datatransfer::clipboard::XClipboard > const & rxClipboard, bool bCut );
374 void Paste( css::uno::Reference< css::datatransfer::clipboard::XClipboard > const & rxClipboard, bool bUseSpecial = false );
375
376 void SetVisDocStartPos( const Point& rPos ) { aVisDocStartPos = rPos; }
377
378 long GetVisDocLeft() const { return aVisDocStartPos.X(); }
379 long GetVisDocTop() const { return aVisDocStartPos.Y(); }
380 long GetVisDocRight() const { return aVisDocStartPos.X() + ( !IsVertical() ? aOutArea.GetWidth() : aOutArea.GetHeight() ); }
381 long GetVisDocBottom() const { return aVisDocStartPos.Y() + ( !IsVertical() ? aOutArea.GetHeight() : aOutArea.GetWidth() ); }
382 tools::Rectangle GetVisDocArea() const;
383
384 const EditSelection& GetEditSelection() const { return aEditSelection; }
385 void SetEditSelection( const EditSelection& rEditSelection );
386 bool HasSelection() const { return aEditSelection.HasRange(); }
387
388 void SelectionChanged();
389 void DrawSelectionXOR() { DrawSelectionXOR( aEditSelection ); }
390 void DrawSelectionXOR( EditSelection, vcl::Region* pRegion = nullptr, OutputDevice* pTargetDevice = nullptr );
391 void GetSelectionRectangles(EditSelection aTmpSel, std::vector<tools::Rectangle>& rLogicRects);
392
393 vcl::Window* GetWindow() const { return pOutWin; }
394
395 void SetSelectionMode( EESelectionMode eMode );
396
397 inline PointerStyle GetPointer();
398
399 inline vcl::Cursor* GetCursor();
400
401 void AddDragAndDropListeners();
402 void RemoveDragAndDropListeners();
403
404 bool IsBulletArea( const Point& rPos, sal_Int32* pPara );
405
406// For the Selection Engine...
407 void CreateAnchor();
408 void DeselectAll();
409 bool SetCursorAtPoint( const Point& rPointPixel );
410 bool IsSelectionAtPoint( const Point& rPosPixel );
411 bool IsInSelection( const EditPaM& rPaM );
412
413
414 void SetAnchorMode( EEAnchorMode eMode );
415 EEAnchorMode GetAnchorMode() const { return eAnchorMode; }
416 void CalcAnchorPoint();
417 void RecalcOutputArea();
418
419 tools::Rectangle GetEditCursor() const;
420
421 void ShowCursor( bool bGotoCursor, bool bForceVisCursor );
422 Pair Scroll( long ndX, long ndY, ScrollRangeCheck nRangeCheck = ScrollRangeCheck::NoNegative );
423
424 void SetInsertMode( bool bInsert );
425 bool IsInsertMode() const { return !( nControl & EVControlBits::OVERWRITE ); }
426
427 bool IsPasteEnabled() const { return bool( nControl & EVControlBits::ENABLEPASTE ); }
428
429 bool DoSingleLinePaste() const { return bool( nControl & EVControlBits::SINGLELINEPASTE ); }
430 bool DoAutoScroll() const { return bool( nControl & EVControlBits::AUTOSCROLL ); }
431 bool DoAutoSize() const { return bool( nControl & EVControlBits::AUTOSIZE ); }
432 bool DoAutoWidth() const { return bool( nControl & EVControlBits::AUTOSIZEX); }
433 bool DoAutoHeight() const { return bool( nControl & EVControlBits::AUTOSIZEY); }
434 bool DoInvalidateMore() const { return bool( nControl & EVControlBits::INVONEMORE ); }
435
436 void SetBackgroundColor( const Color& rColor );
437 const Color& GetBackgroundColor() const {
438 return ( pBackgroundColor ? *pBackgroundColor : pOutWin->GetBackground().GetColor() ); }
439
440 /// Informs this edit view about which view shell contains it.
441 void RegisterViewShell(OutlinerViewShell* pViewShell);
442 const OutlinerViewShell* GetViewShell() const;
443 /// Informs this edit view about which other shell listens to it.
444 void RegisterOtherShell(OutlinerViewShell* pViewShell);
445
446 bool IsWrongSpelledWord( const EditPaM& rPaM, bool bMarkIfWrong );
447 OUString SpellIgnoreWord();
448
449 const SvxFieldItem* GetField( const Point& rPos, sal_Int32* pPara, sal_Int32* pPos ) const;
450 void DeleteSelected();
451
452 // If possible invalidate more than OutputArea, for the DrawingEngine text frame
453 void SetInvalidateMore( sal_uInt16 nPixel ) { nInvMore = nPixel; }
454 sal_uInt16 GetInvalidateMore() const { return static_cast<sal_uInt16>(nInvMore); }
455
456 void InitLOKSpecialPositioning(MapUnit eUnit, const tools::Rectangle& rOutputArea,
457 const Point& rVisDocStartPos);
458 void SetLOKSpecialOutputArea(const tools::Rectangle& rOutputArea);
459 tools::Rectangle GetLOKSpecialOutputArea() const;
460 void SetLOKSpecialVisArea(const tools::Rectangle& rVisArea);
461 tools::Rectangle GetLOKSpecialVisArea() const;
462 bool HasLOKSpecialPositioning() const;
463
464 void SuppressLOKMessages(bool bSet) { mbSuppressLOKMessages = bSet; }
465 bool IsSuppressLOKMessages() const { return mbSuppressLOKMessages; }
466};
467
468
469// ImpEditEngine
470
471
472class ImpEditEngine : public SfxListener
473{
474 friend class EditEngine;
475
476 typedef EditEngine::ViewsType ViewsType;
477
478private:
479 std::shared_ptr<editeng::SharedVclResources> pSharedVCL;
480
481
482 // Data ...
483
484
485 // Document Specific data ...
486 ParaPortionList aParaPortionList; // Formatting
487 Size aPaperSize; // Layout
488 Size aMinAutoPaperSize; // Layout ?
489 Size aMaxAutoPaperSize; // Layout ?
490 EditDoc aEditDoc; // Document content
491
492 // Engine Specific data ...
493 EditEngine* pEditEngine;
494 ViewsType aEditViews;
495 EditView* pActiveView;
496 std::unique_ptr<TextRanger> pTextRanger;
497
498 SfxStyleSheetPool* pStylePool;
499 SfxItemPool* pTextObjectPool;
500
501 VclPtr< VirtualDevice> pVirtDev;
502 VclPtr< OutputDevice > pRefDev;
503 VclPtr<VirtualDevice> mpOwnDev;
504
505 svtools::ColorConfig maColorConfig;
506 mutable std::unique_ptr<SvtCTLOptions> pCTLOptions;
507
508 mutable std::unique_ptr<SfxItemSet> pEmptyItemSet;
509 EditUndoManager* pUndoManager;
510 std::unique_ptr<ESelection> pUndoMarkSelection;
511
512 std::unique_ptr<ImplIMEInfos> mpIMEInfos;
513
514 OUString aWordDelimiters;
515
516 EditSelFunctionSet aSelFuncSet;
517 EditSelectionEngine aSelEngine;
518
519 Color maBackgroundColor;
520
521 sal_uInt16 nStretchX;
522 sal_uInt16 nStretchY;
523
524 CharCompressType nAsianCompressionMode;
525
526 EEHorizontalTextDirection eDefaultHorizontalTextDirection;
527
528 sal_Int32 nBigTextObjectStart;
529 css::uno::Reference< css::linguistic2::XSpellChecker1 > xSpeller;
530 css::uno::Reference< css::linguistic2::XHyphenator > xHyphenator;
531 std::unique_ptr<SpellInfo> pSpellInfo;
532 mutable css::uno::Reference < css::i18n::XBreakIterator > xBI;
533 mutable css::uno::Reference < css::i18n::XExtendedInputSequenceChecker > xISC;
534
535 std::unique_ptr<ConvInfo> pConvInfo;
536
537 OUString aAutoCompleteText;
538
539 InternalEditStatus aStatus;
540
541 LanguageType eDefLanguage;
542
543 OnDemandLocaleDataWrapper xLocaleDataWrapper;
544 OnDemandTransliterationWrapper xTransliterationWrapper;
545
546 // For Formatting / Update...
547 std::vector<std::unique_ptr<DeletedNodeInfo> > aDeletedNodes;
548 tools::Rectangle aInvalidRect;
549 sal_uInt32 nCurTextHeight;
550 sal_uInt32 nCurTextHeightNTP; // without trailing empty paragraphs
551 sal_uInt16 nOnePixelInRef;
552
553 IdleFormattter aIdleFormatter;
554
555 Timer aOnlineSpellTimer;
556
557 // For Chaining
558 sal_Int32 mnOverflowingPara = -1;
559 sal_Int32 mnOverflowingLine = -1;
560 bool mbNeedsChainingHandling = false;
561
562 // If it is detected at one point that the StatusHdl has to be called, but
563 // this should not happen immediately (critical section):
564 Timer aStatusTimer;
565 Size aLOKSpecialPaperSize;
566
567 Link<EditStatus&,void> aStatusHdlLink;
568 Link<EENotify&,void> aNotifyHdl;
569 Link<HtmlImportInfo&,void> aHtmlImportHdl;
570 Link<RtfImportInfo&,void> aRtfImportHdl;
571 Link<MoveParagraphsInfo&,void> aBeginMovingParagraphsHdl;
572 Link<MoveParagraphsInfo&,void> aEndMovingParagraphsHdl;
573 Link<PasteOrDropInfos&,void> aBeginPasteOrDropHdl;
574 Link<PasteOrDropInfos&,void> aEndPasteOrDropHdl;
575 Link<LinkParamNone*,void> aModifyHdl;
576 Link<EditView*,void> maBeginDropHdl;
577 Link<EditView*,void> maEndDropHdl;
578
579 bool bKernAsianPunctuation:1;
580 bool bAddExtLeading:1;
581 bool bIsFormatting:1;
582 bool bFormatted:1;
583 bool bInSelection:1;
584 bool bIsInUndo:1;
585 bool bUpdate:1;
586 bool bUndoEnabled:1;
587 bool bDowning:1;
588 bool bUseAutoColor:1;
589 bool bForceAutoColor:1;
590 bool bCallParaInsertedOrDeleted:1;
591 bool bFirstWordCapitalization:1; // specifies if auto-correction should capitalize the first word or not
592 bool mbLastTryMerge:1;
593 bool mbReplaceLeadingSingleQuotationMark:1;
594
595 bool mbNbspRunNext; // can't be a bitfield as it is passed as bool&
596
597
598 // Methods...
599
600
601 void CursorMoved( const ContentNode* pPrevNode );
602 void ParaAttribsChanged( ContentNode const * pNode, bool bIgnoreUndoCheck = false );
603 void TextModified();
604 void CalcHeight( ParaPortion* pPortion );
605
606 void InsertUndo( std::unique_ptr<EditUndo> pUndo, bool bTryMerge = false );
607 void ResetUndoManager();
608 bool HasUndoManager() const { return pUndoManager != nullptr; }
609
610 std::unique_ptr<EditUndoSetAttribs> CreateAttribUndo( EditSelection aSel, const SfxItemSet& rSet );
611
612 std::unique_ptr<EditTextObject> GetEmptyTextObject();
613
614 EditPaM GetPaM( Point aDocPos, bool bSmart = true );
615 EditPaM GetPaM( ParaPortion* pPortion, Point aPos, bool bSmart );
616 long GetXPos(const ParaPortion* pParaPortion, const EditLine* pLine, sal_Int32 nIndex, bool bPreferPortionStart = false) const;
617 long GetPortionXOffset(const ParaPortion* pParaPortion, const EditLine* pLine, sal_Int32 nTextPortion) const;
618 sal_Int32 GetChar(const ParaPortion* pParaPortion, const EditLine* pLine, long nX, bool bSmart = true);
619 Range GetInvalidYOffsets( ParaPortion* pPortion );
620 Range GetLineXPosStartEnd( const ParaPortion* pParaPortion, const EditLine* pLine ) const;
621
622 void ParaAttribsToCharAttribs( ContentNode* pNode );
623 void GetCharAttribs( sal_Int32 nPara, std::vector<EECharAttrib>& rLst ) const;
624
625 std::unique_ptr<EditTextObject>
626 CreateTextObject(EditSelection aSelection, SfxItemPool*, bool bAllowBigObjects = false, sal_Int32 nBigObjStart = 0);
627 EditSelection InsertTextObject( const EditTextObject&, EditPaM aPaM );
628 EditSelection PasteText( css::uno::Reference< css::datatransfer::XTransferable > const & rxDataObj, const OUString& rBaseURL, const EditPaM& rPaM, bool bUseSpecial );
629
630 void CheckPageOverflow();
631
632 void Clear();
633 EditPaM RemoveText();
634 bool CreateLines( sal_Int32 nPara, sal_uInt32 nStartPosY );
635 void CreateAndInsertEmptyLine( ParaPortion* pParaPortion );
636 bool FinishCreateLines( ParaPortion* pParaPortion );
637 void CreateTextPortions( ParaPortion* pParaPortion, sal_Int32& rStartPos /*, sal_Bool bCreateBlockPortions */ );
638 void RecalcTextPortion( ParaPortion* pParaPortion, sal_Int32 nStartPos, sal_Int32 nNewChars );
639 sal_Int32 SplitTextPortion( ParaPortion* pParaPortion, sal_Int32 nPos, EditLine* pCurLine = nullptr );
640 void SeekCursor( ContentNode* pNode, sal_Int32 nPos, SvxFont& rFont, OutputDevice* pOut = nullptr );
641 void RecalcFormatterFontMetrics( FormatterFontMetric& rCurMetrics, SvxFont& rFont );
642 void CheckAutoPageSize();
643
644 void ImpBreakLine( ParaPortion* pParaPortion, EditLine* pLine, TextPortion const * pPortion, sal_Int32 nPortionStart, long nRemainingWidth, bool bCanHyphenate );
645 void ImpAdjustBlocks( ParaPortion* pParaPortion, EditLine* pLine, long nRemainingSpace );
646 EditPaM ImpConnectParagraphs( ContentNode* pLeft, ContentNode* pRight, bool bBackward = false );
647 EditPaM ImpDeleteSelection(const EditSelection& rCurSel);
648 EditPaM ImpInsertParaBreak( EditPaM& rPaM, bool bKeepEndingAttribs = true );
649 EditPaM ImpInsertParaBreak( const EditSelection& rEditSelection );
650 EditPaM ImpInsertText(const EditSelection& aCurEditSelection, const OUString& rStr);
651 EditPaM ImpInsertFeature(const EditSelection& rCurSel, const SfxPoolItem& rItem);
652 void ImpRemoveChars( const EditPaM& rPaM, sal_Int32 nChars );
653 void ImpRemoveParagraph( sal_Int32 nPara );
654 EditSelection ImpMoveParagraphs( Range aParagraphs, sal_Int32 nNewPos );
655
656 EditPaM ImpFastInsertText( EditPaM aPaM, const OUString& rStr );
657 EditPaM ImpFastInsertParagraph( sal_Int32 nPara );
658
659 bool ImpCheckRefMapMode();
660
661 bool ImplHasText() const;
662
663 void ImpFindKashidas( ContentNode* pNode, sal_Int32 nStart, sal_Int32 nEnd, std::vector<sal_Int32>& rArray );
664
665 void InsertContent( ContentNode* pNode, sal_Int32 nPos );
666 EditPaM SplitContent( sal_Int32 nNode, sal_Int32 nSepPos );
667 EditPaM ConnectContents( sal_Int32 nLeftNode, bool bBackward );
668
669 void ShowParagraph( sal_Int32 nParagraph, bool bShow );
670
671 EditPaM PageUp( const EditPaM& rPaM, EditView const * pView);
672 EditPaM PageDown( const EditPaM& rPaM, EditView const * pView);
673 EditPaM CursorUp( const EditPaM& rPaM, EditView const * pEditView );
674 EditPaM CursorDown( const EditPaM& rPaM, EditView const * pEditView );
675 EditPaM CursorLeft( const EditPaM& rPaM, sal_uInt16 nCharacterIteratorMode = css::i18n::CharacterIteratorMode::SKIPCELL );
676 EditPaM CursorRight( const EditPaM& rPaM, sal_uInt16 nCharacterIteratorMode = css::i18n::CharacterIteratorMode::SKIPCELL );
677 EditPaM CursorStartOfLine( const EditPaM& rPaM );
678 EditPaM CursorEndOfLine( const EditPaM& rPaM );
679 static EditPaM CursorStartOfParagraph( const EditPaM& rPaM );
680 static EditPaM CursorEndOfParagraph( const EditPaM& rPaM );
681 EditPaM CursorStartOfDoc();
682 EditPaM CursorEndOfDoc();
683 EditPaM WordLeft( const EditPaM& rPaM );
684 EditPaM WordRight( const EditPaM& rPaM, sal_Int16 nWordType = css::i18n::WordType::ANYWORD_IGNOREWHITESPACES );
685 EditPaM StartOfWord( const EditPaM& rPaM );
686 EditPaM EndOfWord( const EditPaM& rPaM );
687 EditSelection SelectWord( const EditSelection& rCurSelection, sal_Int16 nWordType = css::i18n::WordType::ANYWORD_IGNOREWHITESPACES, bool bAcceptStartOfWord = true );
688 EditSelection SelectSentence( const EditSelection& rCurSel ) const;
689 EditPaM CursorVisualLeftRight( EditView const * pEditView, const EditPaM& rPaM, sal_uInt16 nCharacterIteratorMode, bool bToLeft );
690 EditPaM CursorVisualStartEnd( EditView const * pEditView, const EditPaM& rPaM, bool bStart );
691
692
693 void InitScriptTypes( sal_Int32 nPara );
694 sal_uInt16 GetI18NScriptType( const EditPaM& rPaM, sal_Int32* pEndPos = nullptr ) const;
695 SvtScriptType GetItemScriptType( const EditSelection& rSel ) const;
696 bool IsScriptChange( const EditPaM& rPaM ) const;
697 bool HasScriptType( sal_Int32 nPara, sal_uInt16 nType ) const;
698
699 bool ImplCalcAsianCompression( ContentNode* pNode, TextPortion* pTextPortion, sal_Int32 nStartPos,
700 long* pDXArray, sal_uInt16 n100thPercentFromMax, bool bManipulateDXArray );
701 void ImplExpandCompressedPortions( EditLine* pLine, ParaPortion* pParaPortion, long nRemainingWidth );
702
703 void ImplInitLayoutMode( OutputDevice* pOutDev, sal_Int32 nPara, sal_Int32 nIndex );
704 LanguageType ImplCalcDigitLang(LanguageType eCurLang) const;
705 void ImplInitDigitMode(OutputDevice* pOutDev, LanguageType eLang);
706 static OUString convertDigits(const OUString &rString, sal_Int32 nStt, sal_Int32 nLen, LanguageType eDigitLang);
707
708 EditPaM ReadText( SvStream& rInput, EditSelection aSel );
709 EditPaM ReadRTF( SvStream& rInput, EditSelection aSel );
710 EditPaM ReadXML( SvStream& rInput, EditSelection aSel );
711 EditPaM ReadHTML( SvStream& rInput, const OUString& rBaseURL, EditSelection aSel, SvKeyValueIterator* pHTTPHeaderAttrs );
712 ErrCode WriteText( SvStream& rOutput, EditSelection aSel );
713 ErrCode WriteRTF( SvStream& rOutput, EditSelection aSel );
714 void WriteXML(SvStream& rOutput, const EditSelection& rSel);
715
716 void WriteItemAsRTF( const SfxPoolItem& rItem, SvStream& rOutput, sal_Int32 nPara, sal_Int32 nPos,
717 std::vector<std::unique_ptr<SvxFontItem>>& rFontTable, SvxColorList& rColorList );
718 bool WriteItemListAsRTF( ItemList& rLst, SvStream& rOutput, sal_Int32 nPara, sal_Int32 nPos,
719 std::vector<std::unique_ptr<SvxFontItem>>& rFontTable, SvxColorList& rColorList );
720 sal_Int32 LogicToTwips( sal_Int32 n );
721
722 inline short GetXValue( short nXValue ) const;
723 inline long GetXValue( long nXValue ) const;
724
725 inline short GetYValue( short nYValue ) const;
726 inline sal_uInt16 GetYValue( sal_uInt16 nYValue ) const;
727
728 ContentNode* GetPrevVisNode( ContentNode const * pCurNode );
729 ContentNode* GetNextVisNode( ContentNode const * pCurNode );
730
731 const ParaPortion* GetPrevVisPortion( const ParaPortion* pCurPortion ) const;
732 const ParaPortion* GetNextVisPortion( const ParaPortion* pCurPortion ) const;
733
734 void SetBackgroundColor( const Color& rColor ) { maBackgroundColor = rColor; }
735 const Color& GetBackgroundColor() const { return maBackgroundColor; }
736
737 long CalcVertLineSpacing(Point& rStartPos) const;
738
739 Color GetAutoColor() const;
740 void EnableAutoColor( bool b ) { bUseAutoColor = b; }
741 bool IsAutoColorEnabled() const { return bUseAutoColor; }
742 void ForceAutoColor( bool b ) { bForceAutoColor = b; }
743 bool IsForceAutoColor() const { return bForceAutoColor; }
744
745 inline VirtualDevice* GetVirtualDevice( const MapMode& rMapMode, DrawModeFlags nDrawMode );
746 void EraseVirtualDevice() { pVirtDev.disposeAndClear(); }
747
748 DECL_LINK( StatusTimerHdl, Timer *, void)static void LinkStubStatusTimerHdl(void *, Timer *); void StatusTimerHdl
(Timer *)
;
749 DECL_LINK( IdleFormatHdl, Timer *, void)static void LinkStubIdleFormatHdl(void *, Timer *); void IdleFormatHdl
(Timer *)
;
750 DECL_LINK( OnlineSpellHdl, Timer *, void)static void LinkStubOnlineSpellHdl(void *, Timer *); void OnlineSpellHdl
(Timer *)
;
751 DECL_LINK( DocModified, LinkParamNone*, void )static void LinkStubDocModified(void *, LinkParamNone*); void
DocModified(LinkParamNone*)
;
752
753 void CheckIdleFormatter();
754
755 inline const ParaPortion* FindParaPortion( const ContentNode* pNode ) const;
756 inline ParaPortion* FindParaPortion( ContentNode const * pNode );
757
758 css::uno::Reference< css::datatransfer::XTransferable > CreateTransferable( const EditSelection& rSelection );
759
760 void SetValidPaperSize( const Size& rSz );
761
762 css::uno::Reference < css::i18n::XBreakIterator > const & ImplGetBreakIterator() const;
763 css::uno::Reference < css::i18n::XExtendedInputSequenceChecker > const & ImplGetInputSequenceChecker() const;
764
765 void ImplUpdateOverflowingParaNum( sal_uInt32 );
766 void ImplUpdateOverflowingLineNum( sal_uInt32, sal_uInt32, sal_uInt32 );
767
768 void CreateSpellInfo( bool bMultipleDocs );
769 /// Obtains a view shell ID from the active EditView.
770 ViewShellId CreateViewShellId();
771
772 ImpEditEngine(EditEngine* pEditEngine, SfxItemPool* pPool);
773 void InitDoc(bool bKeepParaAttribs);
774 EditDoc& GetEditDoc() { return aEditDoc; }
775 const EditDoc& GetEditDoc() const { return aEditDoc; }
776
777 const ParaPortionList& GetParaPortions() const { return aParaPortionList; }
778 ParaPortionList& GetParaPortions() { return aParaPortionList; }
779
780protected:
781 virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override;
782
783public:
784 virtual ~ImpEditEngine() override;
785 ImpEditEngine(const ImpEditEngine&) = delete;
786 ImpEditEngine& operator=(const ImpEditEngine&) = delete;
787
788 inline EditUndoManager& GetUndoManager();
789 inline SfxUndoManager* SetUndoManager(SfxUndoManager* pNew);
790
791 void SetUpdateMode( bool bUp, EditView* pCurView = nullptr, bool bForceUpdate = false );
792 bool GetUpdateMode() const { return bUpdate; }
793
794 ViewsType& GetEditViews() { return aEditViews; }
795 const ViewsType& GetEditViews() const { return aEditViews; }
796
797 const Size& GetPaperSize() const { return aPaperSize; }
798 void SetPaperSize( const Size& rSz ) { aPaperSize = rSz; }
799
800 void SetVertical( bool bVertical);
801 bool IsVertical() const { return GetEditDoc().IsVertical(); }
802 bool IsTopToBottom() const { return GetEditDoc().IsTopToBottom(); }
803 bool GetDirectVertical() const { return GetEditDoc().GetDirectVertical(); }
804 void SetRotation( TextRotation nRotation);
805 TextRotation GetRotation() const { return GetEditDoc().GetRotation(); }
806
807 bool IsPageOverflow( ) const;
808
809 void SetFixedCellHeight( bool bUseFixedCellHeight );
810 bool IsFixedCellHeight() const { return GetEditDoc().IsFixedCellHeight(); }
811
812 void SetDefaultHorizontalTextDirection( EEHorizontalTextDirection eHTextDir ) { eDefaultHorizontalTextDirection = eHTextDir; }
813 EEHorizontalTextDirection GetDefaultHorizontalTextDirection() const { return eDefaultHorizontalTextDirection; }
814
815
816 void InitWritingDirections( sal_Int32 nPara );
817 bool IsRightToLeft( sal_Int32 nPara ) const;
818 sal_uInt8 GetRightToLeft( sal_Int32 nPara, sal_Int32 nChar, sal_Int32* pStart = nullptr, sal_Int32* pEnd = nullptr );
819 bool HasDifferentRTLLevels( const ContentNode* pNode );
820
821 void SetTextRanger( std::unique_ptr<TextRanger> pRanger );
822 TextRanger* GetTextRanger() const { return pTextRanger.get(); }
823
824 const Size& GetMinAutoPaperSize() const { return aMinAutoPaperSize; }
825 void SetMinAutoPaperSize( const Size& rSz ) { aMinAutoPaperSize = rSz; }
826
827 const Size& GetMaxAutoPaperSize() const { return aMaxAutoPaperSize; }
828 void SetMaxAutoPaperSize( const Size& rSz ) { aMaxAutoPaperSize = rSz; }
829
830 void FormatDoc();
831 void FormatFullDoc();
832 void UpdateViews( EditView* pCurView = nullptr );
833 void Paint( ImpEditView* pView, const tools::Rectangle& rRect, OutputDevice* pTargetDevice );
834 void Paint( OutputDevice* pOutDev, tools::Rectangle aClipRect, Point aStartPos, bool bStripOnly = false, short nOrientation = 0 );
835
836 bool MouseButtonUp( const MouseEvent& rMouseEvent, EditView* pView );
837 bool MouseButtonDown( const MouseEvent& rMouseEvent, EditView* pView );
838 void ReleaseMouse();
839 bool MouseMove( const MouseEvent& rMouseEvent, EditView* pView );
840 void Command( const CommandEvent& rCEvt, EditView* pView );
841
842 EditSelectionEngine& GetSelEngine() { return aSelEngine; }
843 OUString GetSelected( const EditSelection& rSel ) const;
844
845 const SfxItemSet& GetEmptyItemSet() const;
846
847 void UpdateSelections();
848
849 void EnableUndo( bool bEnable );
850 bool IsUndoEnabled() const { return bUndoEnabled; }
851 void SetUndoMode( bool b ) { bIsInUndo = b; }
852 bool IsInUndo() const { return bIsInUndo; }
853
854 void SetCallParaInsertedOrDeleted( bool b ) { bCallParaInsertedOrDeleted = b; }
855 bool IsCallParaInsertedOrDeleted() const { return bCallParaInsertedOrDeleted; }
856
857 bool IsFormatted() const { return bFormatted; }
858 bool IsFormatting() const { return bIsFormatting; }
859
860 void SetText(const OUString& rText);
861 EditPaM DeleteSelected(const EditSelection& rEditSelection);
862 EditPaM InsertTextUserInput( const EditSelection& rCurEditSelection, sal_Unicode c, bool bOverwrite );
863 EditPaM InsertText(const EditSelection& aCurEditSelection, const OUString& rStr);
864 EditPaM AutoCorrect( const EditSelection& rCurEditSelection, sal_Unicode c, bool bOverwrite, vcl::Window const * pFrameWin = nullptr );
865 EditPaM DeleteLeftOrRight( const EditSelection& rEditSelection, sal_uInt8 nMode, DeleteMode nDelMode );
866 EditPaM InsertParaBreak(const EditSelection& rEditSelection);
867 EditPaM InsertLineBreak(const EditSelection& aEditSelection);
868 EditPaM InsertTab(const EditSelection& rEditSelection);
869 EditPaM InsertField(const EditSelection& rCurSel, const SvxFieldItem& rFld);
870 bool UpdateFields();
871
872 EditPaM Read(SvStream& rInput, const OUString& rBaseURL, EETextFormat eFormat, const EditSelection& rSel, SvKeyValueIterator* pHTTPHeaderAttrs = nullptr);
873 void Write(SvStream& rOutput, EETextFormat eFormat, const EditSelection& rSel);
874
875 std::unique_ptr<EditTextObject> CreateTextObject();
876 std::unique_ptr<EditTextObject> CreateTextObject(const EditSelection& rSel);
877 void SetText( const EditTextObject& rTextObject );
878 EditSelection InsertText( const EditTextObject& rTextObject, EditSelection aSel );
879
880 EditSelection const & MoveCursor( const KeyEvent& rKeyEvent, EditView* pEditView );
881
882 EditSelection MoveParagraphs( Range aParagraphs, sal_Int32 nNewPos, EditView* pCurView );
883
884 sal_uInt32 CalcTextHeight( sal_uInt32* pHeightNTP );
885 sal_uInt32 GetTextHeight() const;
886 sal_uInt32 GetTextHeightNTP() const;
887 sal_uInt32 CalcTextWidth( bool bIgnoreExtraSpace);
888 sal_uInt32 CalcParaWidth( sal_Int32 nParagraph, bool bIgnoreExtraSpace );
889 sal_uInt32 CalcLineWidth( ParaPortion* pPortion, EditLine* pLine, bool bIgnoreExtraSpace);
890 sal_Int32 GetLineCount( sal_Int32 nParagraph ) const;
891 sal_Int32 GetLineLen( sal_Int32 nParagraph, sal_Int32 nLine ) const;
892 void GetLineBoundaries( /*out*/sal_Int32& rStart, /*out*/sal_Int32& rEnd, sal_Int32 nParagraph, sal_Int32 nLine ) const;
893 sal_Int32 GetLineNumberAtIndex( sal_Int32 nPara, sal_Int32 nIndex ) const;
894 sal_uInt16 GetLineHeight( sal_Int32 nParagraph, sal_Int32 nLine );
895 sal_uInt32 GetParaHeight( sal_Int32 nParagraph );
896
897 SfxItemSet GetAttribs( sal_Int32 nPara, sal_Int32 nStart, sal_Int32 nEnd, GetAttribsFlags nFlags = GetAttribsFlags::ALL ) const;
898 SfxItemSet GetAttribs( EditSelection aSel, EditEngineAttribs nOnlyHardAttrib = EditEngineAttribs::All );
899 void SetAttribs( EditSelection aSel, const SfxItemSet& rSet, SetAttribsMode nSpecial = SetAttribsMode::NONE );
900 void RemoveCharAttribs( EditSelection aSel, bool bRemoveParaAttribs, sal_uInt16 nWhich );
901 void RemoveCharAttribs( sal_Int32 nPara, sal_uInt16 nWhich = 0, bool bRemoveFeatures = false );
902 void SetFlatMode( bool bFlat );
903
904 void SetParaAttribs( sal_Int32 nPara, const SfxItemSet& rSet );
905 const SfxItemSet& GetParaAttribs( sal_Int32 nPara ) const;
906
907 bool HasParaAttrib( sal_Int32 nPara, sal_uInt16 nWhich ) const;
908 const SfxPoolItem& GetParaAttrib( sal_Int32 nPara, sal_uInt16 nWhich ) const;
909 template<class T>
910 const T& GetParaAttrib( sal_Int32 nPara, TypedWhichId<T> nWhich ) const
911 {
912 return static_cast<const T&>(GetParaAttrib(nPara, sal_uInt16(nWhich)));
913 }
914
915 tools::Rectangle PaMtoEditCursor( EditPaM aPaM, GetCursorFlags nFlags = GetCursorFlags::NONE );
916 tools::Rectangle GetEditCursor( ParaPortion* pPortion, sal_Int32 nIndex, GetCursorFlags nFlags = GetCursorFlags::NONE );
917
918 bool IsModified() const { return aEditDoc.IsModified(); }
919 void SetModifyFlag( bool b ) { aEditDoc.SetModified( b ); }
920 void SetModifyHdl( const Link<LinkParamNone*,void>& rLink ) { aModifyHdl = rLink; }
921 const Link<LinkParamNone*,void>& GetModifyHdl() const { return aModifyHdl; }
922
923 bool IsInSelectionMode() const { return bInSelection; }
924
925// For Undo/Redo
926 void Undo( EditView* pView );
927 void Redo( EditView* pView );
928
929// OV-Special
930 void InvalidateFromParagraph( sal_Int32 nFirstInvPara );
931 EditPaM InsertParagraph( sal_Int32 nPara );
932 std::unique_ptr<EditSelection> SelectParagraph( sal_Int32 nPara );
933
934 void SetStatusEventHdl( const Link<EditStatus&, void>& rLink ) { aStatusHdlLink = rLink; }
935 const Link<EditStatus&,void>& GetStatusEventHdl() const { return aStatusHdlLink; }
936
937 void SetNotifyHdl( const Link<EENotify&,void>& rLink ) { aNotifyHdl = rLink; }
938 const Link<EENotify&,void>& GetNotifyHdl() const { return aNotifyHdl; }
939
940 void FormatAndUpdate( EditView* pCurView = nullptr, bool bCalledFromUndo = false );
941 inline void IdleFormatAndUpdate( EditView* pCurView );
942
943 const svtools::ColorConfig& GetColorConfig() const { return maColorConfig; }
944 bool IsVisualCursorTravelingEnabled();
945 bool DoVisualCursorTraveling();
946
947 EditSelection ConvertSelection( sal_Int32 nStartPara, sal_Int32 nStartPos, sal_Int32 nEndPara, sal_Int32 nEndPos );
948 inline EPaM CreateEPaM( const EditPaM& rPaM );
949 inline EditPaM CreateEditPaM( const EPaM& rEPaM );
950 inline ESelection CreateESel( const EditSelection& rSel );
951 inline EditSelection CreateSel( const ESelection& rSel );
952
953 void SetStyleSheetPool( SfxStyleSheetPool* pSPool );
954 SfxStyleSheetPool* GetStyleSheetPool() const { return pStylePool; }
955
956 void SetStyleSheet( EditSelection aSel, SfxStyleSheet* pStyle );
957 void SetStyleSheet( sal_Int32 nPara, SfxStyleSheet* pStyle );
958 const SfxStyleSheet* GetStyleSheet( sal_Int32 nPara ) const;
959 SfxStyleSheet* GetStyleSheet( sal_Int32 nPara );
960
961 void UpdateParagraphsWithStyleSheet( SfxStyleSheet* pStyle );
962 void RemoveStyleFromParagraphs( SfxStyleSheet const * pStyle );
963
964 OutputDevice* GetRefDevice() const { return pRefDev.get(); }
965 void SetRefDevice( OutputDevice* pRefDef );
966
967 const MapMode& GetRefMapMode() const { return pRefDev->GetMapMode(); }
968 void SetRefMapMode( const MapMode& rMapMode );
969
970 InternalEditStatus& GetStatus() { return aStatus; }
971 void CallStatusHdl();
972 void DelayedCallStatusHdl() { aStatusTimer.Start(); }
973
974 void UndoActionStart( sal_uInt16 nId );
975 void UndoActionStart( sal_uInt16 nId, const ESelection& rSel );
976 void UndoActionEnd();
977
978 EditView* GetActiveView() const { return pActiveView; }
979 void SetActiveView( EditView* pView );
980
981 css::uno::Reference< css::linguistic2::XSpellChecker1 > const &
982 GetSpeller();
983 void SetSpeller( css::uno::Reference< css::linguistic2::XSpellChecker1 > const &xSpl )
984 { xSpeller = xSpl; }
985 const css::uno::Reference< css::linguistic2::XHyphenator >&
986 GetHyphenator() const { return xHyphenator; }
987 void SetHyphenator( css::uno::Reference< css::linguistic2::XHyphenator > const &xHyph )
988 { xHyphenator = xHyph; }
989
990 void GetAllMisspellRanges( std::vector<editeng::MisspellRanges>& rRanges ) const;
991 void SetAllMisspellRanges( const std::vector<editeng::MisspellRanges>& rRanges );
992
993 SpellInfo* GetSpellInfo() const { return pSpellInfo.get(); }
994
995 void SetDefaultLanguage( LanguageType eLang ) { eDefLanguage = eLang; }
996 LanguageType GetDefaultLanguage() const { return eDefLanguage; }
997
998 LanguageType GetLanguage( const EditPaM& rPaM, sal_Int32* pEndPos = nullptr ) const;
999 css::lang::Locale GetLocale( const EditPaM& rPaM ) const;
1000
1001 void DoOnlineSpelling( ContentNode* pThisNodeOnly = nullptr, bool bSpellAtCursorPos = false, bool bInterruptible = true );
1002 EESpellState Spell( EditView* pEditView, bool bMultipleDoc );
1003 EESpellState HasSpellErrors();
1004 void ClearSpellErrors();
1005 EESpellState StartThesaurus( EditView* pEditView );
1006 css::uno::Reference< css::linguistic2::XSpellAlternatives >
1007 ImpSpell( EditView* pEditView );
1008
1009 // text conversion functions
1010 void Convert( EditView* pEditView, LanguageType nSrcLang, LanguageType nDestLang, const vcl::Font *pDestFont, sal_Int32 nOptions, bool bIsInteractive, bool bMultipleDoc );
1011 void ImpConvert( OUString &rConvTxt, LanguageType &rConvTxtLang, EditView* pEditView, LanguageType nSrcLang, const ESelection &rConvRange,
1012 bool bAllowImplicitChangesForNotConvertibleText, LanguageType nTargetLang, const vcl::Font *pTargetFont );
1013 ConvInfo * GetConvInfo() const { return pConvInfo.get(); }
1014 bool HasConvertibleTextPortion( LanguageType nLang );
1015 void SetLanguageAndFont( const ESelection &rESel,
1016 LanguageType nLang, sal_uInt16 nLangWhichId,
1017 const vcl::Font *pFont, sal_uInt16 nFontWhichId );
1018
1019 // returns true if input sequence checking should be applied
1020 bool IsInputSequenceCheckingRequired( sal_Unicode nChar, const EditSelection& rCurSel ) const;
1021
1022 //find the next error within the given selection - forward only!
1023 css::uno::Reference< css::linguistic2::XSpellAlternatives >
1024 ImpFindNextError(EditSelection& rSelection);
1025 //spell and return a sentence
1026 bool SpellSentence(EditView const & rView, svx::SpellPortions& rToFill );
1027 //put spelling back to start of current sentence - needed after switch of grammar support
1028 void PutSpellingToSentenceStart( EditView const & rEditView );
1029 //applies a changed sentence
1030 void ApplyChangedSentence(EditView const & rEditView, const svx::SpellPortions& rNewPortions, bool bRecheck );
1031 //adds one or more portions of text to the SpellPortions depending on language changes
1032 void AddPortionIterated(
1033 EditView const & rEditView,
1034 const EditSelection &rSel,
1035 const css::uno::Reference< css::linguistic2::XSpellAlternatives >& xAlt,
1036 svx::SpellPortions& rToFill);
1037 //adds one portion to the SpellPortions
1038 void AddPortion(
1039 const EditSelection &rSel,
1040 const css::uno::Reference< css::linguistic2::XSpellAlternatives >& xAlt,
1041 svx::SpellPortions& rToFill,
1042 bool bIsField );
1043
1044 bool Search( const SvxSearchItem& rSearchItem, EditView* pView );
1045 bool ImpSearch( const SvxSearchItem& rSearchItem, const EditSelection& rSearchSelection, const EditPaM& rStartPos, EditSelection& rFoundSel );
1046 sal_Int32 StartSearchAndReplace( EditView* pEditView, const SvxSearchItem& rSearchItem );
1047 bool HasText( const SvxSearchItem& rSearchItem );
1048
1049 void SetEditTextObjectPool( SfxItemPool* pP ) { pTextObjectPool = pP; }
1050 SfxItemPool* GetEditTextObjectPool() const { return pTextObjectPool; }
1051
1052 const SvxNumberFormat * GetNumberFormat( const ContentNode* pNode ) const;
1053 sal_Int32 GetSpaceBeforeAndMinLabelWidth( const ContentNode *pNode, sal_Int32 *pnSpaceBefore = nullptr, sal_Int32 *pnMinLabelWidth = nullptr ) const;
1054
1055 const SvxLRSpaceItem& GetLRSpaceItem( ContentNode* pNode );
1056 SvxAdjust GetJustification( sal_Int32 nPara ) const;
1057 SvxCellJustifyMethod GetJustifyMethod( sal_Int32 nPara ) const;
1058 SvxCellVerJustify GetVerJustification( sal_Int32 nPara ) const;
1059
1060 void SetCharStretching( sal_uInt16 nX, sal_uInt16 nY );
1061 inline void GetCharStretching( sal_uInt16& rX, sal_uInt16& rY ) const;
1062
1063 sal_Int32 GetBigTextObjectStart() const { return nBigTextObjectStart; }
1064
1065 EditEngine* GetEditEnginePtr() const { return pEditEngine; }
1066
1067 void StartOnlineSpellTimer() { aOnlineSpellTimer.Start(); }
1068 void StopOnlineSpellTimer() { aOnlineSpellTimer.Stop(); }
1069
1070 const OUString& GetAutoCompleteText() const { return aAutoCompleteText; }
1071 void SetAutoCompleteText(const OUString& rStr, bool bUpdateTipWindow);
1072
1073 EditSelection TransliterateText( const EditSelection& rSelection, TransliterationFlags nTransliterationMode );
1074 short ReplaceTextOnly( ContentNode* pNode, sal_Int32 nCurrentStart, const OUString& rText, const css::uno::Sequence< sal_Int32 >& rOffsets );
1075
1076 void SetAsianCompressionMode( CharCompressType n );
1077 CharCompressType GetAsianCompressionMode() const { return nAsianCompressionMode; }
1078
1079 void SetKernAsianPunctuation( bool b );
1080 bool IsKernAsianPunctuation() const { return bKernAsianPunctuation; }
1081
1082 sal_Int32 GetOverflowingParaNum() const { return mnOverflowingPara; }
1083 sal_Int32 GetOverflowingLineNum() const { return mnOverflowingLine; }
1084 void ClearOverflowingParaNum() { mnOverflowingPara = -1; }
1085
1086
1087 void SetAddExtLeading( bool b );
1088 bool IsAddExtLeading() const { return bAddExtLeading; }
1089
1090 static std::shared_ptr<SvxForbiddenCharactersTable> const & GetForbiddenCharsTable();
1091 static void SetForbiddenCharsTable( const std::shared_ptr<SvxForbiddenCharactersTable>& xForbiddenChars );
1092
1093 /** sets a link that is called at the beginning of a drag operation at an edit view */
1094 void SetBeginDropHdl( const Link<EditView*,void>& rLink ) { maBeginDropHdl = rLink; }
1095 const Link<EditView*,void>& GetBeginDropHdl() const { return maBeginDropHdl; }
1096
1097 /** sets a link that is called at the end of a drag operation at an edit view */
1098 void SetEndDropHdl( const Link<EditView*,void>& rLink ) { maEndDropHdl = rLink; }
1099 const Link<EditView*,void>& GetEndDropHdl() const { return maEndDropHdl; }
1100
1101 /// specifies if auto-correction should capitalize the first word or not (default is on)
1102 void SetFirstWordCapitalization( bool bCapitalize ) { bFirstWordCapitalization = bCapitalize; }
1103 bool IsFirstWordCapitalization() const { return bFirstWordCapitalization; }
1104
1105 /** specifies if auto-correction should replace a leading single quotation
1106 mark (apostrophe) or not (default is on) */
1107 void SetReplaceLeadingSingleQuotationMark( bool bReplace ) { mbReplaceLeadingSingleQuotationMark = bReplace; }
1108 bool IsReplaceLeadingSingleQuotationMark() const { return mbReplaceLeadingSingleQuotationMark; }
1109
1110 /** Whether last AutoCorrect inserted a NO-BREAK SPACE that may need to be removed again. */
1111 bool IsNbspRunNext() const { return mbNbspRunNext; }
1112
1113 void Dispose();
1114 void SetLOKSpecialPaperSize(const Size& rSize) { aLOKSpecialPaperSize = rSize; }
1115 const Size& GetLOKSpecialPaperSize() const { return aLOKSpecialPaperSize; }
1116};
1117
1118inline EPaM ImpEditEngine::CreateEPaM( const EditPaM& rPaM )
1119{
1120 const ContentNode* pNode = rPaM.GetNode();
1121 return EPaM( aEditDoc.GetPos( pNode ), rPaM.GetIndex() );
1122}
1123
1124inline EditPaM ImpEditEngine::CreateEditPaM( const EPaM& rEPaM )
1125{
1126 DBG_ASSERT( rEPaM.nPara < aEditDoc.Count(), "CreateEditPaM: invalid paragraph" )do { if (true && (!(rEPaM.nPara < aEditDoc.Count()
))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"
), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit.hxx"
":" "1126" ": "), "%s", "CreateEditPaM: invalid paragraph");
} } while (false)
;
1127 DBG_ASSERT( aEditDoc[ rEPaM.nPara ]->Len() >= rEPaM.nIndex, "CreateEditPaM: invalid Index" )do { if (true && (!(aEditDoc[ rEPaM.nPara ]->Len()
>= rEPaM.nIndex))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit.hxx"
":" "1127" ": "), "%s", "CreateEditPaM: invalid Index"); } }
while (false)
;
1128 return EditPaM( aEditDoc[ rEPaM.nPara], rEPaM.nIndex );
1129}
1130
1131inline ESelection ImpEditEngine::CreateESel( const EditSelection& rSel )
1132{
1133 const ContentNode* pStartNode = rSel.Min().GetNode();
1134 const ContentNode* pEndNode = rSel.Max().GetNode();
1135 ESelection aESel;
1136 aESel.nStartPara = aEditDoc.GetPos( pStartNode );
1137 aESel.nStartPos = rSel.Min().GetIndex();
1138 aESel.nEndPara = aEditDoc.GetPos( pEndNode );
1139 aESel.nEndPos = rSel.Max().GetIndex();
1140 return aESel;
1141}
1142
1143inline EditSelection ImpEditEngine::CreateSel( const ESelection& rSel )
1144{
1145 DBG_ASSERT( rSel.nStartPara < aEditDoc.Count(), "CreateSel: invalid start paragraph" )do { if (true && (!(rSel.nStartPara < aEditDoc.Count
()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"
), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit.hxx"
":" "1145" ": "), "%s", "CreateSel: invalid start paragraph"
); } } while (false)
;
1146 DBG_ASSERT( rSel.nEndPara < aEditDoc.Count(), "CreateSel: invalid end paragraph" )do { if (true && (!(rSel.nEndPara < aEditDoc.Count
()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"
), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit.hxx"
":" "1146" ": "), "%s", "CreateSel: invalid end paragraph");
} } while (false)
;
1147 EditSelection aSel;
1148 aSel.Min().SetNode( aEditDoc[ rSel.nStartPara ] );
1149 aSel.Min().SetIndex( rSel.nStartPos );
1150 aSel.Max().SetNode( aEditDoc[ rSel.nEndPara ] );
1151 aSel.Max().SetIndex( rSel.nEndPos );
1152 DBG_ASSERT( !aSel.DbgIsBuggy( aEditDoc ), "CreateSel: incorrect selection!" )do { if (true && (!(!aSel.DbgIsBuggy( aEditDoc )))) {
sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"
), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit.hxx"
":" "1152" ": "), "%s", "CreateSel: incorrect selection!"); }
} while (false)
;
1153 return aSel;
1154}
1155
1156inline VirtualDevice* ImpEditEngine::GetVirtualDevice( const MapMode& rMapMode, DrawModeFlags nDrawMode )
1157{
1158 if ( !pVirtDev )
1159 pVirtDev = VclPtr<VirtualDevice>::Create();
1160
1161 if ( ( pVirtDev->GetMapMode().GetMapUnit() != rMapMode.GetMapUnit() ) ||
1162 ( pVirtDev->GetMapMode().GetScaleX() != rMapMode.GetScaleX() ) ||
1163 ( pVirtDev->GetMapMode().GetScaleY() != rMapMode.GetScaleY() ) )
1164 {
1165 MapMode aMapMode( rMapMode );
1166 aMapMode.SetOrigin( Point( 0, 0 ) );
1167 pVirtDev->SetMapMode( aMapMode );
1168 }
1169
1170 pVirtDev->SetDrawMode( nDrawMode );
1171
1172 return pVirtDev;
1173}
1174
1175inline void ImpEditEngine::IdleFormatAndUpdate( EditView* pCurView )
1176{
1177 aIdleFormatter.DoIdleFormat( pCurView );
1178}
1179
1180inline EditUndoManager& ImpEditEngine::GetUndoManager()
1181{
1182 if ( !pUndoManager )
1183 {
1184 pUndoManager = new EditUndoManager();
1185 pUndoManager->SetEditEngine(pEditEngine);
1186 }
1187 return *pUndoManager;
1188}
1189
1190inline SfxUndoManager* ImpEditEngine::SetUndoManager(SfxUndoManager* pNew)
1191{
1192 SfxUndoManager* pRetval = pUndoManager;
1193
1194 if(pUndoManager)
1195 {
1196 pUndoManager->SetEditEngine(nullptr);
1197 }
1198
1199 pUndoManager = dynamic_cast< EditUndoManager* >(pNew);
1200
1201 if(pUndoManager)
1202 {
1203 pUndoManager->SetEditEngine(pEditEngine);
1204 }
1205
1206 return pRetval;
1207}
1208
1209inline const ParaPortion* ImpEditEngine::FindParaPortion( const ContentNode* pNode ) const
1210{
1211 sal_Int32 nPos = aEditDoc.GetPos( pNode );
1212 DBG_ASSERT( nPos < GetParaPortions().Count(), "Portionloser Node?" )do { if (true && (!(nPos < GetParaPortions().Count
()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"
), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit.hxx"
":" "1212" ": "), "%s", "Portionloser Node?"); } } while (false
)
;
1213 return GetParaPortions()[ nPos ];
1214}
1215
1216inline ParaPortion* ImpEditEngine::FindParaPortion( ContentNode const * pNode )
1217{
1218 sal_Int32 nPos = aEditDoc.GetPos( pNode );
1219 DBG_ASSERT( nPos < GetParaPortions().Count(), "Portionloser Node?" )do { if (true && (!(nPos < GetParaPortions().Count
()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"
), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit.hxx"
":" "1219" ": "), "%s", "Portionloser Node?"); } } while (false
)
;
1220 return GetParaPortions()[ nPos ];
1221}
1222
1223inline void ImpEditEngine::GetCharStretching( sal_uInt16& rX, sal_uInt16& rY ) const
1224{
1225 rX = nStretchX;
1226 rY = nStretchY;
1227}
1228
1229inline short ImpEditEngine::GetXValue( short nXValue ) const
1230{
1231 if ( !aStatus.DoStretch() || ( nStretchX == 100 ) )
1232 return nXValue;
1233
1234 return static_cast<short>(static_cast<long>(nXValue)*nStretchX/100);
1235}
1236
1237
1238inline long ImpEditEngine::GetXValue( long nXValue ) const
1239{
1240 if ( !aStatus.DoStretch() || ( nStretchX == 100 ) )
1241 return nXValue;
1242
1243 return nXValue*nStretchX/100;
1244}
1245
1246inline short ImpEditEngine::GetYValue( short nYValue ) const
1247{
1248 if ( !aStatus.DoStretch() || ( nStretchY == 100 ) )
1249 return nYValue;
1250
1251 return static_cast<short>(static_cast<long>(nYValue)*nStretchY/100);
1252}
1253
1254inline sal_uInt16 ImpEditEngine::GetYValue( sal_uInt16 nYValue ) const
1255{
1256 if ( !aStatus.DoStretch() || ( nStretchY == 100 ) )
1257 return nYValue;
1258
1259 return static_cast<sal_uInt16>(static_cast<long>(nYValue)*nStretchY/100);
1260}
1261
1262inline PointerStyle ImpEditView::GetPointer()
1263{
1264 if ( !mxPointer )
1265 {
1266 mxPointer = IsVertical() ? PointerStyle::TextVertical : PointerStyle::Text;
1267 return *mxPointer;
1268 }
1269
1270 if(PointerStyle::Text == *mxPointer && IsVertical())
1271 {
1272 mxPointer = PointerStyle::TextVertical;
1273 }
1274 else if(PointerStyle::TextVertical == *mxPointer && !IsVertical())
1275 {
1276 mxPointer = PointerStyle::Text;
1277 }
1278
1279 return *mxPointer;
1280}
1281
1282inline vcl::Cursor* ImpEditView::GetCursor()
1283{
1284 if ( !pCursor )
1285 pCursor.reset( new vcl::Cursor );
1286 return pCursor.get();
1287}
1288
1289void ConvertItem( std::unique_ptr<SfxPoolItem>& rPoolItem, MapUnit eSourceUnit, MapUnit eDestUnit );
1290void ConvertAndPutItems( SfxItemSet& rDest, const SfxItemSet& rSource, const MapUnit* pSourceUnit = nullptr, const MapUnit* pDestUnit = nullptr );
1291AsianCompressionFlags GetCharTypeForCompression( sal_Unicode cChar );
1292Point Rotate( const Point& rPoint, short nOrientation, const Point& rOrigin );
1293
1294
1295/* 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);
7
Calling copy constructor for 'Reference<VirtualDevice>'
10
Returning from copy constructor for 'Reference<VirtualDevice>'
204 m_rInnerRef.clear(); // we should use some 'swap' method ideally ;-)
11
Calling 'Reference::clear'
18
Returning; memory was released
205 if (aTmp.get()) {
19
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)
8
Assuming field 'm_pBody' is non-null
9
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
11.1
Field 'm_pBody' is non-null
11.1
Field 'm_pBody' is non-null
11.1
Field 'm_pBody' is non-null
11.1
Field 'm_pBody' is non-null
11.1
Field 'm_pBody' is non-null
11.1
Field 'm_pBody' is non-null
)
12
Taking true branch
177 {
178 reference_type * const pOld = m_pBody;
179 m_pBody = NULL__null;
180 pOld->release();
13
Calling 'VclReferenceBase::release'
17
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;
20
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)
14
Assuming the condition is true
15
Taking true branch
40 delete this;
16
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