Vertical flow support for OpenType fonts with the least platform dependencies
[WebKit-https.git] / Source / WebCore / platform / SharedBuffer.cpp
1 /*
2  * Copyright (C) 2006, 2008 Apple Inc. All rights reserved.
3  * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
25  */
26
27 #include "config.h"
28 #include "SharedBuffer.h"
29
30 #include "PurgeableBuffer.h"
31 #include <wtf/PassOwnPtr.h>
32
33 using namespace std;
34
35 namespace WebCore {
36
37 static const unsigned segmentSize = 0x1000;
38 static const unsigned segmentPositionMask = 0x0FFF;
39
40 static inline unsigned segmentIndex(unsigned position)
41 {
42     return position / segmentSize;
43 }
44
45 static inline unsigned offsetInSegment(unsigned position)
46 {
47     return position & segmentPositionMask;
48 }
49
50 static inline char* allocateSegment()
51 {
52     return static_cast<char*>(fastMalloc(segmentSize));
53 }
54
55 static inline void freeSegment(char* p)
56 {
57     fastFree(p);
58 }
59
60 SharedBuffer::SharedBuffer()
61     : m_size(0)
62 {
63 }
64
65 SharedBuffer::SharedBuffer(size_t size)
66     : m_size(size)
67     , m_buffer(size)
68 {
69 }
70
71 SharedBuffer::SharedBuffer(const char* data, int size)
72     : m_size(0)
73 {
74     // FIXME: Use unsigned consistently, and check for invalid casts when calling into SharedBuffer from other code.
75     if (size < 0)
76         CRASH();
77
78     append(data, size);
79 }
80
81 SharedBuffer::SharedBuffer(const unsigned char* data, int size)
82     : m_size(0)
83 {
84     // FIXME: Use unsigned consistently, and check for invalid casts when calling into SharedBuffer from other code.
85     if (size < 0)
86         CRASH();
87
88     append(reinterpret_cast<const char*>(data), size);
89 }
90     
91 SharedBuffer::~SharedBuffer()
92 {
93     clear();
94 }
95
96 PassRefPtr<SharedBuffer> SharedBuffer::adoptVector(Vector<char>& vector)
97 {
98     RefPtr<SharedBuffer> buffer = create();
99     buffer->m_buffer.swap(vector);
100     buffer->m_size = buffer->m_buffer.size();
101     return buffer.release();
102 }
103
104 PassRefPtr<SharedBuffer> SharedBuffer::adoptPurgeableBuffer(PassOwnPtr<PurgeableBuffer> purgeableBuffer) 
105
106     ASSERT(!purgeableBuffer->isPurgeable());
107     RefPtr<SharedBuffer> buffer = create();
108     buffer->m_purgeableBuffer = purgeableBuffer;
109     return buffer.release();
110 }
111
112 unsigned SharedBuffer::size() const
113 {
114     if (hasPlatformData())
115         return platformDataSize();
116     
117     if (m_purgeableBuffer)
118         return m_purgeableBuffer->size();
119     
120     return m_size;
121 }
122
123 const char* SharedBuffer::data() const
124 {
125     if (hasPlatformData())
126         return platformData();
127     
128     if (m_purgeableBuffer)
129         return m_purgeableBuffer->data();
130     
131     return buffer().data();
132 }
133
134 void SharedBuffer::append(SharedBuffer* data)
135 {
136     const char* segment;
137     size_t position = 0;
138     while (size_t length = data->getSomeData(segment, position)) {
139         append(segment, length);
140         position += length;
141     }
142 }
143
144 void SharedBuffer::append(const char* data, unsigned length)
145 {
146     ASSERT(!m_purgeableBuffer);
147
148     maybeTransferPlatformData();
149     
150     unsigned positionInSegment = offsetInSegment(m_size - m_buffer.size());
151     m_size += length;
152
153     if (m_size <= segmentSize) {
154         // No need to use segments for small resource data
155         m_buffer.append(data, length);
156         return;
157     }
158
159     char* segment;
160     if (!positionInSegment) {
161         segment = allocateSegment();
162         m_segments.append(segment);
163     } else
164         segment = m_segments.last() + positionInSegment;
165
166     unsigned segmentFreeSpace = segmentSize - positionInSegment;
167     unsigned bytesToCopy = min(length, segmentFreeSpace);
168
169     for (;;) {
170         memcpy(segment, data, bytesToCopy);
171         if (static_cast<unsigned>(length) == bytesToCopy)
172             break;
173
174         length -= bytesToCopy;
175         data += bytesToCopy;
176         segment = allocateSegment();
177         m_segments.append(segment);
178         bytesToCopy = min(length, segmentSize);
179     }
180 }
181
182 void SharedBuffer::append(const Vector<char>& data)
183 {
184     append(data.data(), data.size());
185 }
186
187 void SharedBuffer::clear()
188 {
189     clearPlatformData();
190     
191     for (unsigned i = 0; i < m_segments.size(); ++i)
192         freeSegment(m_segments[i]);
193
194     m_segments.clear();
195     m_size = 0;
196
197     m_buffer.clear();
198     m_purgeableBuffer.clear();
199 #if HAVE(NETWORK_CFDATA_ARRAY_CALLBACK)
200     m_dataArray.clear();
201 #endif
202 }
203
204 PassRefPtr<SharedBuffer> SharedBuffer::copy() const
205 {
206     RefPtr<SharedBuffer> clone(adoptRef(new SharedBuffer));
207     if (m_purgeableBuffer || hasPlatformData()) {
208         clone->append(data(), size());
209         return clone;
210     }
211
212     clone->m_size = m_size;
213     clone->m_buffer.reserveCapacity(m_size);
214     clone->m_buffer.append(m_buffer.data(), m_buffer.size());
215     for (unsigned i = 0; i < m_segments.size(); ++i)
216         clone->m_buffer.append(m_segments[i], segmentSize);
217     return clone;
218 }
219
220 PassOwnPtr<PurgeableBuffer> SharedBuffer::releasePurgeableBuffer()
221
222     ASSERT(hasOneRef()); 
223     return m_purgeableBuffer.release(); 
224 }
225
226 const Vector<char>& SharedBuffer::buffer() const
227 {
228     unsigned bufferSize = m_buffer.size();
229     if (m_size > bufferSize) {
230         m_buffer.resize(m_size);
231         char* destination = m_buffer.data() + bufferSize;
232         unsigned bytesLeft = m_size - bufferSize;
233         for (unsigned i = 0; i < m_segments.size(); ++i) {
234             unsigned bytesToCopy = min(bytesLeft, segmentSize);
235             memcpy(destination, m_segments[i], bytesToCopy);
236             destination += bytesToCopy;
237             bytesLeft -= bytesToCopy;
238             freeSegment(m_segments[i]);
239         }
240         m_segments.clear();
241 #if HAVE(NETWORK_CFDATA_ARRAY_CALLBACK)
242         copyDataArrayAndClear(destination, bytesLeft);
243 #endif
244     }
245     return m_buffer;
246 }
247
248 unsigned SharedBuffer::getSomeData(const char*& someData, unsigned position) const
249 {
250     unsigned totalSize = size();
251     if (position >= totalSize) {
252         someData = 0;
253         return 0;
254     }
255
256     if (hasPlatformData() || m_purgeableBuffer) {
257         ASSERT(position < size());
258         someData = data() + position;
259         return totalSize - position;
260     }
261
262     ASSERT(position < m_size);
263     unsigned consecutiveSize = m_buffer.size();
264     if (position < consecutiveSize) {
265         someData = m_buffer.data() + position;
266         return consecutiveSize - position;
267     }
268  
269     position -= consecutiveSize;
270     unsigned segments = m_segments.size();
271     unsigned maxSegmentedSize = segments * segmentSize;
272     unsigned segment = segmentIndex(position);
273     if (segment < segments) {
274         unsigned bytesLeft = totalSize - consecutiveSize;
275         unsigned segmentedSize = min(maxSegmentedSize, bytesLeft);
276
277         unsigned positionInSegment = offsetInSegment(position);
278         someData = m_segments[segment] + positionInSegment;
279         return segment == segments - 1 ? segmentedSize - position : segmentSize - positionInSegment;
280     }
281 #if HAVE(NETWORK_CFDATA_ARRAY_CALLBACK)
282     ASSERT(maxSegmentedSize <= position);
283     position -= maxSegmentedSize;
284     return copySomeDataFromDataArray(someData, position);
285 #else
286     ASSERT_NOT_REACHED();
287     return 0;
288 #endif
289 }
290
291 #if !USE(CF) || PLATFORM(QT)
292
293 inline void SharedBuffer::clearPlatformData()
294 {
295 }
296
297 inline void SharedBuffer::maybeTransferPlatformData()
298 {
299 }
300
301 inline bool SharedBuffer::hasPlatformData() const
302 {
303     return false;
304 }
305
306 inline const char* SharedBuffer::platformData() const
307 {
308     ASSERT_NOT_REACHED();
309
310     return 0;
311 }
312
313 inline unsigned SharedBuffer::platformDataSize() const
314 {
315     ASSERT_NOT_REACHED();
316     
317     return 0;
318 }
319
320 #endif
321
322 }