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 #if ENABLE(GEOLOCATION)
30
31 #include "Frame.h"
32 #include "Geolocation.h"
33 #include "V8Binding.h"
34 #include "V8CustomPositionCallback.h"
35 #include "V8CustomPositionErrorCallback.h"
36 #include "V8Utilities.h"
37
38 using namespace std;
39 using namespace WTF;
40
41 namespace WebCore {
42
createPositionOptions(v8::Local<v8::Value> value,bool & succeeded)43 static PassRefPtr<PositionOptions> createPositionOptions(v8::Local<v8::Value> value, bool& succeeded)
44 {
45 succeeded = true;
46
47 // Create default options.
48 RefPtr<PositionOptions> options = PositionOptions::create();
49
50 // Argument is optional (hence undefined is allowed), and null is allowed.
51 if (isUndefinedOrNull(value)) {
52 // Use default options.
53 return options.release();
54 }
55
56 // Given the above test, this will always yield an object.
57 v8::Local<v8::Object> object = value->ToObject();
58
59 // For all three properties, we apply the following ...
60 // - If the getter or the property's valueOf method throws an exception, we
61 // quit so as not to risk overwriting the exception.
62 // - If the value is absent or undefined, we don't override the default.
63 v8::Local<v8::Value> enableHighAccuracyValue = object->Get(v8::String::New("enableHighAccuracy"));
64 if (enableHighAccuracyValue.IsEmpty()) {
65 succeeded = false;
66 return 0;
67 }
68 if (!enableHighAccuracyValue->IsUndefined()) {
69 v8::Local<v8::Boolean> enableHighAccuracyBoolean = enableHighAccuracyValue->ToBoolean();
70 if (enableHighAccuracyBoolean.IsEmpty()) {
71 succeeded = false;
72 return 0;
73 }
74 options->setEnableHighAccuracy(enableHighAccuracyBoolean->Value());
75 }
76
77 v8::Local<v8::Value> timeoutValue = object->Get(v8::String::New("timeout"));
78 if (timeoutValue.IsEmpty()) {
79 succeeded = false;
80 return 0;
81 }
82 if (!timeoutValue->IsUndefined()) {
83 v8::Local<v8::Number> timeoutNumber = timeoutValue->ToNumber();
84 if (timeoutNumber.IsEmpty()) {
85 succeeded = false;
86 return 0;
87 }
88 double timeoutDouble = timeoutNumber->Value();
89 // If the value is positive infinity, there's nothing to do.
90 if (!(isinf(timeoutDouble) && timeoutDouble > 0)) {
91 v8::Local<v8::Int32> timeoutInt32 = timeoutValue->ToInt32();
92 if (timeoutInt32.IsEmpty()) {
93 succeeded = false;
94 return 0;
95 }
96 // Wrap to int32 and force non-negative to match behavior of window.setTimeout.
97 options->setTimeout(max(0, timeoutInt32->Value()));
98 }
99 }
100
101 v8::Local<v8::Value> maximumAgeValue = object->Get(v8::String::New("maximumAge"));
102 if (maximumAgeValue.IsEmpty()) {
103 succeeded = false;
104 return 0;
105 }
106 if (!maximumAgeValue->IsUndefined()) {
107 v8::Local<v8::Number> maximumAgeNumber = maximumAgeValue->ToNumber();
108 if (maximumAgeNumber.IsEmpty()) {
109 succeeded = false;
110 return 0;
111 }
112 double maximumAgeDouble = maximumAgeNumber->Value();
113 if (isinf(maximumAgeDouble) && maximumAgeDouble > 0) {
114 // If the value is positive infinity, clear maximumAge.
115 options->clearMaximumAge();
116 } else {
117 v8::Local<v8::Int32> maximumAgeInt32 = maximumAgeValue->ToInt32();
118 if (maximumAgeInt32.IsEmpty()) {
119 succeeded = false;
120 return 0;
121 }
122 // Wrap to int32 and force non-negative to match behavior of window.setTimeout.
123 options->setMaximumAge(max(0, maximumAgeInt32->Value()));
124 }
125 }
126
127 return options.release();
128 }
129
getCurrentPositionCallback(const v8::Arguments & args)130 v8::Handle<v8::Value> V8Geolocation::getCurrentPositionCallback(const v8::Arguments& args)
131 {
132 INC_STATS("DOM.Geolocation.getCurrentPosition()");
133
134 bool succeeded = false;
135
136 RefPtr<PositionCallback> positionCallback = createFunctionOnlyCallback<V8CustomPositionCallback>(args[0], succeeded);
137 if (!succeeded)
138 return v8::Undefined();
139 ASSERT(positionCallback);
140
141 // Argument is optional (hence undefined is allowed), and null is allowed.
142 RefPtr<PositionErrorCallback> positionErrorCallback = createFunctionOnlyCallback<V8CustomPositionErrorCallback>(args[1], succeeded, CallbackAllowUndefined | CallbackAllowNull);
143 if (!succeeded)
144 return v8::Undefined();
145
146 RefPtr<PositionOptions> positionOptions = createPositionOptions(args[2], succeeded);
147 if (!succeeded)
148 return v8::Undefined();
149 ASSERT(positionOptions);
150
151 Geolocation* geolocation = V8Geolocation::toNative(args.Holder());
152 geolocation->getCurrentPosition(positionCallback.release(), positionErrorCallback.release(), positionOptions.release());
153 return v8::Undefined();
154 }
155
watchPositionCallback(const v8::Arguments & args)156 v8::Handle<v8::Value> V8Geolocation::watchPositionCallback(const v8::Arguments& args)
157 {
158 INC_STATS("DOM.Geolocation.watchPosition()");
159
160 bool succeeded = false;
161
162 RefPtr<PositionCallback> positionCallback = createFunctionOnlyCallback<V8CustomPositionCallback>(args[0], succeeded);
163 if (!succeeded)
164 return v8::Undefined();
165 ASSERT(positionCallback);
166
167 // Argument is optional (hence undefined is allowed), and null is allowed.
168 RefPtr<PositionErrorCallback> positionErrorCallback = createFunctionOnlyCallback<V8CustomPositionErrorCallback>(args[1], succeeded, CallbackAllowUndefined | CallbackAllowNull);
169 if (!succeeded)
170 return v8::Undefined();
171
172 RefPtr<PositionOptions> positionOptions = createPositionOptions(args[2], succeeded);
173 if (!succeeded)
174 return v8::Undefined();
175 ASSERT(positionOptions);
176
177 Geolocation* geolocation = V8Geolocation::toNative(args.Holder());
178 int watchId = geolocation->watchPosition(positionCallback.release(), positionErrorCallback.release(), positionOptions.release());
179 return v8::Number::New(watchId);
180 }
181
182 } // namespace WebCore
183
184 #endif // ENABLE(GEOLOCATION)
185