1 /* 2 * Copyright 2009, The Android Open Source Project 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 * * Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * * 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 THE COPYRIGHT HOLDERS ``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 THE COPYRIGHT OWNER 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 "V8Geolocation.h" 28 29 #include "Geolocation.h" 30 31 #include "V8Binding.h" 32 #include "V8CustomPositionCallback.h" 33 #include "V8CustomPositionErrorCallback.h" 34 #include "V8Proxy.h" 35 36 using namespace std; 37 using namespace WTF; 38 39 namespace WebCore { 40 41 static const char typeMismatchError[] = "TYPE_MISMATCH_ERR: DOM Exception 17"; 42 43 static void throwTypeMismatchException() 44 { 45 V8Proxy::throwError(V8Proxy::GeneralError, typeMismatchError); 46 } 47 48 static PassRefPtr<PositionCallback> createPositionCallback(v8::Local<v8::Value> value, bool& succeeded) 49 { 50 succeeded = true; 51 52 // The spec specifies 'FunctionOnly' for this object. 53 if (!value->IsFunction()) { 54 succeeded = false; 55 throwTypeMismatchException(); 56 return 0; 57 } 58 59 Frame* frame = V8Proxy::retrieveFrameForCurrentContext(); 60 return V8CustomPositionCallback::create(value, frame); 61 } 62 63 static PassRefPtr<PositionErrorCallback> createPositionErrorCallback(v8::Local<v8::Value> value, bool& succeeded) 64 { 65 succeeded = true; 66 67 // Argument is optional (hence undefined is allowed), and null is allowed. 68 if (isUndefinedOrNull(value)) 69 return 0; 70 71 // The spec specifies 'FunctionOnly' for this object. 72 if (!value->IsFunction()) { 73 succeeded = false; 74 throwTypeMismatchException(); 75 return 0; 76 } 77 78 Frame* frame = V8Proxy::retrieveFrameForCurrentContext(); 79 return V8CustomPositionErrorCallback::create(value, frame); 80 } 81 82 static PassRefPtr<PositionOptions> createPositionOptions(v8::Local<v8::Value> value, bool& succeeded) 83 { 84 succeeded = true; 85 86 // Create default options. 87 RefPtr<PositionOptions> options = PositionOptions::create(); 88 89 // Argument is optional (hence undefined is allowed), and null is allowed. 90 if (isUndefinedOrNull(value)) { 91 // Use default options. 92 return options.release(); 93 } 94 95 // Given the above test, this will always yield an object. 96 v8::Local<v8::Object> object = value->ToObject(); 97 98 // For all three properties, we apply the following ... 99 // - If the getter or the property's valueOf method throws an exception, we 100 // quit so as not to risk overwriting the exception. 101 // - If the value is absent or undefined, we don't override the default. 102 v8::Local<v8::Value> enableHighAccuracyValue = object->Get(v8::String::New("enableHighAccuracy")); 103 if (enableHighAccuracyValue.IsEmpty()) { 104 succeeded = false; 105 return 0; 106 } 107 if (!enableHighAccuracyValue->IsUndefined()) { 108 v8::Local<v8::Boolean> enableHighAccuracyBoolean = enableHighAccuracyValue->ToBoolean(); 109 if (enableHighAccuracyBoolean.IsEmpty()) { 110 succeeded = false; 111 return 0; 112 } 113 options->setEnableHighAccuracy(enableHighAccuracyBoolean->Value()); 114 } 115 116 v8::Local<v8::Value> timeoutValue = object->Get(v8::String::New("timeout")); 117 if (timeoutValue.IsEmpty()) { 118 succeeded = false; 119 return 0; 120 } 121 if (!timeoutValue->IsUndefined()) { 122 v8::Local<v8::Number> timeoutNumber = timeoutValue->ToNumber(); 123 if (timeoutNumber.IsEmpty()) { 124 succeeded = false; 125 return 0; 126 } 127 double timeoutDouble = timeoutNumber->Value(); 128 // If the value is positive infinity, there's nothing to do. 129 if (!(isinf(timeoutDouble) && timeoutDouble > 0)) { 130 v8::Local<v8::Int32> timeoutInt32 = timeoutValue->ToInt32(); 131 if (timeoutInt32.IsEmpty()) { 132 succeeded = false; 133 return 0; 134 } 135 // Wrap to int32 and force non-negative to match behavior of window.setTimeout. 136 options->setTimeout(max(0, timeoutInt32->Value())); 137 } 138 } 139 140 v8::Local<v8::Value> maximumAgeValue = object->Get(v8::String::New("maximumAge")); 141 if (maximumAgeValue.IsEmpty()) { 142 succeeded = false; 143 return 0; 144 } 145 if (!maximumAgeValue->IsUndefined()) { 146 v8::Local<v8::Number> maximumAgeNumber = maximumAgeValue->ToNumber(); 147 if (maximumAgeNumber.IsEmpty()) { 148 succeeded = false; 149 return 0; 150 } 151 double maximumAgeDouble = maximumAgeNumber->Value(); 152 if (isinf(maximumAgeDouble) && maximumAgeDouble > 0) { 153 // If the value is positive infinity, clear maximumAge. 154 options->clearMaximumAge(); 155 } else { 156 v8::Local<v8::Int32> maximumAgeInt32 = maximumAgeValue->ToInt32(); 157 if (maximumAgeInt32.IsEmpty()) { 158 succeeded = false; 159 return 0; 160 } 161 // Wrap to int32 and force non-negative to match behavior of window.setTimeout. 162 options->setMaximumAge(max(0, maximumAgeInt32->Value())); 163 } 164 } 165 166 return options.release(); 167 } 168 169 v8::Handle<v8::Value> V8Geolocation::getCurrentPositionCallback(const v8::Arguments& args) 170 { 171 INC_STATS("DOM.Geolocation.getCurrentPosition()"); 172 173 bool succeeded = false; 174 175 RefPtr<PositionCallback> positionCallback = createPositionCallback(args[0], succeeded); 176 if (!succeeded) 177 return v8::Undefined(); 178 ASSERT(positionCallback); 179 180 RefPtr<PositionErrorCallback> positionErrorCallback = createPositionErrorCallback(args[1], succeeded); 181 if (!succeeded) 182 return v8::Undefined(); 183 184 RefPtr<PositionOptions> positionOptions = createPositionOptions(args[2], succeeded); 185 if (!succeeded) 186 return v8::Undefined(); 187 ASSERT(positionOptions); 188 189 Geolocation* geolocation = V8Geolocation::toNative(args.Holder()); 190 geolocation->getCurrentPosition(positionCallback.release(), positionErrorCallback.release(), positionOptions.release()); 191 return v8::Undefined(); 192 } 193 194 v8::Handle<v8::Value> V8Geolocation::watchPositionCallback(const v8::Arguments& args) 195 { 196 INC_STATS("DOM.Geolocation.watchPosition()"); 197 198 bool succeeded = false; 199 200 RefPtr<PositionCallback> positionCallback = createPositionCallback(args[0], succeeded); 201 if (!succeeded) 202 return v8::Undefined(); 203 ASSERT(positionCallback); 204 205 RefPtr<PositionErrorCallback> positionErrorCallback = createPositionErrorCallback(args[1], succeeded); 206 if (!succeeded) 207 return v8::Undefined(); 208 209 RefPtr<PositionOptions> positionOptions = createPositionOptions(args[2], succeeded); 210 if (!succeeded) 211 return v8::Undefined(); 212 ASSERT(positionOptions); 213 214 Geolocation* geolocation = V8Geolocation::toNative(args.Holder()); 215 int watchId = geolocation->watchPosition(positionCallback.release(), positionErrorCallback.release(), positionOptions.release()); 216 return v8::Number::New(watchId); 217 } 218 219 } // namespace WebCore 220