/** * Copyright (c) 2015-present, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ package com.facebook.react.flat; import javax.annotation.Nullable; import android.graphics.Rect; import com.facebook.react.bridge.ReadableMap; import com.facebook.react.uimanager.PixelUtil; import com.facebook.react.uimanager.Spacing; import com.facebook.react.uimanager.ReactStylesDiffMap; import com.facebook.react.uimanager.annotations.ReactProp; import com.facebook.react.uimanager.annotations.ReactPropGroup; /** * Node for a react View. */ /* package */ final class RCTView extends FlatShadowNode { private static final int[] SPACING_TYPES = { Spacing.ALL, Spacing.LEFT, Spacing.RIGHT, Spacing.TOP, Spacing.BOTTOM, }; private @Nullable DrawBorder mDrawBorder; boolean mRemoveClippedSubviews; boolean mHorizontal; private @Nullable Rect mHitSlop; @Override /* package */ void handleUpdateProperties(ReactStylesDiffMap styles) { mRemoveClippedSubviews = mRemoveClippedSubviews || (styles.hasKey(PROP_REMOVE_CLIPPED_SUBVIEWS) && styles.getBoolean(PROP_REMOVE_CLIPPED_SUBVIEWS, false)); if (mRemoveClippedSubviews) { mHorizontal = mHorizontal || (styles.hasKey(PROP_HORIZONTAL) && styles.getBoolean(PROP_HORIZONTAL, false)); } super.handleUpdateProperties(styles); } @Override protected void collectState( StateBuilder stateBuilder, float left, float top, float right, float bottom, float clipLeft, float clipTop, float clipRight, float clipBottom) { super.collectState( stateBuilder, left, top, right, bottom, clipLeft, clipTop, clipRight, clipBottom); if (mDrawBorder != null) { mDrawBorder = (DrawBorder) mDrawBorder.updateBoundsAndFreeze( left, top, right, bottom, clipLeft, clipTop, clipRight, clipBottom); stateBuilder.addDrawCommand(mDrawBorder); } } @Override boolean doesDraw() { return mDrawBorder != null || super.doesDraw(); } @Override public void setBackgroundColor(int backgroundColor) { getMutableBorder().setBackgroundColor(backgroundColor); } @Override public void setBorderWidths(int index, float borderWidth) { super.setBorderWidths(index, borderWidth); int type = SPACING_TYPES[index]; getMutableBorder().setBorderWidth(type, PixelUtil.toPixelFromDIP(borderWidth)); } @ReactProp(name = "nativeBackgroundAndroid") public void setHotspot(@Nullable ReadableMap bg) { if (bg != null) { forceMountToView(); } } @ReactPropGroup(names = { "borderColor", "borderLeftColor", "borderRightColor", "borderTopColor", "borderBottomColor" }, customType = "Color", defaultDouble = Double.NaN) public void setBorderColor(int index, double color) { int type = SPACING_TYPES[index]; if (Double.isNaN(color)) { getMutableBorder().resetBorderColor(type); } else { getMutableBorder().setBorderColor(type, (int) color); } } @ReactProp(name = "borderRadius") public void setBorderRadius(float borderRadius) { mClipRadius = borderRadius; if (mClipToBounds && borderRadius > DrawView.MINIMUM_ROUNDED_CLIPPING_VALUE) { // mount to a view if we are overflow: hidden and are clipping, so that we can do one // clipPath to clip all the children of this node (both DrawCommands and Views). forceMountToView(); } getMutableBorder().setBorderRadius(PixelUtil.toPixelFromDIP(borderRadius)); } @ReactProp(name = "borderStyle") public void setBorderStyle(@Nullable String borderStyle) { getMutableBorder().setBorderStyle(borderStyle); } @ReactProp(name = "hitSlop") public void setHitSlop(@Nullable ReadableMap hitSlop) { if (hitSlop == null) { mHitSlop = null; } else { mHitSlop = new Rect( (int) PixelUtil.toPixelFromDIP(hitSlop.getDouble("left")), (int) PixelUtil.toPixelFromDIP(hitSlop.getDouble("top")), (int) PixelUtil.toPixelFromDIP(hitSlop.getDouble("right")), (int) PixelUtil.toPixelFromDIP(hitSlop.getDouble("bottom"))); } } @ReactProp(name = "pointerEvents") public void setPointerEvents(@Nullable String pointerEventsStr) { forceMountToView(); } @Override /* package */ void updateNodeRegion( float left, float top, float right, float bottom, boolean isVirtual) { if (!getNodeRegion().matches(left, top, right, bottom, isVirtual)) { setNodeRegion(mHitSlop == null ? new NodeRegion(left, top, right, bottom, getReactTag(), isVirtual) : new HitSlopNodeRegion(mHitSlop, left, top, right, bottom, getReactTag(), isVirtual)); } } private DrawBorder getMutableBorder() { if (mDrawBorder == null) { mDrawBorder = new DrawBorder(); } else if (mDrawBorder.isFrozen()) { mDrawBorder = (DrawBorder) mDrawBorder.mutableCopy(); } invalidate(); return mDrawBorder; } @Override public boolean clipsSubviews() { return mRemoveClippedSubviews; } }