KHtml

kjs_arraybufferview.h
1 /*
2  * This file is part of the KDE libraries
3  * Copyright (C) 2013 Bernd Buschinski <[email protected]>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18  */
19 
20 #ifndef KJS_ARRAYBUFFERVIEW_H
21 #define KJS_ARRAYBUFFERVIEW_H
22 
23 #include "ecma/kjs_arraybuffer.h"
24 
25 #include <kjs/object.h>
26 #include <kjs/function.h>
27 #include <kjs/function_object.h>
28 #include <kjs/operations.h>
29 #include <kjs/array_instance.h>
30 #include <dom/dom_exception.h>
31 
32 namespace KJS
33 {
34 class ArrayBuffer;
35 
36 // Keep enum outside of template classes, for lut tables
37 namespace ArrayBufferViewBase
38 {
39 enum {
40  Buffer, ByteLength, ByteOffset, Subarray, Length, Set, BytesPerElement
41 };
42 }
43 
44 //type, TypedArrayClass
45 template <class T, class U>
46 class ArrayBufferViewConstructorImp : public KJS::FunctionPrototype
47 {
48 public:
49  ArrayBufferViewConstructorImp(ExecState *exec, DOM::DocumentImpl *d);
50  bool implementsConstruct() const override;
51  using KJS::JSObject::construct;
52  JSObject *construct(ExecState *exec, const List &args) override;
53 
54  JSValue *getValueProperty(ExecState *exec, int token) const;
55  using KJS::JSObject::getOwnPropertySlot;
56  bool getOwnPropertySlot(ExecState *exec, const Identifier &propertyName, PropertySlot &slot) override;
57 private:
58  SharedPtr<DOM::DocumentImpl> doc;
59 };
60 
61 //type, TypedArrayPrototype
62 template <class T, class P>
63 class ArrayBufferView : public JSObject
64 {
65 public:
66  explicit ArrayBufferView(ExecState *exec, ArrayBuffer *buffer, size_t byteOffset, size_t byteLength);
67  virtual ~ArrayBufferView();
68 
69  bool getOwnPropertySlot(ExecState *exec, unsigned i, PropertySlot &slot) override;
70  bool getOwnPropertySlot(ExecState *exec, const Identifier &propertyName, PropertySlot &slot) override;
71  JSValue *getValueProperty(ExecState *exec, int token) const;
72 
73  void put(ExecState *exec, const Identifier &propertyName, JSValue *value, int attr = None) override;
74  void put(ExecState *exec, unsigned propertyName, JSValue *value, int attr = None) override;
75 
76  ArrayBuffer *buffer() const
77  {
78  return m_buffer;
79  }
80  size_t byteLength() const
81  {
82  return m_byteLength;
83  }
84  size_t byteOffset() const
85  {
86  return m_byteOffset;
87  }
88  size_t length() const
89  {
90  return m_length;
91  }
92  inline T *bufferStart() const
93  {
94  return m_bufferStart;
95  }
96 
97 private:
98  // checks if the pos is a valid array index, returns false if not
99  inline bool checkIndex(ExecState *exec, unsigned pos);
100 
101  ProtectedPtr<ArrayBuffer> m_buffer;
102  size_t m_byteOffset;
103  size_t m_byteLength;
104  size_t m_length;
105  T *m_bufferStart;
106 };
107 
108 //unrolled KJS_DEFINE_PROTOTYPE(ArrayBufferViewProto), for template sake
109 
110 //type, TypedArrayClass
111 template <class T, class U>
112 class ArrayBufferViewProto : public KJS::JSObject
113 {
114 public:
115  bool getOwnPropertySlot(KJS::ExecState *, const KJS::Identifier &, KJS::PropertySlot &) override;
116  using JSObject::getOwnPropertySlot;
117 protected:
118  ArrayBufferViewProto(KJS::ExecState *exec);
119 };
120 
121 //unrolled KJS_IMPLEMENT_PROTOFUNC(ArrayBufferViewProtoFunc), for template sake
122 template <class T, class U>
123 class ArrayBufferViewProtoFunc : public KJS::InternalFunctionImp
124 {
125 public:
126  ArrayBufferViewProtoFunc<T, U>(KJS::ExecState *exec, int i, int len, const KJS::Identifier &name)
127  : InternalFunctionImp(static_cast<KJS::FunctionPrototype *>(exec->lexicalInterpreter()->builtinFunctionPrototype()), name), id(i)
128  {
129  put(exec, exec->propertyNames().length, KJS::jsNumber(len), KJS::DontDelete | KJS::ReadOnly | KJS::DontEnum);
130  }
131 
132  KJS::JSValue *callAsFunction(KJS::ExecState *exec, KJS::JSObject *thisObj, const KJS::List &args) override;
133 private:
134  int id;
135 };
136 }
137 
138 #include "kjs_arraybufferview.lut.h"
139 
140 namespace KJS
141 {
142 
143 // unrolled KJS_IMPLEMENT_PROTOTYPE("ArrayBufferView", ArrayBufferViewProto, ArrayBufferViewProtoFunc, ObjectPrototype)
144 // for template sake
145 template <class T, class U>
146 bool ArrayBufferViewProto<T, U>::getOwnPropertySlot(KJS::ExecState *exec, const KJS::Identifier &propertyName, KJS::PropertySlot &slot)
147 {
148  return KJS::getStaticFunctionSlot<ArrayBufferViewProtoFunc<T, U>, KJS::JSObject>(exec, &ArrayBufferViewProtoTable, this, propertyName, slot);
149 }
150 
151 template <class T, class U>
152 ArrayBufferViewProto<T, U>::ArrayBufferViewProto(KJS::ExecState *exec)
153  : KJS::JSObject(ObjectPrototype::self(exec))
154 {
155 }
156 // unroll end
157 
158 // -------------------- ArrayBufferViewProtoFunc ---------------------
159 
160 template <class T, class U>
161 JSValue *ArrayBufferViewProtoFunc<T, U>::callAsFunction(ExecState *exec, JSObject *thisObj, const List &args)
162 {
163  if (!thisObj->inherits(&U::info)) {
164  return jsUndefined();
165  }
166  U *view = static_cast<U *>(thisObj);
167 
168  switch (id) {
169  case ArrayBufferViewBase::Subarray: {
170  //Subarray takes max long/signed size_t
171  // If start or end are negative, it refers to an index from the end of the array
172  ssize_t begin = 0;
173  ssize_t end = 0;
174  double tmp;
175  if (args[0]->getNumber(tmp)) {
176  begin = static_cast<ssize_t>(tmp);
177  }
178  if (args.size() >= 2 && args[1]->getNumber(tmp)) {
179  end = static_cast<ssize_t>(tmp);
180  }
181 
182  // turn negative start/end into a valid positive index
183  if (begin < 0 && view->length() > static_cast<size_t>(-begin)) {
184  begin = view->length() + begin;
185  }
186  if (end < 0 && view->length() > static_cast<size_t>(-end)) {
187  end = view->length() + end;
188  }
189 
190  if (static_cast<size_t>(begin) > view->length()) {
191  begin = view->length();
192  }
193  if (static_cast<size_t>(end) > view->length()) {
194  end = 0;
195  }
196 
197  size_t length = 0;
198  if (begin < end) {
199  length = (end - begin) * sizeof(T);
200  }
201 
202  U *newView = new U(exec, view->buffer(), begin * sizeof(T), length);
203  return newView;
204  }
205  case ArrayBufferViewBase::Set: {
206  JSObject *obj = args[0]->getObject();
207  if (!obj) {
208  return jsUndefined();
209  }
210  if (obj->inherits(&U::info)) {
211  U *other = static_cast<U *>(obj);
212  double tmp;
213  size_t offset = 0;
214  if (args.size() >= 2 && args[1]->getNumber(tmp) && tmp > 0) {
215  offset = static_cast<size_t>(tmp) * sizeof(T);
216  }
217 
218  if (offset > other->byteLength() || other->byteLength() - offset > view->byteLength()) {
219  setDOMException(exec, DOM::DOMException::INDEX_SIZE_ERR);
220  return jsUndefined();
221  }
222  memcpy(view->buffer()->buffer(), other->buffer()->buffer() + offset, std::max<ssize_t>(static_cast<ssize_t>(other->byteLength()) - static_cast<ssize_t>(offset), 0));
223  return jsUndefined();
224  } else if (obj->inherits(&ArrayInstance::info)) {
225  ArrayInstance *array = static_cast<ArrayInstance *>(obj);
226  if (array->getLength() > view->length()) {
227  setDOMException(exec, DOM::DOMException::INDEX_SIZE_ERR);
228  return jsUndefined();
229  }
230  for (unsigned i = 0; i < array->getLength(); ++i) {
231  view->put(exec, i, array->getItem(i));
232  }
233  return jsUndefined();
234  } else {
235  return jsUndefined();
236  }
237  }
238  default:
239  ASSERT_NOT_REACHED();
240  return jsUndefined();
241  }
242 }
243 
244 // -------------------- ArrayBufferViewConstructorImp ---------------------
245 
246 template <class T, class U>
247 ArrayBufferViewConstructorImp<T, U>::ArrayBufferViewConstructorImp(ExecState *exec, DOM::DocumentImpl *d)
248  : KJS::FunctionPrototype(exec),
249  doc(d)
250 {
251 }
252 
253 template <class T, class U>
254 bool ArrayBufferViewConstructorImp<T, U>::implementsConstruct() const
255 {
256  return true;
257 }
258 
259 template <class T, class U>
260 JSObject *ArrayBufferViewConstructorImp<T, U>::construct(ExecState *exec, const List &args)
261 {
262  JSType type = args[0]->type();
263 
264  switch (type) {
265  case ObjectType: {
266  JSObject *obj = args[0]->getObject();
267  if (!obj) {
268  return throwError(exec, TypeError);
269  }
270  if (obj->inherits(&ArrayBuffer::info)) {
271  // new ArrayBufferView(ArrayBuffer, [byteOffset[, byteLength]])
272  ArrayBuffer *buf = static_cast<ArrayBuffer *>(obj);
273 
274  size_t byteOffset = 0, byteLength = 0;
275  double tmp;
276  if (args.size() >= 2 && args[1]->getNumber(tmp) && tmp > 0) {
277  byteOffset = static_cast<size_t>(tmp);
278  }
279 
280  if (args.size() >= 3 && args[2]->getNumber(tmp) && tmp > 0) {
281  byteLength = static_cast<size_t>(tmp) * sizeof(T);
282  }
283 
284  return new U(exec, buf, byteOffset, byteLength);
285  } else if (obj->inherits(&ArrayInstance::info)) {
286  // new ArrayBufferView(Array)
287  ArrayInstance *arr = dynamic_cast<ArrayInstance *>(obj);
288  ArrayBuffer *buf = new ArrayBuffer(arr->getLength()*sizeof(T));
289  U *view = new U(exec, buf, 0, 0);
290  for (unsigned i = 0; i < arr->getLength(); ++i) {
291  view->put(exec, i, arr->getItem(i));
292  }
293  return view;
294  } else if (obj->inherits(&U::info)) {
295  // new ArrayBufferView(ArrayBufferView)
296  U *arr = static_cast<U *>(obj);
297  ArrayBuffer *buf = new ArrayBuffer(arr->buffer()->buffer(), arr->byteLength());
298  U *view = new U(exec, buf, 0, 0);
299  return view;
300  } else {
301  break;
302  }
303  }
304  case NumberType: {
305  // new ArrayBufferView(Length)
306  size_t length = 0;
307  double lengthF = args[0]->getNumber();
308  if (!KJS::isNaN(lengthF) && !KJS::isInf(lengthF) && lengthF > 0) {
309  length = static_cast<size_t>(lengthF);
310  }
311  ArrayBuffer *buf = new ArrayBuffer(length * sizeof(T));
312  return new U(exec, buf, 0, 0);
313  }
314  default:
315  break;
316  }
317  // new ArrayBufferView(), create empty ArrayBuffer
318  ArrayBuffer *buf = new ArrayBuffer(0);
319  return new U(exec, buf, 0, 0);
320 }
321 
322 template <class T, class U>
323 JSValue *ArrayBufferViewConstructorImp<T, U>::getValueProperty(ExecState *, int) const
324 {
325  // switch (id)
326  // {
327  // case ArrayBufferViewFuncImp<T>::BytesPerElement:
328  return jsNumber(sizeof(T));
329  // }
330 }
331 
332 template <class T, class U>
333 bool ArrayBufferViewConstructorImp<T, U>::getOwnPropertySlot(ExecState *exec, const Identifier &propertyName, PropertySlot &slot)
334 {
335  return getStaticPropertySlot<ArrayBufferViewProtoFunc<T, U>, ArrayBufferViewConstructorImp<T, U>, KJS::FunctionPrototype>(exec, &ArrayBufferViewConstTable, this, propertyName, slot);
336 }
337 
338 // -------------------- ArrayBufferView ---------------------
339 
340 template <class T, class P>
341 ArrayBufferView<T, P>::ArrayBufferView(KJS::ExecState *exec, KJS::ArrayBuffer *buffer, size_t byteOffset, size_t byteLength)
342  : JSObject(),
343  m_buffer(buffer),
344  m_byteOffset(byteOffset)
345 {
346  if (byteLength == 0) {
347  if (byteOffset < buffer->byteLength()) {
348  m_byteLength = buffer->byteLength() - byteOffset;
349  } else {
350  m_byteLength = 0;
351  }
352  } else {
353  m_byteLength = byteLength;
354  }
355  m_length = m_byteLength / sizeof(T);
356  setPrototype(P::self(exec));
357  m_bufferStart = reinterpret_cast<T *>(m_buffer->buffer() + m_byteOffset);
358 }
359 
360 template <class T, class P>
361 ArrayBufferView<T, P>::~ArrayBufferView()
362 {
363 }
364 
365 template <class T, class P>
366 bool ArrayBufferView<T, P>::getOwnPropertySlot(ExecState *exec, unsigned int i, PropertySlot &slot)
367 {
368  if (!checkIndex(exec, i)) {
369  return false;
370  }
371 
372  slot.setValue(this, jsNumber(m_bufferStart[i]));
373  return true;
374 }
375 
376 template <class T, class P>
377 bool ArrayBufferView<T, P>::getOwnPropertySlot(ExecState *exec, const Identifier &propertyName, PropertySlot &slot)
378 {
379  bool ok = false;
380  unsigned i = propertyName.toArrayIndex(&ok);
381  if (ok) {
382  return ArrayBufferView<T, P>::getOwnPropertySlot(exec, i, slot);
383  }
384 
385  return getStaticValueSlot< ArrayBufferView<T, P>, JSObject>(exec, &ArrayBufferViewTable, this, propertyName, slot);
386 }
387 
388 template <class T, class P>
389 JSValue *ArrayBufferView<T, P>::getValueProperty(ExecState * /*exec*/, int token) const
390 {
391  switch (token) {
392  case ArrayBufferViewBase::Buffer:
393  return m_buffer;
394  case ArrayBufferViewBase::ByteLength:
395  return jsNumber(m_byteLength);
396  case ArrayBufferViewBase::ByteOffset:
397  return jsNumber(m_byteOffset);
398  case ArrayBufferViewBase::Length:
399  return jsNumber(m_length);
400  default:
401  ASSERT_NOT_REACHED();
402  qCWarning(KHTML_LOG) << "ArrayBufferView<T>::getValueProperty unhandled token " << token;
403  break;
404  }
405  return nullptr;
406 }
407 
408 template <class T, class P>
409 void ArrayBufferView<T, P>::put(ExecState *exec, const Identifier &propertyName, JSValue *value, int attr)
410 {
411  bool ok = false;
412  unsigned i = propertyName.toArrayIndex(&ok);
413  if (ok) {
414  ArrayBufferView<T, P>::put(exec, i, value, attr);
415  } else {
416  KJS::JSObject::put(exec, propertyName, value, attr);
417  }
418 }
419 
420 template <class T, class P>
421 void ArrayBufferView<T, P>::put(ExecState *exec, unsigned int i, JSValue *value, int /*attr*/)
422 {
423  if (!checkIndex(exec, i)) {
424  return;
425  }
426  if (value && value->type() != NumberType) {
427  return;
428  }
429  m_bufferStart[i] = static_cast<T>(value->getNumber());
430 }
431 
432 template <class T, class P>
433 bool ArrayBufferView<T, P>::checkIndex(KJS::ExecState * /*exec*/, unsigned int pos)
434 {
435  if (m_byteOffset + (pos + 1)*sizeof(T) > m_buffer->byteLength()) {
436  return false;
437  }
438  if (pos * sizeof(T) >= m_byteLength) {
439  return false;
440  }
441  return true;
442 }
443 
444 } // namespace KJS
445 
446 #endif //KJS_ARRAYBUFFERVIEW_H
QString name(const QVariant &location)
const QList< QKeySequence > & begin()
Type type(const QSqlDatabase &db)
QPoint pos() const const
KIOCORE_EXPORT TransferJob * put(const QUrl &url, int permissions, JobFlags flags=DefaultFlags)
const QList< QKeySequence > & end()
ObjectType
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Tue Oct 26 2021 22:48:04 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.