Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(186)

Side by Side Diff: runtime/lib/pixels.dart

Issue 2035453002: Pixels class prototype and test (not to be committed). Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: work in progress Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4
5 // TODO(regis): Move abstract class pixels to sdk/lib/core/pixels.dart:
6 abstract class pixels extends num {
7 static const pixels NAN = 0px / 0px;
8 static const pixels INFINITY = 1px / 0px;
9 static const pixels NEGATIVE_INFINITY = -INFINITY;
10 // TODO(regis): Expand as needed with API documentation.
11 }
12
13 class _Pixels implements pixels {
14 static const int _SCALING_BITS = 6;
15 static const int _SCALING_FACTOR = 1 << _SCALING_BITS;
16 static const int _HALF_VALUE = _SCALING_FACTOR >> 1;
17 static const int _NAN_VALUE = (1 << 30) - 1; // Same as kSmiMax32. Positive.
18 static const int _PLUS_INF_VALUE = _NAN_VALUE - 1; // Same as kSmiMax32 - 1.
19 static const int _MINUS_INF_VALUE = -_PLUS_INF_VALUE; // Same as kSmiMin32 + 2.
20
21 // TODO(regis): Detect _NAN_VALUE, _PLUS_INF_VALUE and _MINUS_INF_VALUE as
22 // operands to all operations and treat as non finite values, rather than min and max.
23
24 final int _value;
25 static const pixels _PLUS_ONE = const _Pixels(1 << _SCALING_BITS);
26 static const pixels _MINUS_ONE = const _Pixels(-1 << _SCALING_BITS);
27 static const pixels _PLUS_INF = const _Pixels(_PLUS_INF_VALUE);
28 static const pixels _MINUS_INF = const _Pixels(_MINUS_INF_VALUE);
29 static const pixels _NAN = const _Pixels(_NAN_VALUE);
30
31 // Argument is already a scaled value in valid range.
32 const _Pixels(int this._value);
33
34 // Argument is already a scaled value, but not necessarily in valid range.
35 _Pixels._clamp(int this._value) {
36 if (_value > _PLUS_INF_VALUE) _value = _PLUS_INF_VALUE;
37 else if (_value < _MINUS_INF_VALUE) _value = _MINUS_INF_VALUE;
38 }
39
40 factory _Pixels.fromInteger(int value) => new _Pixels._clamp(value << _SCALING _BITS);
41
42 factory _Pixels.fromDouble(double value) => value.toPixels();
43
44 _Pixels.fromPixelsLiteral(String value) {
45 final decimalPoint = ".".codeUnits.first;
46 final digit0 = "0".codeUnits.first;
47 final digit9 = "9".codeUnits.first;
48 var numerator = 0;
49 var denominator = 1;
50 bool seenDecimalPoint = false;
51 for (var i = 0; i < value.length; i++) {
52 var c = value.codeUnitAt(i);
53 if (!seenDecimalPoint && c == decimalPoint) {
54 seenDecimalPoint = true;
55 } else if (digit0 <= c && c <= digit9) {
56 numerator = numerator*10 + (c - digit0);
57 if (seenDecimalPoint) denominator *= 10;
58 } else {
59 break; // TODO(regis): Error handling. Expect px or PX here.
60 }
61 }
62 _value = (numerator << _SCALING_BITS) ~/ denominator;
63 if (_value > _PLUS_INF_VALUE) _value = _PLUS_INF_VALUE;
64 }
65
66 Type get runtimeType => pixels;
67
68 int get _identityHashCode {
69 return _value;
70 }
71
72 num operator +(num other) {
73 return other._toDoubleOrPixels()._addFromPixels(this);
74 }
75 pixels _addFromPixels(pixels other) {
76 return other._add(this);
77 }
78 pixels _add(pixels other) {
79 return new _Pixels._clamp(_value + other._value);
80 }
81
82 num operator -(num other) {
83 return other._toDoubleOrPixels()._subFromPixels(this);
84 }
85 pixels _subFromPixels(pixels other) {
86 return other._sub(this);
87 }
88 pixels _sub(pixels other) {
89 return new _Pixels._clamp(_value - other._value);
90 }
91
92 num operator *(num other) {
93 return other._toDoubleOrPixels()._mulFromPixels(this);
94 }
95 pixels _mulFromPixels(pixels other) {
96 return other._mul(this);
97 }
98 pixels _mul(pixels other) {
99 // Use rounding.
100 return new _Pixels._clamp((_value*other._value + _HALF_VALUE) >> _SCALING_BI TS);
101 }
102
103 num operator /(num other) {
104 return other._toDoubleOrPixels()._divFromPixels(this);
105 }
106 pixels _divFromPixels(pixels other) {
107 return other._div(this);
108 }
109 pixels _div(pixels other) {
110 if (other._value == 0) {
111 if (_value > 0) {
112 return _PLUS_INF;
113 } else if (_value == 0) {
114 return _NAN;
115 } else {
116 return _MINUS_INF;
117 }
118 }
119 return new _Pixels._clamp((_value << _SCALING_BITS) ~/ other._value);
120 }
121
122 num operator %(num other) {
123 return other._toDoubleOrPixels()._moduloFromPixels(this);
124 }
125 pixels _moduloFromPixels(pixels other) {
126 return other._modulo(this);
127 }
128 pixels _modulo(pixels other) {
129 var q = _div(other); // TODO(regis): Check NAN.
130 if (other._value < 0) {
131 q = q.ceil();
132 } else {
133 q = q.floor();
134 }
135 return _sub(q.toPixels()._mul(other));
136 }
137
138 int operator ~/(num other) {
139 return other._toDoubleOrPixels()._truncDivFromPixels(this);
140 }
141 int _truncDivFromPixels(pixels other) {
142 return other._truncDiv(this);
143 }
144 int _truncDiv(pixels other) {
145 if (other._value == 0) throw const IntegerDivisionByZeroException();
146 return _value ~/ other._value;
147 }
148
149 num remainder(num other) {
150 return other._toDoubleOrPixels()._remainderFromPixels(this);
151 }
152 pixels _remainderFromPixels(pixels other) {
153 return other._remainder(this);
154 }
155 pixels _remainder(pixels other) {
156 if (other._value == 0) throw const IntegerDivisionByZeroException();
157 return new _Pixels._clamp(_value - other._value*(_value ~/ other._value));
158 }
159
160 pixels operator -() {
161 if (isNaN) return this;
162 return new _Pixels(-_value);
163 }
164
165 bool operator ==(other) {
166 if (!(other is num)) return false;
167 return other._equalToPixels(this);
168 }
169 bool _equalToPixels(pixels other) {
170 return other._equal(this);
171 }
172 bool _equal(pixels other) {
173 return _value == other._value;
174 }
175
176 bool _equalToInteger(int other) {
177 return _value == (other << _SCALING_BITS);
178 }
179
180 bool operator <(num other) {
181 return other > this;
182 }
183 bool operator >(num other) {
184 return other._greaterThanFromPixels(this);
185 }
186 bool _greaterThanFromPixels(pixels other) {
187 return other._value > _value;
188 }
189 bool operator >=(num other) {
190 return (this == other) || (this > other);
191 }
192 bool operator <=(num other) {
193 return (this == other) || (this < other);
194 }
195
196 pixels _addFromInteger(int other) {
197 return new _Pixels._clamp((other << _SCALING_BITS) + _value);
198 }
199
200 pixels _subFromInteger(int other) {
201 return new _Pixels._clamp((other << _SCALING_BITS) - _value);
202 }
203
204 pixels _mulFromInteger(int other) {
205 return new _Pixels._clamp(other * _value);
206 }
207
208 pixels _divFromInteger(int other) {
209 if (_value == 0) {
210 if (other > 0) {
211 return _PLUS_INF;
212 } else if (other == 0) {
213 return _NAN;
214 } else {
215 return _MINUS_INF;
216 }
217 }
218 return new _Pixels._clamp((other << (2*_SCALING_BITS)) ~/ _value);
219 }
220
221 pixels _moduloFromInteger(int other) {
222 var q = _divFromInteger(other);
223 if (_value < 0) {
224 q = q.ceil();
225 } else {
226 q = q.floor();
227 }
228 return _mul(q.toPixels())._subFromInteger(other);
229 }
230
231 int _truncDivFromInteger(int other) {
232 if (_value == 0) throw const IntegerDivisionByZeroException();
233 return (other << _SCALING_BITS) ~/ _value;
234 }
235
236 pixels _remainderFromInteger(int other) {
237 if (_value == 0) throw const IntegerDivisionByZeroException();
238 return new _Pixels._clamp(
239 (other << _SCALING_BITS) - _value*((other << _SCALING_BITS) ~/ _value));
240 }
241
242 bool _greaterThanFromInteger(int other) {
243 return (other << _SCALING_BITS) > _value;
244 }
245
246 bool get isNegative {
247 return _value < 0;
248 }
249
250 bool get isInfinite {
251 return (_value == _PLUS_INF_VALUE) || (_value == _MINUS_INF_VALUE);
252 }
253 bool get isNaN => _value == _NAN_VALUE;
254 bool get isFinite {
255 return (_value != _PLUS_INF_VALUE) &&
256 (_value != _MINUS_INF_VALUE) &&
257 (_value != _NAN_VALUE);
258 }
259
260 pixels abs() {
261 return isNegative ? -this : this;
262 }
263
264 pixels get sign {
265 if (_value > 0) return _PLUS_ONE;
266 if (_value < 0) return _MINUS_ONE;
267 return this;
268 }
269
270 int round() {
271 if (!isFinite) throw new UnsupportedError("Must be finite");
272 return (_value + _HALF_VALUE) >> _SCALING_BITS;
273 }
274 int floor() {
275 if (!isFinite) throw new UnsupportedError("Must be finite");
276 return _value >> _SCALING_BITS;
277 }
278 int ceil() {
279 if (!isFinite) throw new UnsupportedError("Must be finite");
280 return (_value + _SCALING_FACTOR - 1) >> _SCALING_BITS;
281 }
282 int truncate() {
283 if (!isFinite) throw new UnsupportedError("Must be finite");
284 return (_value + ((_value < 0) ? (_SCALING_FACTOR - 1) : 0)) >> _SCALING_BIT S;
285 }
286
287 double roundToDouble() => round().toDouble();
288 double floorToDouble() => floor().toDouble();
289 double ceilToDouble() => ceil().toDouble();
290 double truncateToDouble() => truncate().toDouble();
291
292 num clamp(num lowerLimit, num upperLimit) {
293 if (lowerLimit is! num) {
294 throw new ArgumentError.value(lowerLimit, "lowerLimit", "not a number");
295 }
296 if (upperLimit is! num) {
297 throw new ArgumentError.value(upperLimit, "upperLimit", "not a number");
298 }
299
300 if (lowerLimit.compareTo(upperLimit) > 0) {
301 throw new ArgumentError(lowerLimit);
302 }
303 if (lowerLimit.isNaN) return lowerLimit;
304 if (this.compareTo(lowerLimit) < 0) return lowerLimit;
305 if (this.compareTo(upperLimit) > 0) return upperLimit;
306 return this;
307 }
308
309 int toInt() => truncate(); // TODO(regis): Should we use round() instead?
310 double toDouble() {
311 if (_value == _PLUS_INF_VALUE) return double.INFINITY;
312 if (_value == _MINUS_INF_VALUE) return double.NEGATIVE_INFINITY;
313 if (_value == _NAN_VALUE) return double.NAN;
314 return _value / _SCALING_FACTOR;
315 }
316 pixels toPixels() { return this; }
317 pixels _toDoubleOrPixels() { return this; }
318 num _toBigintIfInteger() { return this; }
319
320 String toString() => "${toDouble()}px";
321
322 int compareTo(num other) {
323 const int EQUAL = 0, LESS = -1, GREATER = 1;
324 if (isNaN) {
325 return GREATER; // TODO(regis): Correct?
326 }
327 if (other is double) {
328 double d = other;
329 if (d.isInfinite) {
330 if (isInfinite) {
331 if (((d == double.NEGATIVE_INFINITY) && (_value < 0)) ||
332 ((d == double.INFINITY) && (_value > 0))) {
333 return EQUAL;
334 }
335 }
336 return _value > 0 ? GREATER : LESS;
337 }
338 if (d.isNaN) {
339 return LESS; // TODO(regis): unless this.isNaN? See above.
340 }
341 if ((d == 0.0) && (_value == 0)) {
342 return d.isNegative ? GREATER : EQUAL;
343 }
344 other = other.toPixels();
345 }
346 if (this < other) {
347 return LESS;
348 } else if (this > other) {
349 return GREATER;
350 } else {
351 return EQUAL;
352 }
353 }
354 }
355
OLDNEW
« no previous file with comments | « runtime/lib/integers.dart ('k') | runtime/observatory/tests/service/get_source_report_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698