diff --git a/dom/base/nsISelectionController.idl b/dom/base/nsISelectionController.idl
index d5eaa23812afda8558c511128a7e181beb4d4dec..2bda55e7f2b4aeb81bf28dfc915b36ed5bc1a426 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 a3aaa19283ff9c5455013e54cf105ac88e7a42ef..a1523f2a6020763f26cb4a4275c52fd5af31e392 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 3cd6bfe082131b6409a401c90def8e3fe73d9c47..64a6aae27b8b7fba00da0c1cccb7623763b0e209 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 f8337d0c69f0d5b944bebf6392f1d40931028590..1420c3e0379c597e3b32b20d35cd2fabd23e40a4 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 89f9729dcefc9b38f47164fc5312f0ea25d85b00..b9b637b11924aeca0af697dc3a7c53a564b65d06 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 5c14a34d088b966002088839c544267416d88a6a..0c02d76cfb6b034403c92e682e1494ee05f8bdc0 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 2d7a9ead526f20f3ffb8507c6936fabf0b327d3b..62185e5bb2df663f0b81f76e6b3ba84cae5a5096 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 eb127353c9532ca7e1e4a24cd24e5d5f98d0434c..91d5810037d8efd863bc3f7186af1fe4417bfcad 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 91dc6f2a7acd973e24a0d4a6f6b8fc736b454cea..66d597a4cc017a790c223bea0febdbeea4f038e1 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 1f69ad8c30c73b52b6dc176191c65736d174932c..72a9b976c772a37acb3bbd6d75957ad5bbe613d2 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 };