Home | History | Annotate | Download | only in bridge
      1 /*
      2  * Copyright (C) 2003, 2008, 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 #include "runtime_object.h"
     28 
     29 #include "JSDOMBinding.h"
     30 #include "runtime_method.h"
     31 #include <runtime/Error.h>
     32 #include <runtime/ObjectPrototype.h>
     33 
     34 using namespace WebCore;
     35 
     36 namespace JSC {
     37 namespace Bindings {
     38 
     39 const ClassInfo RuntimeObject::s_info = { "RuntimeObject", &JSObjectWithGlobalObject::s_info, 0, 0 };
     40 
     41 RuntimeObject::RuntimeObject(ExecState*, JSGlobalObject* globalObject, Structure* structure, PassRefPtr<Instance> instance)
     42     : JSObjectWithGlobalObject(globalObject, structure)
     43     , m_instance(instance)
     44 {
     45     ASSERT(inherits(&s_info));
     46 }
     47 
     48 RuntimeObject::~RuntimeObject()
     49 {
     50 }
     51 
     52 void RuntimeObject::invalidate()
     53 {
     54     ASSERT(m_instance);
     55     if (m_instance)
     56         m_instance->willInvalidateRuntimeObject();
     57     m_instance = 0;
     58 }
     59 
     60 JSValue RuntimeObject::fallbackObjectGetter(ExecState* exec, JSValue slotBase, const Identifier& propertyName)
     61 {
     62     RuntimeObject* thisObj = static_cast<RuntimeObject*>(asObject(slotBase));
     63     RefPtr<Instance> instance = thisObj->m_instance;
     64 
     65     if (!instance)
     66         return throwInvalidAccessError(exec);
     67 
     68     instance->begin();
     69 
     70     Class *aClass = instance->getClass();
     71     JSValue result = aClass->fallbackObject(exec, instance.get(), propertyName);
     72 
     73     instance->end();
     74 
     75     return result;
     76 }
     77 
     78 JSValue RuntimeObject::fieldGetter(ExecState* exec, JSValue slotBase, const Identifier& propertyName)
     79 {
     80     RuntimeObject* thisObj = static_cast<RuntimeObject*>(asObject(slotBase));
     81     RefPtr<Instance> instance = thisObj->m_instance;
     82 
     83     if (!instance)
     84         return throwInvalidAccessError(exec);
     85 
     86     instance->begin();
     87 
     88     Class *aClass = instance->getClass();
     89     Field* aField = aClass->fieldNamed(propertyName, instance.get());
     90     JSValue result = aField->valueFromInstance(exec, instance.get());
     91 
     92     instance->end();
     93 
     94     return result;
     95 }
     96 
     97 JSValue RuntimeObject::methodGetter(ExecState* exec, JSValue slotBase, const Identifier& propertyName)
     98 {
     99     RuntimeObject* thisObj = static_cast<RuntimeObject*>(asObject(slotBase));
    100     RefPtr<Instance> instance = thisObj->m_instance;
    101 
    102     if (!instance)
    103         return throwInvalidAccessError(exec);
    104 
    105     instance->begin();
    106 
    107     JSValue method = instance->getMethod(exec, propertyName);
    108 
    109     instance->end();
    110 
    111     return method;
    112 }
    113 
    114 bool RuntimeObject::getOwnPropertySlot(ExecState *exec, const Identifier& propertyName, PropertySlot& slot)
    115 {
    116     if (!m_instance) {
    117         throwInvalidAccessError(exec);
    118         return false;
    119     }
    120 
    121     RefPtr<Instance> instance = m_instance;
    122 
    123     instance->begin();
    124 
    125     Class *aClass = instance->getClass();
    126 
    127     if (aClass) {
    128         // See if the instance has a field with the specified name.
    129         Field *aField = aClass->fieldNamed(propertyName, instance.get());
    130         if (aField) {
    131             slot.setCustom(this, fieldGetter);
    132             instance->end();
    133             return true;
    134         } else {
    135             // Now check if a method with specified name exists, if so return a function object for
    136             // that method.
    137             MethodList methodList = aClass->methodsNamed(propertyName, instance.get());
    138             if (methodList.size() > 0) {
    139                 slot.setCustom(this, methodGetter);
    140 
    141                 instance->end();
    142                 return true;
    143             }
    144         }
    145 
    146         // Try a fallback object.
    147         if (!aClass->fallbackObject(exec, instance.get(), propertyName).isUndefined()) {
    148             slot.setCustom(this, fallbackObjectGetter);
    149             instance->end();
    150             return true;
    151         }
    152     }
    153 
    154     instance->end();
    155 
    156     return instance->getOwnPropertySlot(this, exec, propertyName, slot);
    157 }
    158 
    159 bool RuntimeObject::getOwnPropertyDescriptor(ExecState *exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
    160 {
    161     if (!m_instance) {
    162         throwInvalidAccessError(exec);
    163         return false;
    164     }
    165 
    166     RefPtr<Instance> instance = m_instance;
    167     instance->begin();
    168 
    169     Class *aClass = instance->getClass();
    170 
    171     if (aClass) {
    172         // See if the instance has a field with the specified name.
    173         Field *aField = aClass->fieldNamed(propertyName, instance.get());
    174         if (aField) {
    175             PropertySlot slot;
    176             slot.setCustom(this, fieldGetter);
    177             instance->end();
    178             descriptor.setDescriptor(slot.getValue(exec, propertyName), DontDelete);
    179             return true;
    180         } else {
    181             // Now check if a method with specified name exists, if so return a function object for
    182             // that method.
    183             MethodList methodList = aClass->methodsNamed(propertyName, instance.get());
    184             if (methodList.size() > 0) {
    185                 PropertySlot slot;
    186                 slot.setCustom(this, methodGetter);
    187                 instance->end();
    188                 descriptor.setDescriptor(slot.getValue(exec, propertyName), DontDelete | ReadOnly);
    189                 return true;
    190             }
    191         }
    192 
    193         // Try a fallback object.
    194         if (!aClass->fallbackObject(exec, instance.get(), propertyName).isUndefined()) {
    195             PropertySlot slot;
    196             slot.setCustom(this, fallbackObjectGetter);
    197             instance->end();
    198             descriptor.setDescriptor(slot.getValue(exec, propertyName), DontDelete | ReadOnly | DontEnum);
    199             return true;
    200         }
    201     }
    202 
    203     instance->end();
    204 
    205     return instance->getOwnPropertyDescriptor(this, exec, propertyName, descriptor);
    206 }
    207 
    208 void RuntimeObject::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
    209 {
    210     if (!m_instance) {
    211         throwInvalidAccessError(exec);
    212         return;
    213     }
    214 
    215     RefPtr<Instance> instance = m_instance;
    216     instance->begin();
    217 
    218     // Set the value of the property.
    219     Field *aField = instance->getClass()->fieldNamed(propertyName, instance.get());
    220     if (aField)
    221         aField->setValueToInstance(exec, instance.get(), value);
    222     else if (!instance->setValueOfUndefinedField(exec, propertyName, value))
    223         instance->put(this, exec, propertyName, value, slot);
    224 
    225     instance->end();
    226 }
    227 
    228 bool RuntimeObject::deleteProperty(ExecState*, const Identifier&)
    229 {
    230     // Can never remove a property of a RuntimeObject.
    231     return false;
    232 }
    233 
    234 JSValue RuntimeObject::defaultValue(ExecState* exec, PreferredPrimitiveType hint) const
    235 {
    236     if (!m_instance)
    237         return throwInvalidAccessError(exec);
    238 
    239     RefPtr<Instance> instance = m_instance;
    240 
    241     instance->begin();
    242     JSValue result = instance->defaultValue(exec, hint);
    243     instance->end();
    244     return result;
    245 }
    246 
    247 static EncodedJSValue JSC_HOST_CALL callRuntimeObject(ExecState* exec)
    248 {
    249     ASSERT(exec->callee()->inherits(&RuntimeObject::s_info));
    250     RefPtr<Instance> instance(static_cast<RuntimeObject*>(exec->callee())->getInternalInstance());
    251     instance->begin();
    252     JSValue result = instance->invokeDefaultMethod(exec);
    253     instance->end();
    254     return JSValue::encode(result);
    255 }
    256 
    257 CallType RuntimeObject::getCallData(CallData& callData)
    258 {
    259     if (!m_instance)
    260         return CallTypeNone;
    261 
    262     RefPtr<Instance> instance = m_instance;
    263     if (!instance->supportsInvokeDefaultMethod())
    264         return CallTypeNone;
    265 
    266     callData.native.function = callRuntimeObject;
    267     return CallTypeHost;
    268 }
    269 
    270 static EncodedJSValue JSC_HOST_CALL callRuntimeConstructor(ExecState* exec)
    271 {
    272     JSObject* constructor = exec->callee();
    273     ASSERT(constructor->inherits(&RuntimeObject::s_info));
    274     RefPtr<Instance> instance(static_cast<RuntimeObject*>(exec->callee())->getInternalInstance());
    275     instance->begin();
    276     ArgList args(exec);
    277     JSValue result = instance->invokeConstruct(exec, args);
    278     instance->end();
    279 
    280     ASSERT(result);
    281     return JSValue::encode(result.isObject() ? static_cast<JSObject*>(result.asCell()) : constructor);
    282 }
    283 
    284 ConstructType RuntimeObject::getConstructData(ConstructData& constructData)
    285 {
    286     if (!m_instance)
    287         return ConstructTypeNone;
    288 
    289     RefPtr<Instance> instance = m_instance;
    290     if (!instance->supportsConstruct())
    291         return ConstructTypeNone;
    292 
    293     constructData.native.function = callRuntimeConstructor;
    294     return ConstructTypeHost;
    295 }
    296 
    297 void RuntimeObject::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode)
    298 {
    299     if (!m_instance) {
    300         throwInvalidAccessError(exec);
    301         return;
    302     }
    303 
    304     RefPtr<Instance> instance = m_instance;
    305 
    306     instance->begin();
    307     instance->getPropertyNames(exec, propertyNames);
    308     instance->end();
    309 }
    310 
    311 JSObject* RuntimeObject::throwInvalidAccessError(ExecState* exec)
    312 {
    313     return throwError(exec, createReferenceError(exec, "Trying to access object from destroyed plug-in."));
    314 }
    315 
    316 }
    317 }
    318