11cab7e98be73388c67bfecc2845dd8c1278ea92
[platform/framework/web/crosswalk.git] / src / third_party / skia / src / core / SkData.cpp
1 /*
2  * Copyright 2011 Google Inc.
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 "SkData.h"
9 #include "SkLazyPtr.h"
10 #include "SkOSFile.h"
11 #include "SkReadBuffer.h"
12 #include "SkStream.h"
13 #include "SkWriteBuffer.h"
14
15 static void sk_inplace_sentinel_releaseproc(const void*, size_t, void*) {
16     // we should never get called, as we are just a sentinel
17     sk_throw();
18 }
19
20 SkData::SkData(const void* ptr, size_t size, ReleaseProc proc, void* context) {
21     fPtr = const_cast<void*>(ptr);
22     fSize = size;
23     fReleaseProc = proc;
24     fReleaseProcContext = context;
25 }
26
27 // This constructor means we are inline with our fPtr's contents. Thus we set fPtr
28 // to point right after this. We also set our releaseproc to sk_inplace_sentinel_releaseproc,
29 // since we need to handle "delete" ourselves. See internal_displose().
30 //
31 SkData::SkData(size_t size) {
32     fPtr = (char*)(this + 1);   // contents are immediately after this
33     fSize = size;
34     fReleaseProc = sk_inplace_sentinel_releaseproc;
35     fReleaseProcContext = NULL;
36 }
37
38 SkData::~SkData() {
39     if (fReleaseProc) {
40         fReleaseProc(fPtr, fSize, fReleaseProcContext);
41     }
42 }
43
44 void SkData::internal_dispose() const {
45     if (sk_inplace_sentinel_releaseproc == fReleaseProc) {
46         const_cast<SkData*>(this)->fReleaseProc = NULL;    // so we don't call it in our destructor
47
48         this->internal_dispose_restore_refcnt_to_1();
49         this->~SkData();        // explicitly call this for refcnt bookkeeping
50
51         sk_free(const_cast<SkData*>(this));
52     } else {
53         this->internal_dispose_restore_refcnt_to_1();
54         SkDELETE(this);
55     }
56 }
57
58 bool SkData::equals(const SkData* other) const {
59     if (NULL == other) {
60         return false;
61     }
62
63     return fSize == other->fSize && !memcmp(fPtr, other->fPtr, fSize);
64 }
65
66 size_t SkData::copyRange(size_t offset, size_t length, void* buffer) const {
67     size_t available = fSize;
68     if (offset >= available || 0 == length) {
69         return 0;
70     }
71     available -= offset;
72     if (length > available) {
73         length = available;
74     }
75     SkASSERT(length > 0);
76
77     memcpy(buffer, this->bytes() + offset, length);
78     return length;
79 }
80
81 SkData* SkData::PrivateNewWithCopy(const void* srcOrNull, size_t length) {
82     if (0 == length) {
83         return SkData::NewEmpty();
84     }
85     char* storage = (char*)sk_malloc_throw(sizeof(SkData) + length);
86     SkData* data = new (storage) SkData(length);
87     if (srcOrNull) {
88         memcpy(data->writable_data(), srcOrNull, length);
89     }
90     return data;
91 }
92
93 ///////////////////////////////////////////////////////////////////////////////
94
95 SkData* SkData::NewEmptyImpl() {
96     return new SkData(NULL, 0, NULL, NULL);
97 }
98
99 void SkData::DeleteEmpty(SkData* ptr) { SkDELETE(ptr); }
100
101 SkData* SkData::NewEmpty() {
102     SK_DECLARE_STATIC_LAZY_PTR(SkData, empty, NewEmptyImpl, DeleteEmpty);
103     return SkRef(empty.get());
104 }
105
106 // assumes fPtr was allocated via sk_malloc
107 static void sk_free_releaseproc(const void* ptr, size_t, void*) {
108     sk_free((void*)ptr);
109 }
110
111 SkData* SkData::NewFromMalloc(const void* data, size_t length) {
112     return new SkData(data, length, sk_free_releaseproc, NULL);
113 }
114
115 SkData* SkData::NewWithCopy(const void* src, size_t length) {
116     SkASSERT(src);
117     return PrivateNewWithCopy(src, length);
118 }
119
120 SkData* SkData::NewUninitialized(size_t length) {
121     return PrivateNewWithCopy(NULL, length);
122 }
123
124 SkData* SkData::NewWithProc(const void* data, size_t length,
125                             ReleaseProc proc, void* context) {
126     return new SkData(data, length, proc, context);
127 }
128
129 // assumes fPtr was allocated with sk_fmmap
130 static void sk_mmap_releaseproc(const void* addr, size_t length, void*) {
131     sk_fmunmap(addr, length);
132 }
133
134 SkData* SkData::NewFromFILE(SkFILE* f) {
135     size_t size;
136     void* addr = sk_fmmap(f, &size);
137     if (NULL == addr) {
138         return NULL;
139     }
140
141     return SkData::NewWithProc(addr, size, sk_mmap_releaseproc, NULL);
142 }
143
144 SkData* SkData::NewFromFileName(const char path[]) {
145     SkFILE* f = path ? sk_fopen(path, kRead_SkFILE_Flag) : NULL;
146     if (NULL == f) {
147         return NULL;
148     }
149     SkData* data = NewFromFILE(f);
150     sk_fclose(f);
151     return data;
152 }
153
154 SkData* SkData::NewFromFD(int fd) {
155     size_t size;
156     void* addr = sk_fdmmap(fd, &size);
157     if (NULL == addr) {
158         return NULL;
159     }
160
161     return SkData::NewWithProc(addr, size, sk_mmap_releaseproc, NULL);
162 }
163
164 // assumes context is a SkData
165 static void sk_dataref_releaseproc(const void*, size_t, void* context) {
166     SkData* src = reinterpret_cast<SkData*>(context);
167     src->unref();
168 }
169
170 SkData* SkData::NewSubset(const SkData* src, size_t offset, size_t length) {
171     /*
172         We could, if we wanted/need to, just make a deep copy of src's data,
173         rather than referencing it. This would duplicate the storage (of the
174         subset amount) but would possibly allow src to go out of scope sooner.
175      */
176
177     size_t available = src->size();
178     if (offset >= available || 0 == length) {
179         return SkData::NewEmpty();
180     }
181     available -= offset;
182     if (length > available) {
183         length = available;
184     }
185     SkASSERT(length > 0);
186
187     src->ref(); // this will be balanced in sk_dataref_releaseproc
188     return new SkData(src->bytes() + offset, length, sk_dataref_releaseproc,
189                          const_cast<SkData*>(src));
190 }
191
192 SkData* SkData::NewWithCString(const char cstr[]) {
193     size_t size;
194     if (NULL == cstr) {
195         cstr = "";
196         size = 1;
197     } else {
198         size = strlen(cstr) + 1;
199     }
200     return NewWithCopy(cstr, size);
201 }
202
203 ///////////////////////////////////////////////////////////////////////////////
204
205 SkData* SkData::NewFromStream(SkStream* stream, size_t size) {
206     SkAutoDataUnref data(SkData::NewUninitialized(size));
207     if (stream->read(data->writable_data(), size) != size) {
208         return NULL;
209     }
210     return data.detach();
211 }
212