/** * 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.Canvas; import android.graphics.Rect; import android.util.SparseArray; import android.util.SparseIntArray; import android.view.View; import android.view.ViewParent; /** * Underlying logic which handles draw commands, views and node regions when clipping in a * {@link FlatViewGroup}. */ /* package */ abstract class DrawCommandManager { /** * Mount a set of draw commands to this manager. The order the commands are given is the order in * which they should be drawn. If any of the commands are new DrawViews, then mountViews will be * called after by the UIManager. * * @param drawCommands The draw commands to mount. * @param drawViewIndexMap Mapping of ids to index position within the draw command array. * @param maxBottom At each index i, the maximum bottom value (or right value in the case of * horizontal clipping) value of all draw commands at or below i. * @param minTop At each index i, the minimum top value (or left value in the case of horizontal * clipping) value of all draw commands at or below i. * @param willMountViews Whether we are going to also receive a mountViews command in this state * cycle. */ abstract void mountDrawCommands( DrawCommand[] drawCommands, SparseIntArray drawViewIndexMap, float[] maxBottom, float[] minTop, boolean willMountViews); /** * Add and detach a set of views. The views added here will already have a DrawView passed in * mountDrawCommands. * * @param viewResolver * @param viewsToAdd The views to add, by tag. If this is a new view, this will be reactTag, * otherwise it will be -reactTag. This allows to optimize when we have already attached * views. * @param viewsToDetach The views to detach, by tag. These will all be positive. */ abstract void mountViews(ViewResolver viewResolver, int[] viewsToAdd, int[] viewsToDetach); /** * Get the current clipping rect and adjust clipping so that when draw is dispatched we do as * little work as possible. * * @return true if the FlatViewGroup should invalidate. */ abstract boolean updateClippingRect(); /** * Sets an input rect to match the bounds of our current clipping rect. * * @param outClippingRect Set the out */ abstract void getClippingRect(Rect outClippingRect); /** * Return the views that are currently detached, so they can be cleaned up when we are. * * @return A collection of the currently detached views. */ abstract SparseArray<View> getDetachedViews(); /** * Draw the relevant items. This should do as little work as possible. * * @param canvas The canvas to draw on. */ abstract void draw(Canvas canvas); /** * Draws layout bounds for debug. * * @param canvas The canvas to draw on. */ abstract void debugDraw(Canvas canvas); /** * Mount node regions, which are the hit boxes of the shadow node children of this FlatViewGroup, * though some may not have a corresponding draw command. * * @param nodeRegions Array of node regions to mount. * @param maxBottom At each index i, the maximum bottom value (or right value in the case of * horizontal clipping) value of all node regions at or below i. * @param minTop At each index i, the minimum top value (or left value in the case of horizontal * clipping) value of all draw commands at or below i. */ abstract void mountNodeRegions(NodeRegion[] nodeRegions, float[] maxBottom, float[] minTop); /** * Find a matching node region for a touch. * * @param touchX X coordinate of touch. * @param touchY Y coordinate of touch. * @return Matching node region, or null if none are found. */ abstract @Nullable NodeRegion anyNodeRegionWithinBounds(float touchX, float touchY); /** * Find a matching virtual node region for a touch. * * @param touchX X coordinate of touch. * @param touchY Y coordinate of touch. * @return Matching node region, or null if none are found. */ abstract @Nullable NodeRegion virtualNodeRegionWithinBounds(float touchX, float touchY); /** * Event that is fired when a clipped view is dropped. * * @param view the view that is dropped */ abstract void onClippedViewDropped(View view); /** * Throw a runtime exception if a view we are trying to attach is already parented. * * @param view The view to check. */ protected static void ensureViewHasNoParent(View view) { ViewParent oldParent = view.getParent(); if (oldParent != null) { throw new RuntimeException( "Cannot add view " + view + " to DrawCommandManager while it has a parent " + oldParent); } } /** * Get a draw command manager that will clip vertically (The view scrolls up and down). * * @param flatViewGroup FlatViewGroup to use for drawing. * @param drawCommands List of commands to mount. * @return Vertically clipping draw command manager. */ static DrawCommandManager getVerticalClippingInstance( FlatViewGroup flatViewGroup, DrawCommand[] drawCommands) { return new VerticalDrawCommandManager(flatViewGroup, drawCommands); } }