AspectRatio.h (5379B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef mozilla_AspectRatio_h 8 #define mozilla_AspectRatio_h 9 10 /* The aspect ratio of a box, in a "width / height" format. */ 11 12 #include <algorithm> 13 #include <limits> 14 15 #include "mozilla/gfx/BaseSize.h" 16 #include "nsCoord.h" 17 18 namespace IPC { 19 template <typename T> 20 struct ParamTraits; 21 } // namespace IPC 22 23 namespace mozilla { 24 25 enum class LogicalAxis : uint8_t; 26 class LogicalSize; 27 class WritingMode; 28 29 enum class UseBoxSizing : uint8_t { 30 // The aspect ratio works with content box dimensions always. 31 No, 32 // The aspect ratio works with the dimensions of the box specified by 33 // box-sizing. 34 Yes, 35 }; 36 37 struct AspectRatio { 38 friend struct IPC::ParamTraits<mozilla::AspectRatio>; 39 40 AspectRatio() = default; 41 explicit AspectRatio(float aRatio, 42 UseBoxSizing aUseBoxSizing = UseBoxSizing::No) 43 : mRatio(std::max(aRatio, 0.0f)), mUseBoxSizing(aUseBoxSizing) {} 44 45 static AspectRatio FromSize(float aWidth, float aHeight, 46 UseBoxSizing aUseBoxSizing = UseBoxSizing::No) { 47 if (aWidth == 0.0f || aHeight == 0.0f) { 48 // For the degenerate ratio, we don't care about which box sizing we are 49 // using, so using default constructor is fine. 50 return AspectRatio(); 51 } 52 return AspectRatio(aWidth / aHeight, aUseBoxSizing); 53 } 54 55 template <typename T, typename Sub, typename Coord> 56 static AspectRatio FromSize(const gfx::BaseSize<T, Sub, Coord>& aSize) { 57 return FromSize(aSize.Width(), aSize.Height()); 58 } 59 60 explicit operator bool() const { return mRatio != 0.0f; } 61 62 nscoord ApplyTo(nscoord aCoord) const { 63 MOZ_DIAGNOSTIC_ASSERT(*this); 64 return NSCoordSaturatingNonnegativeMultiply(aCoord, mRatio); 65 } 66 67 float ApplyToFloat(float aFloat) const { 68 MOZ_DIAGNOSTIC_ASSERT(*this); 69 return mRatio * aFloat; 70 } 71 72 // Inverts the ratio, in order to get the height / width ratio. 73 [[nodiscard]] AspectRatio Inverted() const { 74 if (!*this) { 75 return AspectRatio(); 76 } 77 // Clamp to a small epsilon, in case mRatio is absurdly large & produces 78 // 0.0f in the division here (so that valid ratios always generate other 79 // valid ratios when inverted). 80 return AspectRatio( 81 std::max(std::numeric_limits<float>::epsilon(), 1.0f / mRatio), 82 mUseBoxSizing); 83 } 84 85 [[nodiscard]] inline AspectRatio ConvertToWritingMode( 86 const WritingMode& aWM) const; 87 88 /** 89 * This method computes the ratio-dependent size by the ratio-determining size 90 * and aspect-ratio (i.e. preferred aspect ratio). Basically this function 91 * will be used in the calculation of 'auto' sizes when the preferred 92 * aspect ratio is not 'auto'. 93 * 94 * @param aRatioDependentAxis The ratio depenedent axis of the box. 95 * @param aWM The writing mode of the box. 96 * @param aRatioDetermingSize The content-box size on the ratio determining 97 * axis. Basically, we use this size and |mRatio| 98 * to compute the size on the ratio-dependent 99 * axis. 100 * @param aContentBoxSizeToBoxSizingAdjust The border padding box size 101 * adjustment. We need this because 102 * aspect-ratio should take the 103 * box-sizing into account if its 104 * style is '<ratio>'. If its style 105 * is 'auto & <ratio>', we should use 106 * content-box dimensions always. 107 * If the callers want the ratio to 108 * apply to the content-box size, we 109 * should pass a zero LogicalSize. 110 * If mUseBoxSizing is No, we ignore 111 * this parameter because we should 112 * use content box dimensions always. 113 * 114 * The return value is the content-box size on the ratio-dependent axis. 115 * Plese see the definition of the ratio-dependent axis and the 116 * ratio-determining axis in the spec: 117 * https://drafts.csswg.org/css-sizing-4/#aspect-ratio 118 */ 119 [[nodiscard]] nscoord ComputeRatioDependentSize( 120 LogicalAxis aRatioDependentAxis, const WritingMode& aWM, 121 nscoord aRatioDeterminingSize, 122 const LogicalSize& aContentBoxSizeToBoxSizingAdjust) const; 123 124 bool operator==(const AspectRatio&) const = default; 125 bool operator!=(const AspectRatio&) const = default; 126 127 bool operator<(const AspectRatio& aOther) const { 128 MOZ_ASSERT( 129 mUseBoxSizing == aOther.mUseBoxSizing, 130 "Do not compare AspectRatio if their mUseBoxSizing are different."); 131 return mRatio < aOther.mRatio; 132 } 133 134 private: 135 // 0.0f represents no aspect ratio. 136 float mRatio = 0.0f; 137 UseBoxSizing mUseBoxSizing = UseBoxSizing::No; 138 }; 139 140 } // namespace mozilla 141 142 #endif // mozilla_AspectRatio_h