1 | /* |
2 | * Copyright (c) 2012, Google Inc. All rights reserved. |
3 | * |
4 | * Redistribution and use in source and binary forms, with or without |
5 | * modification, are permitted provided that the following conditions are |
6 | * met: |
7 | * |
8 | * * Redistributions of source code must retain the above copyright |
9 | * notice, this list of conditions and the following disclaimer. |
10 | * * Redistributions in binary form must reproduce the above |
11 | * copyright notice, this list of conditions and the following disclaimer |
12 | * in the documentation and/or other materials provided with the |
13 | * distribution. |
14 | * * Neither the name of Google Inc. nor the names of its |
15 | * contributors may be used to endorse or promote products derived from |
16 | * this software without specific prior written permission. |
17 | * |
18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
19 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
20 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
21 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
22 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
24 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
25 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
26 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
27 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
28 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
29 | */ |
30 | |
31 | #pragma once |
32 | |
33 | #include <limits.h> |
34 | #include <limits> |
35 | #include <math.h> |
36 | #include <stdlib.h> |
37 | #include <wtf/MathExtras.h> |
38 | #include <wtf/SaturatedArithmetic.h> |
39 | #include <wtf/text/ValueToString.h> |
40 | |
41 | namespace WTF { |
42 | class TextStream; |
43 | } |
44 | |
45 | namespace WebCore { |
46 | |
47 | #ifdef NDEBUG |
48 | |
49 | #define REPORT_OVERFLOW(doesOverflow) ((void)0) |
50 | |
51 | #else |
52 | |
53 | #define REPORT_OVERFLOW(doesOverflow) do \ |
54 | if (!(doesOverflow)) { \ |
55 | WTFReportError(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, "!(%s)", #doesOverflow); \ |
56 | } \ |
57 | while (0) |
58 | |
59 | #endif |
60 | |
61 | static const int kFixedPointDenominator = 64; |
62 | const int intMaxForLayoutUnit = INT_MAX / kFixedPointDenominator; |
63 | const int intMinForLayoutUnit = INT_MIN / kFixedPointDenominator; |
64 | |
65 | class LayoutUnit { |
66 | public: |
67 | LayoutUnit() : m_value(0) { } |
68 | LayoutUnit(int value) { setValue(value); } |
69 | LayoutUnit(unsigned short value) { setValue(value); } |
70 | LayoutUnit(unsigned value) { setValue(value); } |
71 | explicit LayoutUnit(unsigned long value) |
72 | { |
73 | m_value = clampTo<int>(value * kFixedPointDenominator); |
74 | } |
75 | explicit LayoutUnit(unsigned long long value) |
76 | { |
77 | m_value = clampTo<int>(value * kFixedPointDenominator); |
78 | } |
79 | explicit LayoutUnit(float value) |
80 | { |
81 | m_value = clampToInteger(value * kFixedPointDenominator); |
82 | } |
83 | explicit LayoutUnit(double value) |
84 | { |
85 | m_value = clampToInteger(value * kFixedPointDenominator); |
86 | } |
87 | |
88 | LayoutUnit& operator=(const LayoutUnit& other) = default; |
89 | LayoutUnit& operator=(const float& other) { return *this = LayoutUnit(other); } |
90 | |
91 | static LayoutUnit fromFloatCeil(float value) |
92 | { |
93 | LayoutUnit v; |
94 | v.m_value = clampToInteger(ceilf(value * kFixedPointDenominator)); |
95 | return v; |
96 | } |
97 | |
98 | static LayoutUnit fromFloatFloor(float value) |
99 | { |
100 | LayoutUnit v; |
101 | v.m_value = clampToInteger(floorf(value * kFixedPointDenominator)); |
102 | return v; |
103 | } |
104 | |
105 | static LayoutUnit fromFloatRound(float value) |
106 | { |
107 | if (value >= 0) |
108 | return clamp(value + epsilon() / 2.0f); |
109 | return clamp(value - epsilon() / 2.0f); |
110 | } |
111 | |
112 | int toInt() const { return m_value / kFixedPointDenominator; } |
113 | float toFloat() const { return static_cast<float>(m_value) / kFixedPointDenominator; } |
114 | double toDouble() const { return static_cast<double>(m_value) / kFixedPointDenominator; } |
115 | unsigned toUnsigned() const { REPORT_OVERFLOW(m_value >= 0); return toInt(); } |
116 | |
117 | operator int() const { return toInt(); } |
118 | operator float() const { return toFloat(); } |
119 | operator double() const { return toDouble(); } |
120 | explicit operator bool() const { return m_value; } |
121 | |
122 | LayoutUnit& operator++() |
123 | { |
124 | m_value += kFixedPointDenominator; |
125 | return *this; |
126 | } |
127 | |
128 | inline int rawValue() const { return m_value; } |
129 | inline void setRawValue(int value) { m_value = value; } |
130 | void setRawValue(long long value) |
131 | { |
132 | REPORT_OVERFLOW(value > std::numeric_limits<int>::min() && value < std::numeric_limits<int>::max()); |
133 | m_value = static_cast<int>(value); |
134 | } |
135 | |
136 | LayoutUnit abs() const |
137 | { |
138 | LayoutUnit returnValue; |
139 | returnValue.setRawValue(::abs(m_value)); |
140 | return returnValue; |
141 | } |
142 | int ceil() const |
143 | { |
144 | if (UNLIKELY(m_value >= INT_MAX - kFixedPointDenominator + 1)) |
145 | return intMaxForLayoutUnit; |
146 | if (m_value >= 0) |
147 | return (m_value + kFixedPointDenominator - 1) / kFixedPointDenominator; |
148 | return toInt(); |
149 | } |
150 | |
151 | int round() const |
152 | { |
153 | if (m_value > 0) |
154 | return saturatedAddition(rawValue(), kFixedPointDenominator / 2) / kFixedPointDenominator; |
155 | return saturatedSubtraction(rawValue(), (kFixedPointDenominator / 2) - 1) / kFixedPointDenominator; |
156 | } |
157 | |
158 | int floor() const |
159 | { |
160 | if (UNLIKELY(m_value <= INT_MIN + kFixedPointDenominator - 1)) |
161 | return intMinForLayoutUnit; |
162 | if (m_value >= 0) |
163 | return toInt(); |
164 | return (m_value - kFixedPointDenominator + 1) / kFixedPointDenominator; |
165 | } |
166 | |
167 | float ceilToFloat() const |
168 | { |
169 | float floatValue = toFloat(); |
170 | if (static_cast<int>(floatValue * kFixedPointDenominator) == m_value) |
171 | return floatValue; |
172 | if (floatValue > 0) |
173 | return nextafterf(floatValue, std::numeric_limits<float>::max()); |
174 | return nextafterf(floatValue, std::numeric_limits<float>::min()); |
175 | } |
176 | |
177 | LayoutUnit fraction() const |
178 | { |
179 | // Add the fraction to the size (as opposed to the full location) to avoid overflows. |
180 | // Compute fraction using the mod operator to preserve the sign of the value as it may affect rounding. |
181 | LayoutUnit fraction; |
182 | fraction.setRawValue(rawValue() % kFixedPointDenominator); |
183 | return fraction; |
184 | } |
185 | |
186 | bool mightBeSaturated() const |
187 | { |
188 | return rawValue() == std::numeric_limits<int>::max() |
189 | || rawValue() == std::numeric_limits<int>::min(); |
190 | } |
191 | |
192 | static float epsilon() { return 1.0f / kFixedPointDenominator; } |
193 | |
194 | static const LayoutUnit max() |
195 | { |
196 | LayoutUnit m; |
197 | m.m_value = std::numeric_limits<int>::max(); |
198 | return m; |
199 | } |
200 | static const LayoutUnit min() |
201 | { |
202 | LayoutUnit m; |
203 | m.m_value = std::numeric_limits<int>::min(); |
204 | return m; |
205 | } |
206 | |
207 | // Versions of max/min that are slightly smaller/larger than max/min() to allow for roinding without overflowing. |
208 | static const LayoutUnit nearlyMax() |
209 | { |
210 | LayoutUnit m; |
211 | m.m_value = std::numeric_limits<int>::max() - kFixedPointDenominator / 2; |
212 | return m; |
213 | } |
214 | static const LayoutUnit nearlyMin() |
215 | { |
216 | LayoutUnit m; |
217 | m.m_value = std::numeric_limits<int>::min() + kFixedPointDenominator / 2; |
218 | return m; |
219 | } |
220 | |
221 | static LayoutUnit clamp(double value) |
222 | { |
223 | return clampTo<LayoutUnit>(value, LayoutUnit::min(), LayoutUnit::max()); |
224 | } |
225 | |
226 | private: |
227 | static bool isInBounds(int value) |
228 | { |
229 | return ::abs(value) <= std::numeric_limits<int>::max() / kFixedPointDenominator; |
230 | } |
231 | static bool isInBounds(unsigned value) |
232 | { |
233 | return value <= static_cast<unsigned>(std::numeric_limits<int>::max()) / kFixedPointDenominator; |
234 | } |
235 | static bool isInBounds(double value) |
236 | { |
237 | return ::fabs(value) <= std::numeric_limits<int>::max() / kFixedPointDenominator; |
238 | } |
239 | |
240 | inline void setValue(int value) |
241 | { |
242 | if (value > intMaxForLayoutUnit) |
243 | m_value = std::numeric_limits<int>::max(); |
244 | else if (value < intMinForLayoutUnit) |
245 | m_value = std::numeric_limits<int>::min(); |
246 | else |
247 | m_value = value * kFixedPointDenominator; |
248 | } |
249 | inline void setValue(unsigned value) |
250 | { |
251 | if (value >= static_cast<unsigned>(intMaxForLayoutUnit)) |
252 | m_value = std::numeric_limits<int>::max(); |
253 | else |
254 | m_value = value * kFixedPointDenominator; |
255 | } |
256 | |
257 | int m_value; |
258 | }; |
259 | |
260 | inline bool operator<=(const LayoutUnit& a, const LayoutUnit& b) |
261 | { |
262 | return a.rawValue() <= b.rawValue(); |
263 | } |
264 | |
265 | inline bool operator<=(const LayoutUnit& a, float b) |
266 | { |
267 | return a.toFloat() <= b; |
268 | } |
269 | |
270 | inline bool operator<=(const LayoutUnit& a, int b) |
271 | { |
272 | return a <= LayoutUnit(b); |
273 | } |
274 | |
275 | inline bool operator<=(const float a, const LayoutUnit& b) |
276 | { |
277 | return a <= b.toFloat(); |
278 | } |
279 | |
280 | inline bool operator<=(const int a, const LayoutUnit& b) |
281 | { |
282 | return LayoutUnit(a) <= b; |
283 | } |
284 | |
285 | inline bool operator>=(const LayoutUnit& a, const LayoutUnit& b) |
286 | { |
287 | return a.rawValue() >= b.rawValue(); |
288 | } |
289 | |
290 | inline bool operator>=(const LayoutUnit& a, int b) |
291 | { |
292 | return a >= LayoutUnit(b); |
293 | } |
294 | |
295 | inline bool operator>=(const float a, const LayoutUnit& b) |
296 | { |
297 | return a >= b.toFloat(); |
298 | } |
299 | |
300 | inline bool operator>=(const LayoutUnit& a, float b) |
301 | { |
302 | return a.toFloat() >= b; |
303 | } |
304 | |
305 | inline bool operator>=(const int a, const LayoutUnit& b) |
306 | { |
307 | return LayoutUnit(a) >= b; |
308 | } |
309 | |
310 | inline bool operator<(const LayoutUnit& a, const LayoutUnit& b) |
311 | { |
312 | return a.rawValue() < b.rawValue(); |
313 | } |
314 | |
315 | inline bool operator<(const LayoutUnit& a, int b) |
316 | { |
317 | return a < LayoutUnit(b); |
318 | } |
319 | |
320 | inline bool operator<(const LayoutUnit& a, float b) |
321 | { |
322 | return a.toFloat() < b; |
323 | } |
324 | |
325 | inline bool operator<(const LayoutUnit& a, double b) |
326 | { |
327 | return a.toDouble() < b; |
328 | } |
329 | |
330 | inline bool operator<(const int a, const LayoutUnit& b) |
331 | { |
332 | return LayoutUnit(a) < b; |
333 | } |
334 | |
335 | inline bool operator<(const float a, const LayoutUnit& b) |
336 | { |
337 | return a < b.toFloat(); |
338 | } |
339 | |
340 | inline bool operator>(const LayoutUnit& a, const LayoutUnit& b) |
341 | { |
342 | return a.rawValue() > b.rawValue(); |
343 | } |
344 | |
345 | inline bool operator>(const LayoutUnit& a, double b) |
346 | { |
347 | return a.toDouble() > b; |
348 | } |
349 | |
350 | inline bool operator>(const LayoutUnit& a, float b) |
351 | { |
352 | return a.toFloat() > b; |
353 | } |
354 | |
355 | inline bool operator>(const LayoutUnit& a, int b) |
356 | { |
357 | return a > LayoutUnit(b); |
358 | } |
359 | |
360 | inline bool operator>(const int a, const LayoutUnit& b) |
361 | { |
362 | return LayoutUnit(a) > b; |
363 | } |
364 | |
365 | inline bool operator>(const float a, const LayoutUnit& b) |
366 | { |
367 | return a > b.toFloat(); |
368 | } |
369 | |
370 | inline bool operator>(const double a, const LayoutUnit& b) |
371 | { |
372 | return a > b.toDouble(); |
373 | } |
374 | |
375 | inline bool operator!=(const LayoutUnit& a, const LayoutUnit& b) |
376 | { |
377 | return a.rawValue() != b.rawValue(); |
378 | } |
379 | |
380 | inline bool operator!=(const LayoutUnit& a, float b) |
381 | { |
382 | return a != LayoutUnit(b); |
383 | } |
384 | |
385 | inline bool operator!=(const int a, const LayoutUnit& b) |
386 | { |
387 | return LayoutUnit(a) != b; |
388 | } |
389 | |
390 | inline bool operator!=(const LayoutUnit& a, int b) |
391 | { |
392 | return a != LayoutUnit(b); |
393 | } |
394 | |
395 | inline bool operator==(const LayoutUnit& a, const LayoutUnit& b) |
396 | { |
397 | return a.rawValue() == b.rawValue(); |
398 | } |
399 | |
400 | inline bool operator==(const LayoutUnit& a, int b) |
401 | { |
402 | return a == LayoutUnit(b); |
403 | } |
404 | |
405 | inline bool operator==(const int a, const LayoutUnit& b) |
406 | { |
407 | return LayoutUnit(a) == b; |
408 | } |
409 | |
410 | inline bool operator==(const LayoutUnit& a, float b) |
411 | { |
412 | return a.toFloat() == b; |
413 | } |
414 | |
415 | inline bool operator==(const float a, const LayoutUnit& b) |
416 | { |
417 | return a == b.toFloat(); |
418 | } |
419 | |
420 | // For multiplication that's prone to overflow, this bounds it to LayoutUnit::max() and ::min() |
421 | inline LayoutUnit boundedMultiply(const LayoutUnit& a, const LayoutUnit& b) |
422 | { |
423 | int64_t result = static_cast<int64_t>(a.rawValue()) * static_cast<int64_t>(b.rawValue()) / kFixedPointDenominator; |
424 | int32_t high = static_cast<int32_t>(result >> 32); |
425 | int32_t low = static_cast<int32_t>(result); |
426 | uint32_t saturated = (static_cast<uint32_t>(a.rawValue() ^ b.rawValue()) >> 31) + std::numeric_limits<int>::max(); |
427 | // If the higher 32 bits does not match the lower 32 with sign extension the operation overflowed. |
428 | if (high != low >> 31) |
429 | result = saturated; |
430 | |
431 | LayoutUnit returnVal; |
432 | returnVal.setRawValue(static_cast<int>(result)); |
433 | return returnVal; |
434 | } |
435 | |
436 | inline LayoutUnit operator*(const LayoutUnit& a, const LayoutUnit& b) |
437 | { |
438 | return boundedMultiply(a, b); |
439 | } |
440 | |
441 | inline double operator*(const LayoutUnit& a, double b) |
442 | { |
443 | return a.toDouble() * b; |
444 | } |
445 | |
446 | inline float operator*(const LayoutUnit& a, float b) |
447 | { |
448 | return a.toFloat() * b; |
449 | } |
450 | |
451 | inline LayoutUnit operator*(const LayoutUnit& a, int b) |
452 | { |
453 | return a * LayoutUnit(b); |
454 | } |
455 | |
456 | inline LayoutUnit operator*(const LayoutUnit& a, unsigned short b) |
457 | { |
458 | return a * LayoutUnit(b); |
459 | } |
460 | |
461 | inline LayoutUnit operator*(const LayoutUnit& a, unsigned b) |
462 | { |
463 | return a * LayoutUnit(b); |
464 | } |
465 | |
466 | inline LayoutUnit operator*(const LayoutUnit& a, unsigned long b) |
467 | { |
468 | return a * LayoutUnit(b); |
469 | } |
470 | |
471 | inline LayoutUnit operator*(const LayoutUnit& a, unsigned long long b) |
472 | { |
473 | return a * LayoutUnit(b); |
474 | } |
475 | |
476 | inline LayoutUnit operator*(unsigned short a, const LayoutUnit& b) |
477 | { |
478 | return LayoutUnit(a) * b; |
479 | } |
480 | |
481 | inline LayoutUnit operator*(unsigned a, const LayoutUnit& b) |
482 | { |
483 | return LayoutUnit(a) * b; |
484 | } |
485 | |
486 | inline LayoutUnit operator*(unsigned long a, const LayoutUnit& b) |
487 | { |
488 | return LayoutUnit(a) * b; |
489 | } |
490 | |
491 | inline LayoutUnit operator*(unsigned long long a, const LayoutUnit& b) |
492 | { |
493 | return LayoutUnit(a) * b; |
494 | } |
495 | |
496 | inline LayoutUnit operator*(const int a, const LayoutUnit& b) |
497 | { |
498 | return LayoutUnit(a) * b; |
499 | } |
500 | |
501 | inline float operator*(const float a, const LayoutUnit& b) |
502 | { |
503 | return a * b.toFloat(); |
504 | } |
505 | |
506 | inline double operator*(const double a, const LayoutUnit& b) |
507 | { |
508 | return a * b.toDouble(); |
509 | } |
510 | |
511 | inline LayoutUnit operator/(const LayoutUnit& a, const LayoutUnit& b) |
512 | { |
513 | LayoutUnit returnVal; |
514 | long long rawVal = static_cast<long long>(kFixedPointDenominator) * a.rawValue() / b.rawValue(); |
515 | returnVal.setRawValue(clampTo<int>(rawVal)); |
516 | return returnVal; |
517 | } |
518 | |
519 | inline float operator/(const LayoutUnit& a, float b) |
520 | { |
521 | return a.toFloat() / b; |
522 | } |
523 | |
524 | inline double operator/(const LayoutUnit& a, double b) |
525 | { |
526 | return a.toDouble() / b; |
527 | } |
528 | |
529 | inline LayoutUnit operator/(const LayoutUnit& a, int b) |
530 | { |
531 | return a / LayoutUnit(b); |
532 | } |
533 | |
534 | inline LayoutUnit operator/(const LayoutUnit& a, unsigned short b) |
535 | { |
536 | return a / LayoutUnit(b); |
537 | } |
538 | |
539 | inline LayoutUnit operator/(const LayoutUnit& a, unsigned b) |
540 | { |
541 | return a / LayoutUnit(b); |
542 | } |
543 | |
544 | inline LayoutUnit operator/(const LayoutUnit& a, unsigned long b) |
545 | { |
546 | return a / LayoutUnit(b); |
547 | } |
548 | |
549 | inline LayoutUnit operator/(const LayoutUnit& a, unsigned long long b) |
550 | { |
551 | return a / LayoutUnit(b); |
552 | } |
553 | |
554 | inline float operator/(const float a, const LayoutUnit& b) |
555 | { |
556 | return a / b.toFloat(); |
557 | } |
558 | |
559 | inline double operator/(const double a, const LayoutUnit& b) |
560 | { |
561 | return a / b.toDouble(); |
562 | } |
563 | |
564 | inline LayoutUnit operator/(const int a, const LayoutUnit& b) |
565 | { |
566 | return LayoutUnit(a) / b; |
567 | } |
568 | |
569 | inline LayoutUnit operator/(unsigned short a, const LayoutUnit& b) |
570 | { |
571 | return LayoutUnit(a) / b; |
572 | } |
573 | |
574 | inline LayoutUnit operator/(unsigned a, const LayoutUnit& b) |
575 | { |
576 | return LayoutUnit(a) / b; |
577 | } |
578 | |
579 | inline LayoutUnit operator/(unsigned long a, const LayoutUnit& b) |
580 | { |
581 | return LayoutUnit(a) / b; |
582 | } |
583 | |
584 | inline LayoutUnit operator/(unsigned long long a, const LayoutUnit& b) |
585 | { |
586 | return LayoutUnit(a) / b; |
587 | } |
588 | |
589 | inline LayoutUnit operator+(const LayoutUnit& a, const LayoutUnit& b) |
590 | { |
591 | LayoutUnit returnVal; |
592 | returnVal.setRawValue(saturatedAddition(a.rawValue(), b.rawValue())); |
593 | return returnVal; |
594 | } |
595 | |
596 | inline LayoutUnit operator+(const LayoutUnit& a, int b) |
597 | { |
598 | return a + LayoutUnit(b); |
599 | } |
600 | |
601 | inline float operator+(const LayoutUnit& a, float b) |
602 | { |
603 | return a.toFloat() + b; |
604 | } |
605 | |
606 | inline double operator+(const LayoutUnit& a, double b) |
607 | { |
608 | return a.toDouble() + b; |
609 | } |
610 | |
611 | inline LayoutUnit operator+(const int a, const LayoutUnit& b) |
612 | { |
613 | return LayoutUnit(a) + b; |
614 | } |
615 | |
616 | inline float operator+(const float a, const LayoutUnit& b) |
617 | { |
618 | return a + b.toFloat(); |
619 | } |
620 | |
621 | inline double operator+(const double a, const LayoutUnit& b) |
622 | { |
623 | return a + b.toDouble(); |
624 | } |
625 | |
626 | inline LayoutUnit operator-(const LayoutUnit& a, const LayoutUnit& b) |
627 | { |
628 | LayoutUnit returnVal; |
629 | returnVal.setRawValue(saturatedSubtraction(a.rawValue(), b.rawValue())); |
630 | return returnVal; |
631 | } |
632 | |
633 | inline LayoutUnit operator-(const LayoutUnit& a, int b) |
634 | { |
635 | return a - LayoutUnit(b); |
636 | } |
637 | |
638 | inline LayoutUnit operator-(const LayoutUnit& a, unsigned b) |
639 | { |
640 | return a - LayoutUnit(b); |
641 | } |
642 | |
643 | inline float operator-(const LayoutUnit& a, float b) |
644 | { |
645 | return a.toFloat() - b; |
646 | } |
647 | |
648 | inline LayoutUnit operator-(const int a, const LayoutUnit& b) |
649 | { |
650 | return LayoutUnit(a) - b; |
651 | } |
652 | |
653 | inline float operator-(const float a, const LayoutUnit& b) |
654 | { |
655 | return a - b.toFloat(); |
656 | } |
657 | |
658 | inline LayoutUnit operator-(const LayoutUnit& a) |
659 | { |
660 | LayoutUnit returnVal; |
661 | returnVal.setRawValue(-a.rawValue()); |
662 | return returnVal; |
663 | } |
664 | |
665 | // For returning the remainder after a division with integer results. |
666 | inline LayoutUnit intMod(const LayoutUnit& a, const LayoutUnit& b) |
667 | { |
668 | // This calculates the modulo so that: a = static_cast<int>(a / b) * b + intMod(a, b). |
669 | LayoutUnit returnVal; |
670 | returnVal.setRawValue(a.rawValue() % b.rawValue()); |
671 | return returnVal; |
672 | } |
673 | |
674 | inline LayoutUnit operator%(const LayoutUnit& a, const LayoutUnit& b) |
675 | { |
676 | // This calculates the modulo so that: a = (a / b) * b + a % b. |
677 | LayoutUnit returnVal; |
678 | long long rawVal = (static_cast<long long>(kFixedPointDenominator) * a.rawValue()) % b.rawValue(); |
679 | returnVal.setRawValue(rawVal / kFixedPointDenominator); |
680 | return returnVal; |
681 | } |
682 | |
683 | inline LayoutUnit operator%(const LayoutUnit& a, int b) |
684 | { |
685 | return a % LayoutUnit(b); |
686 | } |
687 | |
688 | inline LayoutUnit operator%(int a, const LayoutUnit& b) |
689 | { |
690 | return LayoutUnit(a) % b; |
691 | } |
692 | |
693 | inline LayoutUnit& operator+=(LayoutUnit& a, const LayoutUnit& b) |
694 | { |
695 | a.setRawValue(saturatedAddition(a.rawValue(), b.rawValue())); |
696 | return a; |
697 | } |
698 | |
699 | inline LayoutUnit& operator+=(LayoutUnit& a, int b) |
700 | { |
701 | a = a + b; |
702 | return a; |
703 | } |
704 | |
705 | inline LayoutUnit& operator+=(LayoutUnit& a, float b) |
706 | { |
707 | a = a + b; |
708 | return a; |
709 | } |
710 | |
711 | inline float& operator+=(float& a, const LayoutUnit& b) |
712 | { |
713 | a = a + b; |
714 | return a; |
715 | } |
716 | |
717 | inline LayoutUnit& operator-=(LayoutUnit& a, int b) |
718 | { |
719 | a = a - b; |
720 | return a; |
721 | } |
722 | |
723 | inline LayoutUnit& operator-=(LayoutUnit& a, const LayoutUnit& b) |
724 | { |
725 | a.setRawValue(saturatedSubtraction(a.rawValue(), b.rawValue())); |
726 | return a; |
727 | } |
728 | |
729 | inline LayoutUnit& operator-=(LayoutUnit& a, float b) |
730 | { |
731 | a = a - b; |
732 | return a; |
733 | } |
734 | |
735 | inline float& operator-=(float& a, const LayoutUnit& b) |
736 | { |
737 | a = a - b; |
738 | return a; |
739 | } |
740 | |
741 | inline LayoutUnit& operator*=(LayoutUnit& a, const LayoutUnit& b) |
742 | { |
743 | a = a * b; |
744 | return a; |
745 | } |
746 | // operator*=(LayoutUnit& a, int b) is supported by the operator above plus LayoutUnit(int). |
747 | |
748 | inline LayoutUnit& operator*=(LayoutUnit& a, float b) |
749 | { |
750 | a = a * b; |
751 | return a; |
752 | } |
753 | |
754 | inline float& operator*=(float& a, const LayoutUnit& b) |
755 | { |
756 | a = a * b; |
757 | return a; |
758 | } |
759 | |
760 | inline LayoutUnit& operator/=(LayoutUnit& a, const LayoutUnit& b) |
761 | { |
762 | a = a / b; |
763 | return a; |
764 | } |
765 | // operator/=(LayoutUnit& a, int b) is supported by the operator above plus LayoutUnit(int). |
766 | |
767 | inline LayoutUnit& operator/=(LayoutUnit& a, float b) |
768 | { |
769 | a = a / b; |
770 | return a; |
771 | } |
772 | |
773 | inline float& operator/=(float& a, const LayoutUnit& b) |
774 | { |
775 | a = a / b; |
776 | return a; |
777 | } |
778 | |
779 | WEBCORE_EXPORT WTF::TextStream& operator<<(WTF::TextStream&, const LayoutUnit&); |
780 | |
781 | inline int roundToInt(LayoutUnit value) |
782 | { |
783 | return value.round(); |
784 | } |
785 | |
786 | inline int floorToInt(LayoutUnit value) |
787 | { |
788 | return value.floor(); |
789 | } |
790 | |
791 | inline float roundToDevicePixel(LayoutUnit value, float pixelSnappingFactor, bool needsDirectionalRounding = false) |
792 | { |
793 | double valueToRound = value.toDouble(); |
794 | if (needsDirectionalRounding) |
795 | valueToRound -= LayoutUnit::epsilon() / (2 * kFixedPointDenominator); |
796 | |
797 | if (valueToRound >= 0) |
798 | return round(valueToRound * pixelSnappingFactor) / pixelSnappingFactor; |
799 | |
800 | // This adjusts directional rounding on negative halfway values. It produces the same direction for both negative and positive values. |
801 | // Instead of rounding negative halfway cases away from zero, we translate them to positive values before rounding. |
802 | // It helps snapping relative negative coordinates to the same position as if they were positive absolute coordinates. |
803 | unsigned translateOrigin = -value.rawValue(); |
804 | return (round((valueToRound + translateOrigin) * pixelSnappingFactor) / pixelSnappingFactor) - translateOrigin; |
805 | } |
806 | |
807 | inline float floorToDevicePixel(LayoutUnit value, float pixelSnappingFactor) |
808 | { |
809 | return floorf((value.rawValue() * pixelSnappingFactor) / kFixedPointDenominator) / pixelSnappingFactor; |
810 | } |
811 | |
812 | inline float ceilToDevicePixel(LayoutUnit value, float pixelSnappingFactor) |
813 | { |
814 | return ceilf((value.rawValue() * pixelSnappingFactor) / kFixedPointDenominator) / pixelSnappingFactor; |
815 | } |
816 | |
817 | inline int roundToInt(float value) { return roundToInt(LayoutUnit(value)); } |
818 | inline float roundToDevicePixel(float value, float pixelSnappingFactor, bool needsDirectionalRounding = false) { return roundToDevicePixel(LayoutUnit(value), pixelSnappingFactor, needsDirectionalRounding); } |
819 | inline float floorToDevicePixel(float value, float pixelSnappingFactor) { return floorToDevicePixel(LayoutUnit(value), pixelSnappingFactor); } |
820 | inline float ceilToDevicePixel(float value, float pixelSnappingFactor) { return ceilToDevicePixel(LayoutUnit(value), pixelSnappingFactor); } |
821 | |
822 | inline LayoutUnit absoluteValue(const LayoutUnit& value) |
823 | { |
824 | return value.abs(); |
825 | } |
826 | |
827 | inline bool isIntegerValue(const LayoutUnit value) |
828 | { |
829 | return value.toInt() == value; |
830 | } |
831 | |
832 | inline namespace StringLiterals { |
833 | |
834 | inline LayoutUnit operator"" _lu(unsigned long long value) |
835 | { |
836 | return LayoutUnit(value); |
837 | } |
838 | |
839 | } |
840 | |
841 | } // namespace WebCore |
842 | |
843 | #ifndef NDEBUG |
844 | |
845 | namespace WTF { |
846 | |
847 | // This structure is used by PODIntervalTree for debugging. |
848 | template<> struct ValueToString<WebCore::LayoutUnit> { |
849 | static String string(WebCore::LayoutUnit value) { return String::numberToStringFixedPrecision(value.toFloat()); } |
850 | }; |
851 | |
852 | } // namespace WTF |
853 | |
854 | #endif |
855 | |