Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/gfx/2d/Coord.h
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3
/* This Source Code Form is subject to the terms of the Mozilla Public
4
 * License, v. 2.0. If a copy of the MPL was not distributed with this
5
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
#ifndef MOZILLA_GFX_COORD_H_
8
#define MOZILLA_GFX_COORD_H_
9
10
#include "mozilla/Attributes.h"
11
#include "mozilla/TypeTraits.h" // For IsSame
12
#include "Types.h"
13
#include "BaseCoord.h"
14
15
#include <cmath>
16
17
namespace mozilla {
18
19
template <typename> struct IsPixel;
20
21
namespace gfx {
22
23
template <class units> struct IntCoordTyped;
24
template <class units, class F = Float> struct CoordTyped;
25
26
// CommonType<coord, primitive> is a metafunction that returns the type of the
27
// result of an arithmetic operation on the underlying type of a strongly-typed
28
// coordinate type 'coord', and a primitive type 'primitive'. C++ rules for
29
// arithmetic conversions are designed to avoid losing information - for
30
// example, the result of adding an int and a float is a float - and we want
31
// the same behaviour when mixing our coordinate types with primitive types.
32
// We get C++ to compute the desired result type using 'decltype'.
33
34
template <class coord, class primitive>
35
struct CommonType;
36
37
template <class units, class primitive>
38
struct CommonType<IntCoordTyped<units>, primitive> {
39
    typedef decltype(int32_t() + primitive()) type;
40
};
41
42
template <class units, class F, class primitive>
43
struct CommonType<CoordTyped<units, F>, primitive> {
44
    typedef decltype(F() + primitive()) type;
45
};
46
47
// This is a base class that provides mixed-type operator overloads between
48
// a strongly-typed Coord and a primitive value. It is needed to avoid
49
// ambiguities at mixed-type call sites, because Coord classes are implicitly
50
// convertible to their underlying value type. As we transition more of our code
51
// to strongly-typed classes, we may be able to remove some or all of these
52
// overloads.
53
54
template <bool B, class coord, class primitive>
55
struct CoordOperatorsHelper {
56
  // Using SFINAE (Substitution Failure Is Not An Error) to suppress redundant
57
  // operators
58
};
59
60
template <class coord, class primitive>
61
struct CoordOperatorsHelper<true, coord, primitive> {
62
  friend bool operator==(coord aA, primitive aB) {
63
    return aA.value == aB;
64
  }
65
  friend bool operator==(primitive aA, coord aB) {
66
    return aA == aB.value;
67
  }
68
  friend bool operator!=(coord aA, primitive aB) {
69
    return aA.value != aB;
70
  }
71
  friend bool operator!=(primitive aA, coord aB) {
72
    return aA != aB.value;
73
  }
74
75
  typedef typename CommonType<coord, primitive>::type result_type;
76
77
  friend result_type operator+(coord aA, primitive aB) {
78
    return aA.value + aB;
79
  }
80
  friend result_type operator+(primitive aA, coord aB) {
81
    return aA + aB.value;
82
  }
83
  friend result_type operator-(coord aA, primitive aB) {
84
    return aA.value - aB;
85
  }
86
  friend result_type operator-(primitive aA, coord aB) {
87
    return aA - aB.value;
88
  }
89
  friend result_type operator*(coord aCoord, primitive aScale) {
90
    return aCoord.value * aScale;
91
  }
92
  friend result_type operator*(primitive aScale, coord aCoord) {
93
    return aScale * aCoord.value;
94
  }
95
  friend result_type operator/(coord aCoord, primitive aScale) {
96
    return aCoord.value / aScale;
97
  }
98
  // 'scale / coord' is intentionally omitted because it doesn't make sense.
99
};
100
101
// Note: 'IntCoordTyped<units>' and 'CoordTyped<units>' do not derive from
102
// 'units' to work around https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61959.
103
104
template<class units>
105
struct IntCoordTyped :
106
  public BaseCoord< int32_t, IntCoordTyped<units> >,
107
  public CoordOperatorsHelper< true, IntCoordTyped<units>, float >,
108
  public CoordOperatorsHelper< true, IntCoordTyped<units>, double > {
109
  static_assert(IsPixel<units>::value,
110
                "'units' must be a coordinate system tag");
111
112
  typedef BaseCoord< int32_t, IntCoordTyped<units> > Super;
113
114
  constexpr IntCoordTyped() : Super() {}
115
0
  constexpr MOZ_IMPLICIT IntCoordTyped(int32_t aValue) : Super(aValue) {}
116
};
117
118
template<class units, class F>
119
struct CoordTyped :
120
  public BaseCoord< F, CoordTyped<units, F> >,
121
  public CoordOperatorsHelper< !IsSame<F, int32_t>::value, CoordTyped<units, F>, int32_t >,
122
  public CoordOperatorsHelper< !IsSame<F, uint32_t>::value, CoordTyped<units, F>, uint32_t >,
123
  public CoordOperatorsHelper< !IsSame<F, double>::value, CoordTyped<units, F>, double >,
124
  public CoordOperatorsHelper< !IsSame<F, float>::value, CoordTyped<units, F>, float > {
125
  static_assert(IsPixel<units>::value,
126
                "'units' must be a coordinate system tag");
127
128
  typedef BaseCoord< F, CoordTyped<units, F> > Super;
129
130
  constexpr CoordTyped() : Super() {}
131
0
  constexpr MOZ_IMPLICIT CoordTyped(F aValue) : Super(aValue) {}
132
  explicit constexpr CoordTyped(const IntCoordTyped<units>& aCoord) : Super(F(aCoord.value)) {}
133
134
  void Round() {
135
    this->value = floor(this->value + 0.5);
136
  }
137
  void Truncate() {
138
    this->value = int32_t(this->value);
139
  }
140
141
  IntCoordTyped<units> Rounded() const {
142
    return IntCoordTyped<units>(int32_t(floor(this->value + 0.5)));
143
  }
144
  IntCoordTyped<units> Truncated() const {
145
    return IntCoordTyped<units>(int32_t(this->value));
146
  }
147
};
148
149
} // namespace gfx
150
} // namespace mozilla
151
152
#endif /* MOZILLA_GFX_COORD_H_ */