| // Copyright 2015 Google Inc. All Rights Reserved. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #ifndef COBALT_DOM_DATA_VIEW_H_ |
| #define COBALT_DOM_DATA_VIEW_H_ |
| |
| #include <algorithm> |
| #include <iterator> |
| |
| #include "build/build_config.h" |
| #include "cobalt/dom/array_buffer.h" |
| #include "cobalt/script/exception_state.h" |
| #include "cobalt/script/wrappable.h" |
| |
| namespace cobalt { |
| namespace dom { |
| |
| // DataView is used to access the underlying ArrayBuffer with support of common |
| // types and endianness. |
| // https://www.khronos.org/registry/typedarray/specs/latest/#8 |
| class DataView : public script::Wrappable { |
| public: |
| // Web API: DataView |
| // |
| DataView(const scoped_refptr<ArrayBuffer>& buffer, |
| script::ExceptionState* exception_state); |
| DataView(const scoped_refptr<ArrayBuffer>& buffer, uint32 byte_offset, |
| script::ExceptionState* exception_state); |
| DataView(const scoped_refptr<ArrayBuffer>& buffer, uint32 byte_offset, |
| uint32 byte_length, script::ExceptionState* exception_state); |
| |
| // C++ macro to generate accessor for each supported types. |
| #define DATA_VIEW_ACCESSOR_FOR_EACH(MacroOp) \ |
| MacroOp(Int8, int8) MacroOp(Uint8, uint8) MacroOp(Int16, int16) \ |
| MacroOp(Uint16, uint16) MacroOp(Int32, int32) MacroOp(Uint32, uint32) \ |
| MacroOp(Float32, float) MacroOp(Float64, double) |
| |
| // The following macro generates the accessors for each types listed above. |
| // According to the spec, For getter without an endianness parameter it is |
| // default to big endian. Note that it may generate extra accessors for |
| // int8/uint8 which has an 'little_endian' parameter, this is redundant but |
| // should work as int8/uint8 behalf the same when accessed in any endian mode. |
| #define DEFINE_DATA_VIEW_ACCESSOR(DomType, CppType) \ |
| CppType Get##DomType(uint32 byte_offset, \ |
| script::ExceptionState* exception_state) const { \ |
| return Get##DomType(byte_offset, false, exception_state); \ |
| } \ |
| CppType Get##DomType(uint32 byte_offset, bool little_endian, \ |
| script::ExceptionState* exception_state) const { \ |
| return GetElement<CppType>(byte_offset, little_endian, exception_state); \ |
| } \ |
| void Set##DomType(uint32 byte_offset, CppType value, \ |
| script::ExceptionState* exception_state) { \ |
| Set##DomType(byte_offset, value, false, exception_state); \ |
| } \ |
| void Set##DomType(uint32 byte_offset, CppType value, bool little_endian, \ |
| script::ExceptionState* exception_state) { \ |
| SetElement<CppType>(byte_offset, value, little_endian, exception_state); \ |
| } |
| |
| DATA_VIEW_ACCESSOR_FOR_EACH(DEFINE_DATA_VIEW_ACCESSOR) |
| #undef DEFINE_DATA_VIEW_ACCESSOR |
| |
| // Web API: ArrayBufferView (implements) |
| // |
| const scoped_refptr<ArrayBuffer>& buffer() { return buffer_; } |
| uint32 byte_offset() const { return byte_offset_; } |
| uint32 byte_length() const { return byte_length_; } |
| |
| DEFINE_WRAPPABLE_TYPE(DataView); |
| |
| private: |
| static void CopyBytes(const uint8* src, size_t size, bool little_endian, |
| uint8* dest) { |
| #if defined(ARCH_CPU_LITTLE_ENDIAN) |
| bool need_reverse = !little_endian; |
| #else // defined(ARCH_CPU_LITTLE_ENDIAN) |
| bool need_reverse = little_endian; |
| #endif // defined(ARCH_CPU_LITTLE_ENDIAN) |
| if (need_reverse) { |
| #if defined(COMPILER_MSVC) |
| std::reverse_copy(src, src + size, |
| stdext::checked_array_iterator<uint8*>(dest, size)); |
| #else // defined(COMPILER_MSVC) |
| std::reverse_copy(src, src + size, dest); |
| #endif // defined(COMPILER_MSVC) |
| } else { |
| memcpy(dest, src, size); |
| } |
| } |
| |
| template <typename ElementType> |
| ElementType GetElement(uint32 byte_offset, bool little_endian, |
| script::ExceptionState* exception_state) const { |
| if (byte_offset + sizeof(ElementType) > byte_length_) { |
| exception_state->SetSimpleException(script::kOutsideBounds); |
| // The return value will be ignored. |
| return ElementType(); |
| } |
| ElementType value; |
| CopyBytes(buffer_->data() + byte_offset_ + byte_offset, sizeof(value), |
| little_endian, reinterpret_cast<uint8*>(&value)); |
| return value; |
| } |
| |
| template <typename ElementType> |
| void SetElement(uint32 byte_offset, ElementType value, bool little_endian, |
| script::ExceptionState* exception_state) { |
| if (byte_offset + sizeof(ElementType) > byte_length_) { |
| exception_state->SetSimpleException(script::kOutsideBounds); |
| return; |
| } |
| CopyBytes(reinterpret_cast<uint8*>(&value), sizeof(value), little_endian, |
| buffer_->data() + byte_offset_ + byte_offset); |
| } |
| |
| const scoped_refptr<ArrayBuffer> buffer_; |
| const uint32 byte_offset_; |
| const uint32 byte_length_; |
| |
| DISALLOW_COPY_AND_ASSIGN(DataView); |
| }; |
| |
| } // namespace dom |
| } // namespace cobalt |
| |
| #endif // COBALT_DOM_DATA_VIEW_H_ |