Commit ef282941 authored by Bo Liu's avatar Bo Liu Committed by Commit Bot

android: Raise invisible main frame rank

Before this CL, the ranking order is:
1) visible main frame
2) visible subframe in viewport
3) visible subframe outside of viewport
4) invisible main frame
5) invisible subframe in viewport
6) invisible subframe outside of viewport

This CL moves 4) above 3).

This complicates the comparison algorithm quite a bit, since it's no
longer ok to compare fields independently.

Expand testRanking to cover all cases in the list above.
Also make failures in unit test easier to debug by using
assertArrayEquals.

Bug: 855037
Change-Id: I4aa1c785fcdb6978cfeca9bf8e6989dd6d3153ea
Reviewed-on: https://chromium-review.googlesource.com/1213924Reviewed-by: default avatarSiddhartha S <ssid@chromium.org>
Commit-Queue: Bo <boliu@chromium.org>
Cr-Commit-Position: refs/heads/master@{#589736}
parent 39542c96
......@@ -37,6 +37,17 @@ public class ChildProcessRanking implements Iterable<ChildProcessConnection> {
}
private static class RankComparator implements Comparator<ConnectionWithRank> {
private static int compareByIntersectsViewportAndDepth(
ConnectionWithRank o1, ConnectionWithRank o2) {
if (o1.intersectsViewport && !o2.intersectsViewport) {
return -1;
} else if (!o1.intersectsViewport && o2.intersectsViewport) {
return 1;
}
return (int) (o1.frameDepth - o2.frameDepth);
}
@Override
public int compare(ConnectionWithRank o1, ConnectionWithRank o2) {
// Sort null to the end.
......@@ -52,38 +63,60 @@ public class ChildProcessRanking implements Iterable<ChildProcessConnection> {
assert o2 != null;
// Ranking order:
// * visible or ChildProcessImportance.IMPORTANT
// * ChildProcessImportance.MODERATE
// * intersectsViewport
// * frameDepth (lower value is higher rank)
// Note boostForPendingViews is not used for ranking.
boolean o1IsForeground =
o1.visible || o1.importance == ChildProcessImportance.IMPORTANT;
boolean o2IsForeground =
o2.visible || o2.importance == ChildProcessImportance.IMPORTANT;
if (o1IsForeground && !o2IsForeground) {
// * (visible and main frame) or ChildProcessImportance.IMPORTANT
// * (visible and subframe and intersect viewport) or ChildProcessImportance.MODERATE
// * invisible main frame
// * visible subframe and not intersect viewport
// * invisible subframes
// Within each group, ties are broken by intersect viewport and then frame depth where
// applicable. Note boostForPendingViews is not used for ranking.
boolean o1IsVisibleMainOrImportant = (o1.visible && o1.frameDepth == 0)
|| o1.importance == ChildProcessImportance.IMPORTANT;
boolean o2IsVisibleMainOrImportant = (o2.visible && o2.frameDepth == 0)
|| o2.importance == ChildProcessImportance.IMPORTANT;
if (o1IsVisibleMainOrImportant && o2IsVisibleMainOrImportant) {
return compareByIntersectsViewportAndDepth(o1, o2);
} else if (o1IsVisibleMainOrImportant && !o2IsVisibleMainOrImportant) {
return -1;
} else if (!o1IsForeground && o2IsForeground) {
} else if (!o1IsVisibleMainOrImportant && o2IsVisibleMainOrImportant) {
return 1;
}
boolean o1IsModerate = o1.importance == ChildProcessImportance.MODERATE;
boolean o2IsModerate = o2.importance == ChildProcessImportance.MODERATE;
if (o1IsModerate && !o2IsModerate) {
boolean o1VisibleIntersectSubframeOrModerate =
(o1.visible && o1.frameDepth > 0 && o1.intersectsViewport)
|| o1.importance == ChildProcessImportance.MODERATE;
boolean o2VisibleIntersectSubframeOrModerate =
(o2.visible && o2.frameDepth > 0 && o2.intersectsViewport)
|| o2.importance == ChildProcessImportance.MODERATE;
if (o1VisibleIntersectSubframeOrModerate && o2VisibleIntersectSubframeOrModerate) {
return compareByIntersectsViewportAndDepth(o1, o2);
} else if (o1VisibleIntersectSubframeOrModerate
&& !o2VisibleIntersectSubframeOrModerate) {
return -1;
} else if (!o1IsModerate && o2IsModerate) {
} else if (!o1VisibleIntersectSubframeOrModerate
&& o2VisibleIntersectSubframeOrModerate) {
return 1;
}
if (o1.intersectsViewport && !o2.intersectsViewport) {
boolean o1InvisibleMainFrame = !o1.visible && o1.frameDepth == 0;
boolean o2InvisibleMainFrame = !o2.visible && o2.frameDepth == 0;
if (o1InvisibleMainFrame && o2InvisibleMainFrame) {
return 0;
} else if (o1InvisibleMainFrame && !o2InvisibleMainFrame) {
return -1;
} else if (!o1.intersectsViewport && o2.intersectsViewport) {
} else if (!o1InvisibleMainFrame && o2InvisibleMainFrame) {
return 1;
}
return (int) (o1.frameDepth - o2.frameDepth);
// The rest of the groups can just be ranked by visibility, intersects viewport, and
// frame depth.
if (o1.visible && !o2.visible) {
return -1;
} else if (!o1.visible && o2.visible) {
return 1;
}
return compareByIntersectsViewportAndDepth(o1, o2);
}
}
......
......@@ -29,15 +29,23 @@ public class ChildProcessRankingTest {
private void assertRankingAndRemoveAll(
ChildProcessRanking ranking, ChildProcessConnection[] connections) {
int index = connections.length;
ChildProcessConnection reverseIterationArray[] =
new ChildProcessConnection[connections.length];
for (ChildProcessConnection c : ranking) {
Assert.assertEquals(connections[--index], c);
reverseIterationArray[--index] = c;
}
Assert.assertArrayEquals(connections, reverseIterationArray);
Assert.assertEquals(0, index);
for (int i = connections.length - 1; i >= 0; i--) {
Assert.assertEquals(connections[i], ranking.getLowestRankedConnection());
ranking.removeConnection(connections[i]);
index = connections.length;
ChildProcessConnection reverseRemoveArray[] =
new ChildProcessConnection[connections.length];
for (int i = 0; i < connections.length; ++i) {
ChildProcessConnection c = ranking.getLowestRankedConnection();
reverseRemoveArray[--index] = c;
ranking.removeConnection(c);
}
Assert.assertArrayEquals(connections, reverseRemoveArray);
Assert.assertNull(ranking.getLowestRankedConnection());
}
......@@ -47,20 +55,51 @@ public class ChildProcessRankingTest {
ChildProcessConnection c2 = createConnection();
ChildProcessConnection c3 = createConnection();
ChildProcessConnection c4 = createConnection();
ChildProcessConnection c5 = createConnection();
ChildProcessConnection c6 = createConnection();
ChildProcessConnection c7 = createConnection();
ChildProcessConnection c8 = createConnection();
ChildProcessConnection c9 = createConnection();
ChildProcessConnection c10 = createConnection();
ChildProcessRanking ranking = new ChildProcessRanking(4);
ChildProcessRanking ranking = new ChildProcessRanking(10);
// Insert in lowest ranked to highest ranked order.
ranking.addConnection(c1, false /* foreground */, 1 /* frameDepth */,
// Invisible subframe outside of viewport.
ranking.addConnection(c1, false /* foreground */, 2 /* frameDepth */,
false /* intersectsViewport */, ChildProcessImportance.NORMAL);
ranking.addConnection(c2, false /* foreground */, 0 /* frameDepth */,
ranking.addConnection(c2, false /* foreground */, 1 /* frameDepth */,
false /* intersectsViewport */, ChildProcessImportance.NORMAL);
ranking.addConnection(c3, true /* foreground */, 1 /* frameDepth */,
// Invisible subframe inside viewport.
ranking.addConnection(c3, false /* foreground */, 2 /* frameDepth */,
true /* intersectsViewport */, ChildProcessImportance.NORMAL);
ranking.addConnection(c4, false /* foreground */, 1 /* frameDepth */,
true /* intersectsViewport */, ChildProcessImportance.NORMAL);
// Visible subframe outside viewport.
ranking.addConnection(c5, true /* foreground */, 2 /* frameDepth */,
false /* intersectsViewport */, ChildProcessImportance.NORMAL);
ranking.addConnection(c4, true /* foreground */, 0 /* frameDepth */,
ranking.addConnection(c6, true /* foreground */, 1 /* frameDepth */,
false /* intersectsViewport */, ChildProcessImportance.NORMAL);
assertRankingAndRemoveAll(ranking, new ChildProcessConnection[] {c4, c3, c2, c1});
// Invisible main frame.
ranking.addConnection(c7, false /* foreground */, 0 /* frameDepth */,
true /* intersectsViewport */, ChildProcessImportance.NORMAL);
// Visible subframe inside viewport.
ranking.addConnection(c8, true /* foreground */, 2 /* frameDepth */,
true /* intersectsViewport */, ChildProcessImportance.NORMAL);
ranking.addConnection(c9, true /* foreground */, 1 /* frameDepth */,
true /* intersectsViewport */, ChildProcessImportance.NORMAL);
// Visible main frame.
ranking.addConnection(c10, true /* foreground */, 0 /* frameDepth */,
true /* intersectsViewport */, ChildProcessImportance.NORMAL);
assertRankingAndRemoveAll(
ranking, new ChildProcessConnection[] {c10, c9, c8, c7, c6, c5, c4, c3, c2, c1});
}
@Test
......@@ -96,24 +135,24 @@ public class ChildProcessRankingTest {
// c1,2 are in one tab, and c3,4 are in second tab.
ranking.addConnection(c1, true /* foreground */, 1 /* frameDepth */,
false /* intersectsViewport */, ChildProcessImportance.NORMAL);
true /* intersectsViewport */, ChildProcessImportance.NORMAL);
ranking.addConnection(c2, true /* foreground */, 0 /* frameDepth */,
false /* intersectsViewport */, ChildProcessImportance.NORMAL);
true /* intersectsViewport */, ChildProcessImportance.NORMAL);
ranking.addConnection(c3, false /* foreground */, 1 /* frameDepth */,
false /* intersectsViewport */, ChildProcessImportance.NORMAL);
true /* intersectsViewport */, ChildProcessImportance.NORMAL);
ranking.addConnection(c4, false /* foreground */, 0 /* frameDepth */,
false /* intersectsViewport */, ChildProcessImportance.NORMAL);
true /* intersectsViewport */, ChildProcessImportance.NORMAL);
Assert.assertEquals(c3, ranking.getLowestRankedConnection());
// Switch from tab c1,2 to tab c3,c4.
ranking.updateConnection(c1, false /* foreground */, 1 /* frameDepth */,
false /* intersectsViewport */, ChildProcessImportance.NORMAL);
true /* intersectsViewport */, ChildProcessImportance.NORMAL);
ranking.updateConnection(c2, false /* foreground */, 0 /* frameDepth */,
false /* intersectsViewport */, ChildProcessImportance.NORMAL);
true /* intersectsViewport */, ChildProcessImportance.NORMAL);
ranking.updateConnection(c3, true /* foreground */, 1 /* frameDepth */,
false /* intersectsViewport */, ChildProcessImportance.NORMAL);
true /* intersectsViewport */, ChildProcessImportance.NORMAL);
ranking.updateConnection(c4, true /* foreground */, 0 /* frameDepth */,
false /* intersectsViewport */, ChildProcessImportance.NORMAL);
true /* intersectsViewport */, ChildProcessImportance.NORMAL);
assertRankingAndRemoveAll(ranking, new ChildProcessConnection[] {c4, c3, c2, c1});
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment