diff options
Diffstat (limited to 'svx/source')
-rw-r--r-- | svx/source/svdraw/svdedxv.cxx | 373 | ||||
-rw-r--r-- | svx/source/svdraw/svdotextdecomposition.cxx | 13 | ||||
-rw-r--r-- | svx/source/svdraw/svdotxat.cxx | 20 | ||||
-rw-r--r-- | svx/source/svdraw/svdoutl.cxx | 16 |
4 files changed, 397 insertions, 25 deletions
diff --git a/svx/source/svdraw/svdedxv.cxx b/svx/source/svdraw/svdedxv.cxx index 65dede8abcb1..8348988b2ca1 100644 --- a/svx/source/svdraw/svdedxv.cxx +++ b/svx/source/svdraw/svdedxv.cxx @@ -65,6 +65,9 @@ #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> @@ -103,7 +106,6 @@ SdrObjEditView::~SdrObjEditView() assert(nullptr == mpOldTextEditUndoManager); // should have been reset } - bool SdrObjEditView::IsAction() const { return IsMacroObj() || SdrGlueEditView::IsAction(); @@ -353,39 +355,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 tools::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 + tools::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()) { - const SdrOutliner* pActiveOutliner = GetTextEditOutliner(); + // 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); + } + } + } +} - if(pActiveOutliner) +void SdrObjEditView::EditViewSelectionChange(const std::vector<basegfx::B2DRange>& rLogicRanges) const +{ + if (IsTextEdit()) + { + for (sal_uInt32 a(0); a < maTEOverlayGroup.count(); a++) { - const sal_uInt32 nViewCount(pActiveOutliner->GetViewCount()); + TextEditOverlayObject* pCandidate = dynamic_cast< TextEditOverlayObject* >(&maTEOverlayGroup.getOverlayObject(a)); - if(nViewCount) + if (pCandidate) { - const vcl::Region& rRedrawRegion = rPaintWindow.GetRedrawRegion(); - const tools::Rectangle aCheckRect(rRedrawRegion.GetBoundRect()); + pCandidate->checkSelectionChange(rLogicRanges); + } + } + } +} - for(sal_uInt32 i(0); i < nViewCount; i++) +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 SdrOutliner* pActiveOutliner = GetTextEditOutliner(); + + if (pActiveOutliner) + { + const sal_uInt32 nViewCount(pActiveOutliner->GetViewCount()); + + 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 tools::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; + } } } } @@ -513,8 +774,16 @@ OutlinerView* SdrObjEditView::ImpMakeOutlinerView(vcl::Window* pWin, OutlinerVie // 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; @@ -859,6 +1128,57 @@ bool SdrObjEditView::SdrBeginTextEdit( pTextEditOutlinerView=ImpMakeOutlinerView(pWin,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::OverlayType::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++ ) @@ -1067,6 +1387,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 83078bb72216..76ff4f398612 100644 --- a/svx/source/svdraw/svdotextdecomposition.cxx +++ b/svx/source/svdraw/svdotextdecomposition.cxx @@ -1639,5 +1639,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 20325165a172..b25ead77cc87 100644 --- a/svx/source/svdraw/svdotxat.cxx +++ b/svx/source/svdraw/svdotxat.cxx @@ -287,8 +287,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(SdrUserCallType::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: */ |