<commit_before>/**
 * Copyright (c) 2015-present, Facebook, Inc.
 *
 * 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.uimanager;

import static java.lang.System.arraycopy;

import android.util.Log;
import com.facebook.infer.annotation.Assertions;
import com.facebook.react.uimanager.annotations.ReactPropertyHolder;
import com.facebook.yoga.YogaNodeCloneFunction;
import com.facebook.yoga.YogaAlign;
import com.facebook.yoga.YogaBaselineFunction;
import com.facebook.yoga.YogaConfig;
import com.facebook.yoga.YogaConstants;
import com.facebook.yoga.YogaDirection;
import com.facebook.yoga.YogaDisplay;
import com.facebook.yoga.YogaEdge;
import com.facebook.yoga.YogaFlexDirection;
import com.facebook.yoga.YogaJustify;
import com.facebook.yoga.YogaMeasureFunction;
import com.facebook.yoga.YogaNode;
import com.facebook.yoga.YogaOverflow;
import com.facebook.yoga.YogaPositionType;
import com.facebook.yoga.YogaValue;
import com.facebook.yoga.YogaWrap;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import javax.annotation.Nullable;

/**
 * Base node class for representing virtual tree of React nodes. Shadow nodes are used primarily for
 * layouting therefore it extends {@link YogaNode} to allow that. They also help with handling
 * Common base subclass of {@link YogaNode} for all layout nodes for react-based view. It extends
 * {@link YogaNode} by adding additional capabilities.
 *
 * <p>Instances of this class receive property updates from JS via @{link UIManagerModule}.
 * Subclasses may use {@link #updateShadowNode} to persist some of the updated fields in the node
 * instance that corresponds to a particular view type.
 *
 * <p>Subclasses of {@link ReactShadowNodeImpl} should be created only from {@link ViewManager} that
 * corresponds to a certain type of native view. They will be updated and accessed only from JS
 * thread. Subclasses of {@link ViewManager} may choose to use base class {@link
 * ReactShadowNodeImpl} or custom subclass of it if necessary.
 *
 * <p>The primary use-case for {@link ReactShadowNodeImpl} nodes is to calculate layouting. Although
 * this might be extended. For some examples please refer to ARTGroupYogaNode or ReactTextYogaNode.
 *
 * <p>This class allows for the native view hierarchy to not be an exact copy of the hierarchy
 * received from JS by keeping track of both JS children (e.g. {@link #getChildCount()} and
 * separately native children (e.g. {@link #getNativeChildCount()}). See {@link
 * NativeViewHierarchyOptimizer} for more information.
 */
@ReactPropertyHolder
public class ReactShadowNodeImpl implements ReactShadowNode<ReactShadowNodeImpl> {

  private static final boolean DEBUG = true;
  private static final String TAG = ReactShadowNodeImpl.class.getSimpleName();
  private static final YogaConfig sYogaConfig;
  static {
    sYogaConfig = ReactYogaConfigProvider.get();
    sYogaConfig.setOnCloneNode(new YogaNodeCloneFunction() {
      @Override
      public YogaNode cloneNode(YogaNode oldYogaNode,
          YogaNode parent,
          int childIndex) {
        ReactShadowNodeImpl parentReactShadowNode = (ReactShadowNodeImpl) parent.getData();
        Assertions.assertNotNull(parentReactShadowNode);
        ReactShadowNodeImpl oldReactShadowNode = (ReactShadowNodeImpl) oldYogaNode.getData();
        Assertions.assertNotNull(oldReactShadowNode);

        if (DEBUG) {
          Log.d(
            TAG,
            "YogaNode started cloning: oldYogaNode: " + oldReactShadowNode + " - parent: "
              + parentReactShadowNode + " index: " + childIndex);
        }

        ReactShadowNodeImpl newNode = oldReactShadowNode.mutableCopy();
        parentReactShadowNode.replaceChild(newNode, childIndex);
        return newNode.mYogaNode;
      }
    });
  }

  private int mReactTag;
  private @Nullable String mViewClassName;
  private int mRootTag;
  private @Nullable ThemedReactContext mThemedContext;
  private boolean mShouldNotifyOnLayout;
  private boolean mNodeUpdated = true;
  private @Nullable ArrayList<ReactShadowNodeImpl> mChildren;
  private @Nullable ReactShadowNodeImpl mParent;

