Home | History | Annotate | Download | only in v8
      1 /*
      2  * Copyright (C) 2008, 2009 Google 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 are
      6  * met:
      7  *
      8  *     * Redistributions of source code must retain the above copyright
      9  * notice, this list of conditions and the following disclaimer.
     10  *     * Redistributions in binary form must reproduce the above
     11  * copyright notice, this list of conditions and the following disclaimer
     12  * in the documentation and/or other materials provided with the
     13  * distribution.
     14  *     * Neither the name of Google Inc. nor the names of its
     15  * contributors may be used to endorse or promote products derived from
     16  * this software without specific prior written permission.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29  */
     30 
     31 #include "config.h"
     32 #include "bindings/v8/V8Utilities.h"
     33 
     34 #include "V8MessagePort.h"
     35 #include "bindings/v8/ExceptionMessages.h"
     36 #include "bindings/v8/ScriptState.h"
     37 #include "bindings/v8/V8AbstractEventListener.h"
     38 #include "bindings/v8/V8Binding.h"
     39 #include "bindings/v8/custom/V8ArrayBufferCustom.h"
     40 #include "core/dom/Document.h"
     41 #include "core/dom/ExceptionCode.h"
     42 #include "core/dom/ExecutionContext.h"
     43 #include "core/dom/MessagePort.h"
     44 #include "core/frame/Frame.h"
     45 #include "core/workers/WorkerGlobalScope.h"
     46 #include "wtf/ArrayBuffer.h"
     47 #include "wtf/text/WTFString.h"
     48 #include <v8.h>
     49 
     50 
     51 namespace WebCore {
     52 
     53 // Use an array to hold dependents. It works like a ref-counted scheme.
     54 // A value can be added more than once to the DOM object.
     55 void createHiddenDependency(v8::Handle<v8::Object> object, v8::Local<v8::Value> value, int cacheIndex, v8::Isolate* isolate)
     56 {
     57     v8::Local<v8::Value> cache = object->GetInternalField(cacheIndex);
     58     if (cache->IsNull() || cache->IsUndefined()) {
     59         cache = v8::Array::New(isolate);
     60         object->SetInternalField(cacheIndex, cache);
     61     }
     62 
     63     v8::Local<v8::Array> cacheArray = v8::Local<v8::Array>::Cast(cache);
     64     cacheArray->Set(v8::Integer::New(cacheArray->Length(), isolate), value);
     65 }
     66 
     67 bool extractTransferables(v8::Local<v8::Value> value, MessagePortArray& ports, ArrayBufferArray& arrayBuffers, bool& notASequence, v8::Isolate* isolate)
     68 {
     69     if (isUndefinedOrNull(value)) {
     70         ports.resize(0);
     71         arrayBuffers.resize(0);
     72         return true;
     73     }
     74 
     75     uint32_t length = 0;
     76     if (value->IsArray()) {
     77         v8::Local<v8::Array> array = v8::Local<v8::Array>::Cast(value);
     78         length = array->Length();
     79     } else if (toV8Sequence(value, length, isolate).IsEmpty()) {
     80         notASequence = true;
     81         return false;
     82     }
     83 
     84     v8::Local<v8::Object> transferrables = v8::Local<v8::Object>::Cast(value);
     85 
     86     // Validate the passed array of transferrables.
     87     for (unsigned int i = 0; i < length; ++i) {
     88         v8::Local<v8::Value> transferrable = transferrables->Get(i);
     89         // Validation of non-null objects, per HTML5 spec 10.3.3.
     90         if (isUndefinedOrNull(transferrable)) {
     91             setDOMException(DataCloneError, isolate);
     92             return false;
     93         }
     94         // Validation of Objects implementing an interface, per WebIDL spec 4.1.15.
     95         if (V8MessagePort::hasInstance(transferrable, isolate, worldType(isolate))) {
     96             RefPtr<MessagePort> port = V8MessagePort::toNative(v8::Handle<v8::Object>::Cast(transferrable));
     97             // Check for duplicate MessagePorts.
     98             if (ports.contains(port)) {
     99                 setDOMException(DataCloneError, isolate);
    100                 return false;
    101             }
    102             ports.append(port.release());
    103         } else if (V8ArrayBuffer::hasInstance(transferrable, isolate, worldType(isolate)))
    104             arrayBuffers.append(V8ArrayBuffer::toNative(v8::Handle<v8::Object>::Cast(transferrable)));
    105         else {
    106             setDOMException(DataCloneError, isolate);
    107             return false;
    108         }
    109     }
    110     return true;
    111 }
    112 
    113 bool getMessagePortArray(v8::Local<v8::Value> value, const String& propertyName, MessagePortArray& ports, v8::Isolate* isolate)
    114 {
    115     if (isUndefinedOrNull(value)) {
    116         ports.resize(0);
    117         return true;
    118     }
    119     if (!value->IsArray()) {
    120         throwTypeError(ExceptionMessages::notASequenceTypeProperty(propertyName), isolate);
    121         return false;
    122     }
    123     bool success = false;
    124     ports = toRefPtrNativeArray<MessagePort, V8MessagePort>(value, propertyName, isolate, &success);
    125     return success;
    126 }
    127 
    128 bool getMessagePortArray(v8::Local<v8::Value> value, int argumentIndex, MessagePortArray& ports, v8::Isolate* isolate)
    129 {
    130     if (isUndefinedOrNull(value)) {
    131         ports.resize(0);
    132         return true;
    133     }
    134     if (!value->IsArray()) {
    135         throwTypeError(ExceptionMessages::notAnArrayTypeArgumentOrValue(argumentIndex), isolate);
    136         return false;
    137     }
    138     bool success = false;
    139     ports = toRefPtrNativeArray<MessagePort, V8MessagePort>(value, argumentIndex, isolate, &success);
    140     return success;
    141 }
    142 
    143 void removeHiddenDependency(v8::Handle<v8::Object> object, v8::Local<v8::Value> value, int cacheIndex, v8::Isolate* isolate)
    144 {
    145     v8::Local<v8::Value> cache = object->GetInternalField(cacheIndex);
    146     if (!cache->IsArray())
    147         return;
    148     v8::Local<v8::Array> cacheArray = v8::Local<v8::Array>::Cast(cache);
    149     for (int i = cacheArray->Length() - 1; i >= 0; --i) {
    150         v8::Local<v8::Value> cached = cacheArray->Get(v8::Integer::New(i, isolate));
    151         if (cached->StrictEquals(value)) {
    152             cacheArray->Delete(i);
    153             return;
    154         }
    155     }
    156 }
    157 
    158 void transferHiddenDependency(v8::Handle<v8::Object> object, EventListener* oldValue, v8::Local<v8::Value> newValue, int cacheIndex, v8::Isolate* isolate)
    159 {
    160     if (oldValue) {
    161         V8AbstractEventListener* oldListener = V8AbstractEventListener::cast(oldValue);
    162         if (oldListener) {
    163             v8::Local<v8::Object> oldListenerObject = oldListener->getExistingListenerObject();
    164             if (!oldListenerObject.IsEmpty())
    165                 removeHiddenDependency(object, oldListenerObject, cacheIndex, isolate);
    166         }
    167     }
    168     // Non-callable input is treated as null and ignored
    169     if (newValue->IsFunction())
    170         createHiddenDependency(object, newValue, cacheIndex, isolate);
    171 }
    172 
    173 ExecutionContext* getExecutionContext()
    174 {
    175     if (WorkerScriptController* controller = WorkerScriptController::controllerForContext())
    176         return &controller->workerGlobalScope();
    177 
    178     return currentDocument();
    179 }
    180 
    181 } // namespace WebCore
    182