aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Herb Derby <herb@google.com>2018-02-28 14:03:18 -0500
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2018-03-06 19:56:47 +0000
commit8994150a436f0e813e9a7b8a2dc0ad237f4e3513 (patch)
tree0eccf683220dfe5643d276d83a71592c89dab4d0
parentbe1b3971806e3d80aa9673a36e2b35d0145198ac (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.cpp80
-rw-r--r--src/core/SkMask.h6
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);