| // Copyright 2015 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef CC_RESOURCES_RESOURCE_UTIL_H_ |
| #define CC_RESOURCES_RESOURCE_UTIL_H_ |
| |
| #include <stddef.h> |
| |
| #include <limits> |
| |
| #include "base/macros.h" |
| #include "base/numerics/safe_math.h" |
| #include "cc/base/cc_export.h" |
| #include "cc/base/math_util.h" |
| #include "cc/resources/resource_format.h" |
| #include "ui/gfx/geometry/size.h" |
| |
| namespace cc { |
| |
| class CC_EXPORT ResourceUtil { |
| public: |
| // Returns true if the width is valid and fits in bytes, false otherwise. |
| template <typename T> |
| static bool VerifyWidthInBytes(int width, ResourceFormat format); |
| // Returns true if the size is valid and fits in bytes, false otherwise. |
| template <typename T> |
| static bool VerifySizeInBytes(const gfx::Size& size, ResourceFormat format); |
| |
| // Dies with a CRASH() if the width can not be represented as a positive |
| // number of bytes. |
| template <typename T> |
| static T CheckedWidthInBytes(int width, ResourceFormat format); |
| // Dies with a CRASH() if the size can not be represented as a positive |
| // number of bytes. |
| template <typename T> |
| static T CheckedSizeInBytes(const gfx::Size& size, ResourceFormat format); |
| |
| // Returns the width in bytes but may overflow or return 0. Only do this for |
| // computing widths for sizes that have already been checked. |
| template <typename T> |
| static T UncheckedWidthInBytes(int width, ResourceFormat format); |
| // Returns the size in bytes but may overflow or return 0. Only do this for |
| // sizes that have already been checked. |
| template <typename T> |
| static T UncheckedSizeInBytes(const gfx::Size& size, ResourceFormat format); |
| // Returns the width in bytes aligned but may overflow or return 0. Only do |
| // this for computing widths for sizes that have already been checked. |
| template <typename T> |
| static T UncheckedWidthInBytesAligned(int width, ResourceFormat format); |
| // Returns the size in bytes aligned but may overflow or return 0. Only do |
| // this for sizes that have already been checked. |
| template <typename T> |
| static T UncheckedSizeInBytesAligned(const gfx::Size& size, |
| ResourceFormat format); |
| |
| private: |
| template <typename T> |
| static inline void VerifyType(); |
| |
| template <typename T> |
| static bool VerifyFitsInBytesInternal(int width, |
| int height, |
| ResourceFormat format, |
| bool verify_size, |
| bool aligned); |
| |
| template <typename T> |
| static T BytesInternal(int width, |
| int height, |
| ResourceFormat format, |
| bool verify_size, |
| bool aligned); |
| |
| DISALLOW_COPY_AND_ASSIGN(ResourceUtil); |
| }; |
| |
| template <typename T> |
| bool ResourceUtil::VerifyWidthInBytes(int width, ResourceFormat format) { |
| VerifyType<T>(); |
| return VerifyFitsInBytesInternal<T>(width, 0, format, false, false); |
| } |
| |
| template <typename T> |
| bool ResourceUtil::VerifySizeInBytes(const gfx::Size& size, |
| ResourceFormat format) { |
| VerifyType<T>(); |
| return VerifyFitsInBytesInternal<T>(size.width(), size.height(), format, true, |
| false); |
| } |
| |
| template <typename T> |
| T ResourceUtil::CheckedWidthInBytes(int width, ResourceFormat format) { |
| VerifyType<T>(); |
| DCHECK(VerifyFitsInBytesInternal<T>(width, 0, format, false, false)); |
| base::CheckedNumeric<T> checked_value = BitsPerPixel(format); |
| checked_value *= width; |
| checked_value = MathUtil::CheckedRoundUp<T>(checked_value.ValueOrDie(), 8); |
| checked_value /= 8; |
| return checked_value.ValueOrDie(); |
| } |
| |
| template <typename T> |
| T ResourceUtil::CheckedSizeInBytes(const gfx::Size& size, |
| ResourceFormat format) { |
| VerifyType<T>(); |
| DCHECK(VerifyFitsInBytesInternal<T>(size.width(), size.height(), format, true, |
| false)); |
| base::CheckedNumeric<T> checked_value = BitsPerPixel(format); |
| checked_value *= size.width(); |
| checked_value = MathUtil::CheckedRoundUp<T>(checked_value.ValueOrDie(), 8); |
| checked_value /= 8; |
| checked_value *= size.height(); |
| return checked_value.ValueOrDie(); |
| } |
| |
| template <typename T> |
| T ResourceUtil::UncheckedWidthInBytes(int width, ResourceFormat format) { |
| VerifyType<T>(); |
| DCHECK(VerifyFitsInBytesInternal<T>(width, 0, format, false, false)); |
| return BytesInternal<T>(width, 0, format, false, false); |
| } |
| |
| template <typename T> |
| T ResourceUtil::UncheckedSizeInBytes(const gfx::Size& size, |
| ResourceFormat format) { |
| VerifyType<T>(); |
| DCHECK(VerifyFitsInBytesInternal<T>(size.width(), size.height(), format, true, |
| false)); |
| return BytesInternal<T>(size.width(), size.height(), format, true, false); |
| } |
| |
| template <typename T> |
| T ResourceUtil::UncheckedWidthInBytesAligned(int width, ResourceFormat format) { |
| VerifyType<T>(); |
| DCHECK(VerifyFitsInBytesInternal<T>(width, 0, format, false, true)); |
| return BytesInternal<T>(width, 0, format, false, true); |
| } |
| |
| template <typename T> |
| T ResourceUtil::UncheckedSizeInBytesAligned(const gfx::Size& size, |
| ResourceFormat format) { |
| VerifyType<T>(); |
| DCHECK(VerifyFitsInBytesInternal<T>(size.width(), size.height(), format, true, |
| true)); |
| return BytesInternal<T>(size.width(), size.height(), format, true, true); |
| } |
| |
| template <typename T> |
| void ResourceUtil::VerifyType() { |
| static_assert( |
| std::numeric_limits<T>::is_integer && !std::is_same<T, bool>::value, |
| "T must be non-bool integer type. Preferred type is size_t."); |
| } |
| |
| template <typename T> |
| bool ResourceUtil::VerifyFitsInBytesInternal(int width, |
| int height, |
| ResourceFormat format, |
| bool verify_size, |
| bool aligned) { |
| base::CheckedNumeric<T> checked_value = BitsPerPixel(format); |
| checked_value *= width; |
| if (!checked_value.IsValid()) |
| return false; |
| |
| // Roundup bits to byte (8 bits) boundary. If width is 3 and BitsPerPixel is |
| // 4, then it should return 16, so that row pixels do not get truncated. |
| checked_value = MathUtil::UncheckedRoundUp<T>(checked_value.ValueOrDie(), 8); |
| |
| // If aligned is true, bytes are aligned on 4-bytes boundaries for upload |
| // performance, assuming that GL_PACK_ALIGNMENT or GL_UNPACK_ALIGNMENT have |
| // not changed from default. |
| if (aligned) { |
| checked_value /= 8; |
| if (!checked_value.IsValid()) |
| return false; |
| checked_value = |
| MathUtil::UncheckedRoundUp<T>(checked_value.ValueOrDie(), 4); |
| checked_value *= 8; |
| } |
| |
| if (verify_size) |
| checked_value *= height; |
| if (!checked_value.IsValid()) |
| return false; |
| T value = checked_value.ValueOrDie(); |
| if ((value % 8) != 0) |
| return false; |
| return true; |
| } |
| |
| template <typename T> |
| T ResourceUtil::BytesInternal(int width, |
| int height, |
| ResourceFormat format, |
| bool verify_size, |
| bool aligned) { |
| T bytes = BitsPerPixel(format); |
| bytes *= width; |
| bytes = MathUtil::UncheckedRoundUp<T>(bytes, 8); |
| bytes /= 8; |
| if (aligned) |
| bytes = MathUtil::UncheckedRoundUp<T>(bytes, 4); |
| if (verify_size) |
| bytes *= height; |
| |
| return bytes; |
| } |
| |
| } // namespace cc |
| |
| #endif // CC_RESOURCES_RESOURCE_UTIL_H_ |