• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *
3  * Copyright 2019, The Android Open Source Project
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 #ifndef TEEUI_LIBTEEUI_UTILS_H_
19 #define TEEUI_LIBTEEUI_UTILS_H_
20 
21 #include <math.h>
22 #include <stddef.h>
23 #include <stdint.h>
24 #include <sys/types.h>
25 
26 #include <algorithm>
27 #include <initializer_list>
28 #include <optional>
29 #include <tuple>
30 #include <type_traits>
31 
32 #include <teeui/error.h>
33 #include <teeui/log.h>
34 
35 namespace teeui {
36 
37 using std::optional;
38 
39 template <typename T, size_t elements> class Array {
40     using array_type = T[elements];
41 
42   public:
Array()43     constexpr Array() : data_{} {}
Array(const T (& data)[elements])44     constexpr Array(const T (&data)[elements]) { std::copy(data, data + elements, data_); }
Array(const std::initializer_list<uint8_t> & li)45     constexpr Array(const std::initializer_list<uint8_t>& li) {
46         size_t i = 0;
47         for (auto& item : li) {
48             data_[i] = item;
49             ++i;
50             if (i == elements) break;
51         }
52         for (; i < elements; ++i) {
53             data_[i] = {};
54         }
55     }
56 
data()57     T* data() { return data_; }
data()58     const T* data() const { return data_; }
size()59     constexpr size_t size() const { return elements; }
60 
begin()61     T* begin() { return data_; }
end()62     T* end() { return data_ + elements; }
begin()63     const T* begin() const { return data_; }
end()64     const T* end() const { return data_ + elements; }
65 
fill(const T & v)66     static constexpr Array fill(const T& v) {
67         Array result;
68         for (size_t i = 0; i < elements; ++i) {
69             result.data_[i] = v;
70         }
71         return result;
72     }
73 
74   private:
75     array_type data_;
76 };
77 
78 template <typename T> auto bytesCast(const T& v) -> const uint8_t (&)[sizeof(T)] {
79     return *reinterpret_cast<const uint8_t(*)[sizeof(T)]>(&v);
80 }
81 template <typename T> auto bytesCast(T& v) -> uint8_t (&)[sizeof(T)] {
82     return *reinterpret_cast<uint8_t(*)[sizeof(T)]>(&v);
83 }
84 
85 class ByteBufferProxy {
86     template <typename T> struct has_data {
fhas_data87         template <typename U> static int f(const U*, const void*) { return 0; }
88         template <typename U> static int* f(const U* u, decltype(u->data())) { return nullptr; }
89         static constexpr bool value = std::is_pointer<decltype(f((T*)nullptr, ""))>::value;
90     };
91 
92   public:
93     template <typename T>
94     ByteBufferProxy(const T& buffer, decltype(buffer.data()) = nullptr)
95         : data_(reinterpret_cast<const uint8_t*>(buffer.data())), size_(buffer.size()) {
96         static_assert(sizeof(decltype(*buffer.data())) == 1, "elements to large");
97     }
98 
99     template <size_t size>
ByteBufferProxy(const char (& buffer)[size])100     ByteBufferProxy(const char (&buffer)[size])
101         : data_(reinterpret_cast<const uint8_t*>(buffer)), size_(size - 1) {
102         static_assert(size > 0, "even an empty string must be 0-terminated");
103     }
104 
105     template <size_t size>
ByteBufferProxy(const uint8_t (& buffer)[size])106     ByteBufferProxy(const uint8_t (&buffer)[size]) : data_(buffer), size_(size) {}
107 
ByteBufferProxy()108     ByteBufferProxy() : data_(nullptr), size_(0) {}
109 
data()110     const uint8_t* data() const { return data_; }
size()111     size_t size() const { return size_; }
112 
begin()113     const uint8_t* begin() const { return data_; }
end()114     const uint8_t* end() const { return data_ + size_; }
115 
116   private:
117     const uint8_t* data_;
118     size_t size_;
119 };
120 
121 constexpr const uint8_t kAuthTokenKeySize = 32;
122 constexpr const uint8_t kHmacKeySize = kAuthTokenKeySize;
123 using AuthTokenKey = Array<uint8_t, kAuthTokenKeySize>;
124 using Hmac = AuthTokenKey;
125 
126 /**
127  * Implementer are expected to provide an implementation with the following prototype:
128  *  static optional<array<uint8_t, 32>> hmac256(const uint8_t key[32],
129  *                                     std::initializer_list<ByteBufferProxy> buffers);
130  */
131 template <typename Impl> class HMac {
132   public:
133     template <typename... Data>
hmac256(const AuthTokenKey & key,const Data &...data)134     static optional<Hmac> hmac256(const AuthTokenKey& key, const Data&... data) {
135         return Impl::hmac256(key, {data...});
136     }
137 };
138 
139 bool operator==(const ByteBufferProxy& lhs, const ByteBufferProxy& rhs);
140 
141 template <typename IntType, uint32_t byteOrder> struct choose_hton;
142 
143 template <typename IntType> struct choose_hton<IntType, __ORDER_LITTLE_ENDIAN__> {
144     inline static IntType hton(const IntType& value) {
145         IntType result = {};
146         const unsigned char* inbytes = reinterpret_cast<const unsigned char*>(&value);
147         unsigned char* outbytes = reinterpret_cast<unsigned char*>(&result);
148         for (int i = sizeof(IntType) - 1; i >= 0; --i) {
149             *(outbytes++) = inbytes[i];
150         }
151         return result;
152     }
153 };
154 
155 template <typename IntType> struct choose_hton<IntType, __ORDER_BIG_ENDIAN__> {
156     inline static IntType hton(const IntType& value) { return value; }
157 };
158 
159 template <typename IntType> inline IntType hton(const IntType& value) {
160     return choose_hton<IntType, __BYTE_ORDER__>::hton(value);
161 }
162 
163 template <typename IntType> inline IntType ntoh(const IntType& value) {
164     // same operation as hton
165     return choose_hton<IntType, __BYTE_ORDER__>::hton(value);
166 }
167 
168 enum class Unit : uint8_t {
169     PX,
170     DP,
171     MM,
172 };
173 
174 template <Unit unit> struct UnitT { constexpr static const Unit value = unit; };
175 
176 using px = UnitT<Unit::PX>;
177 using dp = UnitT<Unit::DP>;
178 using mm = UnitT<Unit::MM>;
179 
180 template <typename Unit> static constexpr const char* str = "N/A";
181 
182 template <> static constexpr const char* str<px> = "px";
183 template <> static constexpr const char* str<dp> = "dp";
184 template <> static constexpr const char* str<mm> = "mm";
185 
186 using DefaultNumericType = float;
187 
188 namespace bits {
189 
190 inline long double abs(long double v) {
191     return ::fabsl(v);
192 }
193 inline double abs(double v) {
194     return ::fabs(v);
195 }
196 
197 inline long double ceil(long double v) {
198     return ::ceill(v);
199 }
200 
201 inline double ceil(double v) {
202     return ::ceil(v);
203 }
204 
205 inline long double floor(long double v) {
206     return ::floorl(v);
207 }
208 
209 inline double floor(double v) {
210     return ::floor(v);
211 }
212 
213 inline long double sqrt(long double v) {
214     return ::sqrtl(v);
215 }
216 
217 inline double sqrt(double v) {
218     return ::sqrt(v);
219 }
220 
221 inline float round(float v) {
222     return ::roundf(v);
223 }
224 
225 inline long double round(long double v) {
226     return ::roundl(v);
227 }
228 
229 inline double round(double v) {
230     return ::round(v);
231 }
232 
233 }  // namespace bits
234 
235 template <typename Unit, typename Numeric = DefaultNumericType> class Coordinate;
236 
237 template <typename Numeric> struct Add {
238     constexpr static Coordinate<px, Numeric> eval(const Coordinate<px, Numeric>& v1,
239                                                   const Coordinate<px, Numeric>& v2) {
240         return v1 + v2;
241     }
242 };
243 template <typename Numeric> struct Sub {
244     constexpr static Coordinate<px, Numeric> eval(const Coordinate<px, Numeric>& v1,
245                                                   const Coordinate<px, Numeric>& v2) {
246         return v1 - v2;
247     }
248 };
249 template <typename Numeric> struct Mul {
250     constexpr static Coordinate<px, Numeric> eval(const Coordinate<px, Numeric>& v1,
251                                                   const Coordinate<px, Numeric>& v2) {
252         return v1 * v2;
253     }
254 };
255 template <typename Numeric> struct Div {
256     constexpr static Coordinate<px, Numeric> eval(const Coordinate<px, Numeric>& v1,
257                                                   const Coordinate<px, Numeric>& v2) {
258         return v1 / v2;
259     }
260 };
261 
262 template <typename T1, typename T2, typename Numeric, template <typename> class Op> struct BinOp;
263 
264 template <typename T1, typename T2, typename Numeric> using add = BinOp<T1, T2, Numeric, Add>;
265 template <typename T1, typename T2, typename Numeric> using sub = BinOp<T1, T2, Numeric, Sub>;
266 template <typename T1, typename T2, typename Numeric> using mul = BinOp<T1, T2, Numeric, Mul>;
267 template <typename T1, typename T2, typename Numeric> using div = BinOp<T1, T2, Numeric, Div>;
268 
269 template <typename T1, typename T2, typename Numeric, template <typename> class Op> struct BinOp {
270   private:
271     T1 v1_;
272     T2 v2_;
273 
274   public:
275     constexpr BinOp(const T1& v1, const T2& v2) : v1_(v1), v2_(v2) {}
276     BinOp(const BinOp&) = default;
277     BinOp(BinOp&&) = default;
278 
279     template <typename Context> Coordinate<px, Numeric> eval(const Context& ctx) const {
280         Coordinate<px, Numeric> v1 = ctx = v1_;
281         Coordinate<px, Numeric> v2 = ctx = v2_;
282         return Op<Numeric>::eval(v1, v2);
283     }
284     template <typename T> constexpr add<BinOp, T, Numeric> operator+(const T& v) const {
285         return {*this, v};
286     }
287     template <typename T> constexpr sub<BinOp, T, Numeric> operator-(const T& v) const {
288         return {*this, v};
289     }
290     template <typename T> constexpr mul<BinOp, T, Numeric> operator*(const T& v) const {
291         return {*this, v};
292     }
293     template <typename T> constexpr div<BinOp, T, Numeric> operator/(const T& v) const {
294         return {*this, v};
295     }
296 };
297 
298 template <typename Name, typename ParamType> struct MetaParam {};
299 
300 template <typename Name, typename Unit, typename Numeric>
301 struct MetaParam<Name, Coordinate<Unit, Numeric>> {
302     template <typename T> constexpr add<MetaParam, T, Numeric> operator+(const T& v) const {
303         return {*this, v};
304     }
305     template <typename T> constexpr sub<MetaParam, T, Numeric> operator-(const T& v) const {
306         return {*this, v};
307     }
308     template <typename T> constexpr mul<MetaParam, T, Numeric> operator*(const T& v) const {
309         return {*this, v};
310     }
311     template <typename T> constexpr div<MetaParam, T, Numeric> operator/(const T& v) const {
312         return {*this, v};
313     }
314 };
315 
316 template <typename Name, typename ParamType> class Param {
317   private:
318     ParamType param_;
319 
320   public:
321     Param() : param_{} {}
322     Param(const Param&) = default;
323     Param(Param&&) = default;
324     Param& operator=(const Param&) = default;
325     Param& operator=(Param&&) = default;
326     inline const ParamType& operator*() const { return param_; }
327     inline ParamType& operator*() { return param_; }
328     inline const ParamType* operator->() const { return &param_; }
329     inline ParamType* operator->() { return &param_; }
330 };
331 
332 template <typename Unit, typename Numeric> class Coordinate {
333     Numeric value_;
334 
335   public:
336     using unit_t = Unit;
337     constexpr Coordinate() : value_{} {}
338     constexpr Coordinate(Numeric value) : value_(value) {}
339     Coordinate(const Coordinate&) = default;
340     Coordinate(Coordinate&&) = default;
341     template <typename N> Coordinate(const Coordinate<Unit, N>& other) {
342         if constexpr (std::is_floating_point<N>::value && std::is_integral<Numeric>::value) {
343             value_ = bits::round(other.count());
344         } else {
345             value_ = other.count();
346         }
347     }
348     Coordinate& operator=(const Coordinate& rhs) = default;
349     Coordinate& operator=(Coordinate&& rhs) = default;
350 
351     constexpr Coordinate operator-(const Coordinate& v) const { return value_ - v.value_; }
352     constexpr Coordinate operator+(const Coordinate& v) const { return value_ + v.value_; }
353     constexpr Coordinate& operator-=(const Coordinate& v) {
354         value_ -= v.value_;
355         return *this;
356     }
357     constexpr Coordinate& operator+=(const Coordinate& v) {
358         value_ += v.value_;
359         return *this;
360     }
361     constexpr Coordinate operator*(const Coordinate& v) const { return value_ * v.value_; }
362     constexpr Coordinate& operator*=(const Coordinate& v) {
363         value_ *= v.value_;
364         return *this;
365     }
366     constexpr Coordinate operator/(const Coordinate& v) const { return value_ / v.value_; }
367     constexpr Coordinate& operator/=(const Coordinate& v) {
368         value_ /= v.value_;
369         return *this;
370     }
371     constexpr Coordinate operator-() const { return -value_; }
372 
373     Coordinate abs() const { return bits::abs(value_); }
374     Coordinate ceil() const { return bits::ceil(value_); }
375     Coordinate floor() const { return bits::floor(value_); }
376     Coordinate sqrt() const { return bits::sqrt(value_); }
377 
378     constexpr bool operator==(const Coordinate& v) const { return value_ == v.value_; }
379     constexpr bool operator!=(const Coordinate& v) const { return !(*this == v); }
380     constexpr bool operator<(const Coordinate& v) const { return value_ < v.value_; }
381     constexpr bool operator>(const Coordinate& v) const { return v < *this; }
382     constexpr bool operator<=(const Coordinate& v) const { return !(v < *this); }
383     constexpr bool operator>=(const Coordinate& v) const { return !(*this < v); }
384 
385     template <typename T> constexpr add<Coordinate, T, Numeric> operator+(const T& v) const {
386         return {*this, v};
387     }
388     template <typename T> constexpr sub<Coordinate, T, Numeric> operator-(const T& v) const {
389         return {*this, v};
390     }
391     template <typename T> constexpr mul<Coordinate, T, Numeric> operator*(const T& v) const {
392         return {*this, v};
393     }
394     template <typename T> constexpr div<Coordinate, T, Numeric> operator/(const T& v) const {
395         return {*this, v};
396     }
397 
398     Numeric count() const { return value_; }
399 };
400 
401 template <typename... T> struct MetaList {};
402 
403 template <typename MetaParam> struct metaParam2Param;
404 
405 template <typename ParamName, typename ParamType>
406 struct metaParam2Param<MetaParam<ParamName, ParamType>> {
407     using type = Param<ParamName, ParamType>;
408 };
409 
410 template <typename MetaParam> struct metaParam2ParamType;
411 
412 template <typename ParamName, typename ParamType>
413 struct metaParam2ParamType<MetaParam<ParamName, ParamType>> {
414     using type = ParamType;
415 };
416 
417 template <typename T> struct isCoordinateType { constexpr static const bool value = false; };
418 
419 template <typename Unit, typename Numeric> struct isCoordinateType<Coordinate<Unit, Numeric>> {
420     constexpr static const bool value = true;
421 };
422 
423 template <typename MetaParam> struct isCoordinateParam;
424 
425 template <typename ParamName, typename ParamType>
426 struct isCoordinateParam<MetaParam<ParamName, ParamType>> {
427     constexpr static const bool value = isCoordinateType<ParamType>::value;
428 };
429 
430 template <typename T> struct isMetaParam { constexpr static const bool value = false; };
431 
432 template <typename ParamName, typename ParamType>
433 struct isMetaParam<MetaParam<ParamName, ParamType>> {
434     constexpr static const bool value = true;
435 };
436 
437 template <typename Param, typename Numeric = DefaultNumericType> class context;
438 
439 template <typename... ParamsNames, typename... ParamTypes, typename Numeric>
440 class context<MetaList<MetaParam<ParamsNames, ParamTypes>...>, Numeric> {
441     Numeric mm2px_;
442     Numeric dp2px_;
443     std::tuple<Param<ParamsNames, ParamTypes>...> params_;
444 
445     class Proxy {
446         Numeric valuepx_;
447         Numeric mm2px_, dp2px_;
448 
449       public:
450         Proxy(Numeric valuepx, Numeric mm2px, Numeric dp2px)
451             : valuepx_(valuepx), mm2px_(mm2px), dp2px_(dp2px) {}
452         Proxy(const Proxy&) = default;
453         Proxy(Proxy&&) = default;
454 
455         operator Coordinate<px, Numeric>() const { return valuepx_; }
456         operator Coordinate<mm, Numeric>() const { return valuepx_ / mm2px_; }
457         operator Coordinate<dp, Numeric>() const { return valuepx_ / dp2px_; }
458     };
459 
460   public:
461     explicit context(Numeric mm2px) {
462         mm2px_ = mm2px;
463         dp2px_ = (mm2px * 25.4) / 160.0; /* 1dp = 1/160th of an inch */
464     }
465 
466     context(Numeric mm2px, Numeric dp2px) : mm2px_(mm2px), dp2px_(dp2px) {}
467 
468     context(const context&) = default;
469     context(context&&) = default;
470     context& operator=(const context&) = default;
471     context& operator=(context&&) = default;
472 
473     template <typename MetaParam> auto& getParam() {
474         return std::get<typename metaParam2Param<MetaParam>::type>(params_);
475     }
476     template <typename MetaParam> const auto& getParam() const {
477         return std::get<typename metaParam2Param<MetaParam>::type>(params_);
478     }
479 
480     template <typename MetaParam, typename = std::enable_if_t<isCoordinateParam<MetaParam>::value>>
481     void setParam(const Coordinate<px, Numeric>& v) {
482         *getParam<MetaParam>() = v;
483     }
484 
485     template <typename MetaParam, typename Unit, typename N,
486               typename = std::enable_if_t<isCoordinateParam<MetaParam>::value>>
487     void setParam(const Coordinate<Unit, N>& v) {
488         *getParam<MetaParam>() = *this = v;
489     }
490 
491     template <typename MetaParam>
492     void setParam(std::enable_if_t<!isCoordinateParam<MetaParam>::value,
493                                    const typename metaParam2ParamType<MetaParam>::type>& v) {
494         *getParam<MetaParam>() = v;
495     }
496 
497     Proxy operator=(const Coordinate<px, Numeric>& rhs) const {
498         return {rhs.count(), mm2px_, dp2px_};
499     }
500     Proxy operator=(const Coordinate<mm, Numeric>& rhs) const {
501         return {rhs.count() * mm2px_, mm2px_, dp2px_};
502     }
503     Proxy operator=(const Coordinate<dp, Numeric>& rhs) const {
504         return {rhs.count() * dp2px_, mm2px_, dp2px_};
505     }
506     template <typename T1, typename T2, template <typename> class Op>
507     Proxy operator=(const BinOp<T1, T2, Numeric, Op>& rhs) const {
508         return {rhs.eval(*this).count(), mm2px_, dp2px_};
509     }
510     template <typename ParamName, typename ParamType>
511     std::enable_if_t<isCoordinateParam<MetaParam<ParamName, ParamType>>::value, Proxy>
512     operator=(const MetaParam<ParamName, ParamType>&) const {
513         return {getParam<MetaParam<ParamName, ParamType>>()->count(), mm2px_, dp2px_};
514     }
515     template <typename ParamName, typename ParamType>
516     std::enable_if_t<!isCoordinateParam<MetaParam<ParamName, ParamType>>::value, const ParamType&>
517     operator=(const MetaParam<ParamName, ParamType>&) const {
518         return *getParam<MetaParam<ParamName, ParamType>>();
519     }
520     template <typename T,
521               typename = std::enable_if_t<!(isMetaParam<T>::value || isCoordinateType<T>::value)>>
522     inline T&& operator=(T&& v) const {
523         return std::forward<T>(v);
524     }
525 };
526 
527 using dps = Coordinate<dp>;
528 using mms = Coordinate<mm>;
529 using pxs = Coordinate<px>;
530 
531 constexpr dps operator""_dp(long double dp) {
532     return dps(dp);
533 }
534 constexpr mms operator""_mm(long double mm) {
535     return mms(mm);
536 }
537 constexpr pxs operator""_px(long double px) {
538     return pxs(px);
539 }
540 constexpr dps operator""_dp(unsigned long long dp) {
541     return dps(dp);
542 }
543 constexpr mms operator""_mm(unsigned long long mm) {
544     return mms(mm);
545 }
546 constexpr pxs operator""_px(unsigned long long px) {
547     return pxs(px);
548 }
549 
550 template <typename Coord> class Vec2d {
551     Coord x_, y_;
552 
553   public:
554     constexpr Vec2d() : x_{}, y_{} {}
555     constexpr Vec2d(Coord x, Coord y) : x_(x), y_(y) {}
556     Vec2d(const Vec2d&) = default;
557     Vec2d(Vec2d&&) = default;
558     template <typename N>
559     Vec2d(const Vec2d<Coordinate<typename Coord::unit_t, N>>& other)
560         : x_(other.x()), y_(other.y()) {}
561 
562     Vec2d& operator=(const Vec2d& rhs) = default;
563     Vec2d& operator=(Vec2d&& rhs) = default;
564 
565     Vec2d operator-(const Vec2d& rhs) const { return Vec2d(*this) -= rhs; }
566     Vec2d operator+(const Vec2d& rhs) const { return Vec2d(*this) += rhs; }
567     Vec2d& operator-=(const Vec2d& rhs) {
568         x_ -= rhs.x_;
569         y_ -= rhs.y_;
570         return *this;
571     }
572     Vec2d& operator+=(const Vec2d& rhs) {
573         x_ += rhs.x_;
574         y_ += rhs.y_;
575         return *this;
576     }
577     Coord operator*(const Vec2d& rhs) const { return (x_ * rhs.x_ + y_ * rhs.y_).count(); }
578     Vec2d operator*(const Coord& f) const { return Vec2d(*this) *= f; }
579     Vec2d& operator*=(const Coord& f) {
580         x_ *= f;
581         y_ *= f;
582         return *this;
583     }
584     Vec2d operator/(const Coord& f) { return Vec2d(*this) /= f; }
585     Vec2d& operator/=(const Coord& f) {
586         x_ /= f;
587         y_ /= f;
588         return *this;
589     }
590     bool operator==(const Vec2d& rhs) const { return x_ == rhs.x() && y_ == rhs.y(); }
591     Coord length() const {
592         Coord factor = *this * *this;
593         return bits::sqrt(factor.count());
594     }
595     Vec2d unit() const { return Vec2d(*this) /= length(); }
596     Coord x() const { return x_; }
597     Coord y() const { return y_; }
598 };
599 
600 #ifdef TEEUI_DO_LOG_DEBUG
601 template <typename Unit, typename Numeric>
602 std::ostream& operator<<(std::ostream& out, const Coordinate<Unit, Numeric>& p) {
603     out << std::setprecision(10) << p.count() << str<Unit>;
604     return out;
605 }
606 
607 template <typename Coord> std::ostream& operator<<(std::ostream& out, const Vec2d<Coord>& p) {
608     out << "Vec2d(" << p.x() << ", " << p.y() << ")";
609     return out;
610 }
611 #endif
612 
613 using Color = uint32_t;
614 
615 template <typename Coord> using Point = Vec2d<Coord>;
616 
617 Color drawLinePoint(Point<pxs> a, Point<pxs> b, Point<pxs> px_origin, Color c,
618                     pxs width = pxs(1.0));
619 
620 Color drawCirclePoint(Point<pxs> center, pxs r, Point<pxs> px_origin, Color c);
621 
622 using PxPoint = Point<pxs>;
623 using PxVec = Vec2d<pxs>;
624 
625 /*
626  * Computes the intersection of the lines given by ax + b and cy + d.
627  * The result may be empty if there is no solution.
628  */
629 optional<PxPoint> intersect(const PxVec& a, const PxPoint& b, const PxVec& c, const PxPoint& d);
630 
631 namespace bits {
632 
633 static constexpr const ssize_t kIntersectEmpty = -1;
634 /**
635  * Returned by the intersect if the object is in the positive half plane of the given line.
636  */
637 static constexpr const ssize_t kIntersectAllPositive = -2;
638 
639 ssize_t intersect(const PxPoint* oBegin, const PxPoint* oEnd, const PxPoint& lineA,
640                   const PxPoint& lineB, PxPoint* nBegin, PxPoint* nEnd);
641 
642 pxs area(const PxPoint* begin, const PxPoint* end);
643 
644 }  // namespace bits
645 
646 /**
647  * A ConvexObject is given by a list of 2D vertexes. Each vertex must lie on the positive half-plane
648  * of the line denoted by its two predecessors. A point is considered inside of the convex object
649  * if it is on the positive half-plane of all lines given by any two subsequent vertexes.
650  *
651  * ConvexObjects have fixed size given by the capacity template argument. The geometric object
652  * that they describe may have any number of vertexes between 3 and capacity.
653  */
654 template <size_t capacity> class ConvexObject {
655     template <size_t other_cap> friend class ConvexObject;
656 
657   protected:
658     PxPoint points_[capacity];
659     size_t fill_;
660 
661   public:
662     ConvexObject() : fill_(0) {}
663     explicit constexpr ConvexObject(std::initializer_list<PxPoint> l) : fill_(0) {
664         if (l.size() > capacity) return;
665         for (const auto& p : l) {
666             points_[fill_++] = p;
667         }
668     }
669     ConvexObject(const ConvexObject& other) = default;
670     ConvexObject(ConvexObject&& other) = default;
671     ConvexObject& operator=(const ConvexObject& other) = default;
672     ConvexObject& operator=(ConvexObject&& other) = default;
673 
674     constexpr size_t size() const { return fill_; }
675 
676     constexpr const PxPoint* begin() const { return &points_[0]; }
677     constexpr const PxPoint* end() const { return &points_[fill_]; }
678 
679     template <size_t result_cap>
680     optional<ConvexObject<result_cap>> intersect(const PxPoint& A, const PxPoint& B) const {
681         static_assert(result_cap >= capacity,
682                       "resulting capacity must be at least as large as the original");
683         ConvexObject<result_cap> result;
684         ssize_t vCount =
685             bits::intersect(begin(), end(), A, B, &result.points_[0], &result.points_[result_cap]);
686         if (vCount == bits::kIntersectEmpty) return {};
687         // -2 is returned if the object is in the positive half plane of the line (may be tangent)
688         if (vCount == bits::kIntersectAllPositive) {
689             std::copy(begin(), end(), &result.points_[0]);
690             vCount = fill_;
691         }
692         result.fill_ = vCount;
693         return result;
694     }
695 
696     template <size_t result_cap, size_t arg_cap>
697     optional<ConvexObject<result_cap>> intersect(const ConvexObject<arg_cap>& other) const {
698         return intersect<result_cap>(other.begin(), other.end());
699     }
700 
701     template <size_t result_cap>
702     optional<ConvexObject<result_cap>> intersect(const PxPoint* begin, const PxPoint* end) const {
703         if (end - begin < 3) return {};
704         auto b = begin;
705         auto a = end - 1;
706         auto result = intersect<result_cap>(*a, *b);
707         a = b++;
708         while (result && b != end) {
709             result = result->template intersect<result_cap>(*a, *b);
710             a = b++;
711         }
712         return result;
713     }
714 
715     pxs area() const { return bits::area(begin(), end()); }
716 
717     void push_back(const PxPoint& p) {
718         if (fill_ < capacity) {
719             points_[fill_++] = p;
720         }
721     }
722 };
723 
724 #ifdef TEEUI_DO_LOG_DEBUG
725 template <size_t capacity>
726 std::ostream& operator<<(std::ostream& out, const ConvexObject<capacity>& o) {
727     out << "ConvexObject(";
728     bool first = true;
729     for (const auto& p : o) {
730         if (first)
731             first = false;
732         else
733             out << ", ";
734         out << p;
735     }
736     out << ")";
737     return out;
738 }
739 #endif
740 
741 template <typename Coord> class Box {
742     Point<Coord> topLeft_;
743     Vec2d<Coord> extend_;
744 
745   public:
746     Box() {}
747     template <typename N>
748     Box(const Box<Coordinate<typename Coord::unit_t, N>>& other)
749         : topLeft_(other.topLeft()), extend_(other.extend()) {}
750     Box(const Coord& x, const Coord& y, const Coord& w, const Coord& h)
751         : topLeft_(x, y), extend_(w, h) {}
752     Box(const Point<Coord>& topLeft, const Vec2d<Coord>& extend)
753         : topLeft_(topLeft), extend_(extend) {}
754     bool contains(Point<Coord> p) const {
755         p -= topLeft_;
756         return p.y().count() >= 0 && p.y().count() <= extend_.y().count() && p.x().count() >= 0 &&
757                p.x().count() <= extend_.x().count();
758     }
759     bool contains(const Box& other) const {
760         auto br = bottomRight();
761         auto obr = other.bottomRight();
762         return topLeft_.x() <= other.topLeft_.x() && br.x() >= obr.x() &&
763                topLeft_.y() <= other.topLeft_.y() && br.y() >= obr.y();
764     }
765     bool overlaps(const Box& other) const {
766         auto br = bottomRight();
767         auto obr = other.bottomRight();
768         return topLeft_.x() < obr.x() && other.topLeft_.x() < br.x() && topLeft_.y() < obr.y() &&
769                other.topLeft_.y() < obr.y();
770     }
771 
772     /**
773      * fitsInside only compares the extend of the boxes. It returns true if this box would fit
774      * inside the other box regardless of their absolute positions.
775      */
776     bool fitsInside(const Box& other) const { return w() <= other.w() && h() <= other.w(); }
777     Point<Coord> bottomRight() const { return topLeft_ + extend_; }
778     Point<Coord> topLeft() const { return topLeft_; }
779     Vec2d<Coord> extend() const { return extend_; }
780     Coord x() const { return topLeft_.x(); }
781     Coord y() const { return topLeft_.y(); }
782     Coord w() const { return extend_.x(); }
783     Coord h() const { return extend_.y(); }
784 
785     Box merge(const Box& other) const {
786         Coord x = std::min(topLeft_.x(), other.topLeft_.x());
787         Coord y = std::min(topLeft_.y(), other.topLeft_.y());
788         auto br = bottomRight();
789         auto obr = other.bottomRight();
790         Coord w = std::max(br.x(), obr.x()) - x;
791         Coord h = std::max(br.y(), obr.y()) - y;
792         return {x, y, w, h};
793     }
794 
795     /**
796      * Returns a box that contains the this box and the given point.
797      */
798     Box merge(const Point<Coord>& p) const {
799         auto br = bottomRight();
800         TEEUI_LOG << "A tl: " << topLeft_ << " br: " << br << " new: " << p << ENDL;
801         Coord x = std::min(topLeft_.x(), p.x());
802         Coord y = std::min(topLeft_.y(), p.y());
803         Coord w = std::max(br.x(), p.x()) - x;
804         Coord h = std::max(br.y(), p.y()) - y;
805         TEEUI_LOG << "B x: " << x << " y: " << y << " w: " << w << " h: " << h << ENDL;
806         return {x, y, w, h};
807     }
808 
809     /**
810      * Returns a box that contains this box and all of the given points.
811      */
812     Box merge(const Point<Coord>* begin, const Point<Coord>* end) const {
813         auto tl = topLeft();
814         auto br = bottomRight();
815         while (begin != end) {
816             TEEUI_LOG << "A tl: " << tl << " br: " << br << " new: " << *begin << ENDL;
817             tl = {std::min(tl.x(), begin->x()), std::min(tl.y(), begin->y())};
818             br = {std::max(br.x(), begin->x()), std::max(br.y(), begin->y())};
819             TEEUI_LOG << "B tl: " << tl << " br: " << br << " new: " << *begin << ENDL;
820             ++begin;
821         }
822         return {tl, br - tl};
823     }
824 
825     /**
826      * Creates a box that contains all of the given points.
827      */
828     static Box boundingBox(const Point<Coord>* begin, const Point<Coord>* end) {
829         if (begin == end) return {};
830         Box result(*begin, {0, 0});
831         result.merge(begin + 1, end);
832         return result;
833     }
834 
835     /*
836      * Translates the Box by the given offset. And returns a reference to itself
837      */
838     Box& translateSelf(const Point<Coord>& offset) {
839         topLeft_ += offset;
840         return *this;
841     }
842     /*
843      * Returns copy of this box translated by offset.
844      */
845     Box translate(const Point<Coord>& offset) const& {
846         Box result = *this;
847         result.topLeft_ += offset;
848         return result;
849     }
850     /*
851      * When called on a temporary just reuse this box.
852      */
853     Box translate(const Point<Coord>& offset) && {
854         topLeft_ += offset;
855         return *this;
856     }
857 };
858 
859 #ifdef TEEUI_DO_LOG_DEBUG
860 template <typename Coord> std::ostream& operator<<(std::ostream& out, const Box<Coord>& p) {
861     out << "Box(x: " << p.x().count() << " y: " << p.y().count() << " w: " << p.w().count()
862         << " h: " << p.h().count() << ")";
863     return out;
864 }
865 #endif
866 
867 enum class EventType : uint8_t {
868     KeyDown,
869     KeyUp,
870     KeyMoved,
871 };
872 
873 struct Event {
874     uint32_t x_;
875     uint32_t y_;
876     EventType event_;
877 };
878 
879 template <typename Fn> struct Callback;
880 
881 template <typename Ret, typename... Args> struct Callback<Ret(Args...)> {
882     Ret (*callback_)(Args... args, void* priv_data);
883     void* priv_data_;
884     Ret operator()(Args... args) const { return callback_(args..., priv_data_); }
885 };
886 
887 template <typename Ret, typename... Args>
888 Callback<Ret(Args...)> makeCallback(Ret (*fn)(Args..., void*), void* priv_data) {
889     return {fn, priv_data};
890 }
891 
892 template <typename Fn, typename Ret, typename... Args> struct CallbackHelper {
893     Fn fn_;
894     operator Callback<Ret(Args...)>() {
895         return makeCallback<Ret, Args...>(
896             [](Args... args, void* priv_data) -> Ret {
897                 return reinterpret_cast<CallbackHelper*>(priv_data)->fn_(args...);
898             },
899             this);
900     }
901 };
902 
903 using CallbackEvent = Callback<Error(Event)>;
904 using PixelDrawer = Callback<Error(uint32_t, uint32_t, Color)>;
905 
906 template <typename Fn>
907 using PixelDrawerHelper = CallbackHelper<Fn, Error, uint32_t, uint32_t, Color>;
908 
909 template <typename Fn> PixelDrawerHelper<Fn> makePixelDrawer(Fn fn) {
910     return PixelDrawerHelper<Fn>{fn};
911 }
912 
913 template <typename Derived> struct LayoutElement {
914     Box<pxs> bounds_;
915     LayoutElement() = default;
916     template <typename Context>
917     LayoutElement(const Context& context)
918         : bounds_{context = Derived::pos_x, context = Derived::pos_y, context = Derived::dim_w,
919                   context = Derived::dim_h} {}
920 
921     Error draw(const PixelDrawer&) { return Error::OK; }
922     Error hit(const Event&) { return Error::OK; }
923 };
924 
925 template <typename... Elements, typename Context>
926 std::tuple<Elements...> instantiateLayout(MetaList<Elements...>, const Context& context) {
927     std::tuple<Elements...> result{Elements(context)...};
928     return result;
929 }
930 
931 template <typename T> struct MetaList2Layout;
932 
933 template <typename... Elements> struct MetaList2Layout<MetaList<Elements...>> {
934     using type = std::tuple<Elements...>;
935 };
936 
937 template <typename T> using layout_t = typename MetaList2Layout<T>::type;
938 
939 template <typename... Coords>
940 constexpr inline std::tuple<Vec2d<Coords>...> makeConvexObject(const Vec2d<Coords>&... points) {
941     return {points...};
942 }
943 
944 template <size_t capacity, typename Tuple, typename Context, size_t... I>
945 constexpr inline ConvexObject<capacity>
946 initConvexObject(const Context& context, const Tuple& outline, std::index_sequence<I...>) {
947     return ConvexObject<capacity>(
948         {PxVec(context = std::get<I>(outline).x(), context = std::get<I>(outline).y())...});
949 }
950 
951 template <size_t capacity, typename... Points, typename Context>
952 constexpr inline ConvexObject<capacity> initConvexObject(const Context& context,
953                                                          const std::tuple<Points...>& outline) {
954     return initConvexObject<capacity>(context, outline, std::index_sequence_for<Points...>{});
955 }
956 
957 template <size_t capacity, typename Tuple, typename Context, size_t... I, size_t size>
958 constexpr inline void initConvexObjectArray(const Context& context,
959                                             ConvexObject<capacity> (&out)[size], const Tuple& t,
960                                             std::index_sequence<I...>) {
961     static_assert(sizeof...(I) <= size,
962                   "Array to initialize must be big enough to hold all tuple elements");
963     [](auto...) {}((out[I] = initConvexObject<capacity>(context, std::get<I>(t)))...);
964 }
965 
966 template <size_t capacity, typename... COs, typename Context, size_t size>
967 constexpr inline void initConvexObjectArray(const Context& context,
968                                             ConvexObject<capacity> (&out)[size],
969                                             const std::tuple<COs...>& t) {
970     initConvexObjectArray(context, out, t, std::index_sequence_for<COs...>());
971 }
972 
973 template <typename Iterator> class Range {
974     Iterator begin_;
975     Iterator end_;
976 
977   public:
978     Range(Iterator begin, Iterator end) : begin_(begin), end_(end) {}
979     const Iterator begin() const { return begin_; }
980     const Iterator end() const { return end_; }
981 };
982 
983 template <typename Iterator> Range<Iterator> makeRange(Iterator begin, Iterator end) {
984     return {begin, end};
985 }
986 
987 }  // namespace teeui
988 
989 #define Position(x, y)                                                                             \
990     static const constexpr auto pos_x = x;                                                         \
991     static const constexpr auto pos_y = y
992 
993 #define Dimension(w, h)                                                                            \
994     static const constexpr auto dim_w = w;                                                         \
995     static const constexpr auto dim_h = h
996 
997 #define BEGIN_ELEMENT(name, type, ...)                                                             \
998     struct name : public type<name, ##__VA_ARGS__> {                                               \
999         name() = default;                                                                          \
1000         template <typename Context>                                                                \
1001         name(const Context& context) : type<name, ##__VA_ARGS__>(context) {}
1002 
1003 #define END_ELEMENT() }
1004 
1005 #define DECLARE_TYPED_PARAMETER(name, type)                                                        \
1006     struct Param_##name {};                                                                        \
1007     using name = ::teeui::MetaParam<Param_##name, type>
1008 
1009 #define DECLARE_PARAMETER(name) DECLARE_TYPED_PARAMETER(name, ::teeui::pxs)
1010 
1011 #define CONSTANT(name, value) static constexpr const auto name = value
1012 
1013 #define BOTTOM_EDGE_OF(name) (name::pos_y + name::dim_h)
1014 
1015 #define CONVEX_OBJECT(...) makeConvexObject(__VA_ARGS__)
1016 
1017 #define CONVEX_OBJECTS(...) std::make_tuple(__VA_ARGS__)
1018 
1019 /**
1020  * Creates a new Layout with the name "name" followed by a list of Layout elements as defined with
1021  * BEGIN_ELEMENT(name).
1022  */
1023 #define NEW_LAYOUT(name, ...) using name = ::teeui::MetaList<__VA_ARGS__>
1024 
1025 #define NEW_PARAMETER_SET(name, ...) using name = ::teeui::MetaList<__VA_ARGS__>
1026 
1027 #define LABELS(name, ...) using ::teeui::MetaList<__VA_ARGS__>
1028 
1029 #define TEXT_ID(textId) static_cast<uint32_t>(textId)
1030 #endif  // TEEUI_LIBTEEUI_UTILS_H_
1031