blob: 2edc4a7ff58832f55ba2ad3e2bcd390909accbe4 [file] [log] [blame]
Igor Murashkinb3a78b22014-04-17 14:01:13 -07001/*
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.util;
18
Lajos Molnar0f491d72014-09-09 21:11:23 -070019import static com.android.internal.util.Preconditions.checkNotNull;
Jeff Sharkey5b836f22014-08-27 14:46:32 -070020import static com.android.internal.util.Preconditions.checkArgumentFinite;
21
Igor Murashkinb3a78b22014-04-17 14:01:13 -070022/**
23 * Immutable class for describing width and height dimensions in some arbitrary
24 * unit.
25 * <p>
26 * Width and height are finite values stored as a floating point representation.
27 * </p>
28 */
Jeff Sharkey5ef33982014-09-04 18:13:39 -070029public final class SizeF {
Igor Murashkinb3a78b22014-04-17 14:01:13 -070030 /**
31 * Create a new immutable SizeF instance.
32 *
33 * <p>Both the {@code width} and the {@code height} must be a finite number.
34 * In particular, {@code NaN} and positive/negative infinity are illegal values.</p>
35 *
36 * @param width The width of the size
37 * @param height The height of the size
38 *
39 * @throws IllegalArgumentException
40 * if either {@code width} or {@code height} was not finite.
41 */
42 public SizeF(final float width, final float height) {
43 mWidth = checkArgumentFinite(width, "width");
44 mHeight = checkArgumentFinite(height, "height");
45 }
46
47 /**
48 * Get the width of the size (as an arbitrary unit).
49 * @return width
50 */
51 public float getWidth() {
52 return mWidth;
53 }
54
55 /**
56 * Get the height of the size (as an arbitrary unit).
57 * @return height
58 */
59 public float getHeight() {
60 return mHeight;
61 }
62
63 /**
64 * Check if this size is equal to another size.
65 *
66 * <p>Two sizes are equal if and only if both their widths and heights are the same.</p>
67 *
68 * <p>For this purpose, the width/height float values are considered to be the same if and only
69 * if the method {@link Float#floatToIntBits(float)} returns the identical {@code int} value
70 * when applied to each.</p>
71 *
72 * @return {@code true} if the objects were equal, {@code false} otherwise
73 */
74 @Override
75 public boolean equals(final Object obj) {
76 if (obj == null) {
77 return false;
78 }
79 if (this == obj) {
80 return true;
81 }
82 if (obj instanceof SizeF) {
83 final SizeF other = (SizeF) obj;
84 return mWidth == other.mWidth && mHeight == other.mHeight;
85 }
86 return false;
87 }
88
89 /**
90 * Return the size represented as a string with the format {@code "WxH"}
91 *
92 * @return string representation of the size
93 */
94 @Override
95 public String toString() {
96 return mWidth + "x" + mHeight;
97 }
98
Lajos Molnar0f491d72014-09-09 21:11:23 -070099 private static NumberFormatException invalidSizeF(String s) {
100 throw new NumberFormatException("Invalid SizeF: \"" + s + "\"");
101 }
102
103 /**
104 * Parses the specified string as a size value.
105 * <p>
106 * The ASCII characters {@code \}{@code u002a} ('*') and
107 * {@code \}{@code u0078} ('x') are recognized as separators between
108 * the width and height.</p>
109 * <p>
110 * For any {@code SizeF s}: {@code SizeF.parseSizeF(s.toString()).equals(s)}.
111 * However, the method also handles sizes expressed in the
112 * following forms:</p>
113 * <p>
114 * "<i>width</i>{@code x}<i>height</i>" or
115 * "<i>width</i>{@code *}<i>height</i>" {@code => new SizeF(width, height)},
116 * where <i>width</i> and <i>height</i> are string floats potentially
117 * containing a sign, such as "-10.3", "+7" or "5.2", but not containing
118 * an {@code 'x'} (such as a float in hexadecimal string format).</p>
119 *
120 * <pre>{@code
121 * SizeF.parseSizeF("3.2*+6").equals(new SizeF(3.2f, 6.0f)) == true
122 * SizeF.parseSizeF("-3x-6").equals(new SizeF(-3.0f, -6.0f)) == true
123 * SizeF.parseSizeF("4 by 3") => throws NumberFormatException
124 * }</pre>
125 *
126 * @param string the string representation of a size value.
127 * @return the size value represented by {@code string}.
128 *
129 * @throws NumberFormatException if {@code string} cannot be parsed
130 * as a size value.
131 * @throws NullPointerException if {@code string} was {@code null}
132 */
133 public static SizeF parseSizeF(String string)
134 throws NumberFormatException {
135 checkNotNull(string, "string must not be null");
136
137 int sep_ix = string.indexOf('*');
138 if (sep_ix < 0) {
139 sep_ix = string.indexOf('x');
140 }
141 if (sep_ix < 0) {
142 throw invalidSizeF(string);
143 }
144 try {
145 return new SizeF(Float.parseFloat(string.substring(0, sep_ix)),
146 Float.parseFloat(string.substring(sep_ix + 1)));
147 } catch (NumberFormatException e) {
148 throw invalidSizeF(string);
149 } catch (IllegalArgumentException e) {
150 throw invalidSizeF(string);
151 }
152 }
153
Igor Murashkinb3a78b22014-04-17 14:01:13 -0700154 /**
155 * {@inheritDoc}
156 */
157 @Override
158 public int hashCode() {
159 return Float.floatToIntBits(mWidth) ^ Float.floatToIntBits(mHeight);
160 }
161
162 private final float mWidth;
163 private final float mHeight;
Jeff Sharkey5b836f22014-08-27 14:46:32 -0700164}