  // layout-only nodes
  private boolean mIsLayoutOnly;
  private int mTotalNativeChildren = 0;
  private @Nullable ReactShadowNodeImpl mNativeParent;
  private @Nullable ArrayList<ReactShadowNodeImpl> mNativeChildren;
  private int mScreenX;
  private int mScreenY;
  private int mScreenWidth;
  private int mScreenHeight;
  private final Spacing mDefaultPadding = new Spacing(0);
  private final float[] mPadding = new float[Spacing.ALL + 1];
  private final boolean[] mPaddingIsPercent = new boolean[Spacing.ALL + 1];
  private YogaNode mYogaNode;
  private ReactShadowNode mOriginalReactShadowNode = null;

  private @Nullable ReactStylesDiffMap mNewProps;

  public ReactShadowNodeImpl() {
    if (!isVirtual()) {
      YogaNode node = YogaNodePool.get().acquire();
      mYogaNode = node == null ? new YogaNode(sYogaConfig) : node;
      mYogaNode.setData(this);
      Arrays.fill(mPadding, YogaConstants.UNDEFINED);
    } else {
      mYogaNode = null;
    }
  }

  protected ReactShadowNodeImpl(ReactShadowNodeImpl original) {
    mReactTag = original.mReactTag;
    mRootTag = original.mRootTag;
    mViewClassName = original.mViewClassName;
    mThemedContext = original.mThemedContext;
    mShouldNotifyOnLayout = original.mShouldNotifyOnLayout;
    mIsLayoutOnly = original.mIsLayoutOnly;
    mNativeParent = original.mNativeParent;
    // Cloned nodes should be always updated.
    mNodeUpdated = true;
    // "cached" screen coordinates are not cloned because FabricJS not always clone the last
    // ReactShadowNode that was rendered in the screen.
    mScreenX = 0;
    mScreenY = 0;
    mScreenWidth = 0;
    mScreenHeight = 0;
    arraycopy(original.mPadding, 0, mPadding, 0, original.mPadding.length);
    arraycopy(original.mPaddingIsPercent, 0, mPaddingIsPercent, 0, original.mPaddingIsPercent.length);
    mNewProps = null;
    mParent = null;
    mOriginalReactShadowNode = original;
  }

  private void replaceChild(ReactShadowNodeImpl newNode, int childIndex) {
    mChildren.remove(childIndex);
    mChildren.add(childIndex, newNode);
    newNode.mParent = this;
  }

  /**
   * @return a copy of this object (no including copy of its children or the underlying yogaNode).
   */
  protected ReactShadowNodeImpl copy() {
    return new ReactShadowNodeImpl(this);
  }

  @Override
  public ReactShadowNodeImpl mutableCopy() {
    ReactShadowNodeImpl copy = copy();
    copy.mYogaNode = mYogaNode.clone();
    copy.mNativeChildren = mNativeChildren == null ? null : new ArrayList<>(mNativeChildren);
    copy.mTotalNativeChildren = mTotalNativeChildren;
    copy.mChildren = mChildren == null ? null : new ArrayList<>(mChildren);
    copy.mYogaNode.setData(copy);
    return copy;
  }

  @Override
  public ReactShadowNodeImpl mutableCopyWithNewChildren() {
    ReactShadowNodeImpl copy = copy();
    copy.mYogaNode = mYogaNode.cloneWithNewChildren();
    copy.mNativeChildren = null;
    copy.mChildren = null;
    copy.mTotalNativeChildren = 0;
    copy.mYogaNode.setData(copy);
    return copy;
  }

  @Override
  public ReactShadowNodeImpl mutableCopyWithNewProps(@Nullable ReactStylesDiffMap newProps) {
    ReactShadowNodeImpl copy = mutableCopy();
    if (newProps != null) {
      copy.updateProperties(newProps);
      copy.mNewProps = newProps;
    }
    return copy;
  }

