Tools.h (6053B)
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_GFX_TOOLS_H_ 8 #define MOZILLA_GFX_TOOLS_H_ 9 10 #include <math.h> 11 12 #include <utility> 13 14 #include "Point.h" 15 #include "Types.h" 16 #include "mozilla/CheckedInt.h" 17 #include "mozilla/MemoryReporting.h" // for MallocSizeOf 18 19 namespace mozilla { 20 namespace gfx { 21 22 static inline bool IsOperatorBoundByMask(CompositionOp aOp) { 23 switch (aOp) { 24 case CompositionOp::OP_IN: 25 case CompositionOp::OP_OUT: 26 case CompositionOp::OP_DEST_IN: 27 case CompositionOp::OP_DEST_ATOP: 28 case CompositionOp::OP_SOURCE: 29 return false; 30 default: 31 return true; 32 } 33 } 34 35 template <class T> 36 struct ClassStorage { 37 char bytes[sizeof(T)]; 38 39 const T* addr() const { return (const T*)bytes; } 40 T* addr() { return (T*)(void*)bytes; } 41 }; 42 43 static inline bool FuzzyEqual(Float aA, Float aB, Float aErr) { 44 if ((aA + aErr >= aB) && (aA - aErr <= aB)) { 45 return true; 46 } 47 return false; 48 } 49 50 static inline void NudgeToInteger(float* aVal) { 51 float r = floorf(*aVal + 0.5f); 52 // The error threshold should be proportional to the rounded value. This 53 // bounds the relative error introduced by the nudge operation. However, 54 // when the rounded value is 0, the error threshold can't be proportional 55 // to the rounded value (we'd never round), so we just choose the same 56 // threshold as for a rounded value of 1. 57 if (FuzzyEqual(r, *aVal, r == 0.0f ? 1e-6f : fabs(r * 1e-6f))) { 58 *aVal = r; 59 } 60 } 61 62 static inline void NudgeToInteger(float* aVal, float aErr) { 63 float r = floorf(*aVal + 0.5f); 64 if (FuzzyEqual(r, *aVal, aErr)) { 65 *aVal = r; 66 } 67 } 68 69 static inline void NudgeToInteger(double* aVal) { 70 float f = float(*aVal); 71 NudgeToInteger(&f); 72 *aVal = f; 73 } 74 75 static inline Float Distance(Point aA, Point aB) { 76 return hypotf(aB.x - aA.x, aB.y - aA.y); 77 } 78 79 template <typename T, int alignment = 16> 80 struct AlignedArray final { 81 typedef T value_type; 82 83 AlignedArray() : mPtr(nullptr), mStorage(nullptr), mCount(0) {} 84 85 explicit MOZ_ALWAYS_INLINE AlignedArray(size_t aCount, bool aZero = false) 86 : mPtr(nullptr), mStorage(nullptr), mCount(0) { 87 Realloc(aCount, aZero); 88 } 89 90 MOZ_ALWAYS_INLINE ~AlignedArray() { Dealloc(); } 91 92 void Dealloc() { 93 // If we fail this assert we'll need to uncomment the loop below to make 94 // sure dtors are properly invoked. If we do that, we should check that the 95 // comment about compiler dead code elimination is in fact true for all the 96 // compilers that we care about. 97 static_assert(std::is_trivially_destructible<T>::value, 98 "Destructors must be invoked for this type"); 99 #if 0 100 for (size_t i = 0; i < mCount; ++i) { 101 // Since we used the placement |operator new| function to construct the 102 // elements of this array we need to invoke their destructors manually. 103 // For types where the destructor does nothing the compiler's dead code 104 // elimination step should optimize this loop away. 105 mPtr[i].~T(); 106 } 107 #endif 108 109 free(mStorage); 110 mStorage = nullptr; 111 mPtr = nullptr; 112 } 113 114 MOZ_ALWAYS_INLINE void Realloc(size_t aCount, bool aZero = false) { 115 free(mStorage); 116 CheckedInt32 storageByteCount = 117 CheckedInt32(sizeof(T)) * aCount + (alignment - 1); 118 if (!storageByteCount.isValid()) { 119 mStorage = nullptr; 120 mPtr = nullptr; 121 mCount = 0; 122 return; 123 } 124 // We don't create an array of T here, since we don't want ctors to be 125 // invoked at the wrong places if we realign below. 126 if (aZero) { 127 // calloc can be more efficient than new[] for large chunks, 128 // so we use calloc/malloc/free for everything. 129 mStorage = static_cast<uint8_t*>(calloc(1u, storageByteCount.value())); 130 } else { 131 mStorage = static_cast<uint8_t*>(malloc(storageByteCount.value())); 132 } 133 if (!mStorage) { 134 mStorage = nullptr; 135 mPtr = nullptr; 136 mCount = 0; 137 return; 138 } 139 if (uintptr_t(mStorage) % alignment) { 140 // Our storage does not start at a <alignment>-byte boundary. Make sure 141 // mPtr does! 142 mPtr = (T*)(uintptr_t(mStorage) + alignment - 143 (uintptr_t(mStorage) % alignment)); 144 } else { 145 mPtr = (T*)(mStorage); 146 } 147 // Now that mPtr is pointing to the aligned position we can use placement 148 // |operator new| to invoke any ctors at the correct positions. For types 149 // that have a no-op default constructor the compiler's dead code 150 // elimination step should optimize this away. 151 mPtr = new (mPtr) T[aCount]; 152 mCount = aCount; 153 } 154 155 void Swap(AlignedArray<T, alignment>& aOther) { 156 std::swap(mPtr, aOther.mPtr); 157 std::swap(mStorage, aOther.mStorage); 158 std::swap(mCount, aOther.mCount); 159 } 160 161 size_t HeapSizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const { 162 return aMallocSizeOf(mStorage); 163 } 164 165 MOZ_ALWAYS_INLINE operator T*() { return mPtr; } 166 167 T* mPtr; 168 169 private: 170 uint8_t* mStorage; 171 size_t mCount; 172 }; 173 174 /** 175 * Returns aWidth * aBytesPerPixel increased, if necessary, so that it divides 176 * exactly into |alignment|. 177 * 178 * Note that currently |alignment| must be a power-of-2. If for some reason we 179 * want to support NPOT alignment we can revert back to this functions old 180 * implementation. 181 */ 182 template <int alignment> 183 int32_t GetAlignedStride(int32_t aWidth, int32_t aBytesPerPixel) { 184 static_assert(alignment > 0 && (alignment & (alignment - 1)) == 0, 185 "This implementation currently require power-of-two alignment"); 186 const int32_t mask = alignment - 1; 187 CheckedInt32 stride = 188 CheckedInt32(aWidth) * CheckedInt32(aBytesPerPixel) + CheckedInt32(mask); 189 if (stride.isValid()) { 190 return stride.value() & ~mask; 191 } 192 return 0; 193 } 194 195 } // namespace gfx 196 } // namespace mozilla 197 198 #endif /* MOZILLA_GFX_TOOLS_H_ */