[Libreoffice-commits] core.git: Branch 'private/swe/libreoffice-5-2+backports' - 6 commits - editeng/source include/editeng include/svx sd/source svx/source

Armin Le Grand Armin.Le.Grand at cib.de
Thu Aug 17 08:10:43 UTC 2017


 editeng/source/editeng/editeng.cxx          |   17 -
 editeng/source/editeng/editundo.cxx         |    4 
 editeng/source/editeng/editview.cxx         |   73 +++--
 editeng/source/editeng/impedit.cxx          |  138 ++++++---
 editeng/source/editeng/impedit.hxx          |   38 ++
 editeng/source/editeng/impedit2.cxx         |   44 +--
 editeng/source/editeng/impedit3.cxx         |   17 -
 editeng/source/editeng/impedit4.cxx         |   28 -
 include/editeng/editeng.hxx                 |    6 
 include/editeng/editview.hxx                |   30 ++
 include/svx/svdedxv.hxx                     |   12 
 include/svx/svdotext.hxx                    |   10 
 include/svx/svdoutl.hxx                     |    2 
 sd/source/ui/view/Outliner.cxx              |   11 
 svx/source/svdraw/svdedxv.cxx               |  407 ++++++++++++++++++++++++++--
 svx/source/svdraw/svdotextdecomposition.cxx |   13 
 svx/source/svdraw/svdotxat.cxx              |   20 +
 svx/source/svdraw/svdoutl.cxx               |   16 +
 18 files changed, 747 insertions(+), 139 deletions(-)

New commits:
commit 9a30881a9f2ecee77942355e94337674b9ae0304
Author: Armin Le Grand <Armin.Le.Grand at cib.de>
Date:   Thu Aug 10 20:08:56 2017 +0200

    editviewoverlay: corrected AttributeChange
    
    EditView on Overlay visualization needs to handle
    selection change when e.g. FontSize attribute of
    a selected text portion changes. Changed handling
    so that selection overlay is an integral part of
    text visualization overlay and refreshing text
    visualization always refreshes selection visuals,
    but not the other way around. Both anyways check
    for real change, so just extra testing is avoided
    which is still the better solution
    
    Change-Id: I3ce6570fd9a18a7c1d7ced4bc4ca9aeda57538e0
    Reviewed-on: https://gerrit.libreoffice.org/40993
    Tested-by: Jenkins <ci at libreoffice.org>
    Reviewed-by: Armin Le Grand <Armin.Le.Grand at cib.de>

diff --git a/include/editeng/editview.hxx b/include/editeng/editview.hxx
index fd9df8c420ce..1250b823dded 100644
--- a/include/editeng/editview.hxx
+++ b/include/editeng/editview.hxx
@@ -92,7 +92,14 @@ public:
     EditViewCallbacks() {}
     virtual ~EditViewCallbacks();
 
+    // call this when text visualization changed in any way. It
+    // will also update selection, so no need to call this self
+    // additionally (but will also do no harm)
     virtual void EditViewInvalidate() const = 0;
+
+    // call this when only selection is changed. Text change will
+    // then *not* be checked and not be reacted on. Still, when
+    // only the selection is changed, this is useful and faster
     virtual void EditViewSelectionChange() const = 0;
 };
 
diff --git a/svx/source/svdraw/svdedxv.cxx b/svx/source/svdraw/svdedxv.cxx
index cdf17fad637b..6e772c032061 100644
--- a/svx/source/svdraw/svdedxv.cxx
+++ b/svx/source/svdraw/svdedxv.cxx
@@ -329,7 +329,6 @@ namespace
 
     public:
         TextEditOverlayObject(
-            sdr::overlay::OverlaySelection* pOverlaySelection,
             const Color& rColor,
             OutlinerView& rOutlinerView,
             bool bVisualizeSurroundingFrame);
@@ -377,12 +376,11 @@ namespace
     }
 
     TextEditOverlayObject::TextEditOverlayObject(
-        sdr::overlay::OverlaySelection* pOverlaySelection,
         const Color& rColor,
         OutlinerView& rOutlinerView,
         bool bVisualizeSurroundingFrame)
     :   OverlayObject(rColor),
-        mpOverlaySelection(pOverlaySelection),
+        mpOverlaySelection(nullptr),
         mrOutlinerView(rOutlinerView),
         maLastRange(),
         maRange(),
@@ -392,6 +390,15 @@ namespace
     {
         // no AA for TextEdit overlay
         allowAntiAliase(false);
+
+        // create local OverlaySelection - this is an integral part of EditText
+        // visualization
+        const std::vector< basegfx::B2DRange > aEmptySelection;
+        mpOverlaySelection = new sdr::overlay::OverlaySelection(
+            sdr::overlay::OVERLAY_TRANSPARENT,
+            rColor,
+            aEmptySelection,
+            true);
     }
 
     TextEditOverlayObject::~TextEditOverlayObject()
@@ -498,6 +505,10 @@ namespace
             // if there really *was* a change signal the OverlayManager to
             // refresh this object's visualization
             objectChange();
+
+            // on data change, always do a SelectionChange, too
+            // since the selection is an integral part of text visualization
+            checkSelectionChange();
         }
     }
 
@@ -530,7 +541,8 @@ namespace
 // TextEdit
 
 // callback from the active EditView, forward to evtl. existing instances of the
-// TextEditOverlayObject(s)
+// TextEditOverlayObject(s). This will additionally update the selection which
+// is an integral part of the text visualization
 void SdrObjEditView::EditViewInvalidate() const
 {
     if (IsTextEdit())
@@ -552,6 +564,9 @@ void SdrObjEditView::EditViewInvalidate() const
     }
 }
 
