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