• 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 Param, typename Numeric = DefaultNumericType> class context;
263 template <typename T1, typename T2, typename Numeric, template <typename> class Op> struct BinOp;
264 
265 template <typename T1, typename T2, typename Numeric> using add = BinOp<T1, T2, Numeric, Add>;
266 template <typename T1, typename T2, typename Numeric> using sub = BinOp<T1, T2, Numeric, Sub>;
267 template <typename T1, typename T2, typename Numeric> using mul = BinOp<T1, T2, Numeric, Mul>;
268 template <typename T1, typename T2, typename Numeric> using div = BinOp<T1, T2, Numeric, Div>;
269 
270 template <typename T1, typename T2, typename Numeric, template <typename> class Op> struct BinOp {
271   private:
272     T1 v1_;
273     T2 v2_;
274 
275   public:
276     constexpr BinOp(const T1& v1, const T2& v2) : v1_(v1), v2_(v2) {}
277     BinOp(const BinOp&) = default;
278     BinOp(BinOp&&) = default;
279 
280     template <typename Context> Coordinate<px, Numeric> eval(const Context& ctx) const {
281         Coordinate<px, Numeric> v1 = ctx = v1_;
282         Coordinate<px, Numeric> v2 = ctx = v2_;
283         return Op<Numeric>::eval(v1, v2);
284     }
285     template <typename T> constexpr add<BinOp, T, Numeric> operator+(const T& v) const {
286         return {*this, v};
287     }
288     template <typename T> constexpr sub<BinOp, T, Numeric> operator-(const T& v) const {
289         return {*this, v};
290     }
291     template <typename T> constexpr mul<BinOp, T, Numeric> operator*(const T& v) const {
292         return {*this, v};
293     }
294     template <typename T> constexpr div<BinOp, T, Numeric> operator/(const T& v) const {
295         return {*this, v};
296     }
297 };
298 
299 template <typename Name, typename ParamType> struct MetaParam {};
300 
301 template <typename Name, typename Unit, typename Numeric>
302 struct MetaParam<Name, Coordinate<Unit, Numeric>> {
303     template <typename T> constexpr add<MetaParam, T, Numeric> operator+(const T& v) const {
304         return {*this, v};
305     }
306     template <typename T> constexpr sub<MetaParam, T, Numeric> operator-(const T& v) const {
307         return {*this, v};
308     }
309     template <typename T> constexpr mul<MetaParam, T, Numeric> operator*(const T& v) const {
310         return {*this, v};
311     }
312     template <typename T> constexpr div<MetaParam, T, Numeric> operator/(const T& v) const {
313         return {*this, v};
314     }
315 };
316 
317 template <typename Name, typename ParamType> struct Param {
318     ParamType param_;
319     Param() : param_{} {}
320     Param(const Param&) = default;
321     Param(Param&&) = default;
322     Param& operator=(const Param&) = default;
323     Param& operator=(Param&&) = default;
324 };
325 
326 template <typename Unit, typename Numeric> class Coordinate {
327     Numeric value_;
328 
329   public:
330     using unit_t = Unit;
331     constexpr Coordinate() : value_{} {}
332     constexpr Coordinate(Numeric value) : value_(value) {}
333     Coordinate(const Coordinate&) = default;
334     Coordinate(Coordinate&&) = default;
335     template <typename N> Coordinate(const Coordinate<Unit, N>& other) {
336         if constexpr (std::is_floating_point<N>::value && std::is_integral<Numeric>::value) {
337             value_ = bits::round(other.count());
338         } else {
339             value_ = other.count();
340         }
341     }
342     Coordinate& operator=(const Coordinate& rhs) = default;
343     Coordinate& operator=(Coordinate&& rhs) = default;
344 
345     constexpr Coordinate operator-(const Coordinate& v) const { return value_ - v.value_; }
346     constexpr Coordinate operator+(const Coordinate& v) const { return value_ + v.value_; }
347     constexpr Coordinate& operator-=(const Coordinate& v) {
348         value_ -= v.value_;
349         return *this;
350     }
351     constexpr Coordinate& operator+=(const Coordinate& v) {
352         value_ += v.value_;
353         return *this;
354     }
355     constexpr Coordinate operator*(const Coordinate& v) const { return value_ * v.value_; }
356     constexpr Coordinate& operator*=(const Coordinate& v) {
357         value_ *= v.value_;
358         return *this;
359     }
360     constexpr Coordinate operator/(const Coordinate& v) const { return value_ / v.value_; }
361     constexpr Coordinate& operator/=(const Coordinate& v) {
362         value_ /= v.value_;
363         return *this;
364     }
365     constexpr Coordinate operator-() const { return -value_; }
366 
367     Coordinate abs() const { return bits::abs(value_); }
368     Coordinate ceil() const { return bits::ceil(value_); }
369     Coordinate floor() const { return bits::floor(value_); }
370     Coordinate sqrt() const { return bits::sqrt(value_); }
371 
372     constexpr bool operator==(const Coordinate& v) const { return value_ == v.value_; }
373     constexpr bool operator!=(const Coordinate& v) const { return !(*this == v); }
374     constexpr bool operator<(const Coordinate& v) const { return value_ < v.value_; }
375     constexpr bool operator>(const Coordinate& v) const { return v < *this; }
376     constexpr bool operator<=(const Coordinate& v) const { return !(v < *this); }
377     constexpr bool operator>=(const Coordinate& v) const { return !(*this < v); }
378 
379     template <typename T> constexpr add<Coordinate, T, Numeric> operator+(const T& v) const {
380         return {*this, v};
381     }
382     template <typename T> constexpr sub<Coordinate, T, Numeric> operator-(const T& v) const {
383         return {*this, v};
384     }
385     template <typename T> constexpr mul<Coordinate, T, Numeric> operator*(const T& v) const {
386         return {*this, v};
387     }
388     template <typename T> constexpr div<Coordinate, T, Numeric> operator/(const T& v) const {
389         return {*this, v};
390     }
391 
392     Numeric count() const { return value_; }
393 };
394 
395 template <typename... T> struct MetaList {};
396 
397 template <typename MetaParam> struct metaParam2Param;
398 
399 template <typename ParamName, typename ParamType>
400 struct metaParam2Param<MetaParam<ParamName, ParamType>> {
401     using type = Param<ParamName, ParamType>;
402 };
403 
404 template <typename MetaParam> struct metaParam2ParamType;
405 
406 template <typename ParamName, typename ParamType>
407 struct metaParam2ParamType<MetaParam<ParamName, ParamType>> {
408     using type = ParamType;
409 };
410 
411 template <typename T> struct isCoordinateType { constexpr static const bool value = false; };
412 
413 template <typename Unit, typename Numeric> struct isCoordinateType<Coordinate<Unit, Numeric>> {
414     constexpr static const bool value = true;
415 };
416 
417 template <typename MetaParam> struct isCoordinateParam;
418 
419 template <typename ParamName, typename ParamType>
420 struct isCoordinateParam<MetaParam<ParamName, ParamType>> {
421     constexpr static const bool value = isCoordinateType<ParamType>::value;
422 };
423 
424 template <typename T> struct isMetaParam { constexpr static const bool value = false; };
425 
426 template <typename ParamName, typename ParamType>
427 struct isMetaParam<MetaParam<ParamName, ParamType>> {
428     constexpr static const bool value = true;
429 };
430 
431 template <typename... ParamsNames, typename... ParamTypes, typename Numeric>
432 class context<MetaList<MetaParam<ParamsNames, ParamTypes>...>, Numeric> {
433     Numeric mm2px_;
434     Numeric dp2px_;
435     std::tuple<Param<ParamsNames, ParamTypes>...> params_;
436 
437     class Proxy {
438         Numeric valuepx_;
439         Numeric mm2px_, dp2px_;
440 
441       public:
442         Proxy(Numeric valuepx, Numeric mm2px, Numeric dp2px)
443             : valuepx_(valuepx), mm2px_(mm2px), dp2px_(dp2px) {}
444         Proxy(const Proxy&) = default;
445         Proxy(Proxy&&) = default;
446 
447         operator Coordinate<px, Numeric>() const { return valuepx_; }
448         operator Coordinate<mm, Numeric>() const { return valuepx_ / mm2px_; }
449         operator Coordinate<dp, Numeric>() const { return valuepx_ / dp2px_; }
450     };
451 
452   public:
453     context(Numeric mm2px, Numeric dp2px) : mm2px_(mm2px), dp2px_(dp2px) {}
454 
455     context(const context&) = default;
456     context(context&&) = default;
457     context& operator=(const context&) = default;
458     context& operator=(context&&) = default;
459 
460     template <typename MetaParam> auto& getParam() {
461         return std::get<typename metaParam2Param<MetaParam>::type>(params_);
462     }
463     template <typename MetaParam> const auto& getParam() const {
464         return std::get<typename metaParam2Param<MetaParam>::type>(params_);
465     }
466 
467     template <typename MetaParam, typename = std::enable_if_t<isCoordinateParam<MetaParam>::value>>
468     void setParam(const Coordinate<px, Numeric>& v) {
469         getParam<MetaParam>().param_ = v;
470     }
471 
472     template <typename MetaParam, typename Unit, typename N,
473               typename = std::enable_if_t<isCoordinateParam<MetaParam>::value>>
474     void setParam(const Coordinate<Unit, N>& v) {
475         getParam<MetaParam>().param_ = *this = v;
476     }
477 
478     template <typename MetaParam>
479     void setParam(std::enable_if_t<!isCoordinateParam<MetaParam>::value,
480                                    const typename metaParam2ParamType<MetaParam>::type>& v) {
481         getParam<MetaParam>().param_ = v;
482     }
483 
484     Proxy operator=(const Coordinate<px, Numeric>& rhs) const {
485         return {rhs.count(), mm2px_, dp2px_};
486     }
487     Proxy operator=(const Coordinate<mm, Numeric>& rhs) const {
488         return {rhs.count() * mm2px_, mm2px_, dp2px_};
489     }
490     Proxy operator=(const Coordinate<dp, Numeric>& rhs) const {
491         return {rhs.count() * dp2px_, mm2px_, dp2px_};
492     }
493     template <typename T1, typename T2, template <typename> class Op>
494     Proxy operator=(const BinOp<T1, T2, Numeric, Op>& rhs) const {
495         return {rhs.eval(*this).count(), mm2px_, dp2px_};
496     }
497     template <typename ParamName, typename ParamType>
498     std::enable_if_t<isCoordinateParam<MetaParam<ParamName, ParamType>>::value, Proxy>
499     operator=(const MetaParam<ParamName, ParamType>&) const {
500         return {getParam<MetaParam<ParamName, ParamType>>().param_.count(), mm2px_, dp2px_};
501     }
502     template <typename ParamName, typename ParamType>
503     std::enable_if_t<!isCoordinateParam<MetaParam<ParamName, ParamType>>::value, const ParamType&>
504     operator=(const MetaParam<ParamName, ParamType>&) const {
505         return getParam<MetaParam<ParamName, ParamType>>().param_;
506     }
507     template <typename T,
508               typename = std::enable_if_t<!(isMetaParam<T>::value || isCoordinateType<T>::value)>>
509     inline T&& operator=(T&& v) const {
510         return std::forward<T>(v);
511     }
512 };
513 
514 using dps = Coordinate<dp>;
515 using mms = Coordinate<mm>;
516 using pxs = Coordinate<px>;
517 
518 constexpr dps operator""_dp(long double dp) {
519     return dps(dp);
520 }
521 constexpr mms operator""_mm(long double mm) {
522     return mms(mm);
523 }
524 constexpr pxs operator""_px(long double px) {
525     return pxs(px);
526 }
527 constexpr dps operator""_dp(unsigned long long dp) {
528     return dps(dp);
529 }
530 constexpr mms operator""_mm(unsigned long long mm) {
531     return mms(mm);
532 }
533 constexpr pxs operator""_px(unsigned long long px) {
534     return pxs(px);
535 }
536 
537 template <typename Coord> class Vec2d {
538     Coord x_, y_;
539 
540   public:
541     constexpr Vec2d() : x_{}, y_{} {}
542     constexpr Vec2d(Coord x, Coord y) : x_(x), y_(y) {}
543     Vec2d(const Vec2d&) = default;
544     Vec2d(Vec2d&&) = default;
545     template <typename N>
546     Vec2d(const Vec2d<Coordinate<typename Coord::unit_t, N>>& other)
547         : x_(other.x()), y_(other.y()) {}
548 
549     Vec2d& operator=(const Vec2d& rhs) = default;
550     Vec2d& operator=(Vec2d&& rhs) = default;
551 
552     Vec2d operator-(const Vec2d& rhs) const { return Vec2d(*this) -= rhs; }
553     Vec2d operator+(const Vec2d& rhs) const { return Vec2d(*this) += rhs; }
554     Vec2d& operator-=(const Vec2d& rhs) {
555         x_ -= rhs.x_;
556         y_ -= rhs.y_;
557         return *this;
558     }
559     Vec2d& operator+=(const Vec2d& rhs) {
560         x_ += rhs.x_;
561         y_ += rhs.y_;
562         return *this;
563     }
564     Coord operator*(const Vec2d& rhs) const { return (x_ * rhs.x_ + y_ * rhs.y_).count(); }
565     Vec2d operator*(const Coord& f) const { return Vec2d(*this) *= f; }
566     Vec2d& operator*=(const Coord& f) {
567         x_ *= f;
568         y_ *= f;
569         return *this;
570     }
571     Vec2d operator/(const Coord& f) { return Vec2d(*this) /= f; }
572     Vec2d& operator/=(const Coord& f) {
573         x_ /= f;
574         y_ /= f;
575         return *this;
576     }
577     bool operator==(const Vec2d& rhs) const { return x_ == rhs.x() && y_ == rhs.y(); }
578     Coord length() const {
579         Coord factor = *this * *this;
580         return bits::sqrt(factor.count());
581     }
582     Vec2d unit() const { return Vec2d(*this) /= length(); }
583     Coord x() const { return x_; }
584     Coord y() const { return y_; }
585 };
586 
587 #ifdef TEEUI_DO_LOG_DEBUG
588 template <typename Unit, typename Numeric>
589 std::ostream& operator<<(std::ostream& out, const Coordinate<Unit, Numeric>& p) {
590     out << std::setprecision(10) << p.count() << str<Unit>;
591     return out;
592 }
593 
594 template <typename Coord> std::ostream& operator<<(std::ostream& out, const Vec2d<Coord>& p) {
595     out << "Vec2d(" << p.x() << ", " << p.y() << ")";
596     return out;
597 }
598 #endif
599 
600 using Color = uint32_t;
601 
602 template <typename Coord> using Point = Vec2d<Coord>;
603 
604 Color drawLinePoint(Point<pxs> a, Point<pxs> b, Point<pxs> px_origin, Color c,
605                     pxs width = pxs(1.0));
606 
607 Color drawCirclePoint(Point<pxs> center, pxs r, Point<pxs> px_origin, Color c);
608 
609 using PxPoint = Point<pxs>;
610 using PxVec = Vec2d<pxs>;
611 
612 /*
613  * Computes the intersection of the lines given by ax + b and cy + d.
614  * The result may be empty if there is no solution.
615  */
616 optional<PxPoint> intersect(const PxVec& a, const PxPoint& b, const PxVec& c, const PxPoint& d);
617 
618 namespace bits {
619 
620 static constexpr const ssize_t kIntersectEmpty = -1;
621 /**
622  * Returned by the intersect if the object is in the positive half plane of the given line.
623  */
624 static constexpr const ssize_t kIntersectAllPositive = -2;
625 
626 ssize_t intersect(const PxPoint* oBegin, const PxPoint* oEnd, const PxPoint& lineA,
627                   const PxPoint& lineB, PxPoint* nBegin, PxPoint* nEnd);
628 
629 pxs area(const PxPoint* begin, const PxPoint* end);
630 
631 }  // namespace bits
632 
633 /**
634  * A ConvexObject is given by a list of 2D vertexes. Each vertex must lie on the positive half-plane
635  * of the line denoted by its two predecessors. A point is considered inside of the convex object
636  * if it is on the positive half-plane of all lines given by any two subsequent vertexes.
637  *
638  * ConvexObjects have fixed size given by the capacity template argument. The geometric object
639  * that they describe may have any number of vertexes between 3 and capacity.
640  */
641 template <size_t capacity> class ConvexObject {
642     template <size_t other_cap> friend class ConvexObject;
643 
644   protected:
645     PxPoint points_[capacity];
646     size_t fill_;
647 
648   public:
649     ConvexObject() : fill_(0) {}
650     explicit constexpr ConvexObject(std::initializer_list<PxPoint> l) : fill_(0) {
651         if (l.size() > capacity) return;
652         for (const auto& p : l) {
653             points_[fill_++] = p;
654         }
655     }
656     ConvexObject(const ConvexObject& other) = default;
657     ConvexObject(ConvexObject&& other) = default;
658     ConvexObject& operator=(const ConvexObject& other) = default;
659     ConvexObject& operator=(ConvexObject&& other) = default;
660 
661     constexpr size_t size() const { return fill_; }
662 
663     constexpr const PxPoint* begin() const { return &points_[0]; }
664     constexpr const PxPoint* end() const { return &points_[fill_]; }
665 
666     template <size_t result_cap>
667     optional<ConvexObject<result_cap>> intersect(const PxPoint& A, const PxPoint& B) const {
668         static_assert(result_cap >= capacity,
669                       "resulting capacity must be at least as large as the original");
670         ConvexObject<result_cap> result;
671         ssize_t vCount =
672             bits::intersect(begin(), end(), A, B, &result.points_[0], &result.points_[result_cap]);
673         if (vCount == bits::kIntersectEmpty) return {};
674         // -2 is returned if the object is in the positive half plane of the line (may be tangent)
675         if (vCount == bits::kIntersectAllPositive) {
676             std::copy(begin(), end(), &result.points_[0]);
677             vCount = fill_;
678         }
679         result.fill_ = vCount;
680         return result;
681     }
682 
683     template <size_t result_cap, size_t arg_cap>
684     optional<ConvexObject<result_cap>> intersect(const ConvexObject<arg_cap>& other) const {
685         return intersect<result_cap>(other.begin(), other.end());
686     }
687 
688     template <size_t result_cap>
689     optional<ConvexObject<result_cap>> intersect(const PxPoint* begin, const PxPoint* end) const {
690         if (end - begin < 3) return {};
691         auto b = begin;
692         auto a = end - 1;
693         auto result = intersect<result_cap>(*a, *b);
694         a = b++;
695         while (result && b != end) {
696             result = result->template intersect<result_cap>(*a, *b);
697             a = b++;
698         }
699         return result;
700     }
701 
702     pxs area() const { return bits::area(begin(), end()); }
703 
704     void push_back(const PxPoint& p) {
705         if (fill_ < capacity) {
706             points_[fill_++] = p;
707         }
708     }
709 };
710 
711 #ifdef TEEUI_DO_LOG_DEBUG
712 template <size_t capacity>
713 std::ostream& operator<<(std::ostream& out, const ConvexObject<capacity>& o) {
714     out << "ConvexObject(";
715     bool first = true;
716     for (const auto& p : o) {
717         if (first)
718             first = false;
719         else
720             out << ", ";
721         out << p;
722     }
723     out << ")";
724     return out;
725 }
726 #endif
727 
728 template <typename Coord> class Box {
729     Point<Coord> topLeft_;
730     Vec2d<Coord> extend_;
731 
732   public:
733     Box() {}
734     template <typename N>
735     Box(const Box<Coordinate<typename Coord::unit_t, N>>& other)
736         : topLeft_(other.topLeft()), extend_(other.extend()) {}
737     Box(const Coord& x, const Coord& y, const Coord& w, const Coord& h)
738         : topLeft_(x, y), extend_(w, h) {}
739     Box(const Point<Coord>& topLeft, const Vec2d<Coord>& extend)
740         : topLeft_(topLeft), extend_(extend) {}
741     bool contains(Point<Coord> p) const {
742         p -= topLeft_;
743         return p.y().count() >= 0 && p.y().count() <= extend_.y().count() && p.x().count() >= 0 &&
744                p.x().count() <= extend_.x().count();
745     }
746     bool contains(const Box& other) const {
747         auto br = bottomRight();
748         auto obr = other.bottomRight();
749         return topLeft_.x() <= other.topLeft_.x() && br.x() >= obr.x() &&
750                topLeft_.y() <= other.topLeft_.y() && br.y() >= obr.y();
751     }
752     bool overlaps(const Box& other) const {
753         auto br = bottomRight();
754         auto obr = other.bottomRight();
755         return topLeft_.x() < obr.x() && other.topLeft_.x() < br.x() && topLeft_.y() < obr.y() &&
756                other.topLeft_.y() < obr.y();
757     }
758 
759     /**
760      * fitsInside only compares the extend of the boxes. It returns true if this box would fit
761      * inside the other box regardless of their absolute positions.
762      */
763     bool fitsInside(const Box& other) const { return w() <= other.w() && h() <= other.w(); }
764     Point<Coord> bottomRight() const { return topLeft_ + extend_; }
765     Point<Coord> topLeft() const { return topLeft_; }
766     Vec2d<Coord> extend() const { return extend_; }
767     Coord x() const { return topLeft_.x(); }
768     Coord y() const { return topLeft_.y(); }
769     Coord w() const { return extend_.x(); }
770     Coord h() const { return extend_.y(); }
771 
772     Box merge(const Box& other) const {
773         Coord x = std::min(topLeft_.x(), other.topLeft_.x());
774         Coord y = std::min(topLeft_.y(), other.topLeft_.y());
775         auto br = bottomRight();
776         auto obr = other.bottomRight();
777         Coord w = std::max(br.x(), obr.x()) - x;
778         Coord h = std::max(br.y(), obr.y()) - y;
779         return {x, y, w, h};
780     }
781 
782     /**
783      * Returns a box that contains the this box and the given point.
784      */
785     Box merge(const Point<Coord>& p) const {
786         auto br = bottomRight();
787         TEEUI_LOG << "A tl: " << topLeft_ << " br: " << br << " new: " << p << ENDL;
788         Coord x = std::min(topLeft_.x(), p.x());
789         Coord y = std::min(topLeft_.y(), p.y());
790         Coord w = std::max(br.x(), p.x()) - x;
791         Coord h = std::max(br.y(), p.y()) - y;
792         TEEUI_LOG << "B x: " << x << " y: " << y << " w: " << w << " h: " << h << ENDL;
793         return {x, y, w, h};
794     }
795 
796     /**
797      * Returns a box that contains this box and all of the given points.
798      */
799     Box merge(const Point<Coord>* begin, const Point<Coord>* end) const {
800         auto tl = topLeft();
801         auto br = bottomRight();
802         while (begin != end) {
803             TEEUI_LOG << "A tl: " << tl << " br: " << br << " new: " << *begin << ENDL;
804             tl = {std::min(tl.x(), begin->x()), std::min(tl.y(), begin->y())};
805             br = {std::max(br.x(), begin->x()), std::max(br.y(), begin->y())};
806             TEEUI_LOG << "B tl: " << tl << " br: " << br << " new: " << *begin << ENDL;
807             ++begin;
808         }
809         return {tl, br - tl};
810     }
811 
812     /**
813      * Creates a box that contains all of the given points.
814      */
815     static Box boundingBox(const Point<Coord>* begin, const Point<Coord>* end) {
816         if (begin == end) return {};
817         Box result(*begin, {0, 0});
818         result.merge(begin + 1, end);
819         return result;
820     }
821 
822     /*
823      * Translates the Box by the given offset. And returns a reference to itself
824      */
825     Box& translateSelf(const Point<Coord>& offset) {
826         topLeft_ += offset;
827         return *this;
828     }
829     /*
830      * Returns copy of this box translated by offset.
831      */
832     Box translate(const Point<Coord>& offset) const& {
833         Box result = *this;
834         result.topLeft_ += offset;
835         return result;
836     }
837     /*
838      * When called on a temporary just reuse this box.
839      */
840     Box translate(const Point<Coord>& offset) && {
841         topLeft_ += offset;
842         return *this;
843     }
844 };
845 
846 #ifdef TEEUI_DO_LOG_DEBUG
847 template <typename Coord> std::ostream& operator<<(std::ostream& out, const Box<Coord>& p) {
848     out << "Box(x: " << p.x().count() << " y: " << p.y().count() << " w: " << p.w().count()
849         << " h: " << p.h().count() << ")";
850     return out;
851 }
852 #endif
853 
854 struct PixelDrawer {
855     Error (*const drawPixel_)(uint32_t, uint32_t, Color, const void* priv_data);
856     const void* priv_data_;
857     Error operator()(uint32_t x, uint32_t y, Color color) const {
858         return drawPixel_(x, y, color, priv_data_);
859     }
860 };
861 
862 template <typename Fn> struct PixelDrawerHelper {
863     Fn fn_;
864     operator PixelDrawer() const {
865         return {[](uint32_t x, uint32_t y, Color color, const void* priv_data) -> Error {
866                     return reinterpret_cast<const PixelDrawerHelper*>(priv_data)->fn_(x, y, color);
867                 },
868                 this};
869     }
870 };
871 
872 template <typename Fn> PixelDrawerHelper<Fn> makePixelDrawer(Fn fn) {
873     return PixelDrawerHelper<Fn>{fn};
874 }
875 
876 template <typename Derived> struct LayoutElement {
877     Box<pxs> bounds_;
878     LayoutElement() = default;
879     template <typename Context>
880     LayoutElement(const Context& context)
881         : bounds_{context = Derived::pos_x, context = Derived::pos_y, context = Derived::dim_w,
882                   context = Derived::dim_h} {}
883 
884     Error draw(const PixelDrawer&) { return Error::OK; }
885 };
886 
887 template <typename... Elements, typename Context>
888 std::tuple<Elements...> instantiateLayout(MetaList<Elements...>, const Context& context) {
889     std::tuple<Elements...> result{Elements(context)...};
890     return result;
891 }
892 
893 template <typename T> struct MetaList2Layout;
894 
895 template <typename... Elements> struct MetaList2Layout<MetaList<Elements...>> {
896     using type = std::tuple<Elements...>;
897 };
898 
899 template <typename T> using layout_t = typename MetaList2Layout<T>::type;
900 
901 template <typename... Coords>
902 constexpr inline std::tuple<Vec2d<Coords>...> makeConvexObject(const Vec2d<Coords>&... points) {
903     return {points...};
904 }
905 
906 template <size_t capacity, typename Tuple, typename Context, size_t... I>
907 constexpr inline ConvexObject<capacity>
908 initConvexObject(const Context& context, const Tuple& outline, std::index_sequence<I...>) {
909     return ConvexObject<capacity>(
910         {PxVec(context = std::get<I>(outline).x(), context = std::get<I>(outline).y())...});
911 }
912 
913 template <size_t capacity, typename... Points, typename Context>
914 constexpr inline ConvexObject<capacity> initConvexObject(const Context& context,
915                                                          const std::tuple<Points...>& outline) {
916     return initConvexObject<capacity>(context, outline, std::index_sequence_for<Points...>{});
917 }
918 
919 template <size_t capacity, typename Tuple, typename Context, size_t... I, size_t size>
920 constexpr inline void initConvexObjectArray(const Context& context,
921                                             ConvexObject<capacity> (&out)[size], const Tuple& t,
922                                             std::index_sequence<I...>) {
923     static_assert(sizeof...(I) <= size,
924                   "Array to initialize must be big enough to hold all tuple elements");
925     [](auto...) {}((out[I] = initConvexObject<capacity>(context, std::get<I>(t)))...);
926 }
927 
928 template <size_t capacity, typename... COs, typename Context, size_t size>
929 constexpr inline void initConvexObjectArray(const Context& context,
930                                             ConvexObject<capacity> (&out)[size],
931                                             const std::tuple<COs...>& t) {
932     initConvexObjectArray(context, out, t, std::index_sequence_for<COs...>());
933 }
934 
935 template <typename Iterator> class Range {
936     Iterator begin_;
937     Iterator end_;
938 
939   public:
940     Range(Iterator begin, Iterator end) : begin_(begin), end_(end) {}
941     const Iterator begin() const { return begin_; }
942     const Iterator end() const { return end_; }
943 };
944 
945 template <typename Iterator> Range<Iterator> makeRange(Iterator begin, Iterator end) {
946     return {begin, end};
947 }
948 
949 }  // namespace teeui
950 
951 #define Position(x, y)                                                                             \
952     static const constexpr auto pos_x = x;                                                         \
953     static const constexpr auto pos_y = y
954 
955 #define Dimension(w, h)                                                                            \
956     static const constexpr auto dim_w = w;                                                         \
957     static const constexpr auto dim_h = h
958 
959 #define BEGIN_ELEMENT(name, type, ...)                                                             \
960     struct name : public type<name, ##__VA_ARGS__> {                                               \
961         name() = default;                                                                          \
962         template <typename Context>                                                                \
963         name(const Context& context) : type<name, ##__VA_ARGS__>(context) {}
964 
965 #define END_ELEMENT() }
966 
967 #define DECLARE_TYPED_PARAMETER(name, type)                                                        \
968     struct Param_##name {};                                                                        \
969     using name = ::teeui::MetaParam<Param_##name, type>
970 
971 #define DECLARE_PARAMETER(name) DECLARE_TYPED_PARAMETER(name, ::teeui::pxs)
972 
973 #define CONSTANT(name, value) static constexpr const auto name = value
974 
975 #define BOTTOM_EDGE_OF(name) (name::pos_y + name::dim_h)
976 
977 #define CONVEX_OBJECT(...) makeConvexObject(__VA_ARGS__)
978 
979 #define CONVEX_OBJECTS(...) std::make_tuple(__VA_ARGS__)
980 
981 /**
982  * Creates a new Layout with the name "name" followed by a list of Layout elements as defined with
983  * BEGIN_ELEMENT(name).
984  */
985 #define NEW_LAYOUT(name, ...) using name = ::teeui::MetaList<__VA_ARGS__>
986 
987 #define NEW_PARAMETER_SET(name, ...) using name = ::teeui::MetaList<__VA_ARGS__>
988 
989 #define LABELS(name, ...) using ::teeui::MetaList<__VA_ARGS__>
990 
991 #endif  // TEEUI_LIBTEEUI_UTILS_H_
992