diff options
author | Herb Derby <herb@google.com> | 2018-02-28 14:03:18 -0500 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2018-03-06 19:56:47 +0000 |
commit | 8994150a436f0e813e9a7b8a2dc0ad237f4e3513 (patch) | |
tree | 0eccf683220dfe5643d276d83a71592c89dab4d0 | |
parent | be1b3971806e3d80aa9673a36e2b35d0145198ac (diff) |
Centralize mask byte calculations
These calculations are usually done in place around the code,
but most implementation don't take the care needed for safe calculation.
I have provided safe implementations for use around the code. It
will take a while to track down all the independant implementations
and convert them over.
BUG=skia:7515
Change-Id: Ice6a9be2e8e5ebef18d472adb26c17b03177ef47
Reviewed-on: https://skia-review.googlesource.com/111120
Reviewed-by: Mike Reed <reed@google.com>
Commit-Queue: Herb Derby <herb@google.com>
-rw-r--r-- | src/core/SkMask.cpp | 80 | ||||
-rw-r--r-- | src/core/SkMask.h | 6 |
2 files changed, 77 insertions, 9 deletions
diff --git a/src/core/SkMask.cpp b/src/core/SkMask.cpp index ea196f9e45..4e8ad29504 100644 --- a/src/core/SkMask.cpp +++ b/src/core/SkMask.cpp @@ -12,24 +12,86 @@ /** returns the product if it is positive and fits in 31 bits. Otherwise this returns 0. */ -static int32_t safeMul32(int32_t a, int32_t b) { - int64_t size = sk_64_mul(a, b); - if (size > 0 && sk_64_isS32(size)) { - return sk_64_asS32(size); +static size_t safe_mul(size_t a, size_t b) { + SkSafeMath safe; + size_t r = safe.mul(a, b); + if (safe) { + return r; } + return 0; } +static size_t safe_align4(size_t v) { + uint64_t adjusted = v + 3; + uint64_t possible = adjusted > v ? (adjusted & ~3) : 0; + return SkTFitsIn<size_t>(possible) ? possible : 0; +} + size_t SkMask::computeImageSize() const { - return safeMul32(fBounds.height(), fRowBytes); + auto height = fBounds.height(); + auto safeHeight = SkTo<uint32_t>(height >= 0 ? height : 0); + return safe_mul(safeHeight, fRowBytes); } size_t SkMask::computeTotalImageSize() const { - size_t size = this->computeImageSize(); - if (fFormat == SkMask::k3D_Format) { - size = safeMul32(SkToS32(size), 3); + return ComputeImageSize(fFormat, fBounds.width(), fBounds.height()); +} + +static size_t bits_to_bytes(size_t bits) { + return (bits + 7) >> 3; +} + +size_t SkMask::AlignmentForMask(SkMask::Format format) { + switch (format) { + case SkMask::kBW_Format: + return alignof(uint8_t); + case SkMask::kA8_Format: + return alignof(uint8_t); + case SkMask::k3D_Format: + return alignof(uint8_t); + case SkMask::kARGB32_Format: + return alignof(uint32_t); + case SkMask::kLCD16_Format: + return alignof(uint16_t); + default: + SK_ABORT("Unknown mask format."); + break; + } + // Should not reach here. + return alignof(uint64_t); +} + +size_t SkMask::ComputeRowBytes(SkMask::Format format, int32_t width) { + auto safeWidth = SkTo<uint32_t>(width >= 0 ? width : 0); + switch (format) { + case SkMask::kBW_Format: + // Always safe. + return SkTo<size_t>(bits_to_bytes(safeWidth)); + case SkMask::kA8_Format: + return safe_align4(static_cast<size_t>(safeWidth)); + case SkMask::k3D_Format: + return safe_align4(static_cast<size_t>(safeWidth)); + case SkMask::kARGB32_Format: + return safe_mul(safeWidth, sizeof(uint32_t)); + case SkMask::kLCD16_Format: + return safe_align4(safe_mul(safeWidth, sizeof(uint16_t))); + default: + SK_ABORT("Unknown mask format."); + break; + } + // Should not reach here. + return 0; +} + +size_t SkMask::ComputeImageSize(SkMask::Format format, int32_t width, int32_t height) { + size_t size = ComputeRowBytes(format, width); + if (format == SkMask::k3D_Format) { + size = safe_mul(size, 3); } - return size; + auto safeHeight = SkTo<uint32_t>(height >= 0 ? height : 0); + auto result = safe_mul(size, safeHeight); + return result; } /** We explicitly use this allocator for SkBimap pixels, so that we can diff --git a/src/core/SkMask.h b/src/core/SkMask.h index d4c5e3599c..c3150c895c 100644 --- a/src/core/SkMask.h +++ b/src/core/SkMask.h @@ -118,6 +118,12 @@ struct SkMask { kUninit_Alloc, kZeroInit_Alloc, }; + + static size_t AlignmentForMask(SkMask::Format format); + // Return 0 if overflow. + static size_t ComputeRowBytes(SkMask::Format format, int32_t width); + // Return 0 if overflow. + static size_t ComputeImageSize(SkMask::Format format, int32_t width, int32_t height); static uint8_t* AllocImage(size_t bytes, AllocType = kUninit_Alloc); static void FreeImage(void* image); |