xref: /aosp_15_r20/external/skia/src/core/SkMask.h (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2006 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 #ifndef SkMask_DEFINED
9 #define SkMask_DEFINED
10 
11 #include "include/core/SkColorPriv.h"
12 #include "include/core/SkRect.h"
13 #include "include/private/SkColorData.h"
14 #include "include/private/base/SkAssert.h"
15 #include "include/private/base/SkTemplates.h"
16 
17 #include <cstddef>
18 #include <cstdint>
19 #include <memory>
20 
21 /** \class SkMask
22     SkMask is used to describe alpha bitmaps, either 1bit, 8bit, or
23     the 3-channel 3D format. These are passed to SkMaskFilter objects.
24 */
25 struct SkMask {
26     enum Format : uint8_t {
27         kBW_Format, //!< 1bit per pixel mask (e.g. monochrome)
28         kA8_Format, //!< 8bits per pixel mask (e.g. antialiasing)
29         k3D_Format, //!< 3 8bit per pixl planes: alpha, mul, add
30         kARGB32_Format,         //!< SkPMColor
31         kLCD16_Format,          //!< 565 alpha for r/g/b
32         kSDF_Format,            //!< 8bits representing signed distance field
33     };
34 
35     enum {
36         kCountMaskFormats = kSDF_Format + 1
37     };
38 
SkMaskSkMask39     SkMask(const uint8_t* img, const SkIRect& bounds, uint32_t rowBytes, Format format)
40         : fImage(img), fBounds(bounds), fRowBytes(rowBytes), fFormat(format) {}
41     uint8_t const * const fImage;
42     const SkIRect fBounds;
43     const uint32_t fRowBytes;
44     const Format fFormat;
45 
IsValidFormatSkMask46     static bool IsValidFormat(uint8_t format) { return format < kCountMaskFormats; }
47 
48     /** Returns true if the mask is empty: i.e. it has an empty bounds.
49      */
isEmptySkMask50     bool isEmpty() const { return fBounds.isEmpty(); }
51 
52     /** Return the byte size of the mask, assuming only 1 plane.
53         Does not account for k3D_Format. For that, use computeTotalImageSize().
54         If there is an overflow of 32bits, then returns 0.
55     */
56     size_t computeImageSize() const;
57 
58     /** Return the byte size of the mask, taking into account
59         any extra planes (e.g. k3D_Format).
60         If there is an overflow of 32bits, then returns 0.
61     */
62     size_t computeTotalImageSize() const;
63 
64     /** Returns the address of the byte that holds the specified bit.
65         Asserts that the mask is kBW_Format, and that x,y are in range.
66         x,y are in the same coordiate space as fBounds.
67     */
getAddr1SkMask68     const uint8_t* getAddr1(int x, int y) const {
69         SkASSERT(kBW_Format == fFormat);
70         SkASSERT(fBounds.contains(x, y));
71         SkASSERT(fImage != nullptr);
72         return fImage + ((x - fBounds.fLeft) >> 3) + (y - fBounds.fTop) * fRowBytes;
73     }
74 
75     /** Returns the address of the specified byte.
76         Asserts that the mask is kA8_Format, and that x,y are in range.
77         x,y are in the same coordiate space as fBounds.
78     */
getAddr8SkMask79     const uint8_t* getAddr8(int x, int y) const {
80         SkASSERT(kA8_Format == fFormat || kSDF_Format == fFormat);
81         SkASSERT(fBounds.contains(x, y));
82         SkASSERT(fImage != nullptr);
83         return fImage + x - fBounds.fLeft + (y - fBounds.fTop) * fRowBytes;
84     }
85 
86     /**
87      *  Return the address of the specified 16bit mask. In the debug build,
88      *  this asserts that the mask's format is kLCD16_Format, and that (x,y)
89      *  are contained in the mask's fBounds.
90      */
getAddrLCD16SkMask91     const uint16_t* getAddrLCD16(int x, int y) const {
92         SkASSERT(kLCD16_Format == fFormat);
93         SkASSERT(fBounds.contains(x, y));
94         SkASSERT(fImage != nullptr);
95         const uint16_t* row = (const uint16_t*)(fImage + (y - fBounds.fTop) * fRowBytes);
96         return row + (x - fBounds.fLeft);
97     }
98 
99     /**
100      *  Return the address of the specified 32bit mask. In the debug build,
101      *  this asserts that the mask's format is 32bits, and that (x,y)
102      *  are contained in the mask's fBounds.
103      */
getAddr32SkMask104     const uint32_t* getAddr32(int x, int y) const {
105         SkASSERT(kARGB32_Format == fFormat);
106         SkASSERT(fBounds.contains(x, y));
107         SkASSERT(fImage != nullptr);
108         const uint32_t* row = (const uint32_t*)(fImage + (y - fBounds.fTop) * fRowBytes);
109         return row + (x - fBounds.fLeft);
110     }
111 
112     /**
113      *  Returns the address of the specified pixel, computing the pixel-size
114      *  at runtime based on the mask format. This will be slightly slower than
115      *  using one of the routines where the format is implied by the name
116      *  e.g. getAddr8 or getAddr32.
117      *
118      *  x,y must be contained by the mask's bounds (this is asserted in the
119      *  debug build, but not checked in the release build.)
120      *
121      *  This should not be called with kBW_Format, as it will give unspecified
122      *  results (and assert in the debug build).
123      */
124     const void* getAddr(int x, int y) const;
125 
126     /** Iterates over the coverage values along a scanline in a given SkMask::Format. Provides
127      *  constructor, copy constructor for creating
128      *  operator++, operator-- for iterating over the coverage values on a scanline
129      *  operator>>= to add row bytes
130      *  operator* to get the coverage value at the current location
131      *  operator< to compare two iterators
132      */
133     template <Format F> struct AlphaIter;
134 };
135 
136 template <> struct SkMask::AlphaIter<SkMask::kBW_Format> {
137     AlphaIter(const uint8_t* ptr, int offset) : fPtr(ptr), fOffset(7 - offset) {}
138     AlphaIter(const AlphaIter& that) : fPtr(that.fPtr), fOffset(that.fOffset) {}
139     AlphaIter& operator++() {
140         if (0 < fOffset ) {
141             --fOffset;
142         } else {
143             ++fPtr;
144             fOffset = 7;
145         }
146         return *this;
147     }
148     AlphaIter& operator--() {
149         if (fOffset < 7) {
150             ++fOffset;
151         } else {
152             --fPtr;
153             fOffset = 0;
154         }
155         return *this;
156     }
157     AlphaIter& operator>>=(uint32_t rb) {
158         fPtr = SkTAddOffset<const uint8_t>(fPtr, rb);
159         return *this;
160     }
161     uint8_t operator*() const { return ((*fPtr) >> fOffset) & 1 ? 0xFF : 0; }
162     bool operator<(const AlphaIter& that) const {
163         return fPtr < that.fPtr || (fPtr == that.fPtr && fOffset > that.fOffset);
164     }
165     const uint8_t* fPtr;
166     int fOffset;
167 };
168 
169 template <> struct SkMask::AlphaIter<SkMask::kA8_Format> {
170     AlphaIter(const uint8_t* ptr) : fPtr(ptr) {}
171     AlphaIter(const AlphaIter& that) : fPtr(that.fPtr) {}
172     AlphaIter& operator++() { ++fPtr; return *this; }
173     AlphaIter& operator--() { --fPtr; return *this; }
174     AlphaIter& operator>>=(uint32_t rb) {
175         fPtr = SkTAddOffset<const uint8_t>(fPtr, rb);
176         return *this;
177     }
178     uint8_t operator*() const { return *fPtr; }
179     bool operator<(const AlphaIter& that) const { return fPtr < that.fPtr; }
180     const uint8_t* fPtr;
181 };
182 
183 template <> struct SkMask::AlphaIter<SkMask::kARGB32_Format> {
184     AlphaIter(const uint32_t* ptr) : fPtr(ptr) {}
185     AlphaIter(const AlphaIter& that) : fPtr(that.fPtr) {}
186     AlphaIter& operator++() { ++fPtr; return *this; }
187     AlphaIter& operator--() { --fPtr; return *this; }
188     AlphaIter& operator>>=(uint32_t rb) {
189         fPtr = SkTAddOffset<const uint32_t>(fPtr, rb);
190         return *this;
191     }
192     uint8_t operator*() const { return SkGetPackedA32(*fPtr); }
193     bool operator<(const AlphaIter& that) const { return fPtr < that.fPtr; }
194     const uint32_t* fPtr;
195 };
196 
197 template <> struct SkMask::AlphaIter<SkMask::kLCD16_Format> {
198     AlphaIter(const uint16_t* ptr) : fPtr(ptr) {}
199     AlphaIter(const AlphaIter& that) : fPtr(that.fPtr) {}
200     AlphaIter& operator++() { ++fPtr; return *this; }
201     AlphaIter& operator--() { --fPtr; return *this; }
202     AlphaIter& operator>>=(uint32_t rb) {
203         fPtr = SkTAddOffset<const uint16_t>(fPtr, rb);
204         return *this;
205     }
206     uint8_t operator*() const {
207         unsigned packed = *fPtr;
208         unsigned r = SkPacked16ToR32(packed);
209         unsigned g = SkPacked16ToG32(packed);
210         unsigned b = SkPacked16ToB32(packed);
211         return (r + g + b) / 3;
212     }
213     bool operator<(const AlphaIter& that) const { return fPtr < that.fPtr; }
214     const uint16_t* fPtr;
215 };
216 
217 ///////////////////////////////////////////////////////////////////////////////
218 
219 struct SkMaskBuilder : public SkMask {
220     SkMaskBuilder() : SkMask(nullptr, {0}, 0, SkMask::Format::kBW_Format) {}
221     SkMaskBuilder(const SkMaskBuilder&) = delete;
222     SkMaskBuilder(SkMaskBuilder&&) = default;
223     SkMaskBuilder& operator=(const SkMaskBuilder&) = delete;
224     SkMaskBuilder& operator=(SkMaskBuilder&& that) {
225         this->image() = that.image();
226         this->bounds() = that.bounds();
227         this->rowBytes() = that.rowBytes();
228         this->format() = that.format();
229         that.image() = nullptr;
230         return *this;
231     }
232 
233     SkMaskBuilder(uint8_t* img, const SkIRect& bounds, uint32_t rowBytes, Format format)
234         : SkMask(img, bounds, rowBytes, format) {}
235 
236     uint8_t*& image() { return *const_cast<uint8_t**>(&fImage); }
237     SkIRect& bounds() { return *const_cast<SkIRect*>(&fBounds); }
238     uint32_t& rowBytes() { return *const_cast<uint32_t*>(&fRowBytes); }
239     Format& format() { return *const_cast<Format*>(&fFormat); }
240 
241     /** Returns the address of the byte that holds the specified bit.
242         Asserts that the mask is kBW_Format, and that x,y are in range.
243         x,y are in the same coordiate space as fBounds.
244     */
245     uint8_t* getAddr1(int x, int y) {
246         return const_cast<uint8_t*>(this->SkMask::getAddr1(x, y));
247     }
248 
249     /** Returns the address of the specified byte.
250         Asserts that the mask is kA8_Format, and that x,y are in range.
251         x,y are in the same coordiate space as fBounds.
252     */
253     uint8_t* getAddr8(int x, int y) {
254         return const_cast<uint8_t*>(this->SkMask::getAddr8(x, y));
255     }
256 
257     /**
258      *  Return the address of the specified 16bit mask. In the debug build,
259      *  this asserts that the mask's format is kLCD16_Format, and that (x,y)
260      *  are contained in the mask's fBounds.
261      */
262     uint16_t* getAddrLCD16(int x, int y) {
263         return const_cast<uint16_t*>(this->SkMask::getAddrLCD16(x, y));
264     }
265 
266     /**
267      *  Return the address of the specified 32bit mask. In the debug build,
268      *  this asserts that the mask's format is 32bits, and that (x,y)
269      *  are contained in the mask's fBounds.
270      */
271     uint32_t* getAddr32(int x, int y) {
272         return const_cast<uint32_t*>(this->SkMask::getAddr32(x, y));
273     }
274 
275     /**
276      *  Returns the address of the specified pixel, computing the pixel-size
277      *  at runtime based on the mask format. This will be slightly slower than
278      *  using one of the routines where the format is implied by the name
279      *  e.g. getAddr8 or getAddr32.
280      *
281      *  x,y must be contained by the mask's bounds (this is asserted in the
282      *  debug build, but not checked in the release build.)
283      *
284      *  This should not be called with kBW_Format, as it will give unspecified
285      *  results (and assert in the debug build).
286      */
287     void* getAddr(int x, int y) {
288         return const_cast<void*>(this->SkMask::getAddr(x, y));
289     }
290 
291     enum AllocType {
292         kUninit_Alloc,
293         kZeroInit_Alloc,
294     };
295     static uint8_t* AllocImage(size_t bytes, AllocType = kUninit_Alloc);
296     static void FreeImage(void* image);
297 
298     enum CreateMode {
299         kJustComputeBounds_CreateMode,      //!< compute bounds and return
300         kJustRenderImage_CreateMode,        //!< render into preallocate mask
301         kComputeBoundsAndRenderImage_CreateMode  //!< compute bounds, alloc image and render into it
302     };
303 
304     /**
305      *  Returns initial destination mask data padded by radiusX and radiusY
306      */
307     static SkMaskBuilder PrepareDestination(int radiusX, int radiusY, const SkMask& src);
308 };
309 
310 /**
311  *  \using SkAutoMaskImage
312  *
313  *  Stack class used to manage the fImage buffer in a SkMask.
314  *  When this object loses scope, the buffer is freed with SkMask::FreeImage().
315  */
316 using SkAutoMaskFreeImage = std::unique_ptr<uint8_t, SkFunctionObject<SkMaskBuilder::FreeImage>>;
317 
318 #endif
319