Outline.java revision 77b5cad3efedd20f2b7cc14d87ccce1b0261960a
1/* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.graphics; 18 19import android.annotation.NonNull; 20import android.graphics.drawable.Drawable; 21import android.view.View; 22 23/** 24 * Defines a simple shape, used for bounding graphical regions. 25 * <p> 26 * Can be used with a View, or computed by a Drawable, to drive the shape of shadows cast by a 27 * View, or to clip the contents of the View. 28 * 29 * @see View#setOutline(Outline) 30 * @see Drawable#getOutline(Outline) 31 */ 32public final class Outline { 33 /** @hide */ 34 public Path mPath; 35 36 /** @hide */ 37 public Rect mRect; 38 /** @hide */ 39 public float mRadius; 40 /** @hide */ 41 public float mAlpha; 42 43 /** 44 * Constructs an empty Outline. Call one of the setter methods to make 45 * the outline valid for use with a View. 46 */ 47 public Outline() {} 48 49 /** 50 * Constructs an Outline with a copy of the data in src. 51 */ 52 public Outline(@NonNull Outline src) { 53 set(src); 54 } 55 56 /** 57 * Sets the outline to be empty. 58 * 59 * @see #isEmpty() 60 */ 61 public void setEmpty() { 62 mPath = null; 63 mRect = null; 64 mRadius = 0; 65 } 66 67 /** 68 * Returns whether the Outline is empty. 69 * <p> 70 * Outlines are empty when constructed, or if {@link #setEmpty()} is called, 71 * until a setter method is called 72 * 73 * @see #setEmpty() 74 */ 75 public boolean isEmpty() { 76 return mRect == null && mPath == null; 77 } 78 79 80 /** 81 * Returns whether the outline can be used to clip a View. 82 * 83 * Currently, only outlines that can be represented as a rectangle, circle, or round rect 84 * support clipping. 85 * 86 * @see {@link View#setClipToOutline(boolean)} 87 */ 88 public boolean canClip() { 89 return !isEmpty() && mRect != null; 90 } 91 92 /** 93 * Sets the alpha represented by the Outline. 94 * 95 * Content producing a fully opaque (alpha = 1.0f) outline is assumed, by the drawing system, 96 * to fully cover content beneath it, meaning content beneath may be optimized away. 97 * 98 * @hide 99 */ 100 public void setAlpha(float alpha) { 101 mAlpha = alpha; 102 } 103 104 /** 105 * Sets the alpha represented by the Outline. 106 * 107 * @hide 108 */ 109 public float getAlpha() { 110 return mAlpha; 111 } 112 113 /** 114 * Replace the contents of this Outline with the contents of src. 115 * 116 * @param src Source outline to copy from. 117 */ 118 public void set(@NonNull Outline src) { 119 if (src.mPath != null) { 120 if (mPath == null) { 121 mPath = new Path(); 122 } 123 mPath.set(src.mPath); 124 mRect = null; 125 } 126 if (src.mRect != null) { 127 if (mRect == null) { 128 mRect = new Rect(); 129 } 130 mRect.set(src.mRect); 131 } 132 mRadius = src.mRadius; 133 mAlpha = src.mAlpha; 134 } 135 136 /** 137 * Sets the Outline to the rounded rect defined by the input rect, and corner radius. 138 */ 139 public void setRect(int left, int top, int right, int bottom) { 140 setRoundRect(left, top, right, bottom, 0.0f); 141 } 142 143 /** 144 * Convenience for {@link #setRect(int, int, int, int)} 145 */ 146 public void setRect(@NonNull Rect rect) { 147 setRect(rect.left, rect.top, rect.right, rect.bottom); 148 } 149 150 /** 151 * Sets the Outline to the rounded rect defined by the input rect, and corner radius. 152 * 153 * Passing a zero radius is equivalent to calling {@link #setRect(int, int, int, int)} 154 */ 155 public void setRoundRect(int left, int top, int right, int bottom, float radius) { 156 if (left >= right || top >= bottom) { 157 setEmpty(); 158 return; 159 } 160 161 if (mRect == null) mRect = new Rect(); 162 mRect.set(left, top, right, bottom); 163 mRadius = radius; 164 mPath = null; 165 } 166 167 /** 168 * Convenience for {@link #setRoundRect(int, int, int, int, float)} 169 */ 170 public void setRoundRect(@NonNull Rect rect, float radius) { 171 setRoundRect(rect.left, rect.top, rect.right, rect.bottom, radius); 172 } 173 174 /** 175 * Sets the outline to the oval defined by input rect. 176 */ 177 public void setOval(int left, int top, int right, int bottom) { 178 if (left >= right || top >= bottom) { 179 setEmpty(); 180 return; 181 } 182 183 if ((bottom - top) == (right - left)) { 184 // represent circle as round rect, for efficiency, and to enable clipping 185 setRoundRect(left, top, right, bottom, (bottom - top) / 2.0f); 186 return; 187 } 188 189 if (mPath == null) mPath = new Path(); 190 mPath.reset(); 191 mPath.addOval(left, top, right, bottom, Path.Direction.CW); 192 mRect = null; 193 } 194 195 /** 196 * Convenience for {@link #setOval(int, int, int, int)} 197 */ 198 public void setOval(@NonNull Rect rect) { 199 setOval(rect.left, rect.top, rect.right, rect.bottom); 200 } 201 202 /** 203 * Sets the Constructs an Outline from a {@link android.graphics.Path#isConvex() convex path}. 204 */ 205 public void setConvexPath(@NonNull Path convexPath) { 206 if (convexPath.isEmpty()) { 207 setEmpty(); 208 return; 209 } 210 211 if (!convexPath.isConvex()) { 212 throw new IllegalArgumentException("path must be convex"); 213 } 214 if (mPath == null) mPath = new Path(); 215 216 mPath.set(convexPath); 217 mRect = null; 218 mRadius = -1.0f; 219 } 220} 221