Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

package com.facebook.react.bridge;

import com.facebook.react.fabric.mounting.mountitems.IntBufferMountItem;

import java.util.ArrayList;

public interface ViewMutationsListener {
/**
* Called right before view mutations are dispatched. This is useful if a
* module needs to do something before the views are created/removed.
*/
void willMountViewMutations(ArrayList<IntBufferMountItem> mutations);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.facebook.react.fabric.mounting.mountitems;

import com.facebook.react.fabric.mounting.mountitems.IntBufferMountItem;

public enum InstructionType {
CREATE, DELETE, INSERT, REMOVE, UPDATE_PROPS, UPDATE_STATE, UPDATE_LAYOUT, UPDATE_EVENT_EMITTER,
UPDATE_PADDING, UPDATE_OVERFLOW_INSET, REMOVE_DELETE_TREE
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,14 @@
import com.facebook.react.fabric.mounting.MountingManager;
import com.facebook.react.fabric.mounting.SurfaceMountingManager;
import com.facebook.react.uimanager.StateWrapper;
import com.facebook.react.uimanager.UIManagerModule;
import com.facebook.systrace.Systrace;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import android.view.View;

/**
* This class represents a batch of {@link MountItem}s, represented directly as int buffers to
* remove the need for actual MountItem instances.
Expand Down Expand Up @@ -117,70 +123,226 @@ public void execute(@NonNull MountingManager mountingManager) {

beginMarkers("mountViews");

ArrayList<IntBufferMountItem> mutationsArray = new ArrayList<>();

// we put views in the mount item objects also for some operations since tags
// are only mapped to ViewState which are internal.
// In most cases we will need the view to perform an action in the listener
int i = 0, j = 0;
while (i < mIntBufferLen) {
int rawType = mIntBuffer[i++];
int type = rawType & ~INSTRUCTION_FLAG_MULTIPLE;
int numInstructions = ((rawType & INSTRUCTION_FLAG_MULTIPLE) != 0 ? mIntBuffer[i++] : 1);
for (int k = 0; k < numInstructions; k++) {
IntBufferMountItem item;
if (type == INSTRUCTION_CREATE) {
String componentName = getFabricComponentName((String) mObjBuffer[j++]);
surfaceMountingManager.createView(
componentName,
mIntBuffer[i++],
mObjBuffer[j++],
castToState(mObjBuffer[j++]),
castToEventEmitter(mObjBuffer[j++]),
mIntBuffer[i++] == 1);
int reactTag = mIntBuffer[i++];
View view = null;
if (surfaceMountingManager.getViewExists(reactTag)) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Other than creating objects we are increasing cost of this method my resolving Views earlier just to share with the listener, but we are not reusing these views on the call to surfaceMountingManager below, again this method is part of the critical path, and this will bring unnecessary regressions

view = surfaceMountingManager.getView(reactTag);
}
Object props = mObjBuffer[j++];
StateWrapper stateWrapper = castToState(mObjBuffer[j++]);
EventEmitterWrapper eventEmitterWrapper = castToEventEmitter(mObjBuffer[j++]);
boolean isLayoutable = mIntBuffer[i++] == 1;
item = new IntBufferMountItemCreate(reactTag,
view, componentName, props, stateWrapper, eventEmitterWrapper, isLayoutable);

} else if (type == INSTRUCTION_DELETE) {
surfaceMountingManager.deleteView(mIntBuffer[i++]);
int reactTag = mIntBuffer[i++];
item = new IntBufferMountItemDelete(reactTag, null);
} else if (type == INSTRUCTION_INSERT) {
int tag = mIntBuffer[i++];
View view = null;
if (surfaceMountingManager.getViewExists(tag)) {
view = surfaceMountingManager.getView(tag);
}
int parentTag = mIntBuffer[i++];
surfaceMountingManager.addViewAt(parentTag, tag, mIntBuffer[i++]);
View parentView = null;
if (surfaceMountingManager.getViewExists(parentTag)) {
parentView = surfaceMountingManager.getView(parentTag);
}
int index = mIntBuffer[i++];
item = new IntBufferMountItemInsert(tag, view, parentTag, parentView, index);
} else if (type == INSTRUCTION_REMOVE) {
surfaceMountingManager.removeViewAt(mIntBuffer[i++], mIntBuffer[i++], mIntBuffer[i++]);
int tag = mIntBuffer[i++];
View view = null;
if (surfaceMountingManager.getViewExists(tag)) {
view = surfaceMountingManager.getView(tag);
}
int parentTag = mIntBuffer[i++];
View parentView = null;
if (surfaceMountingManager.getViewExists(parentTag)) {
parentView = surfaceMountingManager.getView(parentTag);
}
int index = mIntBuffer[i++];
item = new IntBufferMountItemRemove(tag, view, parentTag, parentView, index);
} else if (type == INSTRUCTION_REMOVE_DELETE_TREE) {
surfaceMountingManager.removeDeleteTreeAt(
mIntBuffer[i++], mIntBuffer[i++], mIntBuffer[i++]);
int tag = mIntBuffer[i++];
View view = null;
if (surfaceMountingManager.getViewExists(tag)) {
view = surfaceMountingManager.getView(tag);
}
int parentTag = mIntBuffer[i++];
View parentView = null;
if (surfaceMountingManager.getViewExists(parentTag)) {
parentView = surfaceMountingManager.getView(parentTag);
}
int index = mIntBuffer[i++];
item = new IntBufferMountItemRemoveDeleteTree(tag, view, parentTag, parentView, index);
} else if (type == INSTRUCTION_UPDATE_PROPS) {
surfaceMountingManager.updateProps(mIntBuffer[i++], mObjBuffer[j++]);
int reactTag = mIntBuffer[i++];
View view = null;
if (surfaceMountingManager.getViewExists(reactTag)) {
view = surfaceMountingManager.getView(reactTag);
}
Object props = mObjBuffer[j++];
item = new IntBufferMountItemUpdateProps(reactTag, view, props);
} else if (type == INSTRUCTION_UPDATE_STATE) {
surfaceMountingManager.updateState(mIntBuffer[i++], castToState(mObjBuffer[j++]));
int reactTag = mIntBuffer[i++];
View view = null;
if (surfaceMountingManager.getViewExists(reactTag)) {
view = surfaceMountingManager.getView(reactTag);
}
StateWrapper stateWrapper = castToState(mObjBuffer[j++]);
item = new IntBufferMountItemUpdateState(reactTag, view, stateWrapper);
} else if (type == INSTRUCTION_UPDATE_LAYOUT) {
int reactTag = mIntBuffer[i++];
View view = null;
if (surfaceMountingManager.getViewExists(reactTag)) {
view = surfaceMountingManager.getView(reactTag);
}
int parentTag = mIntBuffer[i++];
View parentView = null;
if (surfaceMountingManager.getViewExists(parentTag)) {
parentView = surfaceMountingManager.getView(parentTag);
}
int x = mIntBuffer[i++];
int y = mIntBuffer[i++];
int width = mIntBuffer[i++];
int height = mIntBuffer[i++];
int displayType = mIntBuffer[i++];

surfaceMountingManager.updateLayout(
reactTag, parentTag, x, y, width, height, displayType);

item = new IntBufferMountItemUpdateLayout(reactTag, view, parentTag, parentView, x, y,
width, height, displayType);
} else if (type == INSTRUCTION_UPDATE_PADDING) {
surfaceMountingManager.updatePadding(
mIntBuffer[i++], mIntBuffer[i++], mIntBuffer[i++], mIntBuffer[i++], mIntBuffer[i++]);
int reactTag = mIntBuffer[i++];
View view = null;
if (surfaceMountingManager.getViewExists(reactTag)) {
view = surfaceMountingManager.getView(reactTag);
}
int left = mIntBuffer[i++];
int top = mIntBuffer[i++];
int right = mIntBuffer[i++];
int bottom = mIntBuffer[i++];
item = new IntBufferMountItemUpdatePadding(reactTag, view, left, top, right, bottom);
} else if (type == INSTRUCTION_UPDATE_OVERFLOW_INSET) {
int reactTag = mIntBuffer[i++];
View view = null;
if (surfaceMountingManager.getViewExists(reactTag)) {
view = surfaceMountingManager.getView(reactTag);
}
int overflowInsetLeft = mIntBuffer[i++];
int overflowInsetTop = mIntBuffer[i++];
int overflowInsetRight = mIntBuffer[i++];
int overflowInsetBottom = mIntBuffer[i++];

surfaceMountingManager.updateOverflowInset(
reactTag,
overflowInsetLeft,
overflowInsetTop,
overflowInsetRight,
overflowInsetBottom);
item = new IntBufferMountItemUpdateOverflowInset(reactTag, view, overflowInsetLeft,
overflowInsetTop, overflowInsetRight, overflowInsetBottom);
} else if (type == INSTRUCTION_UPDATE_EVENT_EMITTER) {
surfaceMountingManager.updateEventEmitter(
mIntBuffer[i++], castToEventEmitter(mObjBuffer[j++]));
int reactTag = mIntBuffer[i++];
EventEmitterWrapper eventEmitterWrapper = castToEventEmitter(mObjBuffer[j++]);
item = new IntBufferMountItemUpdateEventEmitter(reactTag, null, eventEmitterWrapper);
} else {
throw new IllegalArgumentException(
"Invalid type argument to IntBufferBatchMountItem: " + type + " at index: " + i);
"Invalid type argument to IntBufferBatchMountItem: " + type + " at index: " + i);
}
mutationsArray.add(item);
}
}

surfaceMountingManager.getContext().getNativeModule(UIManagerModule.class).viewMutationsWillMount(mutationsArray);

for (IntBufferMountItem elem: mutationsArray) {
switch (elem.getInstructionType()) {
case CREATE: {
IntBufferMountItemCreate createElem = (IntBufferMountItemCreate) elem;
surfaceMountingManager.createView(
createElem.getComponentName(),
createElem.getReactTag(),
createElem.getProps(),
createElem.getStateWrapper(),
createElem.getEventEmitterWrapper(),
createElem.isLayoutable());
break;
}
case DELETE: {
IntBufferMountItemDelete deleteElem = (IntBufferMountItemDelete) elem;
surfaceMountingManager.deleteView(deleteElem.getReactTag());
break;
}
case INSERT: {
IntBufferMountItemInsert insertElem = (IntBufferMountItemInsert) elem;
surfaceMountingManager.addViewAt(insertElem.getParentTag(), insertElem.getReactTag(), insertElem.getIndex());
break;
}
case REMOVE: {
IntBufferMountItemRemove removeElem = (IntBufferMountItemRemove) elem;
surfaceMountingManager.removeViewAt(removeElem.getReactTag(), removeElem.getParentTag(), removeElem.getIndex());
break;
}
case REMOVE_DELETE_TREE: {
IntBufferMountItemRemoveDeleteTree removeDeleteTreeElem = (IntBufferMountItemRemoveDeleteTree) elem;
surfaceMountingManager.removeDeleteTreeAt(removeDeleteTreeElem.getReactTag(),
removeDeleteTreeElem.getParentTag(), removeDeleteTreeElem.getIndex());
break;
}
case UPDATE_PROPS: {
IntBufferMountItemUpdateProps updatePropsElem = (IntBufferMountItemUpdateProps) elem;
surfaceMountingManager.updateProps(updatePropsElem.getReactTag(),
updatePropsElem.getProps());
break;
}
case UPDATE_STATE: {
IntBufferMountItemUpdateState updateStateElem = (IntBufferMountItemUpdateState) elem;
surfaceMountingManager.updateState(updateStateElem.getReactTag(),
updateStateElem.getStateWrapper());
break;
}
case UPDATE_LAYOUT: {
IntBufferMountItemUpdateLayout updateLayoutElem = (IntBufferMountItemUpdateLayout) elem;
surfaceMountingManager.updateLayout(updateLayoutElem.getReactTag(),
updateLayoutElem.getParentTag(), updateLayoutElem.getX(), updateLayoutElem.getY(),
updateLayoutElem.getWidth(), updateLayoutElem.getHeight(),
updateLayoutElem.getDisplayType());
break;
}
case UPDATE_PADDING: {
IntBufferMountItemUpdatePadding updatePaddingElem = (IntBufferMountItemUpdatePadding) elem;
surfaceMountingManager.updatePadding(updatePaddingElem.getReactTag(),
updatePaddingElem.getLeft(), updatePaddingElem.getTop(),
updatePaddingElem.getRight(), updatePaddingElem.getBottom());
break;
}
case UPDATE_OVERFLOW_INSET: {
IntBufferMountItemUpdateOverflowInset updateOverflowInsetElem =
(IntBufferMountItemUpdateOverflowInset) elem;
surfaceMountingManager.updateOverflowInset(updateOverflowInsetElem.getReactTag(),
updateOverflowInsetElem.getOverflowInsetLeft(),
updateOverflowInsetElem.getOverflowInsetTop(),
updateOverflowInsetElem.getOverflowInsetRight(),
updateOverflowInsetElem.getOverflowInsetBottom());
break;
}
case UPDATE_EVENT_EMITTER: {
IntBufferMountItemUpdateEventEmitter updateEventEmitterElem =
(IntBufferMountItemUpdateEventEmitter) elem;
surfaceMountingManager.updateEventEmitter(updateEventEmitterElem.getReactTag(),
updateEventEmitterElem.getEventEmitterWrapper());
break;
}
default: {
throw new IllegalArgumentException(
"Invalid type argument to IntBufferBatchMountItem: " + elem.getInstructionType());
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.facebook.react.fabric.mounting.mountitems;

import com.facebook.react.fabric.mounting.mountitems.IntBufferMountItem;
import com.facebook.react.fabric.mounting.mountitems.InstructionType;

import android.view.View;

public abstract class IntBufferMountItem {
private final InstructionType instructionType;
private final int reactTag;
private final View view;

public IntBufferMountItem(InstructionType instructionType, int reactTag, View view) {
this.instructionType = instructionType;
this.reactTag = reactTag;
this.view = view;
}

public InstructionType getInstructionType() {
return instructionType;
}

public int getReactTag() {
return reactTag;
}

public View getView() {
return view;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package com.facebook.react.fabric.mounting.mountitems;

import com.facebook.react.fabric.mounting.mountitems.InstructionType;
import com.facebook.react.fabric.mounting.mountitems.IntBufferMountItem;
import com.facebook.react.uimanager.StateWrapper;
import com.facebook.react.fabric.events.EventEmitterWrapper;

import android.view.View;

public class IntBufferMountItemCreate extends IntBufferMountItem {

private final String componentName;
private final Object props;
private final StateWrapper stateWrapper;
private final EventEmitterWrapper eventEmitterWrapper;
private final boolean isLayoutable;

public IntBufferMountItemCreate(int reactTag, View view, String componentName, Object props, StateWrapper stateWrapper, EventEmitterWrapper eventEmitterWrapper, boolean isLayoutable) {
super(InstructionType.CREATE, reactTag, view);
this.componentName = componentName;
this.props = props;
this.stateWrapper = stateWrapper;
this.eventEmitterWrapper = eventEmitterWrapper;
this.isLayoutable = isLayoutable;
}

public String getComponentName() {
return componentName;
}

public Object getProps() {
return props;
}

public StateWrapper getStateWrapper() {
return stateWrapper;
}

public EventEmitterWrapper getEventEmitterWrapper() {
return eventEmitterWrapper;
}

public boolean isLayoutable() {
return isLayoutable;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.facebook.react.fabric.mounting.mountitems;

import com.facebook.react.fabric.mounting.mountitems.IntBufferMountItem;
import com.facebook.react.fabric.mounting.mountitems.InstructionType;

import android.view.View;

public class IntBufferMountItemDelete extends IntBufferMountItem {

public IntBufferMountItemDelete(int reactTag, View view) {
super(InstructionType.DELETE, reactTag, view);
}
}
Loading