+// callback from the active EditView, forward to evtl. existing instances of the
+// TextEditOverlayObject(s). This cvall *only* updates the selection visualization
+// which is e.g. used when only the selection is changed, but not the text
 void SdrObjEditView::EditViewSelectionChange() const
 {
     if (IsTextEdit())
@@ -573,10 +588,9 @@ void SdrObjEditView::TextEditDrawing(SdrPaintWindow& rPaintWindow) const
     if (!comphelper::LibreOfficeKit::isActive())
     {
         // adapt all TextEditOverlayObject(s), so call EditViewInvalidate()
-        // and EditViewSelectionChange() to update accordingly. Suppress new
+        // to update accordingly (will update selection, too). Suppress new
         // stuff when LibreOficeKit is active
         EditViewInvalidate();
-        EditViewSelectionChange();
     }
     else
     {
@@ -1107,22 +1121,13 @@ bool SdrObjEditView::SdrBeginTextEdit(
                             rtl::Reference< sdr::overlay::OverlayManager > xManager = rPageWindow.GetOverlayManager();
                             if (xManager.is())
                             {
-                                const std::vector< basegfx::B2DRange > aEmptySelection;
-
-                                sdr::overlay::OverlaySelection* pNewOverlaySelection = new sdr::overlay::OverlaySelection(
-                                    sdr::overlay::OVERLAY_TRANSPARENT,
-                                    aHilightColor,
-                                    aEmptySelection,
-                                    true);
-
-                                sdr::overlay::OverlayObject* pNewTextEditOverlayObject = new TextEditOverlayObject(
-                                    pNewOverlaySelection,
+                                TextEditOverlayObject* pNewTextEditOverlayObject = new TextEditOverlayObject(
                                     aHilightColor,
                                     *pTextEditOutlinerView,
                                     bVisualizeSurroundingFrame);
 
                                 xManager->add(*pNewTextEditOverlayObject);
-                                xManager->add(*pNewOverlaySelection);
+                                xManager->add(const_cast<sdr::overlay::OverlaySelection&>(*pNewTextEditOverlayObject->getOverlaySelection()));
 
                                 maTEOverlayGroup.append(*pNewTextEditOverlayObject);
                             }
commit 720d4eccd20d0485e9ad497fef83341f83118234
Author: Armin Le Grand <Armin.Le.Grand at cib.de>
Date:   Thu Aug 10 11:43:28 2017 +0200

    editviewoverlay: Adapted URL in edit mode
    
    For histotrical reasons a URL in edit mode is
    visualized in a single line. To keep compatible,
    also do this when EditView is on Overlay
    
    Change-Id: Ib11b1716aa558c13295a8a02e2845a88fa98ed11

diff --git a/editeng/source/editeng/impedit3.cxx b/editeng/source/editeng/impedit3.cxx
index 262c727e9e51..4159e5b3cab2 100644
--- a/editeng/source/editeng/impedit3.cxx
+++ b/editeng/source/editeng/impedit3.cxx
@@ -3172,7 +3172,14 @@ void ImpEditEngine::Paint( OutputDevice* pOutDev, Rectangle aClipRect, Point aSt
                                     nTextLen = aText.getLength();
                                     ExtraPortionInfo *pExtraInfo = rTextPortion.GetExtraInfos();
                                     // Do not split the Fields into different lines while editing
-                                    if( bStripOnly && !bParsingFields && pExtraInfo && pExtraInfo->lineBreaksList.size() )
+                                    // With EditView on Overlay bStripOnly is now set for stripping to
+                                    // primitives. To stay compatible in EditMode use pActiveView to detect
+                                    // when we are in EditMode. For whatever reason URLs are drawn as single
+                                    // line in edit mode, originally clipped against edit area (which is no
+                                    // longer done in Overlay mode and allows to *read* the URL).
+                                    // It would be difficult to change this due to needed adaptions in
+                                    // EditEngine (look for lineBreaksList creation)
+                                    if( nullptr == pActiveView && bStripOnly && !bParsingFields && pExtraInfo && pExtraInfo->lineBreaksList.size() )
                                     {
                                         bParsingFields = true;
                                         itSubLines = pExtraInfo->lineBreaksList.begin();
commit b4d6ecc25162e56546ce52a38803e470023825e0
Author: Armin Le Grand <Armin.Le.Grand at cib.de>
Date:   Wed Aug 9 19:10:46 2017 +0200

    editviewoverlay: correct reaction on property change
    
    Do not hand over LogicalSelectionRanges directly on
    selection change, better let the visulizer do what
    he needs. On AttributeChange, tge resulting repaint
    needs to refresh all OverlayObjects, not only text,
    but also the selection to make look okay e.g. at
    font size change
    
    Change-Id: Ibb9737c33d6f85a9f68df3edbb989c0443cd4a5c

diff --git a/editeng/source/editeng/impedit.cxx b/editeng/source/editeng/impedit.cxx
index 858fbc6f7e88..2b0b236696f6 100644
--- a/editeng/source/editeng/impedit.cxx
+++ b/editeng/source/editeng/impedit.cxx
@@ -175,24 +175,8 @@ void ImpEditView::SelectionChanged()
 {
     if (hasEditViewCallbacks())
     {
-        std::vector<Rectangle> aLogicRects;
-        std::vector<basegfx::B2DRange> aLogicRanges;
-        const Size aLogicPixel(pOutWin ? pOutWin->PixelToLogic(Size(1, 1)) : Size(1, 1));
-
-        GetSelectionRectangles(GetEditSelection(), aLogicRects);
-
-        for (const auto& aRect : aLogicRects)
-        {
-            // convert from logic Rectangles to logic Ranges, do not forget to add
-            // one Unit (in this case logical unit, thus calculate first)
-            aLogicRanges.push_back(
-                basegfx::B2DRange(
-                    aRect.Left(), aRect.Top(),
-                    aRect.Right() + aLogicPixel.Width(), aRect.Bottom() + aLogicPixel.Height()));
-        }
-
         // use callback to tell about change in selection visualisation
-        mpEditViewCallbacks->EditViewSelectionChange(aLogicRanges);
+        mpEditViewCallbacks->EditViewSelectionChange();
     }
 }
 
@@ -207,7 +191,7 @@ void ImpEditView::SelectionChanged()
 // the Region*, see GetSelectionRectangles below.
 void ImpEditView::DrawSelectionXOR( EditSelection aTmpSel, vcl::Region* pRegion, OutputDevice* pTargetDevice )
 {
-    if (hasEditViewCallbacks() && !pRegion)
+    if (hasEditViewCallbacks() && !pRegion && !comphelper::LibreOfficeKit::isActive())
     {
         // we are done, do *not* visualize self
         // CAUTION: do not use when comphelper::LibreOfficeKit::isActive()
diff --git a/include/editeng/editview.hxx b/include/editeng/editview.hxx
index 0fdb6f95be5f..fd9df8c420ce 100644
--- a/include/editeng/editview.hxx
+++ b/include/editeng/editview.hxx
@@ -93,7 +93,7 @@ public:
     virtual ~EditViewCallbacks();
 
     virtual void EditViewInvalidate() const = 0;
-    virtual void EditViewSelectionChange(const std::vector<basegfx::B2DRange>& rLogicRanges) const = 0;
+    virtual void EditViewSelectionChange() const = 0;
 };
 
 class EDITENG_DLLPUBLIC EditView
diff --git a/include/svx/svdedxv.hxx b/include/svx/svdedxv.hxx
index 090f34994f58..037dbfe95219 100644
--- a/include/svx/svdedxv.hxx
+++ b/include/svx/svdedxv.hxx
@@ -64,7 +64,7 @@ class SVX_DLLPUBLIC SdrObjEditView: public SdrGlueEditView, public EditViewCallb
     // Now derived from EditViewCallbacks and overriding these callbacks to
     // allow own EditText visualization
     virtual void EditViewInvalidate() const override;
-    virtual void EditViewSelectionChange(const std::vector<basegfx::B2DRange>& rLogicRanges) const override;
+    virtual void EditViewSelectionChange() const override;
 
     // The OverlayObjects used for visualizing active TextEdit (currently
     // using TextEditOverlayObject, but not limitied to it
diff --git a/svx/source/svdraw/svdedxv.cxx b/svx/source/svdraw/svdedxv.cxx
index 7a8ad7cb4ef0..cdf17fad637b 100644
--- a/svx/source/svdraw/svdedxv.cxx
+++ b/svx/source/svdraw/svdedxv.cxx
@@ -346,7 +346,7 @@ namespace
         // data write access. In this OverlayObject we only have the
         // callback that triggers detecting if something *has* changed
         void checkDataChange(const basegfx::B2DRange& rMinTextEditArea);
-        void checkSelectionChange(const std::vector<basegfx::B2DRange>& rLogicRanges);
+        void checkSelectionChange();
     };
 
     drawinglayer::primitive2d::Primitive2DContainer TextEditOverlayObject::createOverlayObjectPrimitive2DSequence()
@@ -501,11 +501,28 @@ namespace
         }
     }
 
-    void TextEditOverlayObject::checkSelectionChange(const std::vector<basegfx::B2DRange>& rLogicRanges)
+    void TextEditOverlayObject::checkSelectionChange()
     {
-        if (getOverlaySelection())
+        if (getOverlaySelection() && getOverlayManager())
         {
-            mpOverlaySelection->setRanges(rLogicRanges);
+            std::vector<Rectangle> aLogicRects;
+            std::vector<basegfx::B2DRange> aLogicRanges;
+            const Size aLogicPixel(getOverlayManager()->getOutputDevice().PixelToLogic(Size(1, 1)));
+
+            // get logic selection
+            getOutlinerView().GetSelectionRectangles(aLogicRects);
+
+            for (const auto& aRect : aLogicRects)
+            {
+                // convert from logic Rectangles to logic Ranges, do not forget to add
+                // one Unit (in this case logical units for one pixel, pre-calculated)
+                aLogicRanges.push_back(
+                    basegfx::B2DRange(
+                        aRect.Left() - aLogicPixel.Width(), aRect.Top() - aLogicPixel.Height(),
+                        aRect.Right() + aLogicPixel.Width(), aRect.Bottom() + aLogicPixel.Height()));
+            }
+
+            mpOverlaySelection->setRanges(aLogicRanges);
         }
     }
 } // end of anonymous namespace
@@ -535,7 +552,7 @@ void SdrObjEditView::EditViewInvalidate() const
     }
 }
 
-void SdrObjEditView::EditViewSelectionChange(const std::vector<basegfx::B2DRange>& rLogicRanges) const
+void SdrObjEditView::EditViewSelectionChange() const
 {
     if (IsTextEdit())
     {
@@ -545,7 +562,7 @@ void SdrObjEditView::EditViewSelectionChange(const std::vector<basegfx::B2DRange
 
             if (pCandidate)
             {
-                pCandidate->checkSelectionChange(rLogicRanges);
+                pCandidate->checkSelectionChange();
             }
         }
     }
@@ -555,10 +572,11 @@ void SdrObjEditView::TextEditDrawing(SdrPaintWindow& rPaintWindow) const
 {
     if (!comphelper::LibreOfficeKit::isActive())
     {
-        // adapt TextEditOverlayObject(s). Need also to do this here to
-        // update the current values accordingly. Suppress new stuff when
-        // LibreOficeKit is active
+        // adapt all TextEditOverlayObject(s), so call EditViewInvalidate()
+        // and EditViewSelectionChange() to update accordingly. Suppress new
+        // stuff when LibreOficeKit is active
         EditViewInvalidate();
+        EditViewSelectionChange();
     }
     else
     {
commit acb4a6dc1fb2b60a66dece73095eab026c9b93f3
Author: Armin Le Grand <Armin.Le.Grand at cib.de>
Date:   Wed Aug 9 16:35:47 2017 +0200

    editviewoverlay: more cases secured
    
    Added support for vertical text, checked all
    combinations for text positioning, secured cursor
    stuff, ensured collaboration with LibreOfficeKit
    
    Change-Id: I98d1187700907c0c72abdccb9c9979496f6c20cf

diff --git a/editeng/source/editeng/impedit.cxx b/editeng/source/editeng/impedit.cxx
index ff189f7e7c07..858fbc6f7e88 100644
--- a/editeng/source/editeng/impedit.cxx
+++ b/editeng/source/editeng/impedit.cxx
@@ -210,6 +210,10 @@ void ImpEditView::DrawSelectionXOR( EditSelection aTmpSel, vcl::Region* pRegion,
     if (hasEditViewCallbacks() && !pRegion)
     {
         // we are done, do *not* visualize self
+        // CAUTION: do not use when comphelper::LibreOfficeKit::isActive()
+        // due to event stuff triggered below. That *should* probably be moved
+        // to SelectionChanged() which exists now, but I do not know enough about
+        // that stuff to do it
         return;
     }
 
diff --git a/svx/source/svdraw/svdedxv.cxx b/svx/source/svdraw/svdedxv.cxx
index 08f5e9542a74..7a8ad7cb4ef0 100644
--- a/svx/source/svdraw/svdedxv.cxx
+++ b/svx/source/svdraw/svdedxv.cxx
@@ -457,12 +457,23 @@ namespace
             drawinglayer::primitive2d::Primitive2DContainer aNewTextPrimitives;
 
             // active Outliner is always in unified oriented coordinate system (currently)
-            // so just translate to TopLeft of visible Range
-            Rectangle aVisArea(mrOutlinerView.GetVisArea());
+            // so just translate to TopLeft of visible Range. Keep in mind that top-left
+            // depends on vertical text and top-to-bottom text attribures
+            const Rectangle aVisArea(mrOutlinerView.GetVisArea());
+            const bool bVerticalWriting(pSdrOutliner->IsVertical());
+            const bool bTopToBottom(true); // pSdrOutliner->IsTopToBottom() not yet invented
+            const double fStartInX(
+                bVerticalWriting && bTopToBottom
+                ? aOutArea.Right() - aVisArea.Left()
+                : aOutArea.Left() - aVisArea.Left());
+            const double fStartInY(
+                bVerticalWriting && !bTopToBottom
+                ? aOutArea.Bottom() - aVisArea.Top()
+                : aOutArea.Top() - aVisArea.Top());
 
             aNewTransformB.translate(
-                aOutArea.Left() - aVisArea.Left(),
-                aOutArea.Top() - aVisArea.Top());
+                fStartInX,
+                fStartInY);
 
             // get the current TextPrimitives. This is the most expensive part
             // of this mechanism, it *may* be possible to buffer layouted
@@ -501,9 +512,6 @@ namespace
 
 // TextEdit
 
-// file-local static bool to control old/new behaviour of active TextEdit visualization
-static bool bAllowTextEditVisualizatkionOnOverlay(true);
-
 // callback from the active EditView, forward to evtl. existing instances of the
 // TextEditOverlayObject(s)
 void SdrObjEditView::EditViewInvalidate() const
@@ -545,10 +553,11 @@ void SdrObjEditView::EditViewSelectionChange(const std::vector<basegfx::B2DRange
 
 void SdrObjEditView::TextEditDrawing(SdrPaintWindow& rPaintWindow) const
 {
-    if (bAllowTextEditVisualizatkionOnOverlay)
+    if (!comphelper::LibreOfficeKit::isActive())
     {
         // adapt TextEditOverlayObject(s). Need also to do this here to
-        // update the current values accordingly
+        // update the current values accordingly. Suppress new stuff when
+        // LibreOficeKit is active
         EditViewInvalidate();
     }
     else
@@ -1055,9 +1064,10 @@ bool SdrObjEditView::SdrBeginTextEdit(
 
             pTextEditOutlinerView=ImpMakeOutlinerView(pWin,!bEmpty,pGivenOutlinerView);
 
-            if (bAllowTextEditVisualizatkionOnOverlay && pTextEditOutlinerView)
+            if (!comphelper::LibreOfficeKit::isActive() && pTextEditOutlinerView)
             {
-                // activate visualization of EditView on Overlay
+                // activate visualization of EditView on Overlay, suppress when
+                // LibreOfficeKit is active
                 pTextEditOutlinerView->GetEditView().setEditViewCallbacks(this);
 
                 const SvtOptionsDrawinglayer aSvtOptionsDrawinglayer;
@@ -1291,8 +1301,9 @@ SdrEndTextEditKind SdrObjEditView::SdrEndTextEdit(bool bDontDeleteReally)
         GetModel()->Broadcast(aHint);
     }
 
-    // if new mechanism was used, clean it up
-    if (bAllowTextEditVisualizatkionOnOverlay && pTextEditOutlinerView)
+    // if new mechanism was used, clean it up. At cleanup no need to check
+    // for LibreOfficeKit
+    if (pTextEditOutlinerView)
     {
         pTextEditOutlinerView->GetEditView().setEditViewCallbacks(nullptr);
         maTEOverlayGroup.clear();
commit e7096928f6a6ec039e1c4a9ce77b52532bde57ae
Author: Armin Le Grand <Armin.Le.Grand at cib.de>
Date:   Sun Aug 6 00:26:35 2017 +0200

    editviewoverlay: EditViewSelection reorganized
    
    The Selection visualization in EditVierw is organized
    to use XOR for visualization, thus DrawSelection is
    used e.g. before and after changes to the Selection.
    Ensured athat all changers of selection have to use
    SetEditSelection by making return of GetEditSelection
    const. This allows to use a central and safe
    SelectionChanged which is needed for alternatives of
    Selection visualization.
    
    Change-Id: I994553f3be6b58fd595aa500922d8d1d8ddd36d4

diff --git a/editeng/source/editeng/editeng.cxx b/editeng/source/editeng/editeng.cxx
index 17152125fb60..5e9ae378d6a4 100644
--- a/editeng/source/editeng/editeng.cxx
+++ b/editeng/source/editeng/editeng.cxx
@@ -72,6 +72,7 @@
 #include <vcl/help.hxx>
 #include <com/sun/star/datatransfer/clipboard/XClipboard.hpp>
 #include <com/sun/star/i18n/InputSequenceCheckMode.hpp>
+#include <comphelper/lok.hxx>
 
 #include <svl/srchdefs.hxx>
 
@@ -630,7 +631,7 @@ ESelection EditEngine::GetWord( const ESelection& rSelection, sal_uInt16 nWordTy
     return pE->pImpEditEngine->CreateESel( aSel );
 }
 
-void EditEngine::CursorMoved(ContentNode* pPrevNode)
+void EditEngine::CursorMoved(const ContentNode* pPrevNode)
 {
     pImpEditEngine->CursorMoved(pPrevNode);
 }
@@ -645,12 +646,12 @@ bool EditEngine::IsIdleFormatterActive() const
     return pImpEditEngine->aIdleFormatter.IsActive();
 }
 
-ParaPortion* EditEngine::FindParaPortion(ContentNode* pNode)
+ParaPortion* EditEngine::FindParaPortion(ContentNode const * pNode)
 {
     return pImpEditEngine->FindParaPortion(pNode);
 }
 
-const ParaPortion* EditEngine::FindParaPortion(ContentNode* pNode) const
+const ParaPortion* EditEngine::FindParaPortion(ContentNode const * pNode) const
 {
     return pImpEditEngine->FindParaPortion(pNode);
 }
@@ -1161,7 +1162,7 @@ bool EditEngine::PostKeyEvent( const KeyEvent& rKeyEvent, EditView* pEditView, v
                         break;
                     }
 
-                    pEditView->pImpEditView->DrawSelection();
+                    pEditView->pImpEditView->DrawSelectionXOR();
                     pImpEditEngine->UndoActionStart( EDITUNDO_DELETE );
                     aCurSel = pImpEditEngine->DeleteLeftOrRight( aCurSel, nDel, nMode );
                     pImpEditEngine->UndoActionEnd( EDITUNDO_DELETE );
@@ -1201,7 +1202,7 @@ bool EditEngine::PostKeyEvent( const KeyEvent& rKeyEvent, EditView* pEditView, v
             {
                 if ( !bReadOnly )
                 {
-                    pEditView->pImpEditView->DrawSelection();
+                    pEditView->pImpEditView->DrawSelectionXOR();
                     if ( !rKeyEvent.GetKeyCode().IsMod1() && !rKeyEvent.GetKeyCode().IsMod2() )
                     {
                         pImpEditEngine->UndoActionStart( EDITUNDO_INSERT );
@@ -1256,7 +1257,7 @@ bool EditEngine::PostKeyEvent( const KeyEvent& rKeyEvent, EditView* pEditView, v
                 if ( !bReadOnly && IsSimpleCharInput( rKeyEvent ) )
                 {
                     sal_Unicode nCharCode = rKeyEvent.GetCharCode();
-                    pEditView->pImpEditView->DrawSelection();
+                    pEditView->pImpEditView->DrawSelectionXOR();
                     // Autocorrection?
                     SvxAutoCorrect* pAutoCorrect = SvxAutoCorrCfg::Get().GetAutoCorrect();
                     if ( ( pImpEditEngine->GetStatus().DoAutoCorrect() ) &&
@@ -1349,6 +1350,10 @@ bool EditEngine::PostKeyEvent( const KeyEvent& rKeyEvent, EditView* pEditView, v
     }
 
     pEditView->pImpEditView->SetEditSelection( aCurSel );
+    if (comphelper::LibreOfficeKit::isActive())
+    {
+        pEditView->pImpEditView->DrawSelectionXOR();
+    }
     pImpEditEngine->UpdateSelections();
 
     if ( ( !IsVertical() && ( nCode != KEY_UP ) && ( nCode != KEY_DOWN ) ) ||
diff --git a/editeng/source/editeng/editundo.cxx b/editeng/source/editeng/editundo.cxx
index f900867d7f5d..8b8f290880cd 100644
--- a/editeng/source/editeng/editundo.cxx
+++ b/editeng/source/editeng/editundo.cxx
@@ -65,7 +65,7 @@ bool EditUndoManager::Undo()
         }
     }
 
-    mpEditEngine->GetActiveView()->GetImpEditView()->DrawSelection(); // Remove the old selection
+    mpEditEngine->GetActiveView()->GetImpEditView()->DrawSelectionXOR(); // Remove the old selection
 
     mpEditEngine->SetUndoMode( true );
     bool bDone = SfxUndoManager::Undo();
@@ -100,7 +100,7 @@ bool EditUndoManager::Redo()
         }
     }
 
-    mpEditEngine->GetActiveView()->GetImpEditView()->DrawSelection(); // Remove the old selection
+    mpEditEngine->GetActiveView()->GetImpEditView()->DrawSelectionXOR(); // Remove the old selection
 
     mpEditEngine->SetUndoMode( true );
     bool bDone = SfxUndoManager::Redo();
diff --git a/editeng/source/editeng/editview.cxx b/editeng/source/editeng/editview.cxx
index d7db92bf6039..108a0875886d 100644
--- a/editeng/source/editeng/editview.cxx
+++ b/editeng/source/editeng/editview.cxx
@@ -236,7 +236,7 @@ void EditView::SetSelection( const ESelection& rESel )
     // manipulates the selection:
     if ( !pImpEditView->GetEditSelection().HasRange() )
     {
-        ContentNode* pNode = pImpEditView->GetEditSelection().Max().GetNode();
+        const ContentNode* pNode = pImpEditView->GetEditSelection().Max().GetNode();
         pImpEditView->pEditEngine->CursorMoved( pNode );
     }
     EditSelection aNewSelection( pImpEditView->pEditEngine->pImpEditEngine->ConvertSelection(
@@ -261,9 +261,9 @@ void EditView::SetSelection( const ESelection& rESel )
         aNewSelection.Max() = EditPaM( pNode, pNode->Len() );
     }
 
-    pImpEditView->DrawSelection();
+    pImpEditView->DrawSelectionXOR();
     pImpEditView->SetEditSelection( aNewSelection );
-    pImpEditView->DrawSelection();
+    pImpEditView->DrawSelectionXOR();
     bool bGotoCursor = pImpEditView->DoAutoScroll();
     ShowCursor( bGotoCursor );
 }
@@ -298,7 +298,7 @@ SvtScriptType EditView::GetSelectedScriptType() const
 
 void EditView::GetSelectionRectangles(std::vector<Rectangle>& rLogicRects) const
 {
-    return pImpEditView->GetSelectionRectangles(rLogicRects);
+    return pImpEditView->GetSelectionRectangles(pImpEditView->GetEditSelection(), rLogicRects);
 }
 
 void EditView::Paint( const Rectangle& rRect, OutputDevice* pTargetDevice )
@@ -368,7 +368,7 @@ void EditView::InsertText( const OUString& rStr, bool bSelect )
 {
 
     EditEngine* pEE = pImpEditView->pEditEngine;
-    pImpEditView->DrawSelection();
+    pImpEditView->DrawSelectionXOR();
 
     EditPaM aPaM1;
     if ( bSelect )
@@ -458,15 +458,15 @@ void EditView::SetAttribs( const SfxItemSet& rSet )
 {
     DBG_ASSERT( !pImpEditView->aEditSelection.IsInvalid(), "Blind Selection in ...." );
 
-    pImpEditView->DrawSelection();
-    pImpEditView->pEditEngine->SetAttribs( pImpEditView->GetEditSelection(), rSet, ATTRSPECIAL_WHOLEWORD );
+    pImpEditView->DrawSelectionXOR();
+    pImpEditView->pEditEngine->SetAttribs( pImpEditView->GetEditSelection(), rSet, ATTRSPECIAL_WHOLEWORD);
     pImpEditView->pEditEngine->FormatAndUpdate( this );
 }
 
 void EditView::RemoveAttribsKeepLanguages( bool bRemoveParaAttribs )
 {
 
-    pImpEditView->DrawSelection();
+    pImpEditView->DrawSelectionXOR();
     pImpEditView->pEditEngine->UndoActionStart( EDITUNDO_RESETATTRIBS );
     EditSelection aSelection( pImpEditView->GetEditSelection() );
 
@@ -486,7 +486,7 @@ void EditView::RemoveAttribsKeepLanguages( bool bRemoveParaAttribs )
 void EditView::RemoveAttribs( bool bRemoveParaAttribs, sal_uInt16 nWhich )
 {
 
-    pImpEditView->DrawSelection();
+    pImpEditView->DrawSelectionXOR();
     pImpEditView->pEditEngine->UndoActionStart( EDITUNDO_RESETATTRIBS );
     pImpEditView->pEditEngine->RemoveCharAttribs( pImpEditView->GetEditSelection(), bRemoveParaAttribs, nWhich  );
     pImpEditView->pEditEngine->UndoActionEnd( EDITUNDO_RESETATTRIBS );
@@ -520,7 +520,7 @@ void EditView::Redo()
 sal_uInt32 EditView::Read( SvStream& rInput, const OUString& rBaseURL, EETextFormat eFormat, SvKeyValueIterator* pHTTPHeaderAttrs )
 {
     EditSelection aOldSel( pImpEditView->GetEditSelection() );
-    pImpEditView->DrawSelection();
+    pImpEditView->DrawSelectionXOR();
     pImpEditView->pEditEngine->pImpEditEngine->UndoActionStart( EDITUNDO_READ );
     EditPaM aEndPaM = pImpEditView->pEditEngine->pImpEditEngine->Read( rInput, rBaseURL, eFormat, aOldSel, pHTTPHeaderAttrs );
     pImpEditView->pEditEngine->pImpEditEngine->UndoActionEnd( EDITUNDO_READ );
@@ -631,7 +631,7 @@ EditTextObject* EditView::CreateTextObject()
 
 void EditView::InsertText( const EditTextObject& rTextObject )
 {
-    pImpEditView->DrawSelection();
+    pImpEditView->DrawSelectionXOR();
 
     pImpEditView->pEditEngine->UndoActionStart( EDITUNDO_INSERT );
     EditSelection aTextSel( pImpEditView->pEditEngine->InsertText( rTextObject, pImpEditView->GetEditSelection() ) );
@@ -714,9 +714,9 @@ void EditView::TransliterateText( sal_Int32 nTransliterationMode )
     EditSelection aNewSel = pImpEditView->pEditEngine->TransliterateText( pImpEditView->GetEditSelection(), nTransliterationMode );
     if ( aNewSel != aOldSel )
     {
-        pImpEditView->DrawSelection();
+        pImpEditView->DrawSelectionXOR();
         pImpEditView->SetEditSelection( aNewSel );
-        pImpEditView->DrawSelection();
+        pImpEditView->DrawSelectionXOR();
     }
 }
 
@@ -724,7 +724,7 @@ void EditView::CompleteAutoCorrect( vcl::Window* pFrameWin )
 {
     if ( !pImpEditView->HasSelection() && pImpEditView->pEditEngine->pImpEditEngine->GetStatus().DoAutoCorrect() )
     {
-        pImpEditView->DrawSelection();
+        pImpEditView->DrawSelectionXOR();
         EditSelection aSel = pImpEditView->GetEditSelection();
         aSel = pImpEditView->pEditEngine->EndOfWord( aSel.Max() );
         aSel = pImpEditView->pEditEngine->pImpEditEngine->AutoCorrect( aSel, 0, !IsInsertMode(), pFrameWin );
@@ -1009,9 +1009,9 @@ void EditView::ExecuteSpellPopup( const Point& rPosPixel, Link<SpellCallbackInfo
             {
                 // Set Cursor before word...
                 EditPaM aCursor = pImpEditView->GetEditSelection().Min();
-                pImpEditView->DrawSelection();
+                pImpEditView->DrawSelectionXOR();
                 pImpEditView->SetEditSelection( EditSelection( aCursor, aCursor ) );
-                pImpEditView->DrawSelection();
+                pImpEditView->DrawSelectionXOR();
                 // Crashes when no SfxApp
                 pImpEditView->pEditEngine->pImpEditEngine->Spell( this, false );
             }
@@ -1080,17 +1080,17 @@ void EditView::ExecuteSpellPopup( const Point& rPosPixel, Link<SpellCallbackInfo
 void EditView::SelectCurrentWord( sal_Int16 nWordType )
 {
     EditSelection aCurSel( pImpEditView->GetEditSelection() );
-    pImpEditView->DrawSelection();
+    pImpEditView->DrawSelectionXOR();
     aCurSel = pImpEditView->pEditEngine->SelectWord(aCurSel.Max(), nWordType);
     pImpEditView->SetEditSelection( aCurSel );
-    pImpEditView->DrawSelection();
+    pImpEditView->DrawSelectionXOR();
     ShowCursor( true, false );
 }
 
 void EditView::InsertField( const SvxFieldItem& rFld )
 {
     EditEngine* pEE = pImpEditView->pEditEngine;
-    pImpEditView->DrawSelection();
+    pImpEditView->DrawSelectionXOR();
     pEE->UndoActionStart( EDITUNDO_INSERT );
     EditPaM aPaM( pEE->InsertField( pImpEditView->GetEditSelection(), rFld ) );
     pEE->UndoActionEnd( EDITUNDO_INSERT );
@@ -1377,7 +1377,7 @@ void EditView::SetCursorLogicPosition(const Point& rPosition, bool bPoint, bool
 
     if (pImpEditView->GetEditSelection().Min() != aSelection.Min())
         pImpEditView->pEditEngine->CursorMoved(pImpEditView->GetEditSelection().Min().GetNode());
-    pImpEditView->DrawSelection(aSelection);
+    pImpEditView->DrawSelectionXOR(aSelection);
     if (pImpEditView->GetEditSelection() != aSelection)
         pImpEditView->SetEditSelection(aSelection);
     ShowCursor(/*bGotoCursor=*/false);
diff --git a/editeng/source/editeng/impedit.cxx b/editeng/source/editeng/impedit.cxx
index 82bfaeaebfa3..ff189f7e7c07 100644
--- a/editeng/source/editeng/impedit.cxx
+++ b/editeng/source/editeng/impedit.cxx
@@ -97,6 +97,8 @@ ImpEditView::ImpEditView( EditView* pView, EditEngine* pEng, vcl::Window* pWindo
 
     aEditSelection.Min() = pEng->GetEditDoc().GetStartPaM();
     aEditSelection.Max() = pEng->GetEditDoc().GetEndPaM();
+
+    SelectionChanged();
 }
 
 ImpEditView::~ImpEditView()
@@ -134,6 +136,8 @@ void ImpEditView::SetEditSelection( const EditSelection& rEditSelection )
     // set state before notification
     aEditSelection = rEditSelection;
 
+    SelectionChanged();
+
     if (comphelper::LibreOfficeKit::isActive())
         // Tiled rendering: selections are only painted when we are in selection mode.
         pEditEngine->SetInSelectionMode(aEditSelection.HasRange());
@@ -162,19 +166,20 @@ void ImpEditView::SetEditSelection( const EditSelection& rEditSelection )
 }
 
 
-void ImpEditView::DrawSelection( EditSelection aTmpSel, vcl::Region* pRegion, OutputDevice* pTargetDevice )
+// EditView never had a central/secure place to react on SelectionChange since
+// Selection was changed in many places, often by not using SetEditSelection()
+// but (mis)using GetEditSelection() and manipulating this non-const return
+// value. Sorted this out now to have such a place, this is needed for safely
+// change/update the Selection visualization for enhanced mechanisms
+void ImpEditView::SelectionChanged()
 {
-    if (hasEditViewCallbacks() && !pRegion)
+    if (hasEditViewCallbacks())
     {
-        // when we have an own mechanism for painting EditViews, collect the Selection
-        // in a basegfx::B2DRange vector and hand over. To do so, call GetSelectionRectangles
-        // which recursively calls ImpEditView::DrawSelection, but with nullptr != pRegion
         std::vector<Rectangle> aLogicRects;
         std::vector<basegfx::B2DRange> aLogicRanges;
-        OutputDevice* pTarget = pTargetDevice ? pTargetDevice : pOutWin;
-        const Point aPixel(pTarget ? pTarget->LogicToPixel(Point(1, 1)) : Point(1, 1));
+        const Size aLogicPixel(pOutWin ? pOutWin->PixelToLogic(Size(1, 1)) : Size(1, 1));
 
-        GetSelectionRectangles(aLogicRects);
+        GetSelectionRectangles(GetEditSelection(), aLogicRects);
 
         for (const auto& aRect : aLogicRects)
         {
@@ -183,12 +188,27 @@ void ImpEditView::DrawSelection( EditSelection aTmpSel, vcl::Region* pRegion, Ou
             aLogicRanges.push_back(
                 basegfx::B2DRange(
                     aRect.Left(), aRect.Top(),
-                    aRect.Right() + aPixel.X(), aRect.Bottom() + aPixel.Y()));
+                    aRect.Right() + aLogicPixel.Width(), aRect.Bottom() + aLogicPixel.Height()));
         }
 
         // use callback to tell about change in selection visualisation
         mpEditViewCallbacks->EditViewSelectionChange(aLogicRanges);
+    }
+}
 
+// renamed from DrawSelection to DrawSelectionXOR to better reflect what this
+// method was used for: Paint Selection in XOR, change it and again paint it in XOR.
+// This can be safely assumed due to the EditView only being capable of painting the
+// selection in XOR until today.
+// This also means that all places calling DrawSelectionXOR are thoroughly weighted
+// and choosen to make this fragile XOR-paint water-proof and thus contain some
+// information in this sense.
+// Someone thankfully expanded it to collect the SelectionRectangles when called with
+// the Region*, see GetSelectionRectangles below.
+void ImpEditView::DrawSelectionXOR( EditSelection aTmpSel, vcl::Region* pRegion, OutputDevice* pTargetDevice )
+{
+    if (hasEditViewCallbacks() && !pRegion)
+    {
         // we are done, do *not* visualize self
         return;
     }
@@ -240,7 +260,7 @@ void ImpEditView::DrawSelection( EditSelection aTmpSel, vcl::Region* pRegion, Ou
         pPolyPoly = new tools::PolyPolygon;
     }
 
-    DBG_ASSERT( !pEditEngine->IsIdleFormatterActive(), "DrawSelection: Not formatted!" );
+    DBG_ASSERT( !pEditEngine->IsIdleFormatterActive(), "DrawSelectionXOR: Not formatted!" );
     aTmpSel.Adjust( pEditEngine->GetEditDoc() );
 
     ContentNode* pStartNode = aTmpSel.Min().GetNode();
@@ -324,7 +344,7 @@ void ImpEditView::DrawSelection( EditSelection aTmpSel, vcl::Region* pRegion, Ou
                     if ( nTmpEndIndex > nEndIndex )
                         nTmpEndIndex = nEndIndex;
 
-                    DBG_ASSERT( nTmpEndIndex > nTmpStartIndex, "DrawSelection, Start >= End?" );
+                    DBG_ASSERT( nTmpEndIndex > nTmpStartIndex, "DrawSelectionXOR, Start >= End?" );
 
                     long nX1 = pEditEngine->GetXPos(pTmpPortion, &rLine, nTmpStartIndex, true);
                     long nX2 = pEditEngine->GetXPos(pTmpPortion, &rLine, nTmpEndIndex);
@@ -405,10 +425,10 @@ void ImpEditView::DrawSelection( EditSelection aTmpSel, vcl::Region* pRegion, Ou
     }
 }
 
-void ImpEditView::GetSelectionRectangles(std::vector<Rectangle>& rLogicRects)
+void ImpEditView::GetSelectionRectangles(EditSelection aTmpSel, std::vector<Rectangle>& rLogicRects)
 {
     vcl::Region aRegion;
-    DrawSelection(aEditSelection, &aRegion);
+    DrawSelectionXOR(aTmpSel, &aRegion);
     aRegion.GetRegionRectangles(rLogicRects);
 }
 
@@ -534,9 +554,9 @@ void ImpEditView::SetSelectionMode( EESelectionMode eNewMode )
 {
     if ( eSelectionMode != eNewMode )
     {
-        DrawSelection();
+        DrawSelectionXOR();
         eSelectionMode = eNewMode;
-        DrawSelection();    // redraw
+        DrawSelectionXOR();    // redraw
     }
 }
 
@@ -1271,9 +1291,9 @@ bool ImpEditView::IsWrongSpelledWord( const EditPaM& rPaM, bool bMarkIfWrong )
         bIsWrong = rPaM.GetNode()->GetWrongList()->HasWrong( aSel.Min().GetIndex(), aSel.Max().GetIndex() );
         if ( bIsWrong && bMarkIfWrong )
         {
-            DrawSelection();
+            DrawSelectionXOR();
             SetEditSelection( aSel );
-            DrawSelection();
+            DrawSelectionXOR();
         }
     }
     return bIsWrong;
@@ -1294,9 +1314,9 @@ OUString ImpEditView::SpellIgnoreWord()
         {
             aWord = pEditEngine->pImpEditEngine->GetSelected( GetEditSelection() );
             // And deselect
-            DrawSelection();
+            DrawSelectionXOR();
             SetEditSelection( EditSelection( aPaM, aPaM ) );
-            DrawSelection();
+            DrawSelectionXOR();
         }
 
         if ( !aWord.isEmpty() )
@@ -1320,7 +1340,7 @@ OUString ImpEditView::SpellIgnoreWord()
 
 void ImpEditView::DeleteSelected()
 {
-    DrawSelection();
+    DrawSelectionXOR();
 
     pEditEngine->pImpEditEngine->UndoActionStart( EDITUNDO_DELETE );
 
@@ -1457,7 +1477,7 @@ void ImpEditView::Paste( css::uno::Reference< css::datatransfer::clipboard::XCli
             EditSelection aSel( GetEditSelection() );
             if ( aSel.HasRange() )
             {
-                DrawSelection();
+                DrawSelectionXOR();
                 aSel = pEditEngine->DeleteSelection(aSel);
             }
 
@@ -1543,18 +1563,20 @@ bool ImpEditView::IsInSelection( const EditPaM& rPaM )
 void ImpEditView::CreateAnchor()
 {
     pEditEngine->SetInSelectionMode(true);
-    GetEditSelection().Min() = GetEditSelection().Max();
+    EditSelection aNewSelection(GetEditSelection());
+    aNewSelection.Min() = aNewSelection.Max();
+    SetEditSelection(aNewSelection);
+    // const_cast<EditPaM&>(GetEditSelection().Min()) = GetEditSelection().Max();
 }
 
 void ImpEditView::DeselectAll()
 {
     pEditEngine->SetInSelectionMode(false);
-    DrawSelection();
-    GetEditSelection().Min() = GetEditSelection().Max();
-
-    // Selection is empty, still need to draw it due to new forward selection
-    // functionality. When without that, nothing will be drawn (since it's empty)
-    DrawSelection();
+    DrawSelectionXOR();
+    EditSelection aNewSelection(GetEditSelection());
+    aNewSelection.Min() = aNewSelection.Max();
+    SetEditSelection(aNewSelection);
+    // const_cast<EditPaM&>(GetEditSelection().Min()) = GetEditSelection().Max();
 }
 
 bool ImpEditView::IsSelectionAtPoint( const Point& rPosPixel )
@@ -1615,7 +1637,7 @@ bool ImpEditView::SetCursorAtPoint( const Point& rPointPixel )
     }
     else
     {
-        DrawSelection( aTmpNewSel );
+        DrawSelectionXOR( aTmpNewSel );
     }
 
     // set changed text selection
@@ -1725,8 +1747,8 @@ void ImpEditView::dragGestureRecognized(const css::datatransfer::dnd::DragGestur
             pDragAndDropInfo->pField = pField;
             ContentNode* pNode = pEditEngine->GetEditDoc().GetObject( nPara );
             aCopySel = EditSelection( EditPaM( pNode, nPos ), EditPaM( pNode, nPos+1 ) );
-            GetEditSelection() = aCopySel;
-            DrawSelection();
+            SetEditSelection(aCopySel);
+            DrawSelectionXOR();
             bool bGotoCursor = DoAutoScroll();
             ShowCursor( bGotoCursor, /*bForceCursor=*/false );
         }
@@ -1841,7 +1863,7 @@ void ImpEditView::dragDropEnd( const css::datatransfer::dnd::DragSourceDropEvent
                     }
                 }
 
-                DrawSelection();
+                DrawSelectionXOR();
                 EditSelection aDelSel( pEditEngine->pImpEditEngine->CreateSel( aToBeDelSel ) );
                 DBG_ASSERT( !aDelSel.DbgIsBuggy( pEditEngine->GetEditDoc() ), "ToBeDel is buggy!" );
                 pEditEngine->DeleteSelection(aDelSel);
@@ -1851,7 +1873,7 @@ void ImpEditView::dragDropEnd( const css::datatransfer::dnd::DragSourceDropEvent
                     SetEditSelection( pEditEngine->pImpEditEngine->CreateSel( aNewSel ) );
                 }
                 pEditEngine->pImpEditEngine->FormatAndUpdate( pEditEngine->pImpEditEngine->GetActiveView() );
-                DrawSelection();
+                DrawSelectionXOR();
             }
             else
             {
@@ -1905,7 +1927,7 @@ void ImpEditView::drop( const css::datatransfer::dnd::DropTargetDropEvent& rDTDE
             {
                 bChanges = true;
                 // remove Selection ...
-                DrawSelection();
+                DrawSelectionXOR();
                 EditPaM aPaM( pDragAndDropInfo->aDropDest );
 
                 PasteOrDropInfos aPasteOrDropInfos;
diff --git a/editeng/source/editeng/impedit.hxx b/editeng/source/editeng/impedit.hxx
index b323ca026e68..94c3f26fd988 100644
--- a/editeng/source/editeng/impedit.hxx
+++ b/editeng/source/editeng/impedit.hxx
@@ -332,13 +332,14 @@ public:
     long            GetVisDocBottom() const { return aVisDocStartPos.Y() + ( !IsVertical() ? aOutArea.GetHeight() : aOutArea.GetWidth() ); }
     Rectangle       GetVisDocArea() const;
 
-    EditSelection&  GetEditSelection()          { return aEditSelection; }
+    const EditSelection&  GetEditSelection()          { return aEditSelection; }
     void            SetEditSelection( const EditSelection& rEditSelection );
     bool            HasSelection() const { return aEditSelection.HasRange(); }
 
-    void            DrawSelection() { DrawSelection( aEditSelection ); }
-    void            DrawSelection( EditSelection, vcl::Region* pRegion = nullptr, OutputDevice* pTargetDevice = nullptr );
-    void GetSelectionRectangles(std::vector<Rectangle>& rLogicRects);
+    void SelectionChanged();
+    void            DrawSelectionXOR() { DrawSelectionXOR( aEditSelection ); }
+    void            DrawSelectionXOR( EditSelection, vcl::Region* pRegion = nullptr, OutputDevice* pTargetDevice = nullptr );
+    void GetSelectionRectangles(EditSelection aTmpSel, std::vector<Rectangle>& rLogicRects);
 
     vcl::Window*    GetWindow() const           { return pOutWin; }
 
@@ -537,8 +538,8 @@ private:
     // Methods...
 
 
-    void                CursorMoved( ContentNode* pPrevNode );
-    void                ParaAttribsChanged( ContentNode* pNode );
+    void                CursorMoved( const ContentNode* pPrevNode );
+    void                ParaAttribsChanged( ContentNode const * pNode );
     void                TextModified();
     void                CalcHeight( ParaPortion* pPortion );
 
@@ -693,7 +694,7 @@ private:
     void                CheckIdleFormatter();
 
     inline const ParaPortion* FindParaPortion( const ContentNode* pNode ) const;
-    inline ParaPortion* FindParaPortion( ContentNode* pNode );
+    inline ParaPortion* FindParaPortion( ContentNode const * pNode );
 
     css::uno::Reference< css::datatransfer::XTransferable > CreateTransferable( const EditSelection& rSelection );
 
@@ -1147,7 +1148,7 @@ inline const ParaPortion* ImpEditEngine::FindParaPortion( const ContentNode* pNo
     return GetParaPortions()[ nPos ];
 }
 
-inline ParaPortion* ImpEditEngine::FindParaPortion( ContentNode* pNode )
+inline ParaPortion* ImpEditEngine::FindParaPortion( ContentNode const * pNode )
 {
     sal_Int32 nPos = aEditDoc.GetPos( pNode );
     DBG_ASSERT( nPos < GetParaPortions().Count(), "Portionloser Node?" );
diff --git a/editeng/source/editeng/impedit2.cxx b/editeng/source/editeng/impedit2.cxx
index a51c9e475b16..e90aa8f594ab 100644
--- a/editeng/source/editeng/impedit2.cxx
+++ b/editeng/source/editeng/impedit2.cxx
@@ -313,9 +313,9 @@ bool ImpEditEngine::MouseButtonDown( const MouseEvent& rMEvt, EditView* pView )
             aSelEngine.CursorPosChanging( true, false );
 
             EditSelection aNewSelection( SelectWord( aCurSel ) );
-            pView->pImpEditView->DrawSelection();
+            pView->pImpEditView->DrawSelectionXOR();
             pView->pImpEditView->SetEditSelection( aNewSelection );
-            pView->pImpEditView->DrawSelection();
+            pView->pImpEditView->DrawSelectionXOR();
             pView->ShowCursor();
         }
         else if ( rMEvt.GetClicks() == 3 )
@@ -326,9 +326,9 @@ bool ImpEditEngine::MouseButtonDown( const MouseEvent& rMEvt, EditView* pView )
             EditSelection aNewSelection( aCurSel );
             aNewSelection.Min().SetIndex( 0 );
             aNewSelection.Max().SetIndex( aCurSel.Min().GetNode()->Len() );
-            pView->pImpEditView->DrawSelection();
+            pView->pImpEditView->DrawSelectionXOR();
             pView->pImpEditView->SetEditSelection( aNewSelection );
-            pView->pImpEditView->DrawSelection();
+            pView->pImpEditView->DrawSelectionXOR();
             pView->ShowCursor();
         }
     }
@@ -688,11 +688,13 @@ const SfxItemSet& ImpEditEngine::GetEmptyItemSet()
 
 //  MISC
 
-void ImpEditEngine::CursorMoved( ContentNode* pPrevNode )
+void ImpEditEngine::CursorMoved( const ContentNode* pPrevNode )
 {
     // Delete empty attributes, but only if paragraph is not empty!
-    if ( pPrevNode->GetCharAttribs().HasEmptyAttribs() && pPrevNode->Len() )
-        pPrevNode->GetCharAttribs().DeleteEmptyAttribs( aEditDoc.GetItemPool() );
+    if (pPrevNode->GetCharAttribs().HasEmptyAttribs() && pPrevNode->Len())
+    {
+        const_cast<ContentNode*>(pPrevNode)->GetCharAttribs().DeleteEmptyAttribs(aEditDoc.GetItemPool());
+    }
 }
 
 void ImpEditEngine::TextModified()
@@ -708,7 +710,7 @@ void ImpEditEngine::TextModified()
 }
 
 
-void ImpEditEngine::ParaAttribsChanged( ContentNode* pNode )
+void ImpEditEngine::ParaAttribsChanged(ContentNode const * pNode)
 {
     assert(pNode && "ParaAttribsChanged: Which one?");
 
@@ -891,15 +893,27 @@ EditSelection ImpEditEngine::MoveCursor( const KeyEvent& rKeyEvent, EditView* pE
     aSelEngine.SetCurView( pEditView );
     aSelEngine.CursorPosChanging( bKeyModifySelection, aTranslatedKeyEvent.GetKeyCode().IsMod1() );
     EditPaM aOldEnd( pEditView->pImpEditView->GetEditSelection().Max() );
-    pEditView->pImpEditView->GetEditSelection().Max() = aPaM;
+
+    {
+        EditSelection aNewSelection(pEditView->pImpEditView->GetEditSelection());
+        aNewSelection.Max() = aPaM;
+        pEditView->pImpEditView->SetEditSelection(aNewSelection);
+        // const_cast<EditPaM&>(pEditView->pImpEditView->GetEditSelection().Max()) = aPaM;
+    }
+
     if ( bKeyModifySelection )
     {
         // Then the selection is expanded ... or the whole selection is painted in case of tiled rendering.
         EditSelection aTmpNewSel( comphelper::LibreOfficeKit::isActive() ? pEditView->pImpEditView->GetEditSelection().Min() : aOldEnd, aPaM );
-        pEditView->pImpEditView->DrawSelection( aTmpNewSel );
+        pEditView->pImpEditView->DrawSelectionXOR( aTmpNewSel );
     }
     else
-        pEditView->pImpEditView->GetEditSelection().Min() = aPaM;
+    {
+        EditSelection aNewSelection(pEditView->pImpEditView->GetEditSelection());
+        aNewSelection.Min() = aPaM;
+        pEditView->pImpEditView->SetEditSelection(aNewSelection);
+        // const_cast<EditPaM&>(pEditView->pImpEditView->GetEditSelection().Min()) = aPaM;
+    }
 
     return pEditView->pImpEditView->GetEditSelection();
 }
@@ -3379,12 +3393,12 @@ void ImpEditEngine::SetActiveView( EditView* pView )
         return;
 
     if ( pActiveView && pActiveView->HasSelection() )
-        pActiveView->pImpEditView->DrawSelection();
+        pActiveView->pImpEditView->DrawSelectionXOR();
 
     pActiveView = pView;
 
     if ( pActiveView && pActiveView->HasSelection() )
-        pActiveView->pImpEditView->DrawSelection();
+        pActiveView->pImpEditView->DrawSelectionXOR();
 
     //  NN: Quick fix for #78668#:
     //  When editing of a cell in Calc is ended, the edit engine is not deleted,
@@ -4227,7 +4241,7 @@ void ImpEditEngine::IndentBlock( EditView* pEditView, bool bRight )
             aNewSel.nEndPos = 0;
         }
 
-        pEditView->pImpEditView->DrawSelection();
+        pEditView->pImpEditView->DrawSelectionXOR();
         pEditView->pImpEditView->SetEditSelection(
                         pEditView->pImpEditView->GetEditSelection().Max() );
         UndoActionStart( bRight ? EDITUNDO_INDENTBLOCK : EDITUNDO_UNINDENTBLOCK );
@@ -4263,7 +4277,7 @@ void ImpEditEngine::IndentBlock( EditView* pEditView, bool bRight )
         if ( pLastNode->Len() < aNewSel.nEndPos )
             aNewSel.nEndPos = pLastNode->Len();
         pEditView->pImpEditView->SetEditSelection( CreateSel( aNewSel ) );
-        pEditView->pImpEditView->DrawSelection();
+        pEditView->pImpEditView->DrawSelectionXOR();
         pEditView->pImpEditView->ShowCursor( false, true );
     }
 }
diff --git a/editeng/source/editeng/impedit3.cxx b/editeng/source/editeng/impedit3.cxx
index 7ba4d98d0ec4..262c727e9e51 100644
--- a/editeng/source/editeng/impedit3.cxx
+++ b/editeng/source/editeng/impedit3.cxx
@@ -3726,10 +3726,10 @@ void ImpEditEngine::Paint( ImpEditView* pView, const Rectangle& rRect, OutputDev
     else
         pTarget->SetClipRegion();
 
-    // In case of tiled rendering pass a region to DrawSelection(), so that
+    // In case of tiled rendering pass a region to DrawSelectionXOR(), so that
     // selection callbacks are not emitted during every repaint.
     vcl::Region aRegion;
-    pView->DrawSelection(pView->GetEditSelection(), comphelper::LibreOfficeKit::isActive() ? &aRegion : nullptr, pTarget);
+    pView->DrawSelectionXOR(pView->GetEditSelection(), comphelper::LibreOfficeKit::isActive() ? &aRegion : nullptr, pTarget);
 }
 
 void ImpEditEngine::InsertContent( ContentNode* pNode, sal_Int32 nPos )
diff --git a/editeng/source/editeng/impedit4.cxx b/editeng/source/editeng/impedit4.cxx
index ec4a36aa2ec5..07b0fafe91e6 100644
--- a/editeng/source/editeng/impedit4.cxx
+++ b/editeng/source/editeng/impedit4.cxx
@@ -1505,12 +1505,12 @@ EESpellState ImpEditEngine::Spell( EditView* pEditView, bool bMultipleDoc )
 
     if ( !bMultipleDoc )
     {
-        pEditView->pImpEditView->DrawSelection();
+        pEditView->pImpEditView->DrawSelectionXOR();
         if ( aCurSel.Max().GetIndex() > aCurSel.Max().GetNode()->Len() )
             aCurSel.Max().SetIndex( aCurSel.Max().GetNode()->Len() );
         aCurSel.Min() = aCurSel.Max();
         pEditView->pImpEditView->SetEditSelection( aCurSel );
-        pEditView->pImpEditView->DrawSelection();
+        pEditView->pImpEditView->DrawSelectionXOR();
         pEditView->ShowCursor( true, false );
     }
     EESpellState eState = pSpellInfo->eState;
@@ -1630,12 +1630,12 @@ void ImpEditEngine::Convert( EditView* pEditView,
 
     if ( !bMultipleDoc )
     {
-        pEditView->pImpEditView->DrawSelection();
+        pEditView->pImpEditView->DrawSelectionXOR();
         if ( aCurSel.Max().GetIndex() > aCurSel.Max().GetNode()->Len() )
             aCurSel.Max().SetIndex( aCurSel.Max().GetNode()->Len() );
         aCurSel.Min() = aCurSel.Max();
         pEditView->pImpEditView->SetEditSelection( aCurSel );
-        pEditView->pImpEditView->DrawSelection();
+        pEditView->pImpEditView->DrawSelectionXOR();
         pEditView->ShowCursor( true, false );
     }
     delete pConvInfo;
@@ -1833,9 +1833,9 @@ void ImpEditEngine::ImpConvert( OUString &rConvTxt, LanguageType &rConvTxtLang,
         pConvInfo->aConvContinue = CreateEPaM( aCurSel.Max() );
     }
 
-    pEditView->pImpEditView->DrawSelection();
+    pEditView->pImpEditView->DrawSelectionXOR();
     pEditView->pImpEditView->SetEditSelection( aCurSel );
-    pEditView->pImpEditView->DrawSelection();
+    pEditView->pImpEditView->DrawSelectionXOR();
     pEditView->ShowCursor( true, false );
 
     rConvTxt = aRes;
@@ -1903,9 +1903,9 @@ Reference< XSpellAlternatives > ImpEditEngine::ImpSpell( EditView* pEditView )
             pSpellInfo->eState = EE_SPELL_ERRORFOUND;
     }
 
-    pEditView->pImpEditView->DrawSelection();
+    pEditView->pImpEditView->DrawSelectionXOR();
     pEditView->pImpEditView->SetEditSelection( aCurSel );
-    pEditView->pImpEditView->DrawSelection();
+    pEditView->pImpEditView->DrawSelectionXOR();
     pEditView->ShowCursor( true, false );
     return xSpellAlt;
 }
@@ -2496,9 +2496,9 @@ EESpellState ImpEditEngine::StartThesaurus( EditView* pEditView )
     if (xDlg->Execute() == RET_OK)
     {
         // Replace Word...
-        pEditView->pImpEditView->DrawSelection();
+        pEditView->pImpEditView->DrawSelectionXOR();
         pEditView->pImpEditView->SetEditSelection( aCurSel );
-        pEditView->pImpEditView->DrawSelection();
+        pEditView->pImpEditView->DrawSelectionXOR();
         pEditView->InsertText(xDlg->GetWord());
         pEditView->ShowCursor(true, false);
     }
@@ -2538,7 +2538,7 @@ sal_Int32 ImpEditEngine::StartSearchAndReplace( EditView* pEditView, const SvxSe
         SvxSearchItem aTmpItem( rSearchItem );
         aTmpItem.SetBackward( false );
 
-        pEditView->pImpEditView->DrawSelection();
+        pEditView->pImpEditView->DrawSelectionXOR();
 
         aCurSel.Adjust( aEditDoc );
         EditPaM aStartPaM = aTmpItem.GetSelection() ? aCurSel.Min() : aEditDoc.GetStartPaM();
@@ -2563,7 +2563,7 @@ sal_Int32 ImpEditEngine::StartSearchAndReplace( EditView* pEditView, const SvxSe
         }
         else
         {
-            pEditView->pImpEditView->DrawSelection();
+            pEditView->pImpEditView->DrawSelectionXOR();
             pEditView->ShowCursor( true, false );
         }
     }
@@ -2586,7 +2586,7 @@ bool ImpEditEngine::Search( const SvxSearchItem& rSearchItem, EditView* pEditVie
         bFound = ImpSearch( rSearchItem, aSel, aStartPaM, aFoundSel );
     }
 
-    pEditView->pImpEditView->DrawSelection();
+    pEditView->pImpEditView->DrawSelectionXOR();
     if ( bFound )
     {
         // First, set the minimum, so the whole word is in the visible range.
@@ -2597,7 +2597,7 @@ bool ImpEditEngine::Search( const SvxSearchItem& rSearchItem, EditView* pEditVie
     else
         pEditView->pImpEditView->SetEditSelection( aSel.Max() );
 
-    pEditView->pImpEditView->DrawSelection();
+    pEditView->pImpEditView->DrawSelectionXOR();
     pEditView->ShowCursor( true, false );
     return bFound;
 }
diff --git a/include/editeng/editeng.hxx b/include/editeng/editeng.hxx
index 382d3d40a080..50df6d3d29bc 100644
--- a/include/editeng/editeng.hxx
+++ b/include/editeng/editeng.hxx
@@ -160,11 +160,11 @@ private:
                        EditEngine&     operator=( const EditEngine& ) = delete;
     EDITENG_DLLPRIVATE bool            PostKeyEvent( const KeyEvent& rKeyEvent, EditView* pView, vcl::Window* pFrameWin = nullptr );
 
-    EDITENG_DLLPRIVATE void CursorMoved(ContentNode* pPrevNode);
+    EDITENG_DLLPRIVATE void CursorMoved(const ContentNode* pPrevNode);
     EDITENG_DLLPRIVATE void CheckIdleFormatter();
     EDITENG_DLLPRIVATE bool IsIdleFormatterActive() const;
-    EDITENG_DLLPRIVATE ParaPortion* FindParaPortion(ContentNode* pNode);
-    EDITENG_DLLPRIVATE const ParaPortion* FindParaPortion(ContentNode* pNode) const;
+    EDITENG_DLLPRIVATE ParaPortion* FindParaPortion(ContentNode const * pNode);
+    EDITENG_DLLPRIVATE const ParaPortion* FindParaPortion(ContentNode const * pNode) const;
     EDITENG_DLLPRIVATE const ParaPortion* GetPrevVisPortion(const ParaPortion* pCurPortion) const;
 
     EDITENG_DLLPRIVATE css::uno::Reference<
diff --git a/include/editeng/editview.hxx b/include/editeng/editview.hxx
index f3f85a990004..0fdb6f95be5f 100644
--- a/include/editeng/editview.hxx
+++ b/include/editeng/editview.hxx
@@ -54,6 +54,7 @@ class SfxStyleSheet;
 namespace vcl { class Font; }
 class FontList;
 class OutputDevice;
+class OutlinerViewShell;
 
 #include <editeng/editdata.hxx>
 #include <com/sun/star/uno/Reference.h>
diff --git a/svx/source/svdraw/svdedxv.cxx b/svx/source/svdraw/svdedxv.cxx
index 78560b5fd9e3..08f5e9542a74 100644
--- a/svx/source/svdraw/svdedxv.cxx
+++ b/svx/source/svdraw/svdedxv.cxx
@@ -1079,9 +1079,6 @@ bool SdrObjEditView::SdrBeginTextEdit(
                             rtl::Reference< sdr::overlay::OverlayManager > xManager = rPageWindow.GetOverlayManager();
                             if (xManager.is())
                             {
-                                const basegfx::B2DRange aMinTEArea(
-                                    aMinTextEditArea.Left(), aMinTextEditArea.Top(),
-                                    aMinTextEditArea.Right(), aMinTextEditArea.Bottom());
                                 const std::vector< basegfx::B2DRange > aEmptySelection;
 
                                 sdr::overlay::OverlaySelection* pNewOverlaySelection = new sdr::overlay::OverlaySelection(
commit 2662c11294cef950204b798333b4cd2e9c2ddcb3
Author: Armin Le Grand <Armin.Le.Grand at cib.de>
Date:   Fri Aug 4 18:56:43 2017 +0200

    editviewoverlay: Allow EditView to run in Overlay
    
    This is the first basic functionality to get the active
    EditView with EditEngine work in the Overlay which all
    Apps support. Reason is that the current EditEngine 'plugs'
    into the Window and uses Invalidate() calls to repaint
    deeply everything under a text change. While this is
    acceptable for simple cases it can get very slow when
    there are excessive, expensive to paint objects in the
    background, e.g. MasterPages in Draw/Impress with gradients
    and other stuff. This was avoided in older versions (LO51)
    by 'guessing' a good BackgrundColor by the EditEngine,
    not invalidating but painting actively using that guess
    (with better or worse results) which someone removed.
    For the future it is anyways the better way to get the
    EditEngine functionality to Overlay and using Primitives,
    this will be a first step. This may enable Text Editing
    without repainting the Background (fast), using a non-XOR
    selection paint and more. It will need thorough testing
    and further experimenting due to EditEngine being used in
    many places (DrawObjects, Calc Cells, Formular Fields,
    Controls, ...)
    
    Change-Id: Ib9eb0f3999fd61a82ddf7a60ab1ea6ccda3a60da

diff --git a/editeng/source/editeng/editview.cxx b/editeng/source/editeng/editview.cxx
index 609f1d032ae4..d7db92bf6039 100644
--- a/editeng/source/editeng/editview.cxx
+++ b/editeng/source/editeng/editview.cxx
@@ -151,8 +151,12 @@ LanguageType EditView::CheckLanguage(
     return nLang;
 }
 
-// class EditView
+// class EditViewCallbacks
+EditViewCallbacks::~EditViewCallbacks()
+{
+}
 
+// class EditView
 EditView::EditView( EditEngine* pEng, vcl::Window* pWindow )
 {
     pImpEditView = new ImpEditView( this, pEng, pWindow );
@@ -163,6 +167,16 @@ EditView::~EditView()
     delete pImpEditView;
 }
 
+void EditView::setEditViewCallbacks(const EditViewCallbacks* pEditViewCallbacks)
+{
+    pImpEditView->setEditViewCallbacks(pEditViewCallbacks);
+}
+
+bool EditView::hasEditViewCallbacks() const
+{
+    return pImpEditView->hasEditViewCallbacks();
+}
+
 ImpEditEngine* EditView::GetImpEditEngine() const
 {
     return pImpEditView->pEditEngine->pImpEditEngine;
@@ -189,6 +203,23 @@ void EditView::Invalidate()
     }
 }
 
+void EditView::InvalidateWindow(const Rectangle& rClipRect)
+{
+    if (pImpEditView->hasEditViewCallbacks())
+    {
+        // do not invalidate and trigger a global repaint, but forward
+        // the need for change to the applied EditViewCallback, can e.g.
+        // be used to visualize the active edit text in an OverlayObject
+        pImpEditView->mpEditViewCallbacks->EditViewInvalidate();
+    }
+    else
+    {
+        // classic mode: invalidate and trigger full repaint
+        // of the changed area
+        GetWindow()->Invalidate(rClipRect);
+    }
+}
+
 void EditView::SetReadOnly( bool bReadOnly )
 {
     pImpEditView->bReadOnly = bReadOnly;
diff --git a/editeng/source/editeng/impedit.cxx b/editeng/source/editeng/impedit.cxx
index 13d98c05a010..82bfaeaebfa3 100644
--- a/editeng/source/editeng/impedit.cxx
+++ b/editeng/source/editeng/impedit.cxx
@@ -89,6 +89,7 @@ ImpEditView::ImpEditView( EditView* pView, EditEngine* pEng, vcl::Window* pWindo
     bClickedInSelection = false;
     eSelectionMode      = EE_SELMODE_TXTONLY;
     eAnchorMode         = ANCHOR_TOP_LEFT;
+    mpEditViewCallbacks = nullptr;
     nInvMore            = 1;
     nTravelXPos         = TRAVEL_X_DONTKNOW;
     nControl            = EVControlBits::AUTOSCROLL | EVControlBits::ENABLEPASTE;
@@ -163,7 +164,36 @@ void ImpEditView::SetEditSelection( const EditSelection& rEditSelection )
 
 void ImpEditView::DrawSelection( EditSelection aTmpSel, vcl::Region* pRegion, OutputDevice* pTargetDevice )
 {
-    if ( GetSelectionMode() == EE_SELMODE_HIDDEN )
+    if (hasEditViewCallbacks() && !pRegion)
+    {
+        // when we have an own mechanism for painting EditViews, collect the Selection
+        // in a basegfx::B2DRange vector and hand over. To do so, call GetSelectionRectangles
+        // which recursively calls ImpEditView::DrawSelection, but with nullptr != pRegion
+        std::vector<Rectangle> aLogicRects;
+        std::vector<basegfx::B2DRange> aLogicRanges;
+        OutputDevice* pTarget = pTargetDevice ? pTargetDevice : pOutWin;
+        const Point aPixel(pTarget ? pTarget->LogicToPixel(Point(1, 1)) : Point(1, 1));
+
+        GetSelectionRectangles(aLogicRects);
+
+        for (const auto& aRect : aLogicRects)
+        {
+            // convert from logic Rectangles to logic Ranges, do not forget to add
+            // one Unit (in this case logical unit, thus calculate first)
+            aLogicRanges.push_back(
+                basegfx::B2DRange(
+                    aRect.Left(), aRect.Top(),
+                    aRect.Right() + aPixel.X(), aRect.Bottom() + aPixel.Y()));
+        }
+
+        // use callback to tell about change in selection visualisation
+        mpEditViewCallbacks->EditViewSelectionChange(aLogicRanges);
+
+        // we are done, do *not* visualize self
+        return;
+    }
+
+    if (GetSelectionMode() == EE_SELMODE_HIDDEN)
         return;
 
     // It must be ensured before rendering the selection, that the contents of
@@ -377,16 +407,9 @@ void ImpEditView::DrawSelection( EditSelection aTmpSel, vcl::Region* pRegion, Ou
 
 void ImpEditView::GetSelectionRectangles(std::vector<Rectangle>& rLogicRects)
 {
-    bool bMm100ToTwip = pOutWin->GetMapMode().GetMapUnit() == MAP_100TH_MM;
     vcl::Region aRegion;
     DrawSelection(aEditSelection, &aRegion);
     aRegion.GetRegionRectangles(rLogicRects);
-
-    for (Rectangle& rRectangle : rLogicRects)
-    {
-        if (bMm100ToTwip)
-            rRectangle = OutputDevice::LogicToLogic(rRectangle, MAP_100TH_MM, MAP_TWIP);
-    }
 }
 
 void ImpEditView::ImplDrawHighlightRect( OutputDevice* _pTarget, const Point& rDocPosTopLeft, const Point& rDocPosBottomRight, tools::PolyPolygon* pPolyPoly )
@@ -534,6 +557,23 @@ void ImpEditView::SetOutputArea( const Rectangle& rRect )
         SetScrollDiffX( (sal_uInt16)aOutArea.GetWidth() * 2 / 10 );
 }
 
+void ImpEditView::InvalidateAtWindow(const Rectangle& rRect)
+{
+    if (hasEditViewCallbacks())
+    {
+        // do not invalidate and trigger a global repaint, but forward
+        // the need for change to the applied EditViewCallback, can e.g.
+        // be used to visualize the active edit text in an OverlayObject
+        mpEditViewCallbacks->EditViewInvalidate();
+    }
+    else
+    {
+        // classic mode: invalidate and trigger full repaint
+        // of the changed area
+        GetWindow()->Invalidate(rRect);
+    }
+}
+
 void ImpEditView::ResetOutputArea( const Rectangle& rRect )
 {
     // remember old out area
@@ -550,38 +590,46 @@ void ImpEditView::ResetOutputArea( const Rectangle& rRect )
 
         if(aOldArea.Left() > aOutArea.Left())
         {
-            GetWindow()->Invalidate(Rectangle(aOutArea.Left() - nMore, aOldArea.Top() - nMore, aOldArea.Left(), aOldArea.Bottom() + nMore));
+            const Rectangle aRect(aOutArea.Left() - nMore, aOldArea.Top() - nMore, aOldArea.Left(), aOldArea.Bottom() + nMore);
+            InvalidateAtWindow(aRect);
         }
         else if(aOldArea.Left() < aOutArea.Left())
         {
-            GetWindow()->Invalidate(Rectangle(aOldArea.Left() - nMore, aOldArea.Top() - nMore, aOutArea.Left(), aOldArea.Bottom() + nMore));
+            const Rectangle aRect(aOldArea.Left() - nMore, aOldArea.Top() - nMore, aOutArea.Left(), aOldArea.Bottom() + nMore);
+            InvalidateAtWindow(aRect);
         }
 
         if(aOldArea.Right() > aOutArea.Right())
         {
-            GetWindow()->Invalidate(Rectangle(aOutArea.Right(), aOldArea.Top() - nMore, aOldArea.Right() + nMore, aOldArea.Bottom() + nMore));
+            const Rectangle aRect(aOutArea.Right(), aOldArea.Top() - nMore, aOldArea.Right() + nMore, aOldArea.Bottom() + nMore);
+            InvalidateAtWindow(aRect);
         }
         else if(aOldArea.Right() < aOutArea.Right())
         {
-            GetWindow()->Invalidate(Rectangle(aOldArea.Right(), aOldArea.Top() - nMore, aOutArea.Right() + nMore, aOldArea.Bottom() + nMore));
+            const Rectangle aRect(aOldArea.Right(), aOldArea.Top() - nMore, aOutArea.Right() + nMore, aOldArea.Bottom() + nMore);
+            InvalidateAtWindow(aRect);
         }
 
         if(aOldArea.Top() > aOutArea.Top())
         {
-            GetWindow()->Invalidate(Rectangle(aOldArea.Left() - nMore, aOutArea.Top() - nMore, aOldArea.Right() + nMore, aOldArea.Top()));
+            const Rectangle aRect(aOldArea.Left() - nMore, aOutArea.Top() - nMore, aOldArea.Right() + nMore, aOldArea.Top());
+            InvalidateAtWindow(aRect);
         }
         else if(aOldArea.Top() < aOutArea.Top())
         {
-            GetWindow()->Invalidate(Rectangle(aOldArea.Left() - nMore, aOldArea.Top() - nMore, aOldArea.Right() + nMore, aOutArea.Top()));
+            const Rectangle aRect(aOldArea.Left() - nMore, aOldArea.Top() - nMore, aOldArea.Right() + nMore, aOutArea.Top());
+            InvalidateAtWindow(aRect);
         }
 
         if(aOldArea.Bottom() > aOutArea.Bottom())
         {
-            GetWindow()->Invalidate(Rectangle(aOldArea.Left() - nMore, aOutArea.Bottom(), aOldArea.Right() + nMore, aOldArea.Bottom() + nMore));
+            const Rectangle aRect(aOldArea.Left() - nMore, aOutArea.Bottom(), aOldArea.Right() + nMore, aOldArea.Bottom() + nMore);
+            InvalidateAtWindow(aRect);
         }
         else if(aOldArea.Bottom() < aOutArea.Bottom())
         {
-            GetWindow()->Invalidate(Rectangle(aOldArea.Left() - nMore, aOldArea.Bottom(), aOldArea.Right() + nMore, aOutArea.Bottom() + nMore));
+            const Rectangle aRect(aOldArea.Left() - nMore, aOldArea.Bottom(), aOldArea.Right() + nMore, aOutArea.Bottom() + nMore);
+            InvalidateAtWindow(aRect);
         }
     }
 }
@@ -1503,6 +1551,10 @@ void ImpEditView::DeselectAll()
     pEditEngine->SetInSelectionMode(false);
     DrawSelection();
     GetEditSelection().Min() = GetEditSelection().Max();
+
+    // Selection is empty, still need to draw it due to new forward selection
+    // functionality. When without that, nothing will be drawn (since it's empty)
+    DrawSelection();
 }
 
 bool ImpEditView::IsSelectionAtPoint( const Point& rPosPixel )
diff --git a/editeng/source/editeng/impedit.hxx b/editeng/source/editeng/impedit.hxx
index 0a1ac52911e3..b323ca026e68 100644
--- a/editeng/source/editeng/impedit.hxx
+++ b/editeng/source/editeng/impedit.hxx
@@ -247,6 +247,27 @@ private:
     EditSelection       aEditSelection;
     EVAnchorMode        eAnchorMode;
 
+    /// mechanism to change from the classic refresh mode that simply
+    // invalidates the area where text was changed. When set, the invalidate
+    // and the direct repaint of the Window-plugged EditView will be suppressed.
+    // Instead, a consumer that has registered using a EditViewCallbacks
+    // incarnation has to handle that. Used e.g. to represent the edited text
+    // in Draw/Impres in an OverlayObject which avoids evtl. expensive full
+    // repaints of the EditView(s)
+    const EditViewCallbacks* mpEditViewCallbacks;
+
+    bool hasEditViewCallbacks() const
+    {
+        return nullptr != mpEditViewCallbacks;
+    }
+
+    void setEditViewCallbacks(const EditViewCallbacks* pEditViewCallbacks)
+    {
+        mpEditViewCallbacks = pEditViewCallbacks;
+    }
+
+    void InvalidateAtWindow(const Rectangle& rRect);
+
 protected:
 
     // DragAndDropClient
diff --git a/editeng/source/editeng/impedit3.cxx b/editeng/source/editeng/impedit3.cxx
index 0f75baa2ab83..7ba4d98d0ec4 100644
--- a/editeng/source/editeng/impedit3.cxx
+++ b/editeng/source/editeng/impedit3.cxx
@@ -288,7 +288,9 @@ void ImpEditEngine::UpdateViews( EditView* pCurView )
         {
             // convert to window coordinates ....
             aClipRect = pView->pImpEditView->GetWindowPos( aClipRect );
-            pView->GetWindow()->Invalidate( aClipRect );
+
+            // moved to one executing method to allow finer control
+            pView->InvalidateWindow(aClipRect);
         }
     }
 
diff --git a/include/editeng/editview.hxx b/include/editeng/editview.hxx
index 163ea7c6653c..f3f85a990004 100644
--- a/include/editeng/editview.hxx
+++ b/include/editeng/editview.hxx
@@ -70,6 +70,7 @@ namespace linguistic2 {
     class XLanguageGuessing;
 }
 }}}
+namespace basegfx { class B2DRange; }
 
 enum class ScrollRangeCheck
 {
@@ -78,6 +79,21 @@ enum class ScrollRangeCheck
     PaperWidthTextSize = 2,   // VisArea must be within paper width, Text Size
 };
 
+// Helper class that allows to set a callback at the EditView. When
+// set, Invalidates and repains are suppressed at the EditView, but
+// EditViewInvalidate() will be triggered to allow the consumer to
+// react itself as needed.
+// Also Selection visualization is suppressed and EditViewSelectionChange
+// is triggered when Selection changes and needs reaction.
+class EDITENG_DLLPUBLIC EditViewCallbacks
+{
+public:
+    EditViewCallbacks() {}
+    virtual ~EditViewCallbacks();
+
+    virtual void EditViewInvalidate() const = 0;
+    virtual void EditViewSelectionChange(const std::vector<basegfx::B2DRange>& rLogicRanges) const = 0;
+};
 
 class EDITENG_DLLPUBLIC EditView
 {
@@ -100,6 +116,10 @@ public:
                     EditView( EditEngine* pEng, vcl::Window* pWindow );
     virtual         ~EditView();
 
+    // set EditViewCallbacks for external handling of Repaints/Visualization
+    void setEditViewCallbacks(const EditViewCallbacks* pEditViewCallbacks);
+    bool hasEditViewCallbacks() const;
+
     void            SetEditEngine( EditEngine* pEditEngine );
     EditEngine*     GetEditEngine() const;
 
@@ -107,6 +127,8 @@ public:
     vcl::Window*         GetWindow() const;
 
     void            Paint( const Rectangle& rRect, OutputDevice* pTargetDevice = nullptr );
+    Rectangle       GetInvalidateRect() const;
+    void            InvalidateWindow(const Rectangle& rClipRect);
     void            Invalidate();
     Pair            Scroll( long nHorzScroll, long nVertScroll, ScrollRangeCheck nRangeCheck = ScrollRangeCheck::NoNegative );
 
diff --git a/include/svx/svdedxv.hxx b/include/svx/svdedxv.hxx
index 519ba6eb5e2e..090f34994f58 100644
--- a/include/svx/svdedxv.hxx
+++ b/include/svx/svdedxv.hxx
@@ -25,6 +25,7 @@
 #include <svx/svxdllapi.h>
 #include <svx/svdglev.hxx>
 #include <svx/selectioncontroller.hxx>
+#include <editeng/editview.hxx>
 #include <memory>
 
 class SdrOutliner;
@@ -55,11 +56,20 @@ enum SdrEndTextEditKind {SDRENDTEXTEDIT_UNCHANGED, // textobject unchanged
 // - macromod
 
 
-class SVX_DLLPUBLIC SdrObjEditView: public SdrGlueEditView
+class SVX_DLLPUBLIC SdrObjEditView: public SdrGlueEditView, public EditViewCallbacks
 {
     friend class                SdrPageView;
     friend class                ImpSdrEditPara;
 
+    // Now derived from EditViewCallbacks and overriding these callbacks to
+    // allow own EditText visualization
+    virtual void EditViewInvalidate() const override;
+    virtual void EditViewSelectionChange(const std::vector<basegfx::B2DRange>& rLogicRanges) const override;
+
+    // The OverlayObjects used for visualizing active TextEdit (currently
+    // using TextEditOverlayObject, but not limitied to it
+    sdr::overlay::OverlayObjectList           maTEOverlayGroup;
+
 protected:
     // TextEdit
     SdrObjectWeakRef            mxTextEditObj;         // current object in TextEdit
diff --git a/include/svx/svdotext.hxx b/include/svx/svdotext.hxx
index 2adf9949ed1c..692d3b036979 100644
--- a/include/svx/svdotext.hxx
+++ b/include/svx/svdotext.hxx
@@ -616,11 +616,19 @@ public:
         const drawinglayer::geometry::ViewInformation2D& aViewInformation) const;
     void impHandleChainingEventsDuringDecomposition(SdrOutliner &rOutliner) const;
 
-
     // timing generators
     void impGetBlinkTextTiming(drawinglayer::animation::AnimationEntryList& rAnimList) const;
     void impGetScrollTextTiming(drawinglayer::animation::AnimationEntryList& rAnimList, double fFrameLength, double fTextLength) const;
 
+    // Direct decomposer for text visualization when you already have a prepared
+    // Outliner containing all the needed information
+    static void impDecomposeBlockTextPrimitiveDirect(
+        drawinglayer::primitive2d::Primitive2DContainer& rTarget,
+        SdrOutliner& rOutliner,
+        const basegfx::B2DHomMatrix& rNewTransformA,
+        const basegfx::B2DHomMatrix& rNewTransformB,
+        const basegfx::B2DRange& rClipRange);
+
     /** returns false if the given pointer is NULL
         or if the given SdrOutliner contains no text.
         Also checks for one empty paragraph.
diff --git a/include/svx/svdoutl.hxx b/include/svx/svdoutl.hxx
index c76fbb9c2345..ea78a466eefc 100644
--- a/include/svx/svdoutl.hxx
+++ b/include/svx/svdoutl.hxx
@@ -45,6 +45,8 @@ public:
     const SdrPage* getVisualizedPage() const { return mpVisualizedPage; }
 
     virtual OUString CalcFieldValue(const SvxFieldItem& rField, sal_Int32 nPara, sal_Int32 nPos, Color*& rpTxtColor, Color*& rpFldColor) override;
+
+    bool hasEditViewCallbacks() const;
 };
 
 #endif // INCLUDED_SVX_SVDOUTL_HXX
diff --git a/sd/source/ui/view/Outliner.cxx b/sd/source/ui/view/Outliner.cxx
index 42d4a20cbda7..3a4ba9e87d48 100644
--- a/sd/source/ui/view/Outliner.cxx
+++ b/sd/source/ui/view/Outliner.cxx
@@ -792,6 +792,17 @@ bool Outliner::SearchAndReplaceOnce(std::vector<SearchSelection>* pSelections)
         std::vector<Rectangle> aLogicRects;
         pOutlinerView->GetSelectionRectangles(aLogicRects);
 
+        // convert to twips if in 100thmm (seems as if LibreOfficeKit is based on twips?). Do this
+        // here where we have the only place needing this, *not* in ImpEditView::GetSelectionRectangles
+        // which makes that method unusable for others
+        if (pOutlinerView->GetWindow() && MapUnit::MAP_100TH_MM == pOutlinerView->GetWindow()->GetMapMode().GetMapUnit())
+        {
+            for (Rectangle& rRectangle : aLogicRects)
+            {
+                rRectangle = OutputDevice::LogicToLogic(rRectangle, MapUnit::MAP_100TH_MM, MapUnit::MAP_TWIP);
+            }
+        }
+
         std::vector<OString> aLogicRectStrings;
         std::transform(aLogicRects.begin(), aLogicRects.end(), std::back_inserter(aLogicRectStrings), [](const Rectangle& rRectangle) { return rRectangle.toString(); });
         OString sRectangles = comphelper::string::join("; ", aLogicRectStrings);
diff --git a/svx/source/svdraw/svdedxv.cxx b/svx/source/svdraw/svdedxv.cxx
index 968738c6fde0..78560b5fd9e3 100644
--- a/svx/source/svdraw/svdedxv.cxx
+++ b/svx/source/svdraw/svdedxv.cxx
@@ -63,7 +63,11 @@
 #include <svx/sdr/table/tablecontroller.hxx>
 #include <drawinglayer/processor2d/processor2dtools.hxx>
 #include <comphelper/lok.hxx>
-
+#include <sfx2/viewsh.hxx>
+#include <svx/svdviter.hxx>
+#include <svx/sdr/overlay/overlayselection.hxx>
+#include <svx/sdr/overlay/overlaymanager.hxx>
+#include <svx/sdrpagewindow.hxx>
 #include <memory>
 
 void SdrObjEditView::ImpClearVars()
@@ -102,7 +106,6 @@ SdrObjEditView::~SdrObjEditView()
     delete mpOldTextEditUndoManager;
 }
 
-
 bool SdrObjEditView::IsAction() const
 {
     return IsMacroObj() || SdrGlueEditView::IsAction();
@@ -286,39 +289,298 @@ void SdrObjEditView::ModelHasChanged()
     }
 }
 
+namespace
+{
+    /**
+        Helper class to visualize the content of an active EditView as an
+        OverlayObject. These objects work with Primitives and are handled
+        from the OverlayManager(s) in place as needed.
+
+        It allows complete visualization of the content of the active
+        EditView without the need of Invalidates triggered by the EditView
+        and thus avoiding potentially expensive repaints by using the
+        automatically buffered Overlay mechanism.
+
+        It buffers as amuch as possible locally and *only* triggers a real
+        change (see call to objectChange()) when really needed.
+     */
+    class TextEditOverlayObject : public sdr::overlay::OverlayObject
+    {
+    protected:
+        /// local access to associated sdr::overlay::OverlaySelection
+        sdr::overlay::OverlaySelection*     mpOverlaySelection;
+
+        /// local definition depends on active OutlinerView
+        OutlinerView&                       mrOutlinerView;
+
+        /// geometry definitions with buffering
+        basegfx::B2DRange                   maLastRange;
+        basegfx::B2DRange                   maRange;
+
+        /// text content definitions with buffering
+        drawinglayer::primitive2d::Primitive2DContainer     maTextPrimitives;
+        drawinglayer::primitive2d::Primitive2DContainer     maLastTextPrimitives;
+
+        /// bitfield
+        bool                    mbVisualizeSurroundingFrame : 1;
+
+        // geometry creation for OverlayObject, can use local *Last* values
+        virtual drawinglayer::primitive2d::Primitive2DContainer createOverlayObjectPrimitive2DSequence() override;
+
+    public:
+        TextEditOverlayObject(
+            sdr::overlay::OverlaySelection* pOverlaySelection,
+            const Color& rColor,
+            OutlinerView& rOutlinerView,
+            bool bVisualizeSurroundingFrame);
+        virtual ~TextEditOverlayObject() override;
+
+        // data read access
+        const sdr::overlay::OverlaySelection* getOverlaySelection() const { return mpOverlaySelection; }
+        const OutlinerView& getOutlinerView() const { return mrOutlinerView; }
+        bool getVisualizeSurroundingFrame() const { return mbVisualizeSurroundingFrame; }
+
+        /// override to check conditions for last createOverlayObjectPrimitive2DSequence
+        virtual drawinglayer::primitive2d::Primitive2DContainer getOverlayObjectPrimitive2DSequence() const override;
+
+        // data write access. In this OverlayObject we only have the
+        // callback that triggers detecting if something *has* changed
+        void checkDataChange(const basegfx::B2DRange& rMinTextEditArea);
+        void checkSelectionChange(const std::vector<basegfx::B2DRange>& rLogicRanges);
+    };
+
+    drawinglayer::primitive2d::Primitive2DContainer TextEditOverlayObject::createOverlayObjectPrimitive2DSequence()
+    {
+        drawinglayer::primitive2d::Primitive2DContainer aRetval;
+
+        /// outer frame visualization
+        if (getVisualizeSurroundingFrame())
+        {
+            const SvtOptionsDrawinglayer aSvtOptionsDrawinglayer;
+            const double fTransparence(aSvtOptionsDrawinglayer.GetTransparentSelectionPercent() * 0.01);
+            const sal_uInt16 nPixSiz(getOutlinerView().GetInvalidateMore() - 1);
+
+            aRetval.push_back(
+                new drawinglayer::primitive2d::OverlayRectanglePrimitive(
+                    maRange,
+                    getBaseColor().getBColor(),
+                    fTransparence,
+                    std::max(6, nPixSiz - 2), // grow
+                    0.0, // shrink
+                    0.0));
+        }
+
+        // add buffered TextPrimitives
+        aRetval.append(maTextPrimitives);
+
+        return aRetval;
+    }
+
+    TextEditOverlayObject::TextEditOverlayObject(
+        sdr::overlay::OverlaySelection* pOverlaySelection,
+        const Color& rColor,
+        OutlinerView& rOutlinerView,
+        bool bVisualizeSurroundingFrame)
+    :   OverlayObject(rColor),
+        mpOverlaySelection(pOverlaySelection),
+        mrOutlinerView(rOutlinerView),
+        maLastRange(),
+        maRange(),
+        maTextPrimitives(),
+        maLastTextPrimitives(),
+        mbVisualizeSurroundingFrame(bVisualizeSurroundingFrame)
+    {
+        // no AA for TextEdit overlay
+        allowAntiAliase(false);
+    }
+
+    TextEditOverlayObject::~TextEditOverlayObject()
+    {
+        if (getOverlaySelection())
+        {
+            delete mpOverlaySelection;
+            mpOverlaySelection = nullptr;
+        }
+
+        if (getOverlayManager())
+        {
+            getOverlayManager()->remove(*this);
+        }
+    }
+
+    drawinglayer::primitive2d::Primitive2DContainer TextEditOverlayObject::getOverlayObjectPrimitive2DSequence() const
+    {
+        if (!getPrimitive2DSequence().empty())
+        {
+            if (!maRange.equal(maLastRange) || maLastTextPrimitives != maTextPrimitives)
+            {
+                // conditions of last local decomposition have changed, delete to force new evaluation
+                const_cast<TextEditOverlayObject*>(this)->setPrimitive2DSequence(drawinglayer::primitive2d::Primitive2DContainer());
+            }
+        }
+
+        if (getPrimitive2DSequence().empty())
+        {
+            // remember new buffered values
+            const_cast<TextEditOverlayObject*>(this)->maLastRange = maRange;
+            const_cast<TextEditOverlayObject*>(this)->maLastTextPrimitives = maTextPrimitives;
+        }
+
+        // call base implementation
+        return OverlayObject::getOverlayObjectPrimitive2DSequence();
+    }
+
+    void TextEditOverlayObject::checkDataChange(const basegfx::B2DRange& rMinTextEditArea)
+    {
+        bool bObjectChange(false);
+
+        // check current range
+        const Rectangle aOutArea(mrOutlinerView.GetOutputArea());
+        basegfx::B2DRange aNewRange(aOutArea.Left(), aOutArea.Top(), aOutArea.Right(), aOutArea.Bottom());
+        aNewRange.expand(rMinTextEditArea);
+
+        if (aNewRange != maRange)
+        {
+            maRange = aNewRange;
+            bObjectChange = true;
+        }
+
+        // check if text primitives did change
+        SdrOutliner* pSdrOutliner = dynamic_cast<SdrOutliner*>(getOutlinerView().GetOutliner());
+
+        if (pSdrOutliner)
+        {
+            // get TextPrimitives directly from active Outliner
+            basegfx::B2DHomMatrix aNewTransformA;
+            basegfx::B2DHomMatrix aNewTransformB;
+            basegfx::B2DRange aClipRange;
+            drawinglayer::primitive2d::Primitive2DContainer aNewTextPrimitives;
+
+            // active Outliner is always in unified oriented coordinate system (currently)
+            // so just translate to TopLeft of visible Range
+            Rectangle aVisArea(mrOutlinerView.GetVisArea());
+
+            aNewTransformB.translate(
+                aOutArea.Left() - aVisArea.Left(),
+                aOutArea.Top() - aVisArea.Top());
+
+            // get the current TextPrimitives. This is the most expensive part
+            // of this mechanism, it *may* be possible to buffer layouted
+            // primitives per ParaPortion with/in/dependent on the EditEngine
+            // content if needed. For now, get and compare
+            SdrTextObj::impDecomposeBlockTextPrimitiveDirect(
+                aNewTextPrimitives,
+                *pSdrOutliner,
+                aNewTransformA,
+                aNewTransformB,
+                aClipRange);
+
+            if (aNewTextPrimitives != maTextPrimitives)
+            {
+                maTextPrimitives = aNewTextPrimitives;
+                bObjectChange = true;
+            }
+        }
+
+        if (bObjectChange)
+        {
+            // if there really *was* a change signal the OverlayManager to
+            // refresh this object's visualization
+            objectChange();
+        }
+    }
+
+    void TextEditOverlayObject::checkSelectionChange(const std::vector<basegfx::B2DRange>& rLogicRanges)
+    {
+        if (getOverlaySelection())
+        {
+            mpOverlaySelection->setRanges(rLogicRanges);
+        }
+    }
+} // end of anonymous namespace
 
 // TextEdit
 
+// file-local static bool to control old/new behaviour of active TextEdit visualization
+static bool bAllowTextEditVisualizatkionOnOverlay(true);
 
-void SdrObjEditView::TextEditDrawing(SdrPaintWindow& rPaintWindow) const
+// callback from the active EditView, forward to evtl. existing instances of the
+// TextEditOverlayObject(s)
+void SdrObjEditView::EditViewInvalidate() const
 {
-    // draw old text edit stuff
-    if(IsTextEdit())
+    if (IsTextEdit())
+    {
+        // MinTextRange may have changed. Forward it, too
+        const basegfx::B2DRange aMinTextRange(
+            aMinTextEditArea.Left(), aMinTextEditArea.Top(),
+            aMinTextEditArea.Right(), aMinTextEditArea.Bottom());
+
+        for (sal_uInt32 a(0); a < maTEOverlayGroup.count(); a++)
+        {
+            TextEditOverlayObject* pCandidate = dynamic_cast< TextEditOverlayObject* >(&maTEOverlayGroup.getOverlayObject(a));
+
+            if (pCandidate)
+            {
+                pCandidate->checkDataChange(aMinTextRange);
+            }
+        }
+    }
+}
+
+void SdrObjEditView::EditViewSelectionChange(const std::vector<basegfx::B2DRange>& rLogicRanges) const
+{
+    if (IsTextEdit())
     {
-        const SdrOutliner* pActiveOutliner = GetTextEditOutliner();
+        for (sal_uInt32 a(0); a < maTEOverlayGroup.count(); a++)
+        {
+            TextEditOverlayObject* pCandidate = dynamic_cast< TextEditOverlayObject* >(&maTEOverlayGroup.getOverlayObject(a));
+
+            if (pCandidate)
+            {
+                pCandidate->checkSelectionChange(rLogicRanges);
+            }
+        }
+    }
+}
 
-        if(pActiveOutliner)
+void SdrObjEditView::TextEditDrawing(SdrPaintWindow& rPaintWindow) const
+{
+    if (bAllowTextEditVisualizatkionOnOverlay)
+    {
+        // adapt TextEditOverlayObject(s). Need also to do this here to
+        // update the current values accordingly
+        EditViewInvalidate();
+    }
+    else
+    {
+        // draw old text edit stuff
+        if (IsTextEdit())
         {
-            const sal_uInt32 nViewCount(pActiveOutliner->GetViewCount());
+            const SdrOutliner* pActiveOutliner = GetTextEditOutliner();
 
-            if(nViewCount)
+            if (pActiveOutliner)
             {
-                const vcl::Region& rRedrawRegion = rPaintWindow.GetRedrawRegion();
-                const Rectangle aCheckRect(rRedrawRegion.GetBoundRect());
+                const sal_uInt32 nViewCount(pActiveOutliner->GetViewCount());
 
-                for(sal_uInt32 i(0); i < nViewCount; i++)
+                if (nViewCount)
                 {
-                    OutlinerView* pOLV = pActiveOutliner->GetView(i);
-
-                    // If rPaintWindow knows that the output device is a render
-                    // context and is aware of the underlying vcl::Window,
-                    // compare against that; that's how double-buffering can
-                    // still find the matching OutlinerView.
-                    OutputDevice* pOutputDevice = rPaintWindow.GetWindow() ? rPaintWindow.GetWindow() : &rPaintWindow.GetOutputDevice();
-                    if(pOLV->GetWindow() == pOutputDevice || comphelper::LibreOfficeKit::isActive())
+                    const vcl::Region& rRedrawRegion = rPaintWindow.GetRedrawRegion();
+                    const Rectangle aCheckRect(rRedrawRegion.GetBoundRect());
+
+                    for (sal_uInt32 i(0); i < nViewCount; i++)
                     {
-                        ImpPaintOutlinerView(*pOLV, aCheckRect, rPaintWindow.GetTargetOutputDevice());
-                        return;
+                        OutlinerView* pOLV = pActiveOutliner->GetView(i);
+
+                        // If rPaintWindow knows that the output device is a render
+                        // context and is aware of the underlying vcl::Window,
+                        // compare against that; that's how double-buffering can
+                        // still find the matching OutlinerView.
+                        OutputDevice* pOutputDevice = rPaintWindow.GetWindow() ? rPaintWindow.GetWindow() : &rPaintWindow.GetOutputDevice();
+                        if (pOLV->GetWindow() == pOutputDevice || comphelper::LibreOfficeKit::isActive())
+                        {
+                            ImpPaintOutlinerView(*pOLV, aCheckRect, rPaintWindow.GetTargetOutputDevice());
+                            return;
+                        }
                     }
                 }
             }
@@ -446,8 +708,16 @@ OutlinerView* SdrObjEditView::ImpMakeOutlinerView(vcl::Window* pWin, bool /*bNoP
     // create OutlinerView
     OutlinerView* pOutlView=pGivenView;
     pTextEditOutliner->SetUpdateMode(false);
-    if (pOutlView==nullptr) pOutlView = new OutlinerView(pTextEditOutliner,pWin);
-    else pOutlView->SetWindow(pWin);
+
+    if (pOutlView == nullptr)
+    {
+        pOutlView = new OutlinerView(pTextEditOutliner, pWin);
+    }
+    else
+    {
+        pOutlView->SetWindow(pWin);
+    }
+
     // disallow scrolling
     EVControlBits nStat=pOutlView->GetControlWord();
     nStat&=~EVControlBits::AUTOSCROLL;
@@ -785,6 +1055,57 @@ bool SdrObjEditView::SdrBeginTextEdit(
 
             pTextEditOutlinerView=ImpMakeOutlinerView(pWin,!bEmpty,pGivenOutlinerView);
 
+            if (bAllowTextEditVisualizatkionOnOverlay && pTextEditOutlinerView)
+            {
+                // activate visualization of EditView on Overlay
+                pTextEditOutlinerView->GetEditView().setEditViewCallbacks(this);
+
+                const SvtOptionsDrawinglayer aSvtOptionsDrawinglayer;
+                const Color aHilightColor(aSvtOptionsDrawinglayer.getHilightColor());
+                const SdrTextObj* pText = dynamic_cast<SdrTextObj*>(GetTextEditObject());
+                const bool bTextFrame(pText && pText->IsTextFrame());
+                const bool bFitToSize(pTextEditOutliner->GetControlWord() & EEControlBits::STRETCHING);
+                const bool bVisualizeSurroundingFrame(bTextFrame && !bFitToSize);
+                SdrPageView* pPageView = GetSdrPageView();
+
+                if (pPageView)
+                {
+                    for (sal_uInt32 b(0); b < pPageView->PageWindowCount(); b++)
+                    {
+                        const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(b);
+
+                        if (rPageWindow.GetPaintWindow().OutputToWindow())
+                        {
+                            rtl::Reference< sdr::overlay::OverlayManager > xManager = rPageWindow.GetOverlayManager();
+                            if (xManager.is())
+                            {
+                                const basegfx::B2DRange aMinTEArea(
+                                    aMinTextEditArea.Left(), aMinTextEditArea.Top(),
+                                    aMinTextEditArea.Right(), aMinTextEditArea.Bottom());
+                                const std::vector< basegfx::B2DRange > aEmptySelection;
+
+                                sdr::overlay::OverlaySelection* pNewOverlaySelection = new sdr::overlay::OverlaySelection(
+                                    sdr::overlay::OVERLAY_TRANSPARENT,
+                                    aHilightColor,
+                                    aEmptySelection,
+                                    true);
+
+                                sdr::overlay::OverlayObject* pNewTextEditOverlayObject = new TextEditOverlayObject(
+                                    pNewOverlaySelection,
+                                    aHilightColor,
+                                    *pTextEditOutlinerView,
+                                    bVisualizeSurroundingFrame);
+
+                                xManager->add(*pNewTextEditOverlayObject);
+                                xManager->add(*pNewOverlaySelection);
+
+                                maTEOverlayGroup.append(*pNewTextEditOverlayObject);
+                            }
+                        }
+                    }
+                }
+            }
+
             // check if this view is already inserted
             sal_uIntPtr i2,nCount = pTextEditOutliner->GetViewCount();
             for( i2 = 0; i2 < nCount; i2++ )
@@ -973,6 +1294,13 @@ SdrEndTextEditKind SdrObjEditView::SdrEndTextEdit(bool bDontDeleteReally)
         GetModel()->Broadcast(aHint);
     }
 
+    // if new mechanism was used, clean it up
+    if (bAllowTextEditVisualizatkionOnOverlay && pTextEditOutlinerView)
+    {
+        pTextEditOutlinerView->GetEditView().setEditViewCallbacks(nullptr);
+        maTEOverlayGroup.clear();
+    }
+
     mxTextEditObj.reset(nullptr);
     pTextEditPV=nullptr;
     pTextEditWin=nullptr;
diff --git a/svx/source/svdraw/svdotextdecomposition.cxx b/svx/source/svdraw/svdotextdecomposition.cxx
index 3de59d7deed0..c571f2a26ba8 100644
--- a/svx/source/svdraw/svdotextdecomposition.cxx
+++ b/svx/source/svdraw/svdotextdecomposition.cxx
@@ -1614,5 +1614,18 @@ void SdrTextObj::impDecomposeChainedTextPrimitive(
     rTarget = aConverter.getPrimitive2DSequence();
 }
 
+// Direct decomposer for text visualization when you already have a prepared
+// Outliner containing all the needed information
+void SdrTextObj::impDecomposeBlockTextPrimitiveDirect(
+    drawinglayer::primitive2d::Primitive2DContainer& rTarget,
+    SdrOutliner& rOutliner,
+    const basegfx::B2DHomMatrix& rNewTransformA,
+    const basegfx::B2DHomMatrix& rNewTransformB,
+    const basegfx::B2DRange& rClipRange)
+{
+    impTextBreakupHandler aConverter(rOutliner);
+    aConverter.decomposeBlockTextPrimitive(rNewTransformA, rNewTransformB, rClipRange);
+    rTarget.append(aConverter.getPrimitive2DSequence());
+}
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/svdraw/svdotxat.cxx b/svx/source/svdraw/svdotxat.cxx
index f78499f84818..140f6975befe 100644
--- a/svx/source/svdraw/svdotxat.cxx
+++ b/svx/source/svdraw/svdotxat.cxx
@@ -288,8 +288,24 @@ bool SdrTextObj::AdjustTextFrameWidthAndHeight()
         if (dynamic_cast<const SdrCaptionObj *>(this) != nullptr) { // this is a hack
             static_cast<SdrCaptionObj*>(this)->ImpRecalcTail();
         }
-        SetChanged();
-        BroadcastObjectChange();
+
+        // to not slow down EditView visualization on Overlay (see
+        // TextEditOverlayObject) it is necessary to suppress the
+        // Invalidates for the deep repaint when the size of the
+        // TextFrame changed (AdjustTextFrameWidthAndHeight returned
+        // true). The ObjectChanges are valid, invalidate will be
+        // done on EndTextEdit anyways
+        const bool bSuppressChangeWhenEditOnOverlay(
+            IsInEditMode() &&
+            GetTextEditOutliner() &&
+            GetTextEditOutliner()->hasEditViewCallbacks());
+
+        if (!bSuppressChangeWhenEditOnOverlay)
+        {
+            SetChanged();
+            BroadcastObjectChange();
+        }
+
         SendUserCall(SDRUSERCALL_RESIZE,aBoundRect0);
     }
     return bRet;
diff --git a/svx/source/svdraw/svdoutl.cxx b/svx/source/svdraw/svdoutl.cxx
index 1e3ea5e2e150..580dee39b174 100644
--- a/svx/source/svdraw/svdoutl.cxx
+++ b/svx/source/svdraw/svdoutl.cxx
@@ -24,6 +24,7 @@
 #include <svx/svdmodel.hxx>
 #include <editeng/eeitem.hxx>
 #include <svl/itempool.hxx>
+#include <editeng/editview.hxx>
 
 
 SdrOutliner::SdrOutliner( SfxItemPool* pItemPool, OutlinerMode nMode )
@@ -94,4 +95,19 @@ const SdrTextObj* SdrOutliner::GetTextObj() const
         return nullptr;
 }
 
+bool SdrOutliner::hasEditViewCallbacks() const
+{
+    for (size_t a(0); a < GetViewCount(); a++)
+    {
+        OutlinerView* pOutlinerView = GetView(a);
+
+        if (pOutlinerView && pOutlinerView->GetEditView().hasEditViewCallbacks())
+        {
+            return true;
+        }
+    }
+
+    return false;
+}
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */


More information about the Libreoffice-commits mailing list