Home | History | Annotate | Download | only in ui
      1 /*
      2  * Copyright 2019 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #pragma once
     18 
     19 #include <algorithm>
     20 #include <cstdint>
     21 #include <limits>
     22 #include <type_traits>
     23 #include <utility>
     24 
     25 namespace android {
     26 namespace ui {
     27 
     28 // Forward declare a few things.
     29 struct Size;
     30 bool operator==(const Size& lhs, const Size& rhs);
     31 
     32 /**
     33  * A simple value type representing a two-dimensional size
     34  */
     35 struct Size {
     36     int32_t width;
     37     int32_t height;
     38 
     39     // Special values
     40     static const Size INVALID;
     41     static const Size EMPTY;
     42 
     43     // ------------------------------------------------------------------------
     44     // Construction
     45     // ------------------------------------------------------------------------
     46 
     47     Size() : Size(INVALID) {}
     48     template <typename T>
     49     Size(T&& w, T&& h)
     50           : width(Size::clamp<int32_t, T>(std::forward<T>(w))),
     51             height(Size::clamp<int32_t, T>(std::forward<T>(h))) {}
     52 
     53     // ------------------------------------------------------------------------
     54     // Accessors
     55     // ------------------------------------------------------------------------
     56 
     57     int32_t getWidth() const { return width; }
     58     int32_t getHeight() const { return height; }
     59 
     60     template <typename T>
     61     void setWidth(T&& v) {
     62         width = Size::clamp<int32_t, T>(std::forward<T>(v));
     63     }
     64     template <typename T>
     65     void setHeight(T&& v) {
     66         height = Size::clamp<int32_t, T>(std::forward<T>(v));
     67     }
     68 
     69     // ------------------------------------------------------------------------
     70     // Assignment
     71     // ------------------------------------------------------------------------
     72 
     73     void set(const Size& size) { *this = size; }
     74     template <typename T>
     75     void set(T&& w, T&& h) {
     76         set(Size(std::forward<T>(w), std::forward<T>(h)));
     77     }
     78 
     79     // Sets the value to INVALID
     80     void makeInvalid() { set(INVALID); }
     81 
     82     // Sets the value to EMPTY
     83     void clear() { set(EMPTY); }
     84 
     85     // ------------------------------------------------------------------------
     86     // Semantic checks
     87     // ------------------------------------------------------------------------
     88 
     89     // Valid means non-negative width and height
     90     bool isValid() const { return width >= 0 && height >= 0; }
     91 
     92     // Empty means zero width and height
     93     bool isEmpty() const { return *this == EMPTY; }
     94 
     95     // ------------------------------------------------------------------------
     96     // Clamp Helpers
     97     // ------------------------------------------------------------------------
     98 
     99     // Note: We use only features available in C++11 here for compatibility with
    100     // external targets which include this file directly or indirectly and which
    101     // themselves use C++11.
    102 
    103     // C++11 compatible replacement for std::remove_cv_reference_t [C++20]
    104     template <typename T>
    105     using remove_cv_reference_t =
    106             typename std::remove_cv<typename std::remove_reference<T>::type>::type;
    107 
    108     // Takes a value of type FromType, and ensures it can be represented as a value of type ToType,
    109     // clamping the input value to the output range if necessary.
    110     template <typename ToType, typename FromType>
    111     static Size::remove_cv_reference_t<ToType> clamp(
    112             typename std::enable_if<
    113                     std::numeric_limits<Size::remove_cv_reference_t<ToType>>::is_bounded &&
    114                             std::numeric_limits<Size::remove_cv_reference_t<FromType>>::is_bounded,
    115                     FromType&&>::type v) {
    116         static constexpr auto toHighest = std::numeric_limits<remove_cv_reference_t<ToType>>::max();
    117         static constexpr auto toLowest =
    118                 std::numeric_limits<remove_cv_reference_t<ToType>>::lowest();
    119         static constexpr auto fromHighest =
    120                 std::numeric_limits<remove_cv_reference_t<FromType>>::max();
    121         static constexpr auto fromLowest =
    122                 std::numeric_limits<remove_cv_reference_t<FromType>>::lowest();
    123 
    124         // A clamp is needed if the range of FromType is not a subset of the range of ToType
    125         static constexpr bool isClampNeeded = (toLowest > fromLowest) || (toHighest < fromHighest);
    126 
    127         // If a clamp is not needed, the conversion is just a trivial cast.
    128         if (!isClampNeeded) {
    129             return static_cast<ToType>(v);
    130         }
    131 
    132         // Otherwise we leverage implicit conversion to safely compare values of
    133         // different types, to ensure we return a value clamped to the range of
    134         // ToType.
    135         return v < toLowest ? toLowest : (v > toHighest ? toHighest : static_cast<ToType>(v));
    136     }
    137 };
    138 
    139 // ------------------------------------------------------------------------
    140 // Comparisons
    141 // ------------------------------------------------------------------------
    142 
    143 inline bool operator==(const Size& lhs, const Size& rhs) {
    144     return lhs.width == rhs.width && lhs.height == rhs.height;
    145 }
    146 
    147 inline bool operator!=(const Size& lhs, const Size& rhs) {
    148     return !operator==(lhs, rhs);
    149 }
    150 
    151 inline bool operator<(const Size& lhs, const Size& rhs) {
    152     // Orders by increasing width, then height.
    153     if (lhs.width != rhs.width) return lhs.width < rhs.width;
    154     return lhs.height < rhs.height;
    155 }
    156 
    157 } // namespace ui
    158 } // namespace android
    159