1 /*
2 * Copyright 2007 The Android Open Source Project
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "src/core/SkMask.h"
9
10 #include "include/private/base/SkMalloc.h"
11 #include "include/private/base/SkMath.h"
12 #include "include/private/base/SkTFitsIn.h"
13 #include "include/private/base/SkTo.h"
14 #include "src/base/SkSafeMath.h"
15
16 #include <array>
17 #include <climits>
18
19 /** returns the product if it is positive and fits in 31 bits. Otherwise this
20 returns 0.
21 */
safeMul32(int32_t a,int32_t b)22 static int32_t safeMul32(int32_t a, int32_t b) {
23 int64_t size = sk_64_mul(a, b);
24 if (size > 0 && SkTFitsIn<int32_t>(size)) {
25 return size;
26 }
27 return 0;
28 }
29
computeImageSize() const30 size_t SkMask::computeImageSize() const {
31 return safeMul32(fBounds.height(), fRowBytes);
32 }
33
computeTotalImageSize() const34 size_t SkMask::computeTotalImageSize() const {
35 size_t size = this->computeImageSize();
36 if (fFormat == SkMask::k3D_Format) {
37 size = safeMul32(SkToS32(size), 3);
38 }
39 return size;
40 }
41
42 /** We explicitly use this allocator for SkBimap pixels, so that we can
43 freely assign memory allocated by one class to the other.
44 */
AllocImage(size_t size,AllocType at)45 uint8_t* SkMaskBuilder::AllocImage(size_t size, AllocType at) {
46 size_t aligned_size = SkSafeMath::Align4(size);
47 unsigned flags = SK_MALLOC_THROW;
48 if (at == kZeroInit_Alloc) {
49 flags |= SK_MALLOC_ZERO_INITIALIZE;
50 }
51 return static_cast<uint8_t*>(sk_malloc_flags(aligned_size, flags));
52 }
53
54 /** We explicitly use this allocator for SkBimap pixels, so that we can
55 freely assign memory allocated by one class to the other.
56 */
FreeImage(void * image)57 void SkMaskBuilder::FreeImage(void* image) {
58 sk_free(image);
59 }
60
PrepareDestination(int radiusX,int radiusY,const SkMask & src)61 SkMaskBuilder SkMaskBuilder::PrepareDestination(int radiusX, int radiusY, const SkMask& src) {
62 SkSafeMath safe;
63
64 SkMaskBuilder dst;
65 dst.image() = nullptr;
66 dst.format() = SkMask::kA8_Format;
67
68 // dstW = srcW + 2 * radiusX;
69 size_t dstW = safe.add(src.fBounds.width(), safe.add(radiusX, radiusX));
70 // dstH = srcH + 2 * radiusY;
71 size_t dstH = safe.add(src.fBounds.height(), safe.add(radiusY, radiusY));
72
73 size_t toAlloc = safe.mul(dstW, dstH);
74
75 // We can only deal with masks that fit in INT_MAX and sides that fit in int.
76 if (!SkTFitsIn<int>(dstW) || !SkTFitsIn<int>(dstH) || toAlloc > INT_MAX || !safe) {
77 dst.bounds().setEmpty();
78 dst.rowBytes() = 0;
79 return dst;
80 }
81
82 dst.bounds().setWH(SkTo<int>(dstW), SkTo<int>(dstH));
83 dst.bounds().offset(src.fBounds.x(), src.fBounds.y());
84 dst.bounds().offset(-radiusX, -radiusY);
85 dst.rowBytes() = SkTo<uint32_t>(dstW);
86
87 if (src.fImage != nullptr) {
88 dst.image() = SkMaskBuilder::AllocImage(toAlloc);
89 }
90
91 return dst;
92 }
93
94
95 ///////////////////////////////////////////////////////////////////////////////
96
97 static const int gMaskFormatToShift[] = {
98 ~0, // BW -- not supported
99 0, // A8
100 0, // 3D
101 2, // ARGB32
102 1, // LCD16
103 0, // SDF
104 };
105
maskFormatToShift(SkMask::Format format)106 static int maskFormatToShift(SkMask::Format format) {
107 SkASSERT((unsigned)format < std::size(gMaskFormatToShift));
108 SkASSERT(SkMask::kBW_Format != format);
109 return gMaskFormatToShift[format];
110 }
111
getAddr(int x,int y) const112 const void* SkMask::getAddr(int x, int y) const {
113 SkASSERT(kBW_Format != fFormat);
114 SkASSERT(fBounds.contains(x, y));
115 SkASSERT(fImage);
116
117 const char* addr = (const char*)fImage;
118 addr += (y - fBounds.fTop) * fRowBytes;
119 addr += (x - fBounds.fLeft) << maskFormatToShift(fFormat);
120 return addr;
121 }
122