  @Override
  public ReactShadowNodeImpl mutableCopyWithNewChildrenAndProps(@Nullable ReactStylesDiffMap newProps) {
    ReactShadowNodeImpl copy = mutableCopyWithNewChildren();<commit_msg>Support cloning of virtual ReactShadowNodes<commit_after>/**
 * Copyright (c) 2015-present, Facebook, Inc.
 *
 * 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.uimanager;

import static java.lang.System.arraycopy;

import android.util.Log;
import com.facebook.infer.annotation.Assertions;
import com.facebook.react.uimanager.annotations.ReactPropertyHolder;
import com.facebook.yoga.YogaNodeCloneFunction;
import com.facebook.yoga.YogaAlign;
import com.facebook.yoga.YogaBaselineFunction;
import com.facebook.yoga.YogaConfig;
import com.facebook.yoga.YogaConstants;
import com.facebook.yoga.YogaDirection;
import com.facebook.yoga.YogaDisplay;
import com.facebook.yoga.YogaEdge;
import com.facebook.yoga.YogaFlexDirection;
import com.facebook.yoga.YogaJustify;
import com.facebook.yoga.YogaMeasureFunction;
import com.facebook.yoga.YogaNode;
import com.facebook.yoga.YogaOverflow;
import com.facebook.yoga.YogaPositionType;
import com.facebook.yoga.YogaValue;
import com.facebook.yoga.YogaWrap;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import javax.annotation.Nullable;

/**
 * Base node class for representing virtual tree of React nodes. Shadow nodes are used primarily for
 * layouting therefore it extends {@link YogaNode} to allow that. They also help with handling
 * Common base subclass of {@link YogaNode} for all layout nodes for react-based view. It extends
 * {@link YogaNode} by adding additional capabilities.
 *
 * <p>Instances of this class receive property updates from JS via @{link UIManagerModule}.
 * Subclasses may use {@link #updateShadowNode} to persist some of the updated fields in the node
 * instance that corresponds to a particular view type.
 *
 * <p>Subclasses of {@link ReactShadowNodeImpl} should be created only from {@link ViewManager} that
 * corresponds to a certain type of native view. They will be updated and accessed only from JS
 * thread. Subclasses of {@link ViewManager} may choose to use base class {@link
 * ReactShadowNodeImpl} or custom subclass of it if necessary.
 *
 * <p>The primary use-case for {@link ReactShadowNodeImpl} nodes is to calculate layouting. Although
 * this might be extended. For some examples please refer to ARTGroupYogaNode or ReactTextYogaNode.
 *
 * <p>This class allows for the native view hierarchy to not be an exact copy of the hierarchy
 * received from JS by keeping track of both JS children (e.g. {@link #getChildCount()} and
 * separately native children (e.g. {@link #getNativeChildCount()}). See {@link
 * NativeViewHierarchyOptimizer} for more information.
 */
@ReactPropertyHolder
public class ReactShadowNodeImpl implements ReactShadowNode<ReactShadowNodeImpl> {

  private static final boolean DEBUG = true;
  private static final String TAG = ReactShadowNodeImpl.class.getSimpleName();
  private static final YogaConfig sYogaConfig;
  static {
    sYogaConfig = ReactYogaConfigProvider.get();
    sYogaConfig.setOnCloneNode(new YogaNodeCloneFunction() {
      @Override
      public YogaNode cloneNode(YogaNode oldYogaNode,
          YogaNode parent,
          int childIndex) {
        ReactShadowNodeImpl parentReactShadowNode = (ReactShadowNodeImpl) parent.getData();
        Assertions.assertNotNull(parentReactShadowNode);
        ReactShadowNodeImpl oldReactShadowNode = (ReactShadowNodeImpl) oldYogaNode.getData();
        Assertions.assertNotNull(oldReactShadowNode);

        if (DEBUG) {
          Log.d(
            TAG,
            "YogaNode started cloning: oldYogaNode: " + oldReactShadowNode + " - parent: "
              + parentReactShadowNode + " index: " + childIndex);
        }

        ReactShadowNodeImpl newNode = oldReactShadowNode.mutableCopy();
        parentReactShadowNode.replaceChild(newNode, childIndex);
        return newNode.mYogaNode;
      }
    });
  }

  private int mReactTag;
  private @Nullable String mViewClassName;
  private int mRootTag;
  private @Nullable ThemedReactContext mThemedContext;
  private boolean mShouldNotifyOnLayout;
  private boolean mNodeUpdated = true;
  private @Nullable ArrayList<ReactShadowNodeImpl> mChildren;
  private @Nullable ReactShadowNodeImpl mParent;

  // layout-only nodes
  private boolean mIsLayoutOnly;
  private int mTotalNativeChildren = 0;
  private @Nullable ReactShadowNodeImpl mNativeParent;
  private @Nullable ArrayList<ReactShadowNodeImpl> mNativeChildren;
  private int mScreenX;
  private int mScreenY;
  private int mScreenWidth;
  private int mScreenHeight;
  private final Spacing mDefaultPadding = new Spacing(0);
  private final float[] mPadding = new float[Spacing.ALL + 1];
  private final boolean[] mPaddingIsPercent = new boolean[Spacing.ALL + 1];
  private YogaNode mYogaNode;
  private ReactShadowNode mOriginalReactShadowNode = null;

  private @Nullable ReactStylesDiffMap mNewProps;

  public ReactShadowNodeImpl() {
    if (!isVirtual()) {
      YogaNode node = YogaNodePool.get().acquire();
      mYogaNode = node == null ? new YogaNode(sYogaConfig) : node;
      mYogaNode.setData(this);
      Arrays.fill(mPadding, YogaConstants.UNDEFINED);
    } else {
      mYogaNode = null;
    }
  }

  protected ReactShadowNodeImpl(ReactShadowNodeImpl original) {
    mReactTag = original.mReactTag;
    mRootTag = original.mRootTag;
    mViewClassName = original.mViewClassName;
    mThemedContext = original.mThemedContext;
    mShouldNotifyOnLayout = original.mShouldNotifyOnLayout;
    mIsLayoutOnly = original.mIsLayoutOnly;
    mNativeParent = original.mNativeParent;
    // Cloned nodes should be always updated.
    mNodeUpdated = true;
    // "cached" screen coordinates are not cloned because FabricJS not always clone the last
    // ReactShadowNode that was rendered in the screen.
    mScreenX = 0;
    mScreenY = 0;
    mScreenWidth = 0;
    mScreenHeight = 0;
    arraycopy(original.mPadding, 0, mPadding, 0, original.mPadding.length);
    arraycopy(original.mPaddingIsPercent, 0, mPaddingIsPercent, 0, original.mPaddingIsPercent.length);
    mNewProps = null;
    mParent = null;
    mOriginalReactShadowNode = original;
  }

  private void replaceChild(ReactShadowNodeImpl newNode, int childIndex) {
    mChildren.remove(childIndex);
    mChildren.add(childIndex, newNode);
    newNode.mParent = this;
  }

  /**
   * @return a copy of this object (no including copy of its children or the underlying yogaNode).
   */
  protected ReactShadowNodeImpl copy() {
    return new ReactShadowNodeImpl(this);
  }

  @Override
  public ReactShadowNodeImpl mutableCopy() {
    ReactShadowNodeImpl copy = copy();
    if (mYogaNode != null) {
      copy.mYogaNode = mYogaNode.clone();
      copy.mYogaNode.setData(copy);
    } else {
      // Virtual ReactShadowNode do not have a YogaNode associated
      copy.mYogaNode = null;
    }
    copy.mNativeChildren = mNativeChildren == null ? null : new ArrayList<>(mNativeChildren);
    copy.mTotalNativeChildren = mTotalNativeChildren;
    copy.mChildren = mChildren == null ? null : new ArrayList<>(mChildren);
    return copy;
  }

  @Override
  public ReactShadowNodeImpl mutableCopyWithNewChildren() {
    ReactShadowNodeImpl copy = copy();
    if (mYogaNode != null) {
      copy.mYogaNode = mYogaNode.cloneWithNewChildren();
      copy.mYogaNode.setData(copy);
    } else {
      // Virtual ReactShadowNode do not have a YogaNode associated
      copy.mYogaNode = null;
    }
    copy.mNativeChildren = null;
    copy.mChildren = null;
    copy.mTotalNativeChildren = 0;
    return copy;
  }

  @Override
  public ReactShadowNodeImpl mutableCopyWithNewProps(@Nullable ReactStylesDiffMap newProps) {
    ReactShadowNodeImpl copy = mutableCopy();
    if (newProps != null) {
      copy.updateProperties(newProps);
      copy.mNewProps = newProps;
    }
    return copy;
  }

  @Override
  public ReactShadowNodeImpl mutableCopyWithNewChildrenAndProps(@Nullable ReactStylesDiffMap newProps) {
    ReactShadowNodeImpl copy = mutableCopyWithNewChildren();
{'fraction_non_alphanumeric': 0.08100593959307469, 'fraction_numerical': 0.0021483634525464425, 'mean_word_length': 4.184081231575499, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 21, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4233433', 'n_tokens_mistral': 4518, 'n_tokens_neox': 4500, 'n_words': 1293}