Bug 1302470 Part 3: Augment the IsRangeVisible function to test for opaque overdraw. r=mstange

MozReview-Commit-ID: F2qbu0WLl9O

--HG--
extra : rebase_source : 0191d2efdd2e03ccbb087bc90e5dc031552b9c39
This commit is contained in:
Brad Werth 2016-11-09 16:08:56 -08:00
parent 87e7094923
commit b96e085956

View File

@ -1181,6 +1181,42 @@ nsTypeAheadFind::IsRangeVisible(nsIDOMRange *aRange,
return NS_OK;
}
bool
IsFrameVisibleInFrameStack(nsIFrame *aFrame,
const nsTArray<nsIFrame*>& aOrderedFramesFrontToBack)
{
// Visibility requires that aFrame appears in aOrderedFramesFrontToBack,
// and that overlaying frames are not entirely opaque. We stop evaluating
// once we reach aFrame, because we don't want frames underneath aFrame to
// affect the test.
// This definition is conservative; this function will return false in some
// cases where aFrame may actually be visible, including:
// a) aFrame is only partially covered by another frame.
// b) A frame covering aFrame is opaque but empty.
for (nsIFrame* f : aOrderedFramesFrontToBack) {
if (!f) {
continue;
}
if (f == aFrame) {
return true;
}
if (f->StyleEffects()->mOpacity < 1.0f) {
continue;
}
// Something fully opaque is at least partially obscuring aFrame, so
// aFrame is considered not visible.
return false;
}
// We didn't find aFrame, which means it wasn't visible.
return false;
}
bool
nsTypeAheadFind::IsRangeVisible(nsIPresShell *aPresShell,
nsPresContext *aPresContext,
@ -1192,9 +1228,8 @@ nsTypeAheadFind::IsRangeVisible(nsIPresShell *aPresShell,
NS_ASSERTION(aPresShell && aPresContext && aRange && aFirstVisibleRange,
"params are invalid");
// We need to know if the range start is visible.
// Otherwise, return the first visible range start
// in aFirstVisibleRange
// 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);
if (aFlushLayout) {
@ -1202,15 +1237,17 @@ nsTypeAheadFind::IsRangeVisible(nsIPresShell *aPresShell,
}
nsCOMPtr<nsIDOMNode> node;
aRange->GetStartContainer(getter_AddRefs(node));
aRange->GetCommonAncestorContainer(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.
@ -1227,8 +1264,13 @@ nsTypeAheadFind::IsRangeVisible(nsIPresShell *aPresShell,
nsLayoutUtils::GetFramesForArea(rootFrame, r, frames,
nsLayoutUtils::IGNORE_PAINT_SUPPRESSION | nsLayoutUtils::IGNORE_ROOT_SCROLL_FRAME);
}
if (!frames.Length())
if (!frames.Length()) {
return false;
}
if (!IsFrameVisibleInFrameStack(frame, frames)) {
return false;
}
// Detect if we are _inside_ a text control, or something else with its own
// selection controller.