Move WebCore into Source
[WebKit-https.git] / Source / WebCore / html / canvas / WebGLBuffer.cpp
1 /*
2  * Copyright (C) 2009 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 #include "config.h"
27
28 #if ENABLE(3D_CANVAS)
29
30 #include "WebGLBuffer.h"
31
32 #include "ArrayBufferView.h"
33 #include "CheckedInt.h"
34 #include "WebGLRenderingContext.h"
35
36 namespace WebCore {
37     
38 PassRefPtr<WebGLBuffer> WebGLBuffer::create(WebGLRenderingContext* ctx)
39 {
40     return adoptRef(new WebGLBuffer(ctx));
41 }
42
43 WebGLBuffer::WebGLBuffer(WebGLRenderingContext* ctx)
44     : WebGLObject(ctx)
45     , m_target(0)
46     , m_byteLength(0)
47     , m_nextAvailableCacheEntry(0)
48 {
49     setObject(context()->graphicsContext3D()->createBuffer());
50     clearCachedMaxIndices();
51 }
52
53 void WebGLBuffer::deleteObjectImpl(Platform3DObject object)
54 {
55     context()->graphicsContext3D()->deleteBuffer(object);
56 }
57
58 bool WebGLBuffer::associateBufferDataImpl(ArrayBuffer* array, unsigned byteOffset, unsigned byteLength)
59 {
60     if (array && byteLength) {
61         CheckedInt<uint32_t> checkedOffset(byteOffset);
62         CheckedInt<uint32_t> checkedLength(byteLength);
63         CheckedInt<uint32_t> checkedMax = checkedOffset + checkedLength;
64         if (!checkedMax.valid() || checkedMax.value() > array->byteLength())
65             return false;
66     }
67
68     switch (m_target) {
69     case GraphicsContext3D::ELEMENT_ARRAY_BUFFER:
70         m_byteLength = byteLength;
71         clearCachedMaxIndices();
72         if (byteLength) {
73             m_elementArrayBuffer = ArrayBuffer::create(byteLength, 1);
74             if (!m_elementArrayBuffer) {
75                 m_byteLength = 0;
76                 return false;
77             }
78             if (array) {
79                 // We must always clone the incoming data because client-side
80                 // modifications without calling bufferData or bufferSubData
81                 // must never be able to change the validation results.
82                 memcpy(static_cast<unsigned char*>(m_elementArrayBuffer->data()),
83                        static_cast<unsigned char*>(array->data()) + byteOffset,
84                        byteLength);
85             }
86         } else
87             m_elementArrayBuffer = 0;
88         return true;
89     case GraphicsContext3D::ARRAY_BUFFER:
90         m_byteLength = byteLength;
91         return true;
92     default:
93         return false;
94     }
95 }
96
97 bool WebGLBuffer::associateBufferData(int size)
98 {
99     if (size < 0)
100         return false;
101     return associateBufferDataImpl(0, 0, static_cast<unsigned>(size));
102 }
103
104 bool WebGLBuffer::associateBufferData(ArrayBuffer* array)
105 {
106     if (!array)
107         return false;
108     return associateBufferDataImpl(array, 0, array->byteLength());
109 }
110
111 bool WebGLBuffer::associateBufferData(ArrayBufferView* array)
112 {
113     if (!array)
114         return false;
115     return associateBufferDataImpl(array->buffer().get(), array->byteOffset(), array->byteLength());
116 }
117
118 bool WebGLBuffer::associateBufferSubDataImpl(long offset, ArrayBuffer* array, unsigned arrayByteOffset, unsigned byteLength)
119 {
120     if (!array || offset < 0)
121         return false;
122
123     if (byteLength) {
124         CheckedInt<uint32_t> checkedBufferOffset(offset);
125         CheckedInt<uint32_t> checkedArrayOffset(arrayByteOffset);
126         CheckedInt<uint32_t> checkedLength(byteLength);
127         CheckedInt<uint32_t> checkedArrayMax = checkedArrayOffset + checkedLength;
128         CheckedInt<uint32_t> checkedBufferMax = checkedBufferOffset + checkedLength;
129         if (!checkedArrayMax.valid() || checkedArrayMax.value() > array->byteLength() || !checkedBufferMax.valid() || checkedBufferMax.value() > m_byteLength)
130             return false;
131     }
132
133     switch (m_target) {
134     case GraphicsContext3D::ELEMENT_ARRAY_BUFFER:
135         clearCachedMaxIndices();
136         if (byteLength) {
137             if (!m_elementArrayBuffer)
138                 return false;
139             memcpy(static_cast<unsigned char*>(m_elementArrayBuffer->data()) + offset,
140                    static_cast<unsigned char*>(array->data()) + arrayByteOffset,
141                    byteLength);
142         }
143         return true;
144     case GraphicsContext3D::ARRAY_BUFFER:
145         return true;
146     default:
147         return false;
148     }
149 }
150
151 bool WebGLBuffer::associateBufferSubData(long offset, ArrayBuffer* array)
152 {
153     if (!array)
154         return false;
155     return associateBufferSubDataImpl(offset, array, 0, array->byteLength());
156 }
157
158 bool WebGLBuffer::associateBufferSubData(long offset, ArrayBufferView* array)
159 {
160     if (!array)
161         return false;
162     return associateBufferSubDataImpl(offset, array->buffer().get(), array->byteOffset(), array->byteLength());
163 }
164
165 unsigned WebGLBuffer::byteLength() const
166 {
167     return m_byteLength;
168 }
169
170 long WebGLBuffer::getCachedMaxIndex(unsigned long type)
171 {
172     for (size_t i = 0; i < WTF_ARRAY_LENGTH(m_maxIndexCache); ++i)
173         if (m_maxIndexCache[i].type == type)
174             return m_maxIndexCache[i].maxIndex;
175     return -1;
176 }
177
178 void WebGLBuffer::setCachedMaxIndex(unsigned long type, long value)
179 {
180     size_t numEntries = WTF_ARRAY_LENGTH(m_maxIndexCache);
181     for (size_t i = 0; i < numEntries; ++i)
182         if (m_maxIndexCache[i].type == type) {
183             m_maxIndexCache[i].maxIndex = value;
184             return;
185         }
186     m_maxIndexCache[m_nextAvailableCacheEntry].type = type;
187     m_maxIndexCache[m_nextAvailableCacheEntry].maxIndex = value;
188     m_nextAvailableCacheEntry = (m_nextAvailableCacheEntry + 1) % numEntries;
189 }
190
191 void WebGLBuffer::setTarget(unsigned long target)
192 {
193     // In WebGL, a buffer is bound to one target in its lifetime
194     if (m_target)
195         return;
196     if (target == GraphicsContext3D::ARRAY_BUFFER || target == GraphicsContext3D::ELEMENT_ARRAY_BUFFER)
197         m_target = target;
198 }
199
200 void WebGLBuffer::clearCachedMaxIndices()
201 {
202     memset(m_maxIndexCache, 0, sizeof(m_maxIndexCache));
203 }
204
205 }
206
207 #endif // ENABLE(3D_CANVAS)