From 707a9a407d1c757cb1bd80d4b2d90b9f08d2ec60 Mon Sep 17 00:00:00 2001 From: Daniel Holbert <dholbert@cs.stanford.edu> Date: Fri, 28 Oct 2022 17:56:04 +0000 Subject: [PATCH] Bug 1797148: Simplify checkVisibility API (on nsISelectionController and nsIFrame) into a single nsTextFrame::HasVisibleText method. r=masayuki Before this patch, we had two `checkVisibilty` methods on the nsISelectionController interface, backed by several layers of implementation, ultimately backed by a single function on nsTextFrame (which didn't actually do anything meaningful with any of the parameters). As it turns out, this API only had one caller, in HTMLEditUtils.cpp. This patch converts that caller to directly query nsTextFrame (if the given node's primary frame is indeed a nsTextFrame). The direct function-call is renamed to HasVisibleText(), to be a bit clearer about it being text-specific and also to avoid confusion with the (unrelated) recently-specified HTML checkVisibility() API. With these changes, we can remove the API from the nsISelectionController interface and its implementations. This patch also updates the HTMLEditUtils::IsInVisibleTextFrames documentation (with s/all/any/) to reflect the reality of what the nsTextFrame impl actually does. Differential Revision: https://phabricator.services.mozilla.com/D160563 --- dom/base/nsISelectionController.idl | 10 ------- dom/html/TextControlState.cpp | 37 ------------------------ editor/libeditor/HTMLEditUtils.cpp | 35 +++++++---------------- editor/libeditor/HTMLEditUtils.h | 2 +- layout/base/PresShell.cpp | 44 ----------------------------- layout/base/PresShell.h | 4 --- layout/generic/nsIFrame.cpp | 5 ---- layout/generic/nsIFrame.h | 22 --------------- layout/generic/nsTextFrame.cpp | 16 ++--------- layout/generic/nsTextFrame.h | 5 ++-- 10 files changed, 16 insertions(+), 164 deletions(-) diff --git a/dom/base/nsISelectionController.idl b/dom/base/nsISelectionController.idl index d5eaa23812afd..2bda55e7f2b4a 100644 --- a/dom/base/nsISelectionController.idl +++ b/dom/base/nsISelectionController.idl @@ -276,16 +276,6 @@ interface nsISelectionController : nsISelectionDisplay * @param aRight if true will scroll right. if not will scroll left. */ void scrollCharacter(in boolean right); - - /** CheckVisibility will return true if textnode and offsets are actually rendered - * in the current precontext. - * @param aNode textNode to test - * @param aStartOffset offset in dom to first char of textnode to test - * @param aEndOffset offset in dom to last char of textnode to test - * @param aReturnBool boolean returned TRUE if visible FALSE if not - */ - boolean checkVisibility(in Node node, in short startOffset, in short endOffset); - [noscript,nostdcall] boolean checkVisibilityContent(in nsIContent node, in short startOffset, in short endOffset); }; %{ C++ #define NS_ISELECTIONCONTROLLER_CID \ diff --git a/dom/html/TextControlState.cpp b/dom/html/TextControlState.cpp index a3aaa19283ff9..a1523f2a60207 100644 --- a/dom/html/TextControlState.cpp +++ b/dom/html/TextControlState.cpp @@ -376,12 +376,6 @@ class TextInputSelectionController final : public nsSupportsWeakReference, NS_IMETHOD ScrollPage(bool aForward) override; NS_IMETHOD ScrollLine(bool aForward) override; NS_IMETHOD ScrollCharacter(bool aRight) override; - NS_IMETHOD CheckVisibility(nsINode* node, int16_t startOffset, - int16_t EndOffset, bool* _retval) override; - virtual nsresult CheckVisibilityContent(nsIContent* aNode, - int16_t aStartOffset, - int16_t aEndOffset, - bool* aRetval) override; void SelectionWillTakeFocus() override; void SelectionWillLoseFocus() override; @@ -781,37 +775,6 @@ void TextInputSelectionController::SelectionWillLoseFocus() { } } -NS_IMETHODIMP -TextInputSelectionController::CheckVisibility(nsINode* node, - int16_t startOffset, - int16_t EndOffset, - bool* _retval) { - if (!mPresShellWeak) { - return NS_ERROR_NOT_INITIALIZED; - } - nsresult rv; - nsCOMPtr<nsISelectionController> presShell = - do_QueryReferent(mPresShellWeak, &rv); - if (!presShell) { - return NS_ERROR_FAILURE; - } - return presShell->CheckVisibility(node, startOffset, EndOffset, _retval); -} - -nsresult TextInputSelectionController::CheckVisibilityContent( - nsIContent* aNode, int16_t aStartOffset, int16_t aEndOffset, - bool* aRetval) { - if (!mPresShellWeak) { - return NS_ERROR_NOT_INITIALIZED; - } - nsCOMPtr<nsISelectionController> presShell = do_QueryReferent(mPresShellWeak); - if (NS_WARN_IF(!presShell)) { - return NS_ERROR_FAILURE; - } - return presShell->CheckVisibilityContent(aNode, aStartOffset, aEndOffset, - aRetval); -} - /***************************************************************************** * mozilla::TextInputListener *****************************************************************************/ diff --git a/editor/libeditor/HTMLEditUtils.cpp b/editor/libeditor/HTMLEditUtils.cpp index 3cd6bfe082131..64a6aae27b8b7 100644 --- a/editor/libeditor/HTMLEditUtils.cpp +++ b/editor/libeditor/HTMLEditUtils.cpp @@ -38,6 +38,7 @@ #include "nsString.h" // for nsAutoString #include "nsStyledElement.h" #include "nsTextFragment.h" // for nsTextFragment +#include "nsTextFrame.h" // for nsTextFrame namespace mozilla { @@ -451,39 +452,23 @@ bool HTMLEditUtils::IsVisibleTextNode(const Text& aText) { bool HTMLEditUtils::IsInVisibleTextFrames(nsPresContext* aPresContext, const Text& aText) { + // TODO(dholbert): aPresContext is now unused; maybe we can remove it, here + // and in IsEmptyNode? We do use it as a signal (implicitly here, + // more-explicitly in IsEmptyNode) that we are in a "SafeToAskLayout" case... + // If/when we remove it, we should be sure we're not losing that signal of + // strictness, since this function here does absolutely need to query layout. MOZ_ASSERT(aPresContext); - nsIFrame* frame = aText.GetPrimaryFrame(); - if (!frame) { - return false; - } - - nsCOMPtr<nsISelectionController> selectionController; - nsresult rv = frame->GetSelectionController( - aPresContext, getter_AddRefs(selectionController)); - NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), - "nsIFrame::GetSelectionController() failed"); - if (NS_FAILED(rv) || !selectionController) { + if (!aText.TextDataLength()) { return false; } - if (!aText.TextDataLength()) { + nsTextFrame* textFrame = do_QueryFrame(aText.GetPrimaryFrame()); + if (!textFrame) { return false; } - // Ask the selection controller for information about whether any of the - // data in the node is really rendered. This is really something that - // frames know about, but we aren't supposed to talk to frames. So we put - // a call in the selection controller interface, since it's already in bed - // with frames anyway. (This is a fix for bug 22227, and a partial fix for - // bug 46209.) - bool isVisible = false; - rv = selectionController->CheckVisibilityContent( - const_cast<Text*>(&aText), 0, aText.TextDataLength(), &isVisible); - NS_WARNING_ASSERTION( - NS_SUCCEEDED(rv), - "nsISelectionController::CheckVisibilityContent() failed"); - return NS_SUCCEEDED(rv) && isVisible; + return textFrame->HasVisibleText(); } Element* HTMLEditUtils::GetElementOfImmediateBlockBoundary( diff --git a/editor/libeditor/HTMLEditUtils.h b/editor/libeditor/HTMLEditUtils.h index f8337d0c69f0d..1420c3e0379c5 100644 --- a/editor/libeditor/HTMLEditUtils.h +++ b/editor/libeditor/HTMLEditUtils.h @@ -335,7 +335,7 @@ class HTMLEditUtils final { static bool IsVisibleTextNode(const Text& aText); /** - * IsInVisibleTextFrames() returns true if all text in aText is in visible + * IsInVisibleTextFrames() returns true if any text in aText is in visible * text frames. Callers have to guarantee that there is no pending reflow. */ static bool IsInVisibleTextFrames(nsPresContext* aPresContext, diff --git a/layout/base/PresShell.cpp b/layout/base/PresShell.cpp index 89f9729dcefc9..b9b637b11924a 100644 --- a/layout/base/PresShell.cpp +++ b/layout/base/PresShell.cpp @@ -2507,50 +2507,6 @@ PresShell::CompleteMove(bool aForward, bool aExtend) { nsISelectionController::SCROLL_FOR_CARET_MOVE); } -static void DoCheckVisibility(nsPresContext* aPresContext, nsIContent* aNode, - int16_t aStartOffset, int16_t aEndOffset, - bool* aRetval) { - nsIFrame* frame = aNode->GetPrimaryFrame(); - if (!frame) { - // No frame to look at so it must not be visible. - return; - } - - // Start process now to go through all frames to find startOffset. Then check - // chars after that to see if anything until EndOffset is visible. - bool finished = false; - frame->CheckVisibility(aPresContext, aStartOffset, aEndOffset, true, - &finished, aRetval); - // Don't worry about other return value. -} - -NS_IMETHODIMP -PresShell::CheckVisibility(nsINode* node, int16_t startOffset, - int16_t EndOffset, bool* _retval) { - if (!node || startOffset > EndOffset || !_retval || startOffset < 0 || - EndOffset < 0) - return NS_ERROR_INVALID_ARG; - *_retval = false; // initialize return parameter - nsCOMPtr<nsIContent> content(do_QueryInterface(node)); - if (!content) return NS_ERROR_FAILURE; - - DoCheckVisibility(mPresContext, content, startOffset, EndOffset, _retval); - return NS_OK; -} - -nsresult PresShell::CheckVisibilityContent(nsIContent* aNode, - int16_t aStartOffset, - int16_t aEndOffset, bool* aRetval) { - if (!aNode || aStartOffset > aEndOffset || !aRetval || aStartOffset < 0 || - aEndOffset < 0) { - return NS_ERROR_INVALID_ARG; - } - - *aRetval = false; - DoCheckVisibility(mPresContext, aNode, aStartOffset, aEndOffset, aRetval); - return NS_OK; -} - // end implementations nsISelectionController nsIFrame* PresShell::GetRootScrollFrame() const { diff --git a/layout/base/PresShell.h b/layout/base/PresShell.h index 5c14a34d088b9..0c02d76cfb6b0 100644 --- a/layout/base/PresShell.h +++ b/layout/base/PresShell.h @@ -1386,10 +1386,6 @@ class PresShell final : public nsStubDocumentObserver, NS_IMETHOD CompleteScroll(bool aForward) override; MOZ_CAN_RUN_SCRIPT NS_IMETHOD CompleteMove(bool aForward, bool aExtend) override; - NS_IMETHOD CheckVisibility(nsINode* node, int16_t startOffset, - int16_t EndOffset, bool* _retval) override; - nsresult CheckVisibilityContent(nsIContent* aNode, int16_t aStartOffset, - int16_t aEndOffset, bool* aRetval) override; // Notifies that the state of the document has changed. void DocumentStatesChanged(dom::DocumentState); diff --git a/layout/generic/nsIFrame.cpp b/layout/generic/nsIFrame.cpp index 2d7a9ead526f2..62185e5bb2df6 100644 --- a/layout/generic/nsIFrame.cpp +++ b/layout/generic/nsIFrame.cpp @@ -9210,11 +9210,6 @@ bool nsIFrame::BreakWordBetweenPunctuation(const PeekWordState* aState, return aState->mSeenNonPunctuationSinceWhitespace; } -nsresult nsIFrame::CheckVisibility(nsPresContext*, int32_t, int32_t, bool, - bool*, bool*) { - return NS_ERROR_NOT_IMPLEMENTED; -} - std::pair<nsIFrame*, nsIFrame*> nsIFrame::GetContainingBlockForLine( bool aLockScroll) const { const nsIFrame* parentFrame = this; diff --git a/layout/generic/nsIFrame.h b/layout/generic/nsIFrame.h index eb127353c9532..91d5810037d8e 100644 --- a/layout/generic/nsIFrame.h +++ b/layout/generic/nsIFrame.h @@ -3925,28 +3925,6 @@ class nsIFrame : public nsQueryFrame { nsDirection aDirection); public: - /** - * Called to see if the children of the frame are visible from indexstart to - * index end. This does not change any state. Returns true only if the indexes - * are valid and any of the children are visible. For textframes this index - * is the character index. If aStart = aEnd result will be false. - * - * @param aStart start index of first child from 0-N (number of children) - * - * @param aEnd end index of last child from 0-N - * - * @param aRecurse should this frame talk to siblings to get to the contents - * other children? - * - * @param aFinished did this frame have the aEndIndex? or is there more work - * to do - * - * @param _retval return value true or false. false = range is not rendered. - */ - virtual nsresult CheckVisibility(nsPresContext* aContext, int32_t aStartIndex, - int32_t aEndIndex, bool aRecurse, - bool* aFinished, bool* _retval); - /** * Called to tell a frame that one of its child frames is dirty (i.e., * has the NS_FRAME_IS_DIRTY *or* NS_FRAME_HAS_DIRTY_CHILDREN bit diff --git a/layout/generic/nsTextFrame.cpp b/layout/generic/nsTextFrame.cpp index 91dc6f2a7acd9..66d597a4cc017 100644 --- a/layout/generic/nsTextFrame.cpp +++ b/layout/generic/nsTextFrame.cpp @@ -8489,27 +8489,17 @@ nsIFrame::FrameSearchResult nsTextFrame::PeekOffsetWord( return CONTINUE; } -// TODO this needs to be deCOMtaminated with the interface fixed in -// nsIFrame.h, but we won't do that until the old textframe is gone. -nsresult nsTextFrame::CheckVisibility(nsPresContext* aContext, - int32_t aStartIndex, int32_t aEndIndex, - bool aRecurse, bool* aFinished, - bool* aRetval) { - if (!aRetval) return NS_ERROR_NULL_POINTER; - +bool nsTextFrame::HasVisibleText() { // Text in the range is visible if there is at least one character in the // range that is not skipped and is mapped by this frame (which is the primary // frame) or one of its continuations. for (nsTextFrame* f = this; f; f = f->GetNextContinuation()) { int32_t dummyOffset = 0; if (f->PeekOffsetNoAmount(true, &dummyOffset) == FOUND) { - *aRetval = true; - return NS_OK; + return true; } } - - *aRetval = false; - return NS_OK; + return false; } std::pair<int32_t, int32_t> nsTextFrame::GetOffsets() const { diff --git a/layout/generic/nsTextFrame.h b/layout/generic/nsTextFrame.h index 1f69ad8c30c73..72a9b976c772a 100644 --- a/layout/generic/nsTextFrame.h +++ b/layout/generic/nsTextFrame.h @@ -342,9 +342,8 @@ class nsTextFrame : public nsIFrame { PeekWordState* aState, bool aTrimSpaces) final; - nsresult CheckVisibility(nsPresContext* aContext, int32_t aStartIndex, - int32_t aEndIndex, bool aRecurse, bool* aFinished, - bool* _retval) final; + // Helper method that editor code uses to test for visibility. + [[nodiscard]] bool HasVisibleText(); // Flags for aSetLengthFlags enum { ALLOW_FRAME_CREATION_AND_DESTRUCTION = 0x01 }; -- GitLab