Rebased ref, commits from common ancestor: commit cf39722ea5f8fbd58e4fad1999a1bc5724911120 Author: Michael Stahl <michael.st...@cib.de> AuthorDate: Fri Aug 3 18:48:10 2018 +0200 Commit: Michael Stahl <michael.st...@cib.de> CommitDate: Fri Aug 3 18:48:10 2018 +0200
sw_redlinehide_2: try to minimise invalidation on show/hide InvalidateAllContent(Size) will basically format every paragraph in the document from scratch; let's try to optimise this a bit by invalidating only the SwTextFrames that actually contain redlines and the SwPageFrames they're on, and also invalidate the position of all flys anchored at these frames as a precautionary measure. Change-Id: I22ed683dc2225992ee48faa6084f277ef8733e8b diff --git a/sw/source/core/layout/wsfrm.cxx b/sw/source/core/layout/wsfrm.cxx index 239da7288749..e3684accaeae 100644 --- a/sw/source/core/layout/wsfrm.cxx +++ b/sw/source/core/layout/wsfrm.cxx @@ -4207,6 +4207,20 @@ static void UnHideRedlines(SwRootFrame & rLayout, pFrame->SetMergedPara(std::move(pMerged)); } auto const pMerged(pFrame->GetMergedPara()); + if (pMerged) + { + // invalidate SwInvalidateFlags::Size + pFrame->Prepare(PREP_CLEAR, nullptr, false); + pFrame->InvalidatePage(); + if (auto const pObjs = pFrame->GetDrawObjs()) + { // also invalidate position of existing flys + // because they may need to be moved + for (auto const pObject : *pObjs) + { + pObject->InvalidateObjPos(); + } + } + } if (pMerged // do this only *once*, for the *last* frame // otherwise AppendObj would create multiple frames for fly-frames! @@ -4252,6 +4266,16 @@ static void UnHideRedlines(SwRootFrame & rLayout, { if (auto const& pMergedPara = pFrame->GetMergedPara()) { + // invalidate SwInvalidateFlags::Size + pFrame->Prepare(PREP_CLEAR, nullptr, false); + pFrame->InvalidatePage(); + if (auto const pObjs = pFrame->GetDrawObjs()) + { // also invalidate position of existing flys + for (auto const pObject : *pObjs) + { + pObject->InvalidateObjPos(); + } + } // SwFlyAtContentFrame::Modify() always appends to // the master frame, so do the same here. // (RemoveFootnotesForNode must be called at least once) @@ -4434,7 +4458,7 @@ void SwRootFrame::SetHideRedlines(bool const bHideRedlines) UnHideRedlinesExtras(*this, rNodes, rNodes.GetEndOfAutotext()); UnHideRedlines(*this, rNodes, rNodes.GetEndOfContent()); - InvalidateAllContent(SwInvalidateFlags::Size); // ??? TODO what to invalidate? +// InvalidateAllContent(SwInvalidateFlags::Size); // ??? TODO what to invalidate? this is the big hammer } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ commit fc346b71c215587069156a1f49d0d2b11935d5e2 Author: Michael Stahl <michael.st...@cib.de> AuthorDate: Thu Aug 2 17:09:53 2018 +0200 Commit: Michael Stahl <michael.st...@cib.de> CommitDate: Fri Aug 3 18:47:19 2018 +0200 sw_redlinehide_2: show/hide flys in redlines The old implementation would not actually hide at-char flys but move the anchor, which is clearly not ideal; better to hide them. Change-Id: If21d0360e04857752a2c84f5329eadfad7818ac8 diff --git a/sw/source/core/inc/frmtool.hxx b/sw/source/core/inc/frmtool.hxx index 0ffe4a75c0f6..e692bb900ef6 100644 --- a/sw/source/core/inc/frmtool.hxx +++ b/sw/source/core/inc/frmtool.hxx @@ -45,6 +45,8 @@ class GraphicAttr; class SwPageDesc; class SwFrameFormats; class SwRegionRects; +class SwTextNode; +namespace sw { struct Extent; } #define FAR_AWAY (SAL_MAX_INT32 - 20000) // initial position of a Fly #define BROWSE_HEIGHT (56700L * 10L) // 10 Meters @@ -55,6 +57,15 @@ class SwRegionRects; void AppendObjs( const SwFrameFormats *pTable, sal_uLong nIndex, SwFrame *pFrame, SwPageFrame *pPage, SwDoc* doc ); +void AppendObjsOfNode(SwFrameFormats const* pTable, sal_uLong nIndex, + SwFrame * pFrame, SwPageFrame * pPage, SwDoc * pDoc, + std::vector<sw::Extent>::const_iterator * pIter, + std::vector<sw::Extent>::const_iterator const* pEnd); + +void RemoveHiddenObjsOfNode(SwTextNode const& rNode, + std::vector<sw::Extent>::const_iterator * pIter, + std::vector<sw::Extent>::const_iterator const* pEnd); + // draw background with brush or graphics // The 6th parameter indicates that the method should consider background // transparency, saved in the color of the brush item. diff --git a/sw/source/core/layout/frmtool.cxx b/sw/source/core/layout/frmtool.cxx index ad8d07e2cc2f..757af06f176a 100644 --- a/sw/source/core/layout/frmtool.cxx +++ b/sw/source/core/layout/frmtool.cxx @@ -1039,32 +1039,63 @@ static bool IsShown(sal_uLong const nIndex, std::vector<sw::Extent>::const_iterator const*const pEnd) { SwPosition const& rAnchor(*rAnch.GetContentAnchor()); + if (rAnchor.nNode.GetIndex() != nIndex) + { + return false; + } if (pIter && rAnch.GetAnchorId() != RndStdIds::FLY_AT_PARA) { - // TODO are frames sorted by anchor positions perhaps? + // note: frames are not sorted by anchor position. assert(pEnd); assert(rAnch.GetAnchorId() != RndStdIds::FLY_AT_FLY); - for ( ; *pIter != *pEnd; ++*pIter) + for (auto iter = *pIter; iter != *pEnd; ++iter) { - assert((**pIter).pNode->GetIndex() == nIndex); - if ((**pIter).nStart <= rAnchor.nContent.GetIndex()) + assert(iter->pNode->GetIndex() == nIndex); + if (rAnchor.nContent.GetIndex() < iter->nStart) { - // TODO off by one? need < for AS_CHAR but what for AT_CHAR? - if (rAnchor.nContent.GetIndex() < (**pIter).nEnd) - { - return true; - } - else - { - return false; - } + return false; + } + // for AS_CHAR obviously must be < + // for AT_CHAR it is questionable whether < or <= should be used + // and there is the additional corner case of Len() to consider + // prefer < for now for symmetry (and inverted usage with + // "hidden") and handle special case explicitly + if (rAnchor.nContent.GetIndex() < iter->nEnd + || iter->nEnd == iter->pNode->Len()) + { + return true; } } return false; } else { - return rAnch.GetContentAnchor()->nNode.GetIndex() == nIndex; + return true; + } +} + +void RemoveHiddenObjsOfNode(SwTextNode const& rNode, + std::vector<sw::Extent>::const_iterator *const pIter, + std::vector<sw::Extent>::const_iterator const*const pEnd) +{ + std::vector<SwFrameFormat*> const*const pFlys(rNode.GetAnchoredFlys()); + if (!pFlys) + { + return; + } + for (SwFrameFormat * pFrameFormat : *pFlys) + { + SwFormatAnchor const& rAnchor = pFrameFormat->GetAnchor(); + if (rAnchor.GetAnchorId() == RndStdIds::FLY_AT_CHAR + || (rAnchor.GetAnchorId() == RndStdIds::FLY_AS_CHAR + && RES_DRAWFRMFMT == pFrameFormat->Which())) + { + assert(rAnchor.GetContentAnchor()->nNode.GetIndex() == rNode.GetIndex()); + if (!IsShown(rNode.GetIndex(), rAnchor, pIter, pEnd)) + { + pFrameFormat->DelFrames(); + } + } } } diff --git a/sw/source/core/layout/wsfrm.cxx b/sw/source/core/layout/wsfrm.cxx index 68d9e1e418f1..239da7288749 100644 --- a/sw/source/core/layout/wsfrm.cxx +++ b/sw/source/core/layout/wsfrm.cxx @@ -4181,7 +4181,15 @@ static void UnHideRedlines(SwRootFrame & rLayout, { if (pFrame->getRootFrame() == &rLayout) { - frames.push_back(pFrame); + if (pFrame->IsFollow()) + { + frames.push_back(pFrame); + } // when hiding, the loop must remove the anchored flys + else // *before* resetting SetMergedPara anywhere - else + { // the fly deletion code will access multiple of the + // frames with inconsistent MergedPara and assert + frames.insert(frames.begin(), pFrame); + } } } // this messes with pRegisteredIn so do it outside SwIterator @@ -4193,29 +4201,111 @@ static void UnHideRedlines(SwRootFrame & rLayout, rNode.GetRedlineMergeFlag() == SwNode::Merge::NonFirst); if (rNode.IsCreateFrameWhenHidingRedlines()) { - pFrame->SetMergedPara(CheckParaRedlineMerge(*pFrame, - rTextNode, sw::FrameMode::Existing)); - // ??? TODO flys etc. + { + auto pMerged(CheckParaRedlineMerge(*pFrame, + rTextNode, sw::FrameMode::Existing)); + pFrame->SetMergedPara(std::move(pMerged)); + } + auto const pMerged(pFrame->GetMergedPara()); + if (pMerged + // do this only *once*, for the *last* frame + // otherwise AppendObj would create multiple frames for fly-frames! + && !pFrame->GetFollow()) + { + // add visible flys in non-first node to merged frame + // (hidden flys remain and are deleted via DelFrames()) + SwFrameFormats& rTable(*rTextNode.GetDoc()->GetSpzFrameFormats()); + SwPageFrame *const pPage(pFrame->FindPageFrame()); + std::vector<sw::Extent>::const_iterator iterFirst(pMerged->extents.begin()); + std::vector<sw::Extent>::const_iterator iter(iterFirst); + SwTextNode const* pNode(&rTextNode); + for ( ; ; ++iter) + { + if (iter == pMerged->extents.end() + || iter->pNode != pNode) + { + if (pNode == &rTextNode) + { // remove existing hidden at-char anchored flys + RemoveHiddenObjsOfNode( + rTextNode, &iterFirst, &iter); + } + else + { + // pNode's frame has been deleted by CheckParaRedlineMerge() + AppendObjsOfNode(&rTable, + pNode->GetIndex(), pFrame, pPage, + rTextNode.GetDoc(), + &iterFirst, &iter); + } + if (iter == pMerged->extents.end()) + { + break; + } + pNode = iter->pNode; + iterFirst = iter; + } + } + } } } else { if (auto const& pMergedPara = pFrame->GetMergedPara()) { - // the new text frames don't exist yet, so at this point - // we can only delete the footnote frames so they don't - // point to the merged SwTextFrame any more... - SwTextNode const* pNode(&rTextNode); - for (auto const& rExtent : pMergedPara->extents) + // SwFlyAtContentFrame::Modify() always appends to + // the master frame, so do the same here. + // (RemoveFootnotesForNode must be called at least once) + if (!pFrame->IsFollow()) { - if (rExtent.pNode != pNode) + // the new text frames don't exist yet, so at this point + // we can only delete the footnote frames so they don't + // point to the merged SwTextFrame any more... + SwTextNode const* pNode(&rTextNode); + for (auto const& rExtent : pMergedPara->extents) + { + if (rExtent.pNode != pNode) + { + sw::RemoveFootnotesForNode(*pFrame, *rExtent.pNode, nullptr); + // similarly, remove the anchored flys + if (auto const pFlys = rExtent.pNode->GetAnchoredFlys()) + { + for (SwFrameFormat * pFormat : *pFlys) + { + pFormat->DelFrames(/*&rLayout*/); + } + } + pNode = rExtent.pNode; + } + } + // add all flys in first node that are hidden + std::vector<sw::Extent> hidden; + sal_Int32 nLast(0); + for (auto const& rExtent : pMergedPara->extents) + { + if (rExtent.pNode != &rTextNode) + { + break; + } + if (rExtent.nStart != 0) + { + assert(rExtent.nStart != nLast); + + hidden.emplace_back(&rTextNode, nLast, rExtent.nStart); + } + nLast = rExtent.nEnd; + } + if (nLast != rTextNode.Len()) { - sw::RemoveFootnotesForNode(*pFrame, *rExtent.pNode, nullptr); - pNode = rExtent.pNode; + hidden.emplace_back(&rTextNode, nLast, rTextNode.Len()); } + SwFrameFormats& rTable(*rTextNode.GetDoc()->GetSpzFrameFormats()); + auto iterBegin(hidden.cbegin()); + auto const iterEnd(hidden.cend()); + AppendObjsOfNode(&rTable, rTextNode.GetIndex(), pFrame, + pFrame->FindPageFrame(), rTextNode.GetDoc(), + &iterBegin, &iterEnd); } pFrame->SetMergedPara(nullptr); - // ??? TODO flys etc. // ??? TODO recreate? or is invalidate enough? } } _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits