in litho-rendercore-incremental-mount/src/main/java/com/facebook/rendercore/incrementalmount/IncrementalMountExtension.java [370:499]
private static void performIncrementalMount(
final ExtensionState<IncrementalMountExtensionState> extensionState,
final Rect localVisibleRect) {
final IncrementalMountExtensionState state = extensionState.getState();
if (state.mInput == null) {
return;
}
final boolean isTracing = RenderCoreSystrace.isEnabled();
if (isTracing) {
RenderCoreSystrace.beginSection("performIncrementalMount");
}
final List<IncrementalMountOutput> byTopBounds = state.mInput.getOutputsOrderedByTopBounds();
final List<IncrementalMountOutput> byBottomBounds =
state.mInput.getOutputsOrderedByBottomBounds();
final int count = state.mInput.getIncrementalMountOutputCount();
int itemsMounted = 0;
int itemsUnmounted = 0;
if (localVisibleRect.top >= 0 || state.mPreviousLocalVisibleRect.top >= 0) {
// View is going on/off the top of the screen. Check the bottoms to see if there is anything
// that has moved on/off the top of the screen.
while (state.mPreviousBottomsIndex < count
&& localVisibleRect.top
>= byBottomBounds.get(state.mPreviousBottomsIndex).getBounds().bottom) {
final IncrementalMountOutput node = byBottomBounds.get(state.mPreviousBottomsIndex);
final long id = node.getId();
if (extensionState.ownsReference(id)) {
extensionState.releaseMountReference(id, true);
if (IncrementalMountExtensionConfigs.isDebugLoggingEnabled) {
itemsUnmounted++;
}
}
state.mPreviousBottomsIndex++;
}
while (state.mPreviousBottomsIndex > 0
&& localVisibleRect.top
< byBottomBounds.get(state.mPreviousBottomsIndex - 1).getBounds().bottom) {
final IncrementalMountOutput node = byBottomBounds.get(state.mPreviousBottomsIndex - 1);
final long id = node.getId();
// Item should still be in the view port.
if (localVisibleRect.bottom
>= byBottomBounds.get(state.mPreviousBottomsIndex - 1).getBounds().top) {
if (!extensionState.ownsReference(id)) {
extensionState.acquireMountReference(node.getId(), true);
state.mComponentIdsMountedInThisFrame.add(id);
if (IncrementalMountExtensionConfigs.isDebugLoggingEnabled) {
itemsMounted++;
}
}
}
state.mPreviousBottomsIndex--;
}
}
Host root = extensionState.getRootHost();
final int height = root != null ? root.getHeight() : 0;
if (localVisibleRect.bottom < height || state.mPreviousLocalVisibleRect.bottom < height) {
// View is going on/off the bottom of the screen. Check the tops to see if there is anything
// that has changed.
while (state.mPreviousTopsIndex < count
&& localVisibleRect.bottom >= byTopBounds.get(state.mPreviousTopsIndex).getBounds().top) {
final IncrementalMountOutput node = byTopBounds.get(state.mPreviousTopsIndex);
final long id = node.getId();
// Item should still be in the view port.
if (localVisibleRect.top <= byTopBounds.get(state.mPreviousTopsIndex).getBounds().bottom) {
if (!extensionState.ownsReference(id)) {
extensionState.acquireMountReference(node.getId(), true);
state.mComponentIdsMountedInThisFrame.add(id);
if (IncrementalMountExtensionConfigs.isDebugLoggingEnabled) {
itemsMounted++;
}
}
}
state.mPreviousTopsIndex++;
}
while (state.mPreviousTopsIndex > 0
&& localVisibleRect.bottom
< byTopBounds.get(state.mPreviousTopsIndex - 1).getBounds().top) {
final IncrementalMountOutput node = byTopBounds.get(state.mPreviousTopsIndex - 1);
final long id = node.getId();
if (extensionState.ownsReference(id)) {
extensionState.releaseMountReference(id, true);
if (IncrementalMountExtensionConfigs.isDebugLoggingEnabled) {
itemsUnmounted++;
}
}
state.mPreviousTopsIndex--;
}
}
if (IncrementalMountExtensionConfigs.isDebugLoggingEnabled) {
Log.d(
DEBUG_TAG,
"Updates: [Items Mounted=" + itemsMounted + ", Items Unmounted=" + itemsUnmounted + "]");
}
for (long id : state.mMountedOutputIdsWithNestedContent.keySet()) {
if (state.mComponentIdsMountedInThisFrame.contains(id)) {
continue;
}
final Object content = state.mMountedOutputIdsWithNestedContent.get(id);
if (content != null) {
recursivelyNotifyVisibleBoundsChanged(extensionState, id, content);
}
}
state.mComponentIdsMountedInThisFrame.clear();
if (isTracing) {
RenderCoreSystrace.endSection();
}
}