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