summaryrefslogtreecommitdiff
path: root/core/SkMallocPixelRef.cpp
blob: d3bf9d1870c811115cc01d703cac243861224cbd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
/*
 * Copyright 2011 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkMallocPixelRef.h"
#include "SkBitmap.h"
#include "SkFlattenableBuffers.h"

static bool is_valid(const SkImageInfo& info, SkColorTable* ctable) {
    if (info.fWidth < 0 ||
        info.fHeight < 0 ||
        (unsigned)info.fColorType > (unsigned)kLastEnum_SkColorType ||
        (unsigned)info.fAlphaType > (unsigned)kLastEnum_SkAlphaType)
    {
        return false;
    }
    
    // these seem like good checks, but currently we have (at least) tests
    // that expect the pixelref to succeed even when there is a mismatch
    // with colortables. fix?
#if 0
    if (kIndex8_SkColorType == info.fColorType && NULL == ctable) {
        return false;
    }
    if (kIndex8_SkColorType != info.fColorType && NULL != ctable) {
        return false;
    }
#endif
    return true;
}

SkMallocPixelRef* SkMallocPixelRef::NewDirect(const SkImageInfo& info,
                                              void* addr,
                                              size_t rowBytes,
                                              SkColorTable* ctable) {
    if (!is_valid(info, ctable)) {
        return NULL;
    }
    return SkNEW_ARGS(SkMallocPixelRef, (info, addr, rowBytes, ctable, false));
}

SkMallocPixelRef* SkMallocPixelRef::NewAllocate(const SkImageInfo& info,
                                                size_t requestedRowBytes,
                                                SkColorTable* ctable) {
    if (!is_valid(info, ctable)) {
        return NULL;
    }

    int32_t minRB = info.minRowBytes();
    if (minRB < 0) {
        return NULL;    // allocation will be too large
    }
    if (requestedRowBytes > 0 && (int32_t)requestedRowBytes < minRB) {
        return NULL;    // cannot meet requested rowbytes
    }

    int32_t rowBytes;
    if (requestedRowBytes) {
        rowBytes = requestedRowBytes;
    } else {
        rowBytes = minRB;
    }

    Sk64 bigSize;
    bigSize.setMul(info.fHeight, rowBytes);
    if (!bigSize.is32()) {
        return NULL;
    }

    size_t size = bigSize.get32();
    void* addr = sk_malloc_flags(size, 0);
    if (NULL == addr) {
        return NULL;
    }

    return SkNEW_ARGS(SkMallocPixelRef, (info, addr, rowBytes, ctable, true));
}

///////////////////////////////////////////////////////////////////////////////

SkMallocPixelRef::SkMallocPixelRef(const SkImageInfo& info, void* storage,
                                   size_t rowBytes, SkColorTable* ctable,
                                   bool ownsPixels)
    : INHERITED(info)
    , fOwnPixels(ownsPixels)
{
    SkASSERT(is_valid(info, ctable));
    SkASSERT(rowBytes >= info.minRowBytes());

    if (kIndex_8_SkColorType != info.fColorType) {
        ctable = NULL;
    }

    fStorage = storage;
    fCTable = ctable;
    fRB = rowBytes;
    SkSafeRef(ctable);
    
    this->setPreLocked(fStorage, fCTable);
}

SkMallocPixelRef::~SkMallocPixelRef() {
    SkSafeUnref(fCTable);
    if (fOwnPixels) {
        sk_free(fStorage);
    }
}

void* SkMallocPixelRef::onLockPixels(SkColorTable** ctable) {
    *ctable = fCTable;
    return fStorage;
}

void SkMallocPixelRef::onUnlockPixels() {
    // nothing to do
}

size_t SkMallocPixelRef::getAllocatedSizeInBytes() const {
    return this->info().getSafeSize(fRB);
}

void SkMallocPixelRef::flatten(SkFlattenableWriteBuffer& buffer) const {
    this->INHERITED::flatten(buffer);

    buffer.write32(fRB);

    // TODO: replace this bulk write with a chunky one that can trim off any
    // trailing bytes on each scanline (in case rowbytes > width*size)
    size_t size = this->info().getSafeSize(fRB);
    buffer.writeByteArray(fStorage, size);
    buffer.writeBool(fCTable != NULL);
    if (fCTable) {
        fCTable->writeToBuffer(buffer);
    }
}

SkMallocPixelRef::SkMallocPixelRef(SkFlattenableReadBuffer& buffer)
    : INHERITED(buffer, NULL)
    , fOwnPixels(true)
{
    fRB = buffer.read32();
    size_t size = buffer.isValid() ? this->info().getSafeSize(fRB) : 0;
    fStorage = sk_malloc_throw(size);
    buffer.readByteArray(fStorage, size);
    if (buffer.readBool()) {
        fCTable = SkNEW_ARGS(SkColorTable, (buffer));
    } else {
        fCTable = NULL;
    }

    this->setPreLocked(fStorage, fCTable);
}