xref: /aosp_15_r20/external/skia/src/core/SkMask.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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