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 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