Home | History | Annotate | Download | only in javascript
      1 // Copyright 2014 PDFium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
      6 
      7 #include "fpdfsdk/javascript/JS_Value.h"
      8 
      9 #include <time.h>
     10 
     11 #include <algorithm>
     12 #include <cmath>
     13 #include <limits>
     14 #include <vector>
     15 
     16 #include "fpdfsdk/javascript/Document.h"
     17 #include "fpdfsdk/javascript/JS_Define.h"
     18 #include "fpdfsdk/javascript/JS_Object.h"
     19 
     20 namespace {
     21 
     22 const uint32_t g_nan[2] = {0, 0x7FF80000};
     23 
     24 double GetNan() {
     25   return *(double*)g_nan;
     26 }
     27 
     28 double
     29 MakeDate(int year, int mon, int day, int hour, int min, int sec, int ms) {
     30   return JS_MakeDate(JS_MakeDay(year, mon, day),
     31                      JS_MakeTime(hour, min, sec, ms));
     32 }
     33 
     34 }  // namespace
     35 
     36 CJS_Value::CJS_Value(CJS_Runtime* pRuntime) {}
     37 
     38 CJS_Value::CJS_Value(CJS_Runtime* pRuntime, v8::Local<v8::Value> pValue)
     39     : m_pValue(pValue) {}
     40 
     41 CJS_Value::CJS_Value(CJS_Runtime* pRuntime, const int& iValue)
     42     : m_pValue(pRuntime->NewNumber(iValue)) {}
     43 
     44 CJS_Value::CJS_Value(CJS_Runtime* pRuntime, const bool& bValue)
     45     : m_pValue(pRuntime->NewBoolean(bValue)) {}
     46 
     47 CJS_Value::CJS_Value(CJS_Runtime* pRuntime, const float& fValue)
     48     : m_pValue(pRuntime->NewNumber(fValue)) {}
     49 
     50 CJS_Value::CJS_Value(CJS_Runtime* pRuntime, const double& dValue)
     51     : m_pValue(pRuntime->NewNumber(dValue)) {}
     52 
     53 CJS_Value::CJS_Value(CJS_Runtime* pRuntime, CJS_Object* pObj) {
     54   if (pObj)
     55     m_pValue = pObj->ToV8Object();
     56 }
     57 
     58 CJS_Value::CJS_Value(CJS_Runtime* pRuntime, const FX_WCHAR* pWstr)
     59     : m_pValue(pRuntime->NewString(pWstr)) {}
     60 
     61 CJS_Value::CJS_Value(CJS_Runtime* pRuntime, const FX_CHAR* pStr)
     62     : m_pValue(pRuntime->NewString(CFX_WideString::FromLocal(pStr).c_str())) {}
     63 
     64 CJS_Value::CJS_Value(CJS_Runtime* pRuntime, const CJS_Array& array)
     65     : m_pValue(array.ToV8Array(pRuntime)) {}
     66 
     67 CJS_Value::CJS_Value(CJS_Runtime* pRuntime, const CJS_Date& date)
     68     : m_pValue(date.ToV8Date(pRuntime)) {}
     69 
     70 CJS_Value::~CJS_Value() {}
     71 
     72 CJS_Value::CJS_Value(const CJS_Value& other) = default;
     73 
     74 void CJS_Value::Attach(v8::Local<v8::Value> pValue) {
     75   m_pValue = pValue;
     76 }
     77 
     78 void CJS_Value::Detach() {
     79   m_pValue = v8::Local<v8::Value>();
     80 }
     81 
     82 int CJS_Value::ToInt(CJS_Runtime* pRuntime) const {
     83   return pRuntime->ToInt32(m_pValue);
     84 }
     85 
     86 bool CJS_Value::ToBool(CJS_Runtime* pRuntime) const {
     87   return pRuntime->ToBoolean(m_pValue);
     88 }
     89 
     90 double CJS_Value::ToDouble(CJS_Runtime* pRuntime) const {
     91   return pRuntime->ToDouble(m_pValue);
     92 }
     93 
     94 float CJS_Value::ToFloat(CJS_Runtime* pRuntime) const {
     95   return (float)ToDouble(pRuntime);
     96 }
     97 
     98 CJS_Object* CJS_Value::ToCJSObject(CJS_Runtime* pRuntime) const {
     99   v8::Local<v8::Object> pObj = pRuntime->ToObject(m_pValue);
    100   return static_cast<CJS_Object*>(pRuntime->GetObjectPrivate(pObj));
    101 }
    102 
    103 v8::Local<v8::Object> CJS_Value::ToV8Object(CJS_Runtime* pRuntime) const {
    104   return pRuntime->ToObject(m_pValue);
    105 }
    106 
    107 CFX_WideString CJS_Value::ToCFXWideString(CJS_Runtime* pRuntime) const {
    108   return pRuntime->ToWideString(m_pValue);
    109 }
    110 
    111 CFX_ByteString CJS_Value::ToCFXByteString(CJS_Runtime* pRuntime) const {
    112   return CFX_ByteString::FromUnicode(ToCFXWideString(pRuntime));
    113 }
    114 
    115 v8::Local<v8::Value> CJS_Value::ToV8Value(CJS_Runtime* pRuntime) const {
    116   return m_pValue;
    117 }
    118 
    119 v8::Local<v8::Array> CJS_Value::ToV8Array(CJS_Runtime* pRuntime) const {
    120   return pRuntime->ToArray(m_pValue);
    121 }
    122 
    123 void CJS_Value::SetNull(CJS_Runtime* pRuntime) {
    124   m_pValue = pRuntime->NewNull();
    125 }
    126 
    127 void CJS_Value::MaybeCoerceToNumber(CJS_Runtime* pRuntime) {
    128   bool bAllowNaN = false;
    129   if (GetType() == VT_string) {
    130     CFX_ByteString bstr = ToCFXByteString(pRuntime);
    131     if (bstr.GetLength() == 0)
    132       return;
    133     if (bstr == "NaN")
    134       bAllowNaN = true;
    135   }
    136   v8::Isolate* pIsolate = pRuntime->GetIsolate();
    137   v8::TryCatch try_catch(pIsolate);
    138   v8::MaybeLocal<v8::Number> maybeNum =
    139       m_pValue->ToNumber(pIsolate->GetCurrentContext());
    140   if (maybeNum.IsEmpty())
    141     return;
    142   v8::Local<v8::Number> num = maybeNum.ToLocalChecked();
    143   if (std::isnan(num->Value()) && !bAllowNaN)
    144     return;
    145   m_pValue = num;
    146 }
    147 
    148 // static
    149 CJS_Value::Type CJS_Value::GetValueType(v8::Local<v8::Value> value) {
    150   if (value.IsEmpty())
    151     return VT_unknown;
    152   if (value->IsString())
    153     return VT_string;
    154   if (value->IsNumber())
    155     return VT_number;
    156   if (value->IsBoolean())
    157     return VT_boolean;
    158   if (value->IsDate())
    159     return VT_date;
    160   if (value->IsObject())
    161     return VT_object;
    162   if (value->IsNull())
    163     return VT_null;
    164   if (value->IsUndefined())
    165     return VT_undefined;
    166   return VT_unknown;
    167 }
    168 
    169 bool CJS_Value::IsArrayObject() const {
    170   return !m_pValue.IsEmpty() && m_pValue->IsArray();
    171 }
    172 
    173 bool CJS_Value::IsDateObject() const {
    174   return !m_pValue.IsEmpty() && m_pValue->IsDate();
    175 }
    176 
    177 bool CJS_Value::ConvertToArray(CJS_Runtime* pRuntime, CJS_Array& array) const {
    178   if (!IsArrayObject())
    179     return false;
    180   array.Attach(pRuntime->ToArray(m_pValue));
    181   return true;
    182 }
    183 
    184 bool CJS_Value::ConvertToDate(CJS_Runtime* pRuntime, CJS_Date& date) const {
    185   if (!IsDateObject())
    186     return false;
    187   v8::Local<v8::Value> mutable_value = m_pValue;
    188   date.Attach(mutable_value.As<v8::Date>());
    189   return true;
    190 }
    191 
    192 CJS_PropValue::CJS_PropValue(CJS_Runtime* pRuntime)
    193     : m_bIsSetting(0), m_Value(pRuntime), m_pJSRuntime(pRuntime) {}
    194 
    195 CJS_PropValue::CJS_PropValue(CJS_Runtime* pRuntime, const CJS_Value& value)
    196     : m_bIsSetting(0), m_Value(value), m_pJSRuntime(pRuntime) {}
    197 
    198 CJS_PropValue::~CJS_PropValue() {}
    199 
    200 void CJS_PropValue::operator<<(int iValue) {
    201   ASSERT(!m_bIsSetting);
    202   m_Value = CJS_Value(m_pJSRuntime, iValue);
    203 }
    204 
    205 void CJS_PropValue::operator>>(int& iValue) const {
    206   ASSERT(m_bIsSetting);
    207   iValue = m_Value.ToInt(m_pJSRuntime);
    208 }
    209 
    210 void CJS_PropValue::operator<<(bool bValue) {
    211   ASSERT(!m_bIsSetting);
    212   m_Value = CJS_Value(m_pJSRuntime, bValue);
    213 }
    214 
    215 void CJS_PropValue::operator>>(bool& bValue) const {
    216   ASSERT(m_bIsSetting);
    217   bValue = m_Value.ToBool(m_pJSRuntime);
    218 }
    219 
    220 void CJS_PropValue::operator<<(double dValue) {
    221   ASSERT(!m_bIsSetting);
    222   m_Value = CJS_Value(m_pJSRuntime, dValue);
    223 }
    224 
    225 void CJS_PropValue::operator>>(double& dValue) const {
    226   ASSERT(m_bIsSetting);
    227   dValue = m_Value.ToDouble(m_pJSRuntime);
    228 }
    229 
    230 void CJS_PropValue::operator<<(CJS_Object* pObj) {
    231   ASSERT(!m_bIsSetting);
    232   m_Value = CJS_Value(m_pJSRuntime, pObj);
    233 }
    234 
    235 void CJS_PropValue::operator>>(CJS_Object*& ppObj) const {
    236   ASSERT(m_bIsSetting);
    237   ppObj = m_Value.ToCJSObject(m_pJSRuntime);
    238 }
    239 
    240 void CJS_PropValue::operator<<(CJS_Document* pJsDoc) {
    241   ASSERT(!m_bIsSetting);
    242   m_Value = CJS_Value(m_pJSRuntime, pJsDoc);
    243 }
    244 
    245 void CJS_PropValue::operator>>(CJS_Document*& ppJsDoc) const {
    246   ASSERT(m_bIsSetting);
    247   ppJsDoc = static_cast<CJS_Document*>(m_Value.ToCJSObject(m_pJSRuntime));
    248 }
    249 
    250 void CJS_PropValue::operator<<(v8::Local<v8::Object> pObj) {
    251   ASSERT(!m_bIsSetting);
    252   m_Value = CJS_Value(m_pJSRuntime, pObj);
    253 }
    254 
    255 void CJS_PropValue::operator>>(v8::Local<v8::Object>& ppObj) const {
    256   ASSERT(m_bIsSetting);
    257   ppObj = m_Value.ToV8Object(m_pJSRuntime);
    258 }
    259 
    260 void CJS_PropValue::operator<<(CFX_ByteString str) {
    261   ASSERT(!m_bIsSetting);
    262   m_Value = CJS_Value(m_pJSRuntime, str.c_str());
    263 }
    264 
    265 void CJS_PropValue::operator>>(CFX_ByteString& str) const {
    266   ASSERT(m_bIsSetting);
    267   str = m_Value.ToCFXByteString(m_pJSRuntime);
    268 }
    269 
    270 void CJS_PropValue::operator<<(const FX_WCHAR* str) {
    271   ASSERT(!m_bIsSetting);
    272   m_Value = CJS_Value(m_pJSRuntime, str);
    273 }
    274 
    275 void CJS_PropValue::operator>>(CFX_WideString& wide_string) const {
    276   ASSERT(m_bIsSetting);
    277   wide_string = m_Value.ToCFXWideString(m_pJSRuntime);
    278 }
    279 
    280 void CJS_PropValue::operator<<(CFX_WideString wide_string) {
    281   ASSERT(!m_bIsSetting);
    282   m_Value = CJS_Value(m_pJSRuntime, wide_string.c_str());
    283 }
    284 
    285 void CJS_PropValue::operator>>(CJS_Array& array) const {
    286   ASSERT(m_bIsSetting);
    287   m_Value.ConvertToArray(m_pJSRuntime, array);
    288 }
    289 
    290 void CJS_PropValue::operator<<(CJS_Array& array) {
    291   ASSERT(!m_bIsSetting);
    292   m_Value = CJS_Value(m_pJSRuntime, array.ToV8Array(m_pJSRuntime));
    293 }
    294 
    295 void CJS_PropValue::operator>>(CJS_Date& date) const {
    296   ASSERT(m_bIsSetting);
    297   m_Value.ConvertToDate(m_pJSRuntime, date);
    298 }
    299 
    300 void CJS_PropValue::operator<<(CJS_Date& date) {
    301   ASSERT(!m_bIsSetting);
    302   m_Value = CJS_Value(m_pJSRuntime, date);
    303 }
    304 
    305 CJS_Array::CJS_Array() {}
    306 
    307 CJS_Array::CJS_Array(const CJS_Array& other) = default;
    308 
    309 CJS_Array::~CJS_Array() {}
    310 
    311 void CJS_Array::Attach(v8::Local<v8::Array> pArray) {
    312   m_pArray = pArray;
    313 }
    314 
    315 void CJS_Array::GetElement(CJS_Runtime* pRuntime,
    316                            unsigned index,
    317                            CJS_Value& value) const {
    318   if (!m_pArray.IsEmpty())
    319     value.Attach(pRuntime->GetArrayElement(m_pArray, index));
    320 }
    321 
    322 void CJS_Array::SetElement(CJS_Runtime* pRuntime,
    323                            unsigned index,
    324                            const CJS_Value& value) {
    325   if (m_pArray.IsEmpty())
    326     m_pArray = pRuntime->NewArray();
    327 
    328   pRuntime->PutArrayElement(m_pArray, index, value.ToV8Value(pRuntime));
    329 }
    330 
    331 int CJS_Array::GetLength(CJS_Runtime* pRuntime) const {
    332   if (m_pArray.IsEmpty())
    333     return 0;
    334   return pRuntime->GetArrayLength(m_pArray);
    335 }
    336 
    337 v8::Local<v8::Array> CJS_Array::ToV8Array(CJS_Runtime* pRuntime) const {
    338   if (m_pArray.IsEmpty())
    339     m_pArray = pRuntime->NewArray();
    340 
    341   return m_pArray;
    342 }
    343 
    344 CJS_Date::CJS_Date() {}
    345 
    346 CJS_Date::CJS_Date(CJS_Runtime* pRuntime, double dMsecTime)
    347     : m_pDate(pRuntime->NewDate(dMsecTime)) {}
    348 
    349 CJS_Date::CJS_Date(CJS_Runtime* pRuntime,
    350                    int year,
    351                    int mon,
    352                    int day,
    353                    int hour,
    354                    int min,
    355                    int sec)
    356     : m_pDate(pRuntime->NewDate(MakeDate(year, mon, day, hour, min, sec, 0))) {}
    357 
    358 CJS_Date::~CJS_Date() {}
    359 
    360 bool CJS_Date::IsValidDate(CJS_Runtime* pRuntime) const {
    361   return !m_pDate.IsEmpty() && !JS_PortIsNan(pRuntime->ToDouble(m_pDate));
    362 }
    363 
    364 void CJS_Date::Attach(v8::Local<v8::Date> pDate) {
    365   m_pDate = pDate;
    366 }
    367 
    368 int CJS_Date::GetYear(CJS_Runtime* pRuntime) const {
    369   if (!IsValidDate(pRuntime))
    370     return 0;
    371 
    372   return JS_GetYearFromTime(JS_LocalTime(pRuntime->ToDouble(m_pDate)));
    373 }
    374 
    375 void CJS_Date::SetYear(CJS_Runtime* pRuntime, int iYear) {
    376   m_pDate = pRuntime->NewDate(
    377       MakeDate(iYear, GetMonth(pRuntime), GetDay(pRuntime), GetHours(pRuntime),
    378                GetMinutes(pRuntime), GetSeconds(pRuntime), 0));
    379 }
    380 
    381 int CJS_Date::GetMonth(CJS_Runtime* pRuntime) const {
    382   if (!IsValidDate(pRuntime))
    383     return 0;
    384 
    385   return JS_GetMonthFromTime(JS_LocalTime(pRuntime->ToDouble(m_pDate)));
    386 }
    387 
    388 void CJS_Date::SetMonth(CJS_Runtime* pRuntime, int iMonth) {
    389   m_pDate = pRuntime->NewDate(
    390       MakeDate(GetYear(pRuntime), iMonth, GetDay(pRuntime), GetHours(pRuntime),
    391                GetMinutes(pRuntime), GetSeconds(pRuntime), 0));
    392 }
    393 
    394 int CJS_Date::GetDay(CJS_Runtime* pRuntime) const {
    395   if (!IsValidDate(pRuntime))
    396     return 0;
    397 
    398   return JS_GetDayFromTime(JS_LocalTime(pRuntime->ToDouble(m_pDate)));
    399 }
    400 
    401 void CJS_Date::SetDay(CJS_Runtime* pRuntime, int iDay) {
    402   m_pDate = pRuntime->NewDate(
    403       MakeDate(GetYear(pRuntime), GetMonth(pRuntime), iDay, GetHours(pRuntime),
    404                GetMinutes(pRuntime), GetSeconds(pRuntime), 0));
    405 }
    406 
    407 int CJS_Date::GetHours(CJS_Runtime* pRuntime) const {
    408   if (!IsValidDate(pRuntime))
    409     return 0;
    410 
    411   return JS_GetHourFromTime(JS_LocalTime(pRuntime->ToDouble(m_pDate)));
    412 }
    413 
    414 void CJS_Date::SetHours(CJS_Runtime* pRuntime, int iHours) {
    415   m_pDate = pRuntime->NewDate(
    416       MakeDate(GetYear(pRuntime), GetMonth(pRuntime), GetDay(pRuntime), iHours,
    417                GetMinutes(pRuntime), GetSeconds(pRuntime), 0));
    418 }
    419 
    420 int CJS_Date::GetMinutes(CJS_Runtime* pRuntime) const {
    421   if (!IsValidDate(pRuntime))
    422     return 0;
    423 
    424   return JS_GetMinFromTime(JS_LocalTime(pRuntime->ToDouble(m_pDate)));
    425 }
    426 
    427 void CJS_Date::SetMinutes(CJS_Runtime* pRuntime, int minutes) {
    428   m_pDate = pRuntime->NewDate(MakeDate(GetYear(pRuntime), GetMonth(pRuntime),
    429                                        GetDay(pRuntime), GetHours(pRuntime),
    430                                        minutes, GetSeconds(pRuntime), 0));
    431 }
    432 
    433 int CJS_Date::GetSeconds(CJS_Runtime* pRuntime) const {
    434   if (!IsValidDate(pRuntime))
    435     return 0;
    436 
    437   return JS_GetSecFromTime(JS_LocalTime(pRuntime->ToDouble(m_pDate)));
    438 }
    439 
    440 void CJS_Date::SetSeconds(CJS_Runtime* pRuntime, int seconds) {
    441   m_pDate = pRuntime->NewDate(MakeDate(GetYear(pRuntime), GetMonth(pRuntime),
    442                                        GetDay(pRuntime), GetHours(pRuntime),
    443                                        GetMinutes(pRuntime), seconds, 0));
    444 }
    445 
    446 double CJS_Date::ToDouble(CJS_Runtime* pRuntime) const {
    447   return !m_pDate.IsEmpty() ? pRuntime->ToDouble(m_pDate) : 0.0;
    448 }
    449 
    450 CFX_WideString CJS_Date::ToString(CJS_Runtime* pRuntime) const {
    451   return !m_pDate.IsEmpty() ? pRuntime->ToWideString(m_pDate)
    452                             : CFX_WideString();
    453 }
    454 
    455 v8::Local<v8::Date> CJS_Date::ToV8Date(CJS_Runtime* pRuntime) const {
    456   return m_pDate;
    457 }
    458 
    459 double _getLocalTZA() {
    460   if (!FSDK_IsSandBoxPolicyEnabled(FPDF_POLICY_MACHINETIME_ACCESS))
    461     return 0;
    462   time_t t = 0;
    463   time(&t);
    464   localtime(&t);
    465 #if _MSC_VER >= 1900
    466   // In gcc and in Visual Studio prior to VS 2015 'timezone' is a global
    467   // variable declared in time.h. That variable was deprecated and in VS 2015
    468   // is removed, with _get_timezone replacing it.
    469   long timezone = 0;
    470   _get_timezone(&timezone);
    471 #endif
    472   return (double)(-(timezone * 1000));
    473 }
    474 
    475 int _getDaylightSavingTA(double d) {
    476   if (!FSDK_IsSandBoxPolicyEnabled(FPDF_POLICY_MACHINETIME_ACCESS))
    477     return 0;
    478   time_t t = (time_t)(d / 1000);
    479   struct tm* tmp = localtime(&t);
    480   if (!tmp)
    481     return 0;
    482   if (tmp->tm_isdst > 0)
    483     // One hour.
    484     return (int)60 * 60 * 1000;
    485   return 0;
    486 }
    487 
    488 double _Mod(double x, double y) {
    489   double r = fmod(x, y);
    490   if (r < 0)
    491     r += y;
    492   return r;
    493 }
    494 
    495 int _isfinite(double v) {
    496 #if _MSC_VER
    497   return ::_finite(v);
    498 #else
    499   return std::fabs(v) < std::numeric_limits<double>::max();
    500 #endif
    501 }
    502 
    503 double _toInteger(double n) {
    504   return (n >= 0) ? FXSYS_floor(n) : -FXSYS_floor(-n);
    505 }
    506 
    507 bool _isLeapYear(int year) {
    508   return (year % 4 == 0) && ((year % 100 != 0) || (year % 400 != 0));
    509 }
    510 
    511 int _DayFromYear(int y) {
    512   return (int)(365 * (y - 1970.0) + FXSYS_floor((y - 1969.0) / 4) -
    513                FXSYS_floor((y - 1901.0) / 100) +
    514                FXSYS_floor((y - 1601.0) / 400));
    515 }
    516 
    517 double _TimeFromYear(int y) {
    518   return 86400000.0 * _DayFromYear(y);
    519 }
    520 
    521 static const uint16_t daysMonth[12] = {0,   31,  59,  90,  120, 151,
    522                                        181, 212, 243, 273, 304, 334};
    523 static const uint16_t leapDaysMonth[12] = {0,   31,  60,  91,  121, 152,
    524                                            182, 213, 244, 274, 305, 335};
    525 
    526 double _TimeFromYearMonth(int y, int m) {
    527   const uint16_t* pMonth = _isLeapYear(y) ? leapDaysMonth : daysMonth;
    528   return _TimeFromYear(y) + ((double)pMonth[m]) * 86400000;
    529 }
    530 
    531 int _Day(double t) {
    532   return (int)FXSYS_floor(t / 86400000);
    533 }
    534 
    535 int _YearFromTime(double t) {
    536   // estimate the time.
    537   int y = 1970 + static_cast<int>(t / (365.2425 * 86400000));
    538   if (_TimeFromYear(y) <= t) {
    539     while (_TimeFromYear(y + 1) <= t)
    540       y++;
    541   } else {
    542     while (_TimeFromYear(y) > t)
    543       y--;
    544   }
    545   return y;
    546 }
    547 
    548 int _DayWithinYear(double t) {
    549   int year = _YearFromTime(t);
    550   int day = _Day(t);
    551   return day - _DayFromYear(year);
    552 }
    553 
    554 int _MonthFromTime(double t) {
    555   int day = _DayWithinYear(t);
    556   int year = _YearFromTime(t);
    557   if (0 <= day && day < 31)
    558     return 0;
    559   if (31 <= day && day < 59 + _isLeapYear(year))
    560     return 1;
    561   if ((59 + _isLeapYear(year)) <= day && day < (90 + _isLeapYear(year)))
    562     return 2;
    563   if ((90 + _isLeapYear(year)) <= day && day < (120 + _isLeapYear(year)))
    564     return 3;
    565   if ((120 + _isLeapYear(year)) <= day && day < (151 + _isLeapYear(year)))
    566     return 4;
    567   if ((151 + _isLeapYear(year)) <= day && day < (181 + _isLeapYear(year)))
    568     return 5;
    569   if ((181 + _isLeapYear(year)) <= day && day < (212 + _isLeapYear(year)))
    570     return 6;
    571   if ((212 + _isLeapYear(year)) <= day && day < (243 + _isLeapYear(year)))
    572     return 7;
    573   if ((243 + _isLeapYear(year)) <= day && day < (273 + _isLeapYear(year)))
    574     return 8;
    575   if ((273 + _isLeapYear(year)) <= day && day < (304 + _isLeapYear(year)))
    576     return 9;
    577   if ((304 + _isLeapYear(year)) <= day && day < (334 + _isLeapYear(year)))
    578     return 10;
    579   if ((334 + _isLeapYear(year)) <= day && day < (365 + _isLeapYear(year)))
    580     return 11;
    581 
    582   return -1;
    583 }
    584 
    585 int _DateFromTime(double t) {
    586   int day = _DayWithinYear(t);
    587   int year = _YearFromTime(t);
    588   int leap = _isLeapYear(year);
    589   int month = _MonthFromTime(t);
    590   switch (month) {
    591     case 0:
    592       return day + 1;
    593     case 1:
    594       return day - 30;
    595     case 2:
    596       return day - 58 - leap;
    597     case 3:
    598       return day - 89 - leap;
    599     case 4:
    600       return day - 119 - leap;
    601     case 5:
    602       return day - 150 - leap;
    603     case 6:
    604       return day - 180 - leap;
    605     case 7:
    606       return day - 211 - leap;
    607     case 8:
    608       return day - 242 - leap;
    609     case 9:
    610       return day - 272 - leap;
    611     case 10:
    612       return day - 303 - leap;
    613     case 11:
    614       return day - 333 - leap;
    615     default:
    616       return 0;
    617   }
    618 }
    619 
    620 double JS_GetDateTime() {
    621   if (!FSDK_IsSandBoxPolicyEnabled(FPDF_POLICY_MACHINETIME_ACCESS))
    622     return 0;
    623   time_t t = time(nullptr);
    624   struct tm* pTm = localtime(&t);
    625 
    626   int year = pTm->tm_year + 1900;
    627   double t1 = _TimeFromYear(year);
    628 
    629   return t1 + pTm->tm_yday * 86400000.0 + pTm->tm_hour * 3600000.0 +
    630          pTm->tm_min * 60000.0 + pTm->tm_sec * 1000.0;
    631 }
    632 
    633 int JS_GetYearFromTime(double dt) {
    634   return _YearFromTime(dt);
    635 }
    636 
    637 int JS_GetMonthFromTime(double dt) {
    638   return _MonthFromTime(dt);
    639 }
    640 
    641 int JS_GetDayFromTime(double dt) {
    642   return _DateFromTime(dt);
    643 }
    644 
    645 int JS_GetHourFromTime(double dt) {
    646   return (int)_Mod(floor(dt / (60 * 60 * 1000)), 24);
    647 }
    648 
    649 int JS_GetMinFromTime(double dt) {
    650   return (int)_Mod(floor(dt / (60 * 1000)), 60);
    651 }
    652 
    653 int JS_GetSecFromTime(double dt) {
    654   return (int)_Mod(floor(dt / 1000), 60);
    655 }
    656 
    657 double JS_DateParse(const CFX_WideString& str) {
    658   v8::Isolate* pIsolate = v8::Isolate::GetCurrent();
    659   v8::Isolate::Scope isolate_scope(pIsolate);
    660   v8::HandleScope scope(pIsolate);
    661 
    662   v8::Local<v8::Context> context = pIsolate->GetCurrentContext();
    663 
    664   // Use the built-in object method.
    665   v8::Local<v8::Value> v =
    666       context->Global()
    667           ->Get(context, v8::String::NewFromUtf8(pIsolate, "Date",
    668                                                  v8::NewStringType::kNormal)
    669                              .ToLocalChecked())
    670           .ToLocalChecked();
    671   if (v->IsObject()) {
    672     v8::Local<v8::Object> o = v->ToObject(context).ToLocalChecked();
    673     v = o->Get(context, v8::String::NewFromUtf8(pIsolate, "parse",
    674                                                 v8::NewStringType::kNormal)
    675                             .ToLocalChecked())
    676             .ToLocalChecked();
    677     if (v->IsFunction()) {
    678       v8::Local<v8::Function> funC = v8::Local<v8::Function>::Cast(v);
    679       const int argc = 1;
    680       v8::Local<v8::Value> timeStr =
    681           CJS_Runtime::CurrentRuntimeFromIsolate(pIsolate)->NewString(
    682               str.AsStringC());
    683       v8::Local<v8::Value> argv[argc] = {timeStr};
    684       v = funC->Call(context, context->Global(), argc, argv).ToLocalChecked();
    685       if (v->IsNumber()) {
    686         double date = v->ToNumber(context).ToLocalChecked()->Value();
    687         if (!_isfinite(date))
    688           return date;
    689         return JS_LocalTime(date);
    690       }
    691     }
    692   }
    693   return 0;
    694 }
    695 
    696 double JS_MakeDay(int nYear, int nMonth, int nDate) {
    697   if (!_isfinite(nYear) || !_isfinite(nMonth) || !_isfinite(nDate))
    698     return GetNan();
    699   double y = _toInteger(nYear);
    700   double m = _toInteger(nMonth);
    701   double dt = _toInteger(nDate);
    702   double ym = y + FXSYS_floor((double)m / 12);
    703   double mn = _Mod(m, 12);
    704 
    705   double t = _TimeFromYearMonth((int)ym, (int)mn);
    706 
    707   if (_YearFromTime(t) != ym || _MonthFromTime(t) != mn ||
    708       _DateFromTime(t) != 1)
    709     return GetNan();
    710   return _Day(t) + dt - 1;
    711 }
    712 
    713 double JS_MakeTime(int nHour, int nMin, int nSec, int nMs) {
    714   if (!_isfinite(nHour) || !_isfinite(nMin) || !_isfinite(nSec) ||
    715       !_isfinite(nMs))
    716     return GetNan();
    717 
    718   double h = _toInteger(nHour);
    719   double m = _toInteger(nMin);
    720   double s = _toInteger(nSec);
    721   double milli = _toInteger(nMs);
    722 
    723   return h * 3600000 + m * 60000 + s * 1000 + milli;
    724 }
    725 
    726 double JS_MakeDate(double day, double time) {
    727   if (!_isfinite(day) || !_isfinite(time))
    728     return GetNan();
    729 
    730   return day * 86400000 + time;
    731 }
    732 
    733 bool JS_PortIsNan(double d) {
    734   return d != d;
    735 }
    736 
    737 double JS_LocalTime(double d) {
    738   return d + _getLocalTZA() + _getDaylightSavingTA(d);
    739 }
    740 
    741 std::vector<CJS_Value> JS_ExpandKeywordParams(
    742     CJS_Runtime* pRuntime,
    743     const std::vector<CJS_Value>& originals,
    744     size_t nKeywords,
    745     ...) {
    746   ASSERT(nKeywords);
    747 
    748   std::vector<CJS_Value> result(nKeywords, CJS_Value(pRuntime));
    749   size_t size = std::min(originals.size(), nKeywords);
    750   for (size_t i = 0; i < size; ++i)
    751     result[i] = originals[i];
    752 
    753   if (originals.size() != 1 || originals[0].GetType() != CJS_Value::VT_object ||
    754       originals[0].IsArrayObject()) {
    755     return result;
    756   }
    757   v8::Local<v8::Object> pObj = originals[0].ToV8Object(pRuntime);
    758   result[0] = CJS_Value(pRuntime);  // Make unknown.
    759 
    760   va_list ap;
    761   va_start(ap, nKeywords);
    762   for (size_t i = 0; i < nKeywords; ++i) {
    763     const wchar_t* property = va_arg(ap, const wchar_t*);
    764     v8::Local<v8::Value> v8Value = pRuntime->GetObjectProperty(pObj, property);
    765     if (!v8Value->IsUndefined())
    766       result[i] = CJS_Value(pRuntime, v8Value);
    767   }
    768   va_end(ap);
    769   return result;
    770 }
    771