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 
createPositionOptions(ExecState * exec,JSValue value)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 
getCurrentPosition(ExecState * exec)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 
watchPosition(ExecState * exec)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