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