Backed out 5 changesets (
bug 1302470) for causing
bug 1323200 a=backout
Backed out changeset 005adbf78cd2 (
bug 1302470)
Backed out changeset 113f7b13475c (
bug 1302470)
Backed out changeset 3d2569996ebc (
bug 1302470)
Backed out changeset b92b78271941 (
bug 1302470)
Backed out changeset 5b92678afff8 (
bug 1302470)
MozReview-Commit-ID: FgeA5OQV8WP
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -3168,33 +3168,32 @@ nsLayoutUtils::GetFramesForArea(nsIFrame
if (rootScrollFrame) {
builder.SetIgnoreScrollFrame(rootScrollFrame);
}
}
if (aFlags & IGNORE_CROSS_DOC) {
builder.SetDescendIntoSubdocuments(false);
}
- builder.SetHitTestShouldStopAtFirstOpaque(aFlags & ONLY_VISIBLE);
-
builder.EnterPresShell(aFrame);
aFrame->BuildDisplayListForStackingContext(&builder, aRect, &list);
builder.LeavePresShell(aFrame, nullptr);
#ifdef MOZ_DUMP_PAINTING
if (gDumpEventList) {
fprintf_stderr(stderr, "Event handling --- (%d,%d):\n", aRect.x, aRect.y);
std::stringstream ss;
nsFrame::PrintDisplayList(&builder, list, ss);
print_stderr(ss);
}
#endif
nsDisplayItem::HitTestState hitTestState;
+ builder.SetHitTestShouldStopAtFirstOpaque(aFlags & ONLY_VISIBLE);
list.HitTest(&builder, aRect, &hitTestState, &aOutFrames);
list.DeleteAll();
return NS_OK;
}
// aScrollFrameAsScrollable must be non-nullptr and queryable to an nsIFrame
FrameMetrics
nsLayoutUtils::CalculateBasicFrameMetrics(nsIScrollableFrame* aScrollFrame) {
--- a/layout/base/nsLayoutUtils.h
+++ b/layout/base/nsLayoutUtils.h
@@ -820,17 +820,17 @@ public:
static nsIFrame* GetFrameForPoint(nsIFrame* aFrame, nsPoint aPt,
uint32_t aFlags = 0);
/**
* Given aFrame, the root frame of a stacking context, find all descendant
* frames under the area of a rectangle that receives a mouse event,
* or nullptr if there is no such frame.
* @param aRect the rect, relative to the frame origin
- * @param aOutFrames an array to append all the frames found
+ * @param aOutFrames an array to add all the frames found
* @param aFlags some combination of FrameForPointFlags
*/
static nsresult GetFramesForArea(nsIFrame* aFrame, const nsRect& aRect,
nsTArray<nsIFrame*> &aOutFrames,
uint32_t aFlags = 0);
/**
* Transform aRect relative to aFrame up to the coordinate system of
--- a/layout/forms/nsHTMLButtonControlFrame.cpp
+++ b/layout/forms/nsHTMLButtonControlFrame.cpp
@@ -114,17 +114,17 @@ nsHTMLButtonControlFrame::BuildDisplayLi
nsDisplayList onTop;
if (IsVisibleForPainting(aBuilder)) {
mRenderer.DisplayButton(aBuilder, aLists.BorderBackground(), &onTop);
}
nsDisplayListCollection set;
// Do not allow the child subtree to receive events.
- if (!isForEventDelivery || aBuilder->HitTestShouldStopAtFirstOpaque()) {
+ if (!isForEventDelivery) {
DisplayListClipState::AutoSaveRestore clipState(aBuilder);
if (ShouldClipPaintingToBorderBox()) {
nsMargin border = StyleBorder()->GetComputedBorder();
nsRect rect(aBuilder->ToReferenceFrame(this), GetSize());
rect.Deflate(border);
nscoord radii[8];
bool hasRadii = GetPaddingBoxBorderRadii(radii);
--- a/toolkit/components/typeaheadfind/nsITypeAheadFind.idl
+++ b/toolkit/components/typeaheadfind/nsITypeAheadFind.idl
@@ -13,17 +13,17 @@
/******************************** Declarations *******************************/
interface mozIDOMWindow;
interface nsIDocShell;
/****************************** nsTypeAheadFind ******************************/
-[scriptable, uuid(3cfe7906-f189-45a0-8abe-8e4437a23cae)]
+[scriptable, uuid(ae501e28-c57f-4692-ac74-410e1bed98b7)]
interface nsITypeAheadFind : nsISupports
{
/****************************** Initializer ******************************/
/* Necessary initialization that can't happen in the constructor, either
* because function calls here may fail, or because the docShell is
* required. */
void init(in nsIDocShell aDocShell);
@@ -53,17 +53,17 @@ interface nsITypeAheadFind : nsISupports
void setSelectionModeAndRepaint(in short toggle);
/* Collapse the "found match" selection to its start. Because not all
* matches are owned by the same selection controller, this doesn't
* necessarily happen automatically. */
void collapseSelection();
/* Check if a range is visible */
- boolean isRangeVisible(in nsIDOMRange aRange, in boolean aFlushLayout);
+ boolean isRangeVisible(in nsIDOMRange aRange, in boolean aMustBeInViewPort);
/******************************* Attributes ******************************/
readonly attribute AString searchString;
// Most recent search string
attribute boolean caseSensitive; // Searches are case sensitive
attribute boolean entireWord; // Search for whole words only
readonly attribute nsIDOMElement foundLink;
--- a/toolkit/components/typeaheadfind/nsTypeAheadFind.cpp
+++ b/toolkit/components/typeaheadfind/nsTypeAheadFind.cpp
@@ -47,17 +47,16 @@
#include "nsNameSpaceManager.h"
#include "nsIWindowWatcher.h"
#include "nsIObserverService.h"
#include "nsFocusManager.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/Link.h"
#include "nsRange.h"
#include "nsXBLBinding.h"
-#include "nsLayoutUtils.h"
#include "nsTypeAheadFind.h"
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsTypeAheadFind)
NS_INTERFACE_MAP_ENTRY(nsITypeAheadFind)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsITypeAheadFind)
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
NS_INTERFACE_MAP_ENTRY(nsIObserver)
@@ -66,16 +65,18 @@ NS_INTERFACE_MAP_END
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsTypeAheadFind)
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsTypeAheadFind)
NS_IMPL_CYCLE_COLLECTION(nsTypeAheadFind, mFoundLink, mFoundEditable,
mCurrentWindow, mStartFindRange, mSearchRange,
mStartPointRange, mEndPointRange, mSoundInterface,
mFind, mFoundRange)
+static NS_DEFINE_CID(kFrameTraversalCID, NS_FRAMETRAVERSAL_CID);
+
#define NS_FIND_CONTRACTID "@mozilla.org/embedcomp/rangefind;1"
nsTypeAheadFind::nsTypeAheadFind():
mStartLinksOnlyPref(false),
mCaretBrowsingOn(false),
mDidAddObservers(false),
mLastFindLength(0),
mIsSoundInitialized(false),
@@ -416,31 +417,32 @@ nsTypeAheadFind::FindItNow(nsIPresShell
return NS_ERROR_FAILURE;
mFind->SetFindBackwards(aFindPrev);
while (true) { // ----- Outer while loop: go through all docs -----
while (true) { // === Inner while loop: go through a single doc ===
mFind->Find(mTypeAheadBuffer.get(), mSearchRange, mStartPointRange,
mEndPointRange, getter_AddRefs(returnRange));
-
+
if (!returnRange)
break; // Nothing found in this doc, go to outer loop (try next doc)
// ------- Test resulting found range for success conditions ------
bool isInsideLink = false, isStartingLink = false;
if (aIsLinksOnly) {
// Don't check if inside link when searching all text
RangeStartsInsideLink(returnRange, presShell, &isInsideLink,
&isStartingLink);
}
bool usesIndependentSelection;
- if (!IsRangeVisible(presShell, presContext, returnRange, true,
+ if (!IsRangeVisible(presShell, presContext, returnRange,
+ aIsFirstVisiblePreferred, false,
getter_AddRefs(mStartPointRange),
&usesIndependentSelection) ||
(aIsLinksOnly && !isInsideLink) ||
(mStartLinksOnlyPref && aIsLinksOnly && !isStartingLink)) {
// ------ Failure ------
// At this point mStartPointRange got updated to the first
// visible range in the viewport. We _may_ be able to just
// start there, if it's not taking us in the wrong direction.
@@ -810,17 +812,18 @@ nsTypeAheadFind::GetSearchContainers(nsI
if (selection)
selection->GetRangeAt(0, getter_AddRefs(currentSelectionRange));
}
if (!currentSelectionRange) {
// Ensure visible range, move forward if necessary
// This uses ignores the return value, but usese the side effect of
// IsRangeVisible. It returns the first visible range after searchRange
- IsRangeVisible(presShell, presContext, mSearchRange, true,
+ IsRangeVisible(presShell, presContext, mSearchRange,
+ aIsFirstVisiblePreferred, true,
getter_AddRefs(mStartPointRange), nullptr);
}
else {
int32_t startOffset;
nsCOMPtr<nsIDOMNode> startNode;
if (aFindPrev) {
currentSelectionRange->GetStartContainer(getter_AddRefs(startNode));
currentSelectionRange->GetStartOffset(&startOffset);
@@ -1000,28 +1003,28 @@ nsTypeAheadFind::Find(const nsAString& a
// is typed
mStartFindRange = nullptr;
mSelectionController = nullptr;
*aResult = FIND_FOUND;
return NS_OK;
}
- bool atEnd = false;
+ bool atEnd = false;
if (mTypeAheadBuffer.Length()) {
const nsAString& oldStr = Substring(mTypeAheadBuffer, 0, mTypeAheadBuffer.Length());
const nsAString& newStr = Substring(aSearchString, 0, mTypeAheadBuffer.Length());
if (oldStr.Equals(newStr))
atEnd = true;
-
+
const nsAString& newStr2 = Substring(aSearchString, 0, aSearchString.Length());
const nsAString& oldStr2 = Substring(mTypeAheadBuffer, 0, aSearchString.Length());
if (oldStr2.Equals(newStr2))
atEnd = true;
-
+
if (!atEnd)
mStartFindRange = nullptr;
}
if (!mIsSoundInitialized && !mNotFoundSoundURL.IsEmpty()) {
// This makes sure system sound library is loaded so that
// there's no lag before the first sound is played
// by waiting for the first keystroke, we still get the startup time benefits.
@@ -1153,122 +1156,160 @@ nsTypeAheadFind::GetFoundRange(nsIDOMRan
}
mFoundRange->CloneRange(aFoundRange);
return NS_OK;
}
NS_IMETHODIMP
nsTypeAheadFind::IsRangeVisible(nsIDOMRange *aRange,
- bool aFlushLayout,
+ bool aMustBeInViewPort,
bool *aResult)
{
// Jump through hoops to extract the docShell from the range.
nsCOMPtr<nsIDOMNode> node;
aRange->GetStartContainer(getter_AddRefs(node));
nsCOMPtr<nsIDOMDocument> document;
node->GetOwnerDocument(getter_AddRefs(document));
nsCOMPtr<mozIDOMWindowProxy> window;
document->GetDefaultView(getter_AddRefs(window));
nsCOMPtr<nsIWebNavigation> navNav (do_GetInterface(window));
nsCOMPtr<nsIDocShell> docShell (do_GetInterface(navNav));
// Set up the arguments needed to check if a range is visible.
nsCOMPtr<nsIPresShell> presShell (docShell->GetPresShell());
RefPtr<nsPresContext> presContext = presShell->GetPresContext();
nsCOMPtr<nsIDOMRange> startPointRange = new nsRange(presShell->GetDocument());
- *aResult = IsRangeVisible(presShell, presContext, aRange, aFlushLayout,
+ *aResult = IsRangeVisible(presShell, presContext, aRange,
+ aMustBeInViewPort, false,
getter_AddRefs(startPointRange),
nullptr);
return NS_OK;
}
bool
nsTypeAheadFind::IsRangeVisible(nsIPresShell *aPresShell,
nsPresContext *aPresContext,
- nsIDOMRange *aRange,
- bool aFlushLayout,
+ nsIDOMRange *aRange, bool aMustBeInViewPort,
+ bool aGetTopVisibleLeaf,
nsIDOMRange **aFirstVisibleRange,
bool *aUsesIndependentSelection)
{
NS_ASSERTION(aPresShell && aPresContext && aRange && aFirstVisibleRange,
"params are invalid");
- // We need to know if the range start and end are both visible.
- // In all cases, return the first visible range in aFirstVisibleRange.
- aRange->CloneRange(aFirstVisibleRange);
+ // We need to know if the range start is visible.
+ // Otherwise, return the first visible range start
+ // in aFirstVisibleRange
- if (aFlushLayout) {
- aPresShell->FlushPendingNotifications(Flush_Layout);
- }
-
+ aRange->CloneRange(aFirstVisibleRange);
nsCOMPtr<nsIDOMNode> node;
- aRange->GetCommonAncestorContainer(getter_AddRefs(node));
+ aRange->GetStartContainer(getter_AddRefs(node));
nsCOMPtr<nsIContent> content(do_QueryInterface(node));
- if (!content) {
+ if (!content)
return false;
- }
nsIFrame *frame = content->GetPrimaryFrame();
- if (!frame) {
+ if (!frame)
return false; // No frame! Not visible then.
- }
-
- // Having a primary frame doesn't mean that the range is visible inside the
- // viewport. Do a hit-test to determine that quickly and properly.
- bool foundContent = false;
- AutoTArray<nsIFrame*,8> frames;
- nsIFrame *rootFrame = aPresShell->GetRootFrame();
- RefPtr<nsRange> range = static_cast<nsRange*>(aRange);
- RefPtr<mozilla::dom::DOMRectList> rects = range->GetClientRects(true, false);
- for (uint32_t i = 0; i < rects->Length(); ++i) {
- RefPtr<mozilla::dom::DOMRect> rect = rects->Item(i);
- nsRect r(nsPresContext::CSSPixelsToAppUnits((float)rect->X()),
- nsPresContext::CSSPixelsToAppUnits((float)rect->Y()),
- nsPresContext::CSSPixelsToAppUnits((float)rect->Width()),
- nsPresContext::CSSPixelsToAppUnits((float)rect->Height()));
- // Append visible frames to frames array.
- nsLayoutUtils::GetFramesForArea(rootFrame, r, frames,
- nsLayoutUtils::IGNORE_PAINT_SUPPRESSION |
- nsLayoutUtils::IGNORE_ROOT_SCROLL_FRAME |
- nsLayoutUtils::ONLY_VISIBLE);
- // See if any of the frames contain the content. If they do, then the range
- // is visible. We search for the content rather than the original frame,
- // because nsTextContinuation frames might be returned instead of the
- // original frame.
- for (const auto &f: frames) {
- if (f->GetContent() == content) {
- foundContent = true;
- break;
- }
- }
-
- if (foundContent) {
- break;
- }
-
- frames.ClearAndRetainStorage();
- }
-
- // Test that content appears in the list of framesForArea. If it does, then
- // that means that content is at least partly visible.
- if (!foundContent) {
+ if (!frame->StyleVisibility()->IsVisible())
return false;
- }
// Detect if we are _inside_ a text control, or something else with its own
// selection controller.
if (aUsesIndependentSelection) {
*aUsesIndependentSelection =
(frame->GetStateBits() & NS_FRAME_INDEPENDENT_SELECTION);
}
- return true;
+ // ---- We have a frame ----
+ if (!aMustBeInViewPort)
+ return true; // Don't need it to be on screen, just in rendering tree
+
+ // Get the next in flow frame that contains the range start
+ int32_t startRangeOffset, startFrameOffset, endFrameOffset;
+ aRange->GetStartOffset(&startRangeOffset);
+ while (true) {
+ frame->GetOffsets(startFrameOffset, endFrameOffset);
+ if (startRangeOffset < endFrameOffset)
+ break;
+
+ nsIFrame *nextContinuationFrame = frame->GetNextContinuation();
+ if (nextContinuationFrame)
+ frame = nextContinuationFrame;
+ else
+ break;
+ }
+
+ // Set up the variables we need, return true if we can't get at them all
+ const uint16_t kMinPixels = 12;
+ nscoord minDistance = nsPresContext::CSSPixelsToAppUnits(kMinPixels);
+
+ // Get the bounds of the current frame, relative to the current view.
+ // We don't use the more accurate AccGetBounds, because that is
+ // more expensive and the STATE_OFFSCREEN flag that this is used
+ // for only needs to be a rough indicator
+ nsRectVisibility rectVisibility = nsRectVisibility_kAboveViewport;
+
+ if (!aGetTopVisibleLeaf && !frame->GetRect().IsEmpty()) {
+ rectVisibility =
+ aPresShell->GetRectVisibility(frame,
+ nsRect(nsPoint(0,0), frame->GetSize()),
+ minDistance);
+
+ if (rectVisibility != nsRectVisibility_kAboveViewport) {
+ return true;
+ }
+ }
+
+ // We know that the target range isn't usable because it's not in the
+ // view port. Move range forward to first visible point,
+ // this speeds us up a lot in long documents
+ nsCOMPtr<nsIFrameEnumerator> frameTraversal;
+ nsCOMPtr<nsIFrameTraversal> trav(do_CreateInstance(kFrameTraversalCID));
+ if (trav)
+ trav->NewFrameTraversal(getter_AddRefs(frameTraversal),
+ aPresContext, frame,
+ eLeaf,
+ false, // aVisual
+ false, // aLockInScrollView
+ false, // aFollowOOFs
+ false // aSkipPopupChecks
+ );
+
+ if (!frameTraversal)
+ return false;
+
+ while (rectVisibility == nsRectVisibility_kAboveViewport) {
+ frameTraversal->Next();
+ frame = frameTraversal->CurrentItem();
+ if (!frame)
+ return false;
+
+ if (!frame->GetRect().IsEmpty()) {
+ rectVisibility =
+ aPresShell->GetRectVisibility(frame,
+ nsRect(nsPoint(0,0), frame->GetSize()),
+ minDistance);
+ }
+ }
+
+ if (frame) {
+ nsCOMPtr<nsIDOMNode> firstVisibleNode = do_QueryInterface(frame->GetContent());
+
+ if (firstVisibleNode) {
+ frame->GetOffsets(startFrameOffset, endFrameOffset);
+ (*aFirstVisibleRange)->SetStart(firstVisibleNode, startFrameOffset);
+ (*aFirstVisibleRange)->SetEnd(firstVisibleNode, endFrameOffset);
+ }
+ }
+
+ return false;
}
already_AddRefed<nsIPresShell>
nsTypeAheadFind::GetPresShell()
{
if (!mPresShell)
return nullptr;
--- a/toolkit/components/typeaheadfind/nsTypeAheadFind.h
+++ b/toolkit/components/typeaheadfind/nsTypeAheadFind.h
@@ -51,18 +51,18 @@ protected:
void RangeStartsInsideLink(nsIDOMRange *aRange, nsIPresShell *aPresShell,
bool *aIsInsideLink, bool *aIsStartingLink);
void GetSelection(nsIPresShell *aPresShell, nsISelectionController **aSelCon,
nsISelection **aDomSel);
// *aNewRange may not be collapsed. If you want to collapse it in a
// particular way, you need to do it yourself.
bool IsRangeVisible(nsIPresShell *aPresShell, nsPresContext *aPresContext,
- nsIDOMRange *aRange, bool aFlushLayout,
- nsIDOMRange **aNewRange,
+ nsIDOMRange *aRange, bool aMustBeVisible,
+ bool aGetTopVisibleLeaf, nsIDOMRange **aNewRange,
bool *aUsesIndependentSelection);
nsresult FindItNow(nsIPresShell *aPresShell, bool aIsLinksOnly,
bool aIsFirstVisiblePreferred, bool aFindPrev,
uint16_t* aResult);
nsresult GetSearchContainers(nsISupports *aContainer,
nsISelectionController *aSelectionController,
bool aIsFirstVisiblePreferred,
bool aFindPrev, nsIPresShell **aPresShell,
@@ -90,17 +90,17 @@ protected:
// mLastFindLength is the character length of the last find string. It is used for
// disabling the "not found" sound when using backspace or delete
uint32_t mLastFindLength;
// Sound is played asynchronously on some platforms.
// If we destroy mSoundInterface before sound has played, it won't play
nsCOMPtr<nsISound> mSoundInterface;
bool mIsSoundInitialized;
-
+
// where selection was when user started the find
nsCOMPtr<nsIDOMRange> mStartFindRange;
nsCOMPtr<nsIDOMRange> mSearchRange;
nsCOMPtr<nsIDOMRange> mStartPointRange;
nsCOMPtr<nsIDOMRange> mEndPointRange;
// Cached useful interfaces
nsCOMPtr<nsIFind> mFind;
--- a/toolkit/modules/FinderHighlighter.jsm
+++ b/toolkit/modules/FinderHighlighter.jsm
@@ -1132,19 +1132,16 @@ FinderHighlighter.prototype = {
this._updateRangeOutline(dict);
let allRects = [];
if (paintContent || dict.modalHighlightAllMask) {
this._updateDynamicRangesRects(dict);
let DOMRect = window.DOMRect;
for (let [range, rectsAndTexts] of dict.modalHighlightRectsMap) {
- if (!this.finder._fastFind.isRangeVisible(range, false))
- continue;
-
if (dict.updateAllRanges)
rectsAndTexts = this._updateRangeRects(range);
// If a geometry change was detected, we bail out right away here, because
// the current set of ranges has been invalidated.
if (dict.detectedGeometryChange)
return;
--- a/toolkit/modules/FinderIterator.jsm
+++ b/toolkit/modules/FinderIterator.jsm
@@ -562,17 +562,23 @@ this.FinderIterator = {
return frames;
// Casting `window.frames` to an Iterator doesn't work, so we're stuck with
// a plain, old for-loop.
for (let i = 0, l = window.frames.length; i < l; ++i) {
let frame = window.frames[i];
// Don't count matches in hidden frames.
let frameEl = frame && frame.frameElement;
- if (!frameEl || !frameEl.getClientRects().length)
+ if (!frameEl)
+ continue;
+ // Construct a range around the frame element to check its visiblity.
+ let range = window.document.createRange();
+ range.setStart(frameEl, 0);
+ range.setEnd(frameEl, 0);
+ if (!finder._fastFind.isRangeVisible(range, this._getDocShell(range), true))
continue;
// All conditions pass, so push the current frame and its children on the
// stack.
frames.push(frame, ...this._collectFrames(frame, finder));
}
return frames;
},