From 4bb414d51f2850c0da64c0832fb0dbb0378a5707 Mon Sep 17 00:00:00 2001 From: Steve Block Date: Wed, 2 Sep 2009 18:13:59 +0100 Subject: [PATCH] Fixes Geolocation to correctly handle infinite values for PositionOptions properties. This fixes http://b/issue?id=2094429. Change-Id: I01cc5107d4a96840e35cc403161d50dbdf6a1ca2 --- WebCore/bindings/js/JSGeolocationCustom.cpp | 22 +++++++++-- WebCore/bindings/v8/custom/V8GeolocationCustom.cpp | 43 ++++++++++++++++++---- WebCore/page/PositionOptions.h | 12 +++++- 3 files changed, 63 insertions(+), 14 deletions(-) diff --git a/WebCore/bindings/js/JSGeolocationCustom.cpp b/WebCore/bindings/js/JSGeolocationCustom.cpp index 6379a1c55..8ef86011b 100644 --- a/WebCore/bindings/js/JSGeolocationCustom.cpp +++ b/WebCore/bindings/js/JSGeolocationCustom.cpp @@ -101,20 +101,34 @@ static PassRefPtr createPositionOptions(ExecState* exec, JSValu if (exec->hadException()) return 0; if (!timeoutValue.isUndefined()) { - // Wrap to int32 and force non-negative to match behavior of window.setTimeout. - options->setTimeout(max(0, timeoutValue.toInt32(exec))); + double timeoutNumber = timeoutValue.toNumber(exec); if (exec->hadException()) return 0; + // If the value is infinity, there's nothing to do. + if (timeoutNumber != Inf) { + // Wrap to int32 and force non-negative to match behavior of window.setTimeout. + options->setTimeout(max(0, timeoutValue.toInt32(exec))); + if (exec->hadException()) + return 0; + } } JSValue maximumAgeValue = object->get(exec, Identifier(exec, "maximumAge")); if (exec->hadException()) return 0; if (!maximumAgeValue.isUndefined()) { - // Wrap to int32 and force non-negative to match behavior of window.setTimeout. - options->setMaximumAge(max(0, maximumAgeValue.toInt32(exec))); + double maximumAgeNumber = maximumAgeValue.toNumber(exec); if (exec->hadException()) return 0; + if (maximumAgeNumber == Inf) { + // If the value is infinity, clear maximumAge. + options->clearMaximumAge(); + } else { + // Wrap to int32 and force non-negative to match behavior of window.setTimeout. + options->setMaximumAge(max(0, maximumAgeValue.toInt32(exec))); + if (exec->hadException()) + return 0; + } } return options.release(); diff --git a/WebCore/bindings/v8/custom/V8GeolocationCustom.cpp b/WebCore/bindings/v8/custom/V8GeolocationCustom.cpp index 5373626ae..7bc687cbe 100644 --- a/WebCore/bindings/v8/custom/V8GeolocationCustom.cpp +++ b/WebCore/bindings/v8/custom/V8GeolocationCustom.cpp @@ -38,6 +38,7 @@ #include "V8Proxy.h" +using namespace std; using namespace WTF; namespace WebCore { @@ -123,13 +124,28 @@ static PassRefPtr createPositionOptions(v8::Local va return 0; } if (!timeoutValue->IsUndefined()) { - v8::Local timeoutInt32 = timeoutValue->ToInt32(); - if (timeoutInt32.IsEmpty()) { + v8::Local timeoutNumber = timeoutValue->ToNumber(); + if (timeoutNumber.IsEmpty()) { succeeded = false; return 0; } - // Wrap to int32 and force non-negative to match behavior of window.setTimeout. - options->setTimeout(max(0, timeoutInt32->Value())); + double timeoutDouble = timeoutNumber->Value(); + // V8 does not export a public symbol for infinity, so we must use a + // platform type. On Android, it seems that V8 uses 0xf70f000000000000, + // which is the standard way to represent infinity in a double. However, + // numeric_limits::infinity uses the system HUGE_VAL, which is + // different. Therefore we test using isinf() and check that the value + // is positive, which seems to handle things correctly. + // If the value is infinity, there's nothing to do. + if (!(isinf(timeoutDouble) && timeoutDouble > 0)) { + v8::Local timeoutInt32 = timeoutValue->ToInt32(); + if (timeoutInt32.IsEmpty()) { + succeeded = false; + return 0; + } + // Wrap to int32 and force non-negative to match behavior of window.setTimeout. + options->setTimeout(max(0, timeoutInt32->Value())); + } } v8::Local maximumAgeValue = object->Get(v8::String::New("maximumAge")); @@ -138,13 +154,24 @@ static PassRefPtr createPositionOptions(v8::Local va return 0; } if (!maximumAgeValue->IsUndefined()) { - v8::Local maximumAgeInt32 = maximumAgeValue->ToInt32(); - if (maximumAgeInt32.IsEmpty()) { + v8::Local maximumAgeNumber = maximumAgeValue->ToNumber(); + if (maximumAgeNumber.IsEmpty()) { succeeded = false; return 0; } - // Wrap to int32 and force non-negative to match behavior of window.setTimeout. - options->setMaximumAge(max(0, maximumAgeInt32->Value())); + double maximumAgeDouble = maximumAgeNumber->Value(); + if (isinf(maximumAgeDouble) && maximumAgeDouble > 0) { + // If the value is infinity, clear maximumAge. + options->clearMaximumAge(); + } else { + v8::Local maximumAgeInt32 = maximumAgeValue->ToInt32(); + if (maximumAgeInt32.IsEmpty()) { + succeeded = false; + return 0; + } + // Wrap to int32 and force non-negative to match behavior of window.setTimeout. + options->setMaximumAge(max(0, maximumAgeInt32->Value())); + } } return options.release(); diff --git a/WebCore/page/PositionOptions.h b/WebCore/page/PositionOptions.h index ee8530aaf..59009987d 100644 --- a/WebCore/page/PositionOptions.h +++ b/WebCore/page/PositionOptions.h @@ -49,10 +49,17 @@ public: m_hasTimeout = true; m_timeout = timeout; } - int maximumAge() const { return m_maximumAge; } + bool hasMaximumAge() const { return m_hasMaximumAge; } + int maximumAge() const + { + ASSERT(hasMaximumAge()); + return m_maximumAge; + } + void clearMaximumAge() { m_hasMaximumAge = false; } void setMaximumAge(int age) { ASSERT(age >= 0); + m_hasMaximumAge = true; m_maximumAge = age; } @@ -60,13 +67,14 @@ private: PositionOptions() : m_highAccuracy(false) , m_hasTimeout(false) - , m_maximumAge(0) { + setMaximumAge(0); } bool m_highAccuracy; bool m_hasTimeout; int m_timeout; + bool m_hasMaximumAge; int m_maximumAge; }; -- 2.11.0