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