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 ¶m_; } 329 inline ParamType* operator->() { return ¶m_; } 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 context(Numeric mm2px, Numeric dp2px) : mm2px_(mm2px), dp2px_(dp2px) {} 462 463 context(const context&) = default; 464 context(context&&) = default; 465 context& operator=(const context&) = default; 466 context& operator=(context&&) = default; 467 468 template <typename MetaParam> auto& getParam() { 469 return std::get<typename metaParam2Param<MetaParam>::type>(params_); 470 } 471 template <typename MetaParam> const auto& getParam() const { 472 return std::get<typename metaParam2Param<MetaParam>::type>(params_); 473 } 474 475 template <typename MetaParam, typename = std::enable_if_t<isCoordinateParam<MetaParam>::value>> 476 void setParam(const Coordinate<px, Numeric>& v) { 477 *getParam<MetaParam>() = v; 478 } 479 480 template <typename MetaParam, typename Unit, typename N, 481 typename = std::enable_if_t<isCoordinateParam<MetaParam>::value>> 482 void setParam(const Coordinate<Unit, N>& v) { 483 *getParam<MetaParam>() = *this = v; 484 } 485 486 template <typename MetaParam> 487 void setParam(std::enable_if_t<!isCoordinateParam<MetaParam>::value, 488 const typename metaParam2ParamType<MetaParam>::type>& v) { 489 *getParam<MetaParam>() = v; 490 } 491 492 Proxy operator=(const Coordinate<px, Numeric>& rhs) const { 493 return {rhs.count(), mm2px_, dp2px_}; 494 } 495 Proxy operator=(const Coordinate<mm, Numeric>& rhs) const { 496 return {rhs.count() * mm2px_, mm2px_, dp2px_}; 497 } 498 Proxy operator=(const Coordinate<dp, Numeric>& rhs) const { 499 return {rhs.count() * dp2px_, mm2px_, dp2px_}; 500 } 501 template <typename T1, typename T2, template <typename> class Op> 502 Proxy operator=(const BinOp<T1, T2, Numeric, Op>& rhs) const { 503 return {rhs.eval(*this).count(), mm2px_, dp2px_}; 504 } 505 template <typename ParamName, typename ParamType> 506 std::enable_if_t<isCoordinateParam<MetaParam<ParamName, ParamType>>::value, Proxy> 507 operator=(const MetaParam<ParamName, ParamType>&) const { 508 return {getParam<MetaParam<ParamName, ParamType>>()->count(), mm2px_, dp2px_}; 509 } 510 template <typename ParamName, typename ParamType> 511 std::enable_if_t<!isCoordinateParam<MetaParam<ParamName, ParamType>>::value, const ParamType&> 512 operator=(const MetaParam<ParamName, ParamType>&) const { 513 return *getParam<MetaParam<ParamName, ParamType>>(); 514 } 515 template <typename T, 516 typename = std::enable_if_t<!(isMetaParam<T>::value || isCoordinateType<T>::value)>> 517 inline T&& operator=(T&& v) const { 518 return std::forward<T>(v); 519 } 520 }; 521 522 using dps = Coordinate<dp>; 523 using mms = Coordinate<mm>; 524 using pxs = Coordinate<px>; 525 526 constexpr dps operator""_dp(long double dp) { 527 return dps(dp); 528 } 529 constexpr mms operator""_mm(long double mm) { 530 return mms(mm); 531 } 532 constexpr pxs operator""_px(long double px) { 533 return pxs(px); 534 } 535 constexpr dps operator""_dp(unsigned long long dp) { 536 return dps(dp); 537 } 538 constexpr mms operator""_mm(unsigned long long mm) { 539 return mms(mm); 540 } 541 constexpr pxs operator""_px(unsigned long long px) { 542 return pxs(px); 543 } 544 545 template <typename Coord> class Vec2d { 546 Coord x_, y_; 547 548 public: 549 constexpr Vec2d() : x_{}, y_{} {} 550 constexpr Vec2d(Coord x, Coord y) : x_(x), y_(y) {} 551 Vec2d(const Vec2d&) = default; 552 Vec2d(Vec2d&&) = default; 553 template <typename N> 554 Vec2d(const Vec2d<Coordinate<typename Coord::unit_t, N>>& other) 555 : x_(other.x()), y_(other.y()) {} 556 557 Vec2d& operator=(const Vec2d& rhs) = default; 558 Vec2d& operator=(Vec2d&& rhs) = default; 559 560 Vec2d operator-(const Vec2d& rhs) const { return Vec2d(*this) -= rhs; } 561 Vec2d operator+(const Vec2d& rhs) const { return Vec2d(*this) += rhs; } 562 Vec2d& operator-=(const Vec2d& rhs) { 563 x_ -= rhs.x_; 564 y_ -= rhs.y_; 565 return *this; 566 } 567 Vec2d& operator+=(const Vec2d& rhs) { 568 x_ += rhs.x_; 569 y_ += rhs.y_; 570 return *this; 571 } 572 Coord operator*(const Vec2d& rhs) const { return (x_ * rhs.x_ + y_ * rhs.y_).count(); } 573 Vec2d operator*(const Coord& f) const { return Vec2d(*this) *= f; } 574 Vec2d& operator*=(const Coord& f) { 575 x_ *= f; 576 y_ *= f; 577 return *this; 578 } 579 Vec2d operator/(const Coord& f) { return Vec2d(*this) /= f; } 580 Vec2d& operator/=(const Coord& f) { 581 x_ /= f; 582 y_ /= f; 583 return *this; 584 } 585 bool operator==(const Vec2d& rhs) const { return x_ == rhs.x() && y_ == rhs.y(); } 586 Coord length() const { 587 Coord factor = *this * *this; 588 return bits::sqrt(factor.count()); 589 } 590 Vec2d unit() const { return Vec2d(*this) /= length(); } 591 Coord x() const { return x_; } 592 Coord y() const { return y_; } 593 }; 594 595 #ifdef TEEUI_DO_LOG_DEBUG 596 template <typename Unit, typename Numeric> 597 std::ostream& operator<<(std::ostream& out, const Coordinate<Unit, Numeric>& p) { 598 out << std::setprecision(10) << p.count() << str<Unit>; 599 return out; 600 } 601 602 template <typename Coord> std::ostream& operator<<(std::ostream& out, const Vec2d<Coord>& p) { 603 out << "Vec2d(" << p.x() << ", " << p.y() << ")"; 604 return out; 605 } 606 #endif 607 608 using Color = uint32_t; 609 610 template <typename Coord> using Point = Vec2d<Coord>; 611 612 Color drawLinePoint(Point<pxs> a, Point<pxs> b, Point<pxs> px_origin, Color c, 613 pxs width = pxs(1.0)); 614 615 Color drawCirclePoint(Point<pxs> center, pxs r, Point<pxs> px_origin, Color c); 616 617 using PxPoint = Point<pxs>; 618 using PxVec = Vec2d<pxs>; 619 620 /* 621 * Computes the intersection of the lines given by ax + b and cy + d. 622 * The result may be empty if there is no solution. 623 */ 624 optional<PxPoint> intersect(const PxVec& a, const PxPoint& b, const PxVec& c, const PxPoint& d); 625 626 namespace bits { 627 628 static constexpr const ssize_t kIntersectEmpty = -1; 629 /** 630 * Returned by the intersect if the object is in the positive half plane of the given line. 631 */ 632 static constexpr const ssize_t kIntersectAllPositive = -2; 633 634 ssize_t intersect(const PxPoint* oBegin, const PxPoint* oEnd, const PxPoint& lineA, 635 const PxPoint& lineB, PxPoint* nBegin, PxPoint* nEnd); 636 637 pxs area(const PxPoint* begin, const PxPoint* end); 638 639 } // namespace bits 640 641 /** 642 * A ConvexObject is given by a list of 2D vertexes. Each vertex must lie on the positive half-plane 643 * of the line denoted by its two predecessors. A point is considered inside of the convex object 644 * if it is on the positive half-plane of all lines given by any two subsequent vertexes. 645 * 646 * ConvexObjects have fixed size given by the capacity template argument. The geometric object 647 * that they describe may have any number of vertexes between 3 and capacity. 648 */ 649 template <size_t capacity> class ConvexObject { 650 template <size_t other_cap> friend class ConvexObject; 651 652 protected: 653 PxPoint points_[capacity]; 654 size_t fill_; 655 656 public: 657 ConvexObject() : fill_(0) {} 658 explicit constexpr ConvexObject(std::initializer_list<PxPoint> l) : fill_(0) { 659 if (l.size() > capacity) return; 660 for (const auto& p : l) { 661 points_[fill_++] = p; 662 } 663 } 664 ConvexObject(const ConvexObject& other) = default; 665 ConvexObject(ConvexObject&& other) = default; 666 ConvexObject& operator=(const ConvexObject& other) = default; 667 ConvexObject& operator=(ConvexObject&& other) = default; 668 669 constexpr size_t size() const { return fill_; } 670 671 constexpr const PxPoint* begin() const { return &points_[0]; } 672 constexpr const PxPoint* end() const { return &points_[fill_]; } 673 674 template <size_t result_cap> 675 optional<ConvexObject<result_cap>> intersect(const PxPoint& A, const PxPoint& B) const { 676 static_assert(result_cap >= capacity, 677 "resulting capacity must be at least as large as the original"); 678 ConvexObject<result_cap> result; 679 ssize_t vCount = 680 bits::intersect(begin(), end(), A, B, &result.points_[0], &result.points_[result_cap]); 681 if (vCount == bits::kIntersectEmpty) return {}; 682 // -2 is returned if the object is in the positive half plane of the line (may be tangent) 683 if (vCount == bits::kIntersectAllPositive) { 684 std::copy(begin(), end(), &result.points_[0]); 685 vCount = fill_; 686 } 687 result.fill_ = vCount; 688 return result; 689 } 690 691 template <size_t result_cap, size_t arg_cap> 692 optional<ConvexObject<result_cap>> intersect(const ConvexObject<arg_cap>& other) const { 693 return intersect<result_cap>(other.begin(), other.end()); 694 } 695 696 template <size_t result_cap> 697 optional<ConvexObject<result_cap>> intersect(const PxPoint* begin, const PxPoint* end) const { 698 if (end - begin < 3) return {}; 699 auto b = begin; 700 auto a = end - 1; 701 auto result = intersect<result_cap>(*a, *b); 702 a = b++; 703 while (result && b != end) { 704 result = result->template intersect<result_cap>(*a, *b); 705 a = b++; 706 } 707 return result; 708 } 709 710 pxs area() const { return bits::area(begin(), end()); } 711 712 void push_back(const PxPoint& p) { 713 if (fill_ < capacity) { 714 points_[fill_++] = p; 715 } 716 } 717 }; 718 719 #ifdef TEEUI_DO_LOG_DEBUG 720 template <size_t capacity> 721 std::ostream& operator<<(std::ostream& out, const ConvexObject<capacity>& o) { 722 out << "ConvexObject("; 723 bool first = true; 724 for (const auto& p : o) { 725 if (first) 726 first = false; 727 else 728 out << ", "; 729 out << p; 730 } 731 out << ")"; 732 return out; 733 } 734 #endif 735 736 template <typename Coord> class Box { 737 Point<Coord> topLeft_; 738 Vec2d<Coord> extend_; 739 740 public: 741 Box() {} 742 template <typename N> 743 Box(const Box<Coordinate<typename Coord::unit_t, N>>& other) 744 : topLeft_(other.topLeft()), extend_(other.extend()) {} 745 Box(const Coord& x, const Coord& y, const Coord& w, const Coord& h) 746 : topLeft_(x, y), extend_(w, h) {} 747 Box(const Point<Coord>& topLeft, const Vec2d<Coord>& extend) 748 : topLeft_(topLeft), extend_(extend) {} 749 bool contains(Point<Coord> p) const { 750 p -= topLeft_; 751 return p.y().count() >= 0 && p.y().count() <= extend_.y().count() && p.x().count() >= 0 && 752 p.x().count() <= extend_.x().count(); 753 } 754 bool contains(const Box& other) const { 755 auto br = bottomRight(); 756 auto obr = other.bottomRight(); 757 return topLeft_.x() <= other.topLeft_.x() && br.x() >= obr.x() && 758 topLeft_.y() <= other.topLeft_.y() && br.y() >= obr.y(); 759 } 760 bool overlaps(const Box& other) const { 761 auto br = bottomRight(); 762 auto obr = other.bottomRight(); 763 return topLeft_.x() < obr.x() && other.topLeft_.x() < br.x() && topLeft_.y() < obr.y() && 764 other.topLeft_.y() < obr.y(); 765 } 766 767 /** 768 * fitsInside only compares the extend of the boxes. It returns true if this box would fit 769 * inside the other box regardless of their absolute positions. 770 */ 771 bool fitsInside(const Box& other) const { return w() <= other.w() && h() <= other.w(); } 772 Point<Coord> bottomRight() const { return topLeft_ + extend_; } 773 Point<Coord> topLeft() const { return topLeft_; } 774 Vec2d<Coord> extend() const { return extend_; } 775 Coord x() const { return topLeft_.x(); } 776 Coord y() const { return topLeft_.y(); } 777 Coord w() const { return extend_.x(); } 778 Coord h() const { return extend_.y(); } 779 780 Box merge(const Box& other) const { 781 Coord x = std::min(topLeft_.x(), other.topLeft_.x()); 782 Coord y = std::min(topLeft_.y(), other.topLeft_.y()); 783 auto br = bottomRight(); 784 auto obr = other.bottomRight(); 785 Coord w = std::max(br.x(), obr.x()) - x; 786 Coord h = std::max(br.y(), obr.y()) - y; 787 return {x, y, w, h}; 788 } 789 790 /** 791 * Returns a box that contains the this box and the given point. 792 */ 793 Box merge(const Point<Coord>& p) const { 794 auto br = bottomRight(); 795 TEEUI_LOG << "A tl: " << topLeft_ << " br: " << br << " new: " << p << ENDL; 796 Coord x = std::min(topLeft_.x(), p.x()); 797 Coord y = std::min(topLeft_.y(), p.y()); 798 Coord w = std::max(br.x(), p.x()) - x; 799 Coord h = std::max(br.y(), p.y()) - y; 800 TEEUI_LOG << "B x: " << x << " y: " << y << " w: " << w << " h: " << h << ENDL; 801 return {x, y, w, h}; 802 } 803 804 /** 805 * Returns a box that contains this box and all of the given points. 806 */ 807 Box merge(const Point<Coord>* begin, const Point<Coord>* end) const { 808 auto tl = topLeft(); 809 auto br = bottomRight(); 810 while (begin != end) { 811 TEEUI_LOG << "A tl: " << tl << " br: " << br << " new: " << *begin << ENDL; 812 tl = {std::min(tl.x(), begin->x()), std::min(tl.y(), begin->y())}; 813 br = {std::max(br.x(), begin->x()), std::max(br.y(), begin->y())}; 814 TEEUI_LOG << "B tl: " << tl << " br: " << br << " new: " << *begin << ENDL; 815 ++begin; 816 } 817 return {tl, br - tl}; 818 } 819 820 /** 821 * Creates a box that contains all of the given points. 822 */ 823 static Box boundingBox(const Point<Coord>* begin, const Point<Coord>* end) { 824 if (begin == end) return {}; 825 Box result(*begin, {0, 0}); 826 result.merge(begin + 1, end); 827 return result; 828 } 829 830 /* 831 * Translates the Box by the given offset. And returns a reference to itself 832 */ 833 Box& translateSelf(const Point<Coord>& offset) { 834 topLeft_ += offset; 835 return *this; 836 } 837 /* 838 * Returns copy of this box translated by offset. 839 */ 840 Box translate(const Point<Coord>& offset) const& { 841 Box result = *this; 842 result.topLeft_ += offset; 843 return result; 844 } 845 /* 846 * When called on a temporary just reuse this box. 847 */ 848 Box translate(const Point<Coord>& offset) && { 849 topLeft_ += offset; 850 return *this; 851 } 852 }; 853 854 #ifdef TEEUI_DO_LOG_DEBUG 855 template <typename Coord> std::ostream& operator<<(std::ostream& out, const Box<Coord>& p) { 856 out << "Box(x: " << p.x().count() << " y: " << p.y().count() << " w: " << p.w().count() 857 << " h: " << p.h().count() << ")"; 858 return out; 859 } 860 #endif 861 862 enum class EventType : uint8_t { 863 KeyDown, 864 KeyUp, 865 KeyMoved, 866 }; 867 868 struct Event { 869 uint32_t x_; 870 uint32_t y_; 871 EventType event_; 872 }; 873 874 template <typename Fn> struct Callback; 875 876 template <typename Ret, typename... Args> struct Callback<Ret(Args...)> { 877 Ret (*callback_)(Args... args, void* priv_data); 878 void* priv_data_; 879 Ret operator()(Args... args) const { return callback_(args..., priv_data_); } 880 }; 881 882 template <typename Ret, typename... Args> 883 Callback<Ret(Args...)> makeCallback(Ret (*fn)(Args..., void*), void* priv_data) { 884 return {fn, priv_data}; 885 } 886 887 template <typename Fn, typename Ret, typename... Args> struct CallbackHelper { 888 Fn fn_; 889 operator Callback<Ret(Args...)>() { 890 return makeCallback<Ret, Args...>( 891 [](Args... args, void* priv_data) -> Ret { 892 return reinterpret_cast<CallbackHelper*>(priv_data)->fn_(args...); 893 }, 894 this); 895 } 896 }; 897 898 using CallbackEvent = Callback<Error(Event)>; 899 using PixelDrawer = Callback<Error(uint32_t, uint32_t, Color)>; 900 901 template <typename Fn> 902 using PixelDrawerHelper = CallbackHelper<Fn, Error, uint32_t, uint32_t, Color>; 903 904 template <typename Fn> PixelDrawerHelper<Fn> makePixelDrawer(Fn fn) { 905 return PixelDrawerHelper<Fn>{fn}; 906 } 907 908 template <typename Derived> struct LayoutElement { 909 Box<pxs> bounds_; 910 LayoutElement() = default; 911 template <typename Context> 912 LayoutElement(const Context& context) 913 : bounds_{context = Derived::pos_x, context = Derived::pos_y, context = Derived::dim_w, 914 context = Derived::dim_h} {} 915 916 Error draw(const PixelDrawer&) { return Error::OK; } 917 Error hit(const Event&) { return Error::OK; } 918 }; 919 920 template <typename... Elements, typename Context> 921 std::tuple<Elements...> instantiateLayout(MetaList<Elements...>, const Context& context) { 922 std::tuple<Elements...> result{Elements(context)...}; 923 return result; 924 } 925 926 template <typename T> struct MetaList2Layout; 927 928 template <typename... Elements> struct MetaList2Layout<MetaList<Elements...>> { 929 using type = std::tuple<Elements...>; 930 }; 931 932 template <typename T> using layout_t = typename MetaList2Layout<T>::type; 933 934 template <typename... Coords> 935 constexpr inline std::tuple<Vec2d<Coords>...> makeConvexObject(const Vec2d<Coords>&... points) { 936 return {points...}; 937 } 938 939 template <size_t capacity, typename Tuple, typename Context, size_t... I> 940 constexpr inline ConvexObject<capacity> 941 initConvexObject(const Context& context, const Tuple& outline, std::index_sequence<I...>) { 942 return ConvexObject<capacity>( 943 {PxVec(context = std::get<I>(outline).x(), context = std::get<I>(outline).y())...}); 944 } 945 946 template <size_t capacity, typename... Points, typename Context> 947 constexpr inline ConvexObject<capacity> initConvexObject(const Context& context, 948 const std::tuple<Points...>& outline) { 949 return initConvexObject<capacity>(context, outline, std::index_sequence_for<Points...>{}); 950 } 951 952 template <size_t capacity, typename Tuple, typename Context, size_t... I, size_t size> 953 constexpr inline void initConvexObjectArray(const Context& context, 954 ConvexObject<capacity> (&out)[size], const Tuple& t, 955 std::index_sequence<I...>) { 956 static_assert(sizeof...(I) <= size, 957 "Array to initialize must be big enough to hold all tuple elements"); 958 [](auto...) {}((out[I] = initConvexObject<capacity>(context, std::get<I>(t)))...); 959 } 960 961 template <size_t capacity, typename... COs, typename Context, size_t size> 962 constexpr inline void initConvexObjectArray(const Context& context, 963 ConvexObject<capacity> (&out)[size], 964 const std::tuple<COs...>& t) { 965 initConvexObjectArray(context, out, t, std::index_sequence_for<COs...>()); 966 } 967 968 template <typename Iterator> class Range { 969 Iterator begin_; 970 Iterator end_; 971 972 public: 973 Range(Iterator begin, Iterator end) : begin_(begin), end_(end) {} 974 const Iterator begin() const { return begin_; } 975 const Iterator end() const { return end_; } 976 }; 977 978 template <typename Iterator> Range<Iterator> makeRange(Iterator begin, Iterator end) { 979 return {begin, end}; 980 } 981 982 } // namespace teeui 983 984 #define Position(x, y) \ 985 static const constexpr auto pos_x = x; \ 986 static const constexpr auto pos_y = y 987 988 #define Dimension(w, h) \ 989 static const constexpr auto dim_w = w; \ 990 static const constexpr auto dim_h = h 991 992 #define BEGIN_ELEMENT(name, type, ...) \ 993 struct name : public type<name, ##__VA_ARGS__> { \ 994 name() = default; \ 995 template <typename Context> \ 996 name(const Context& context) : type<name, ##__VA_ARGS__>(context) {} 997 998 #define END_ELEMENT() } 999 1000 #define DECLARE_TYPED_PARAMETER(name, type) \ 1001 struct Param_##name {}; \ 1002 using name = ::teeui::MetaParam<Param_##name, type> 1003 1004 #define DECLARE_PARAMETER(name) DECLARE_TYPED_PARAMETER(name, ::teeui::pxs) 1005 1006 #define CONSTANT(name, value) static constexpr const auto name = value 1007 1008 #define BOTTOM_EDGE_OF(name) (name::pos_y + name::dim_h) 1009 1010 #define CONVEX_OBJECT(...) makeConvexObject(__VA_ARGS__) 1011 1012 #define CONVEX_OBJECTS(...) std::make_tuple(__VA_ARGS__) 1013 1014 /** 1015 * Creates a new Layout with the name "name" followed by a list of Layout elements as defined with 1016 * BEGIN_ELEMENT(name). 1017 */ 1018 #define NEW_LAYOUT(name, ...) using name = ::teeui::MetaList<__VA_ARGS__> 1019 1020 #define NEW_PARAMETER_SET(name, ...) using name = ::teeui::MetaList<__VA_ARGS__> 1021 1022 #define LABELS(name, ...) using ::teeui::MetaList<__VA_ARGS__> 1023 1024 #define TEXT_ID(textId) static_cast<uint32_t>(textId) 1025 #endif // TEEUI_LIBTEEUI_UTILS_H_ 1026