Home | History | Annotate | Download | only in js
      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