Home | History | Annotate | Download | only in wtf
      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 #ifndef ArrayBufferView_h
     27 #define ArrayBufferView_h
     28 
     29 #include "wtf/ArrayBuffer.h"
     30 
     31 #include <algorithm>
     32 #include <limits.h>
     33 #include "wtf/PassRefPtr.h"
     34 #include "wtf/RefCounted.h"
     35 #include "wtf/RefPtr.h"
     36 #include "wtf/WTFExport.h"
     37 
     38 namespace WTF {
     39 
     40 class WTF_EXPORT ArrayBufferView : public RefCounted<ArrayBufferView> {
     41   public:
     42     enum ViewType {
     43         TypeInt8,
     44         TypeUint8,
     45         TypeUint8Clamped,
     46         TypeInt16,
     47         TypeUint16,
     48         TypeInt32,
     49         TypeUint32,
     50         TypeFloat32,
     51         TypeFloat64,
     52         TypeDataView
     53     };
     54     virtual ViewType getType() const = 0;
     55 
     56     PassRefPtr<ArrayBuffer> buffer() const
     57     {
     58         return m_buffer;
     59     }
     60 
     61     void* baseAddress() const
     62     {
     63         return m_baseAddress;
     64     }
     65 
     66     unsigned byteOffset() const
     67     {
     68         return m_byteOffset;
     69     }
     70 
     71     virtual unsigned byteLength() const = 0;
     72 
     73     void setNeuterable(bool flag) { m_isNeuterable = flag; }
     74     bool isNeuterable() const { return m_isNeuterable; }
     75 
     76     virtual ~ArrayBufferView();
     77 
     78   protected:
     79     ArrayBufferView(PassRefPtr<ArrayBuffer>, unsigned byteOffset);
     80 
     81     inline bool setImpl(ArrayBufferView*, unsigned byteOffset);
     82 
     83     inline bool setRangeImpl(const char* data, size_t dataByteLength, unsigned byteOffset);
     84 
     85     inline bool zeroRangeImpl(unsigned byteOffset, size_t rangeByteLength);
     86 
     87     static inline void calculateOffsetAndLength(int start, int end, unsigned arraySize,
     88                                          unsigned* offset, unsigned* length);
     89 
     90     // Helper to verify that a given sub-range of an ArrayBuffer is
     91     // within range.
     92     template <typename T>
     93     static bool verifySubRange(PassRefPtr<ArrayBuffer> buffer,
     94                                unsigned byteOffset,
     95                                unsigned numElements)
     96     {
     97         if (!buffer)
     98             return false;
     99         if (sizeof(T) > 1 && byteOffset % sizeof(T))
    100             return false;
    101         if (byteOffset > buffer->byteLength())
    102             return false;
    103         unsigned remainingElements = (buffer->byteLength() - byteOffset) / sizeof(T);
    104         if (numElements > remainingElements)
    105             return false;
    106         return true;
    107     }
    108 
    109     // Input offset is in number of elements from this array's view;
    110     // output offset is in number of bytes from the underlying buffer's view.
    111     template <typename T>
    112     static void clampOffsetAndNumElements(PassRefPtr<ArrayBuffer> buffer,
    113                                           unsigned arrayByteOffset,
    114                                           unsigned *offset,
    115                                           unsigned *numElements)
    116     {
    117         unsigned maxOffset = (UINT_MAX - arrayByteOffset) / sizeof(T);
    118         if (*offset > maxOffset) {
    119             *offset = buffer->byteLength();
    120             *numElements = 0;
    121             return;
    122         }
    123         *offset = arrayByteOffset + *offset * sizeof(T);
    124         *offset = std::min(buffer->byteLength(), *offset);
    125         unsigned remainingElements = (buffer->byteLength() - *offset) / sizeof(T);
    126         *numElements = std::min(remainingElements, *numElements);
    127     }
    128 
    129     virtual void neuter();
    130 
    131     // This is the address of the ArrayBuffer's storage, plus the byte offset.
    132     void* m_baseAddress;
    133 
    134     unsigned m_byteOffset : 31;
    135     bool m_isNeuterable : 1;
    136 
    137   private:
    138     friend class ArrayBuffer;
    139     RefPtr<ArrayBuffer> m_buffer;
    140     ArrayBufferView* m_prevView;
    141     ArrayBufferView* m_nextView;
    142 };
    143 
    144 bool ArrayBufferView::setImpl(ArrayBufferView* array, unsigned byteOffset)
    145 {
    146     if (byteOffset > byteLength()
    147         || byteOffset + array->byteLength() > byteLength()
    148         || byteOffset + array->byteLength() < byteOffset) {
    149         // Out of range offset or overflow
    150         return false;
    151     }
    152 
    153     char* base = static_cast<char*>(baseAddress());
    154     memmove(base + byteOffset, array->baseAddress(), array->byteLength());
    155     return true;
    156 }
    157 
    158 bool ArrayBufferView::setRangeImpl(const char* data, size_t dataByteLength, unsigned byteOffset)
    159 {
    160     if (byteOffset > byteLength()
    161         || byteOffset + dataByteLength > byteLength()
    162         || byteOffset + dataByteLength < byteOffset) {
    163         // Out of range offset or overflow
    164         return false;
    165     }
    166 
    167     char* base = static_cast<char*>(baseAddress());
    168     memmove(base + byteOffset, data, dataByteLength);
    169     return true;
    170 }
    171 
    172 bool ArrayBufferView::zeroRangeImpl(unsigned byteOffset, size_t rangeByteLength)
    173 {
    174     if (byteOffset > byteLength()
    175         || byteOffset + rangeByteLength > byteLength()
    176         || byteOffset + rangeByteLength < byteOffset) {
    177         // Out of range offset or overflow
    178         return false;
    179     }
    180 
    181     char* base = static_cast<char*>(baseAddress());
    182     memset(base + byteOffset, 0, rangeByteLength);
    183     return true;
    184 }
    185 
    186 void ArrayBufferView::calculateOffsetAndLength(int start, int end, unsigned arraySize,
    187                                                unsigned* offset, unsigned* length)
    188 {
    189     if (start < 0)
    190         start += arraySize;
    191     if (start < 0)
    192         start = 0;
    193     if (end < 0)
    194         end += arraySize;
    195     if (end < 0)
    196         end = 0;
    197     if (static_cast<unsigned>(end) > arraySize)
    198         end = arraySize;
    199     if (end < start)
    200         end = start;
    201     *offset = static_cast<unsigned>(start);
    202     *length = static_cast<unsigned>(end - start);
    203 }
    204 
    205 } // namespace WTF
    206 
    207 using WTF::ArrayBufferView;
    208 
    209 #endif // ArrayBufferView_h
    210