/** * Copyright (c) 2017-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. */ // Changes to View.MeasureSpec have been made to reflect renaming of the class to SizeSpec. // Portions of View.MeasureSpec which do not have usage in this library have been omitted. /* * Copyright (C) 2006 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.facebook.litho; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import android.support.annotation.IntDef; import android.view.View; import com.facebook.yoga.YogaMeasureMode; /** * A SizeSpec encapsulates the layout requirements passed from parent to child. * Each SizeSpec represents a requirement for either the width or the height. * A SizeSpec is comprised of a size and a mode. There are two possible * modes: * <dl> * <dt>UNSPECIFIED</dt> * <dd> * The parent has not imposed any constraint on the child. It can be whatever size * it wants. * </dd> * * <dt>EXACTLY</dt> * <dd> * The parent has determined an exact size for the child. The child is going to be * given those bounds regardless of how big it wants to be. * </dd> * * SizeSpecs are implemented as ints to reduce object allocation. This class * is provided to pack and unpack the <size, mode> tuple into the int. */ public class SizeSpec { /** * Size specification mode: The parent has not imposed any constraint * on the child. It can be whatever size it wants. */ public static final int UNSPECIFIED = View.MeasureSpec.UNSPECIFIED; /** * Size specification mode: The parent has determined an exact size * for the child. The child is going to be given those bounds regardless * of how big it wants to be. */ public static final int EXACTLY = View.MeasureSpec.EXACTLY; /** * Size specification mode: The child can be as large as it wants up * to the specified size. */ public static final int AT_MOST = View.MeasureSpec.AT_MOST; @IntDef({UNSPECIFIED, EXACTLY, AT_MOST}) @Retention(RetentionPolicy.SOURCE) public @interface MeasureSpecMode {} /** * Creates a size specification based on the supplied size and mode. * * The mode must always be one of the following: * <ul> * <li>{@link com.facebook.litho.SizeSpec#UNSPECIFIED}</li> * <li>{@link com.facebook.litho.SizeSpec#EXACTLY}</li> * </ul> * * <p><strong>Note:</strong> On API level 17 and lower, makeMeasureSpec's * implementation was such that the order of arguments did not matter * and overflow in either value could impact the resulting MeasureSpec. * {@link android.widget.RelativeLayout} was affected by this bug. * Apps targeting API levels greater than 17 will get the fixed, more strict * behavior.</p> * * @param size the size of the size specification * @param mode the mode of the size specification * @return the size specification based on size and mode */ public static int makeSizeSpec(int size, @MeasureSpecMode int mode) { return View.MeasureSpec.makeMeasureSpec(size, mode); } /** * Extracts the mode from the supplied size specification. * * @param sizeSpec the size specification to extract the mode from * @return {@link com.facebook.litho.SizeSpec#UNSPECIFIED} or * {@link com.facebook.litho.SizeSpec#EXACTLY} */ public static int getMode(int sizeSpec) { return View.MeasureSpec.getMode(sizeSpec); } /** * Extracts the size from the supplied size specification. * * @param sizeSpec the size specification to extract the size from * @return the size in pixels defined in the supplied size specification */ public static int getSize(int sizeSpec) { return View.MeasureSpec.getSize(sizeSpec); } /** * Returns a String representation of the specified measure * specification. * * @param sizeSpec the size specification to convert to a String * @return a String with the following format: "MeasureSpec: MODE SIZE" */ public static String toString(int sizeSpec) { return View.MeasureSpec.toString(sizeSpec); } /** * Resolve a size spec given a preferred size. * * @param sizeSpec The spec to resolve. * @param preferredSize The preferred size. * @return The resolved size. */ public static int resolveSize(int sizeSpec, int preferredSize) { switch (SizeSpec.getMode(sizeSpec)) { case EXACTLY: return SizeSpec.getSize(sizeSpec); case AT_MOST: return Math.min(SizeSpec.getSize(sizeSpec), preferredSize); case UNSPECIFIED: return preferredSize; default: throw new IllegalStateException("Unexpected size mode: " + SizeSpec.getMode(sizeSpec)); } } public static int makeSizeSpecFromCssSpec(float cssSize, YogaMeasureMode cssMode) { final int mode; switch (cssMode) { case EXACTLY: mode = SizeSpec.EXACTLY; break; case UNDEFINED: mode = SizeSpec.UNSPECIFIED; break; case AT_MOST: mode = SizeSpec.AT_MOST; break; default: throw new IllegalArgumentException("Unexpected YogaMeasureMode: " + cssMode); } return makeSizeSpec(FastMath.round(cssSize), mode); } }