1 /* 2 * Copyright (C) 2008 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 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 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 "JSGeolocation.h" 28 29 #include "DOMWindow.h" 30 #include "ExceptionCode.h" 31 #include "Geolocation.h" 32 #include "GeolocationService.h" 33 #include "JSCustomPositionCallback.h" 34 #include "JSCustomPositionErrorCallback.h" 35 #include "JSDOMWindow.h" 36 #include "PositionOptions.h" 37 #include <runtime/InternalFunction.h> 38 39 using namespace JSC; 40 using namespace std; 41 42 namespace WebCore { 43 44 static PassRefPtr<PositionCallback> createPositionCallback(ExecState* exec, JSDOMGlobalObject* globalObject, JSValue value) 45 { 46 // The spec specifies 'FunctionOnly' for this object. 47 if (!value.inherits(&InternalFunction::info)) { 48 setDOMException(exec, TYPE_MISMATCH_ERR); 49 return 0; 50 } 51 52 JSObject* object = asObject(value); 53 return JSCustomPositionCallback::create(object, globalObject); 54 } 55 56 static PassRefPtr<PositionErrorCallback> createPositionErrorCallback(ExecState* exec, JSDOMGlobalObject* globalObject, JSValue value) 57 { 58 // Argument is optional (hence undefined is allowed), and null is allowed. 59 if (value.isUndefinedOrNull()) 60 return 0; 61 62 // The spec specifies 'FunctionOnly' for this object. 63 if (!value.inherits(&InternalFunction::info)) { 64 setDOMException(exec, TYPE_MISMATCH_ERR); 65 return 0; 66 } 67 68 JSObject* object = asObject(value); 69 return JSCustomPositionErrorCallback::create(object, globalObject); 70 } 71 72 static PassRefPtr<PositionOptions> createPositionOptions(ExecState* exec, JSValue value) 73 { 74 // Create default options. 75 RefPtr<PositionOptions> options = PositionOptions::create(); 76 77 // Argument is optional (hence undefined is allowed), and null is allowed. 78 if (value.isUndefinedOrNull()) { 79 // Use default options. 80 return options.release(); 81 } 82 83 // Given the above test, this will always yield an object. 84 JSObject* object = value.toObject(exec); 85 86 // For all three properties, we apply the following ... 87 // - If the getter or the property's valueOf method throws an exception, we 88 // quit so as not to risk overwriting the exception. 89 // - If the value is absent or undefined, we don't override the default. 90 JSValue enableHighAccuracyValue = object->get(exec, Identifier(exec, "enableHighAccuracy")); 91 if (exec->hadException()) 92 return 0; 93 if (!enableHighAccuracyValue.isUndefined()) { 94 options->setEnableHighAccuracy(enableHighAccuracyValue.toBoolean(exec)); 95 if (exec->hadException()) 96 return 0; 97 } 98 99 JSValue timeoutValue = object->get(exec, Identifier(exec, "timeout")); 100 if (exec->hadException()) 101 return 0; 102 if (!timeoutValue.isUndefined()) { 103 double timeoutNumber = timeoutValue.toNumber(exec); 104 if (exec->hadException()) 105 return 0; 106 // If the value is positive infinity, there's nothing to do. 107 if (!(isinf(timeoutNumber) && (timeoutNumber > 0))) { 108 // Wrap to int32 and force non-negative to match behavior of window.setTimeout. 109 options->setTimeout(max(0, timeoutValue.toInt32(exec))); 110 if (exec->hadException()) 111 return 0; 112 } 113 } 114 115 JSValue maximumAgeValue = object->get(exec, Identifier(exec, "maximumAge")); 116 if (exec->hadException()) 117 return 0; 118 if (!maximumAgeValue.isUndefined()) { 119 double maximumAgeNumber = maximumAgeValue.toNumber(exec); 120 if (exec->hadException()) 121 return 0; 122 if (isinf(maximumAgeNumber) && (maximumAgeNumber > 0)) { 123 // If the value is positive infinity, clear maximumAge. 124 options->clearMaximumAge(); 125 } else { 126 // Wrap to int32 and force non-negative to match behavior of window.setTimeout. 127 options->setMaximumAge(max(0, maximumAgeValue.toInt32(exec))); 128 if (exec->hadException()) 129 return 0; 130 } 131 } 132 133 return options.release(); 134 } 135 136 JSValue JSGeolocation::getCurrentPosition(ExecState* exec, const ArgList& args) 137 { 138 // Arguments: PositionCallback, (optional)PositionErrorCallback, (optional)PositionOptions 139 140 RefPtr<PositionCallback> positionCallback = createPositionCallback(exec, static_cast<JSDOMGlobalObject*>(exec->lexicalGlobalObject()), args.at(0)); 141 if (exec->hadException()) 142 return jsUndefined(); 143 ASSERT(positionCallback); 144 145 RefPtr<PositionErrorCallback> positionErrorCallback = createPositionErrorCallback(exec, static_cast<JSDOMGlobalObject*>(exec->lexicalGlobalObject()), args.at(1)); 146 if (exec->hadException()) 147 return jsUndefined(); 148 149 RefPtr<PositionOptions> positionOptions = createPositionOptions(exec, args.at(2)); 150 if (exec->hadException()) 151 return jsUndefined(); 152 ASSERT(positionOptions); 153 154 m_impl->getCurrentPosition(positionCallback.release(), positionErrorCallback.release(), positionOptions.release()); 155 return jsUndefined(); 156 } 157 158 JSValue JSGeolocation::watchPosition(ExecState* exec, const ArgList& args) 159 { 160 // Arguments: PositionCallback, (optional)PositionErrorCallback, (optional)PositionOptions 161 162 RefPtr<PositionCallback> positionCallback = createPositionCallback(exec, static_cast<JSDOMGlobalObject*>(exec->lexicalGlobalObject()), args.at(0)); 163 if (exec->hadException()) 164 return jsUndefined(); 165 ASSERT(positionCallback); 166 167 RefPtr<PositionErrorCallback> positionErrorCallback = createPositionErrorCallback(exec, static_cast<JSDOMGlobalObject*>(exec->lexicalGlobalObject()), args.at(1)); 168 if (exec->hadException()) 169 return jsUndefined(); 170 171 RefPtr<PositionOptions> positionOptions = createPositionOptions(exec, args.at(2)); 172 if (exec->hadException()) 173 return jsUndefined(); 174 ASSERT(positionOptions); 175 176 int watchID = m_impl->watchPosition(positionCallback.release(), positionErrorCallback.release(), positionOptions.release()); 177 return jsNumber(exec, watchID); 178 } 179 180 } // namespace WebCore 181