1 // Copyright 2017 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 "fxjs/xfa/cjx_hostpseudomodel.h" 8 9 #include <memory> 10 #include <vector> 11 12 #include "fxjs/cfxjse_engine.h" 13 #include "fxjs/cfxjse_value.h" 14 #include "fxjs/js_resources.h" 15 #include "xfa/fxfa/cxfa_ffnotify.h" 16 #include "xfa/fxfa/parser/cscript_hostpseudomodel.h" 17 #include "xfa/fxfa/parser/cxfa_layoutprocessor.h" 18 #include "xfa/fxfa/parser/cxfa_node.h" 19 #include "xfa/fxfa/parser/xfa_resolvenode_rs.h" 20 21 namespace { 22 23 int32_t FilterName(const WideStringView& wsExpression, 24 int32_t nStart, 25 WideString& wsFilter) { 26 ASSERT(nStart > -1); 27 int32_t iLength = wsExpression.GetLength(); 28 if (nStart >= iLength) 29 return iLength; 30 31 wchar_t* pBuf = wsFilter.GetBuffer(iLength - nStart); 32 int32_t nCount = 0; 33 const wchar_t* pSrc = wsExpression.unterminated_c_str(); 34 wchar_t wCur; 35 while (nStart < iLength) { 36 wCur = pSrc[nStart++]; 37 if (wCur == ',') 38 break; 39 40 pBuf[nCount++] = wCur; 41 } 42 wsFilter.ReleaseBuffer(nCount); 43 wsFilter.Trim(); 44 return nStart; 45 } 46 47 } // namespace 48 49 const CJX_MethodSpec CJX_HostPseudoModel::MethodSpecs[] = { 50 {"beep", beep_static}, 51 {"documentCountInBatch", documentCountInBatch_static}, 52 {"documentInBatch", documentInBatch_static}, 53 {"exportData", exportData_static}, 54 {"getFocus", getFocus_static}, 55 {"gotoURL", gotoURL_static}, 56 {"importData", importData_static}, 57 {"messageBox", messageBox_static}, 58 {"openList", openList_static}, 59 {"pageDown", pageDown_static}, 60 {"pageUp", pageUp_static}, 61 {"print", print_static}, 62 {"resetData", resetData_static}, 63 {"response", response_static}, 64 {"setFocus", setFocus_static}}; 65 66 CJX_HostPseudoModel::CJX_HostPseudoModel(CScript_HostPseudoModel* model) 67 : CJX_Object(model) { 68 DefineMethods(MethodSpecs, FX_ArraySize(MethodSpecs)); 69 } 70 71 CJX_HostPseudoModel::~CJX_HostPseudoModel() {} 72 73 void CJX_HostPseudoModel::appType(CFXJSE_Value* pValue, 74 bool bSetting, 75 XFA_Attribute eAttribute) { 76 CXFA_FFNotify* pNotify = GetDocument()->GetNotify(); 77 if (!pNotify) 78 return; 79 80 if (bSetting) { 81 ThrowInvalidPropertyException(); 82 return; 83 } 84 pValue->SetString("Exchange"); 85 } 86 87 void CJX_HostPseudoModel::calculationsEnabled(CFXJSE_Value* pValue, 88 bool bSetting, 89 XFA_Attribute eAttribute) { 90 CXFA_FFNotify* pNotify = GetDocument()->GetNotify(); 91 if (!pNotify) 92 return; 93 94 CXFA_FFDoc* hDoc = pNotify->GetHDOC(); 95 if (bSetting) { 96 pNotify->GetDocEnvironment()->SetCalculationsEnabled(hDoc, 97 pValue->ToBoolean()); 98 return; 99 } 100 pValue->SetBoolean(pNotify->GetDocEnvironment()->IsCalculationsEnabled(hDoc)); 101 } 102 103 void CJX_HostPseudoModel::currentPage(CFXJSE_Value* pValue, 104 bool bSetting, 105 XFA_Attribute eAttribute) { 106 CXFA_FFNotify* pNotify = GetDocument()->GetNotify(); 107 if (!pNotify) 108 return; 109 110 CXFA_FFDoc* hDoc = pNotify->GetHDOC(); 111 if (bSetting) { 112 pNotify->GetDocEnvironment()->SetCurrentPage(hDoc, pValue->ToInteger()); 113 return; 114 } 115 pValue->SetInteger(pNotify->GetDocEnvironment()->GetCurrentPage(hDoc)); 116 } 117 118 void CJX_HostPseudoModel::language(CFXJSE_Value* pValue, 119 bool bSetting, 120 XFA_Attribute eAttribute) { 121 CXFA_FFNotify* pNotify = GetDocument()->GetNotify(); 122 if (!pNotify) 123 return; 124 125 if (bSetting) { 126 ThrowException(L"Unable to set language value."); 127 return; 128 } 129 pValue->SetString( 130 pNotify->GetAppProvider()->GetLanguage().UTF8Encode().AsStringView()); 131 } 132 133 void CJX_HostPseudoModel::numPages(CFXJSE_Value* pValue, 134 bool bSetting, 135 XFA_Attribute eAttribute) { 136 CXFA_FFNotify* pNotify = GetDocument()->GetNotify(); 137 if (!pNotify) 138 return; 139 140 CXFA_FFDoc* hDoc = pNotify->GetHDOC(); 141 if (bSetting) { 142 ThrowException(L"Unable to set numPages value."); 143 return; 144 } 145 pValue->SetInteger(pNotify->GetDocEnvironment()->CountPages(hDoc)); 146 } 147 148 void CJX_HostPseudoModel::platform(CFXJSE_Value* pValue, 149 bool bSetting, 150 XFA_Attribute eAttribute) { 151 CXFA_FFNotify* pNotify = GetDocument()->GetNotify(); 152 if (!pNotify) 153 return; 154 155 if (bSetting) { 156 ThrowException(L"Unable to set platform value."); 157 return; 158 } 159 pValue->SetString( 160 pNotify->GetAppProvider()->GetPlatform().UTF8Encode().AsStringView()); 161 } 162 163 void CJX_HostPseudoModel::title(CFXJSE_Value* pValue, 164 bool bSetting, 165 XFA_Attribute eAttribute) { 166 if (!GetDocument()->GetScriptContext()->IsRunAtClient()) 167 return; 168 169 CXFA_FFNotify* pNotify = GetDocument()->GetNotify(); 170 if (!pNotify) 171 return; 172 173 CXFA_FFDoc* hDoc = pNotify->GetHDOC(); 174 if (bSetting) { 175 pNotify->GetDocEnvironment()->SetTitle(hDoc, pValue->ToWideString()); 176 return; 177 } 178 179 WideString wsTitle; 180 pNotify->GetDocEnvironment()->GetTitle(hDoc, wsTitle); 181 pValue->SetString(wsTitle.UTF8Encode().AsStringView()); 182 } 183 184 void CJX_HostPseudoModel::validationsEnabled(CFXJSE_Value* pValue, 185 bool bSetting, 186 XFA_Attribute eAttribute) { 187 CXFA_FFNotify* pNotify = GetDocument()->GetNotify(); 188 if (!pNotify) 189 return; 190 191 CXFA_FFDoc* hDoc = pNotify->GetHDOC(); 192 if (bSetting) { 193 pNotify->GetDocEnvironment()->SetValidationsEnabled(hDoc, 194 pValue->ToBoolean()); 195 return; 196 } 197 198 bool bEnabled = pNotify->GetDocEnvironment()->IsValidationsEnabled(hDoc); 199 pValue->SetBoolean(bEnabled); 200 } 201 202 void CJX_HostPseudoModel::variation(CFXJSE_Value* pValue, 203 bool bSetting, 204 XFA_Attribute eAttribute) { 205 if (!GetDocument()->GetScriptContext()->IsRunAtClient()) 206 return; 207 208 CXFA_FFNotify* pNotify = GetDocument()->GetNotify(); 209 if (!pNotify) 210 return; 211 212 if (bSetting) { 213 ThrowException(L"Unable to set variation value."); 214 return; 215 } 216 pValue->SetString("Full"); 217 } 218 219 void CJX_HostPseudoModel::version(CFXJSE_Value* pValue, 220 bool bSetting, 221 XFA_Attribute eAttribute) { 222 CXFA_FFNotify* pNotify = GetDocument()->GetNotify(); 223 if (!pNotify) 224 return; 225 226 if (bSetting) { 227 ThrowException(L"Unable to set version value."); 228 return; 229 } 230 pValue->SetString("11"); 231 } 232 233 void CJX_HostPseudoModel::name(CFXJSE_Value* pValue, 234 bool bSetting, 235 XFA_Attribute eAttribute) { 236 CXFA_FFNotify* pNotify = GetDocument()->GetNotify(); 237 if (!pNotify) 238 return; 239 240 if (bSetting) { 241 ThrowInvalidPropertyException(); 242 return; 243 } 244 pValue->SetString( 245 pNotify->GetAppProvider()->GetAppName().UTF8Encode().AsStringView()); 246 } 247 248 CJS_Return CJX_HostPseudoModel::gotoURL( 249 CJS_V8* runtime, 250 const std::vector<v8::Local<v8::Value>>& params) { 251 if (!GetDocument()->GetScriptContext()->IsRunAtClient()) 252 return CJS_Return(true); 253 254 if (params.size() != 1) 255 return CJS_Return(JSGetStringFromID(JSMessage::kParamError)); 256 257 CXFA_FFNotify* pNotify = GetDocument()->GetNotify(); 258 if (!pNotify) 259 return CJS_Return(true); 260 261 CXFA_FFDoc* hDoc = pNotify->GetHDOC(); 262 WideString URL = runtime->ToWideString(params[0]); 263 pNotify->GetDocEnvironment()->GotoURL(hDoc, URL); 264 return CJS_Return(true); 265 } 266 267 CJS_Return CJX_HostPseudoModel::openList( 268 CJS_V8* runtime, 269 const std::vector<v8::Local<v8::Value>>& params) { 270 if (!GetDocument()->GetScriptContext()->IsRunAtClient()) 271 return CJS_Return(true); 272 273 if (params.size() != 1) 274 return CJS_Return(JSGetStringFromID(JSMessage::kParamError)); 275 276 CXFA_FFNotify* pNotify = GetDocument()->GetNotify(); 277 if (!pNotify) 278 return CJS_Return(true); 279 280 CXFA_Node* pNode = nullptr; 281 if (params[0]->IsObject()) { 282 pNode = ToNode(runtime->ToXFAObject(params[0])); 283 } else if (params[0]->IsString()) { 284 CFXJSE_Engine* pScriptContext = GetDocument()->GetScriptContext(); 285 if (!pScriptContext) 286 return CJS_Return(true); 287 288 CXFA_Object* pObject = pScriptContext->GetThisObject(); 289 if (!pObject) 290 return CJS_Return(true); 291 292 uint32_t dwFlag = XFA_RESOLVENODE_Children | XFA_RESOLVENODE_Parent | 293 XFA_RESOLVENODE_Siblings; 294 XFA_RESOLVENODE_RS resolveNodeRS; 295 bool iRet = pScriptContext->ResolveObjects( 296 pObject, runtime->ToWideString(params[0]).AsStringView(), 297 &resolveNodeRS, dwFlag, nullptr); 298 if (!iRet || !resolveNodeRS.objects.front()->IsNode()) 299 return CJS_Return(true); 300 301 pNode = resolveNodeRS.objects.front()->AsNode(); 302 } 303 304 CXFA_LayoutProcessor* pDocLayout = GetDocument()->GetDocLayout(); 305 if (!pDocLayout) 306 return CJS_Return(true); 307 308 CXFA_FFWidget* hWidget = 309 pNotify->GetHWidget(pDocLayout->GetLayoutItem(pNode)); 310 if (!hWidget) 311 return CJS_Return(true); 312 313 pNotify->GetDocEnvironment()->SetFocusWidget(pNotify->GetHDOC(), hWidget); 314 pNotify->OpenDropDownList(hWidget); 315 return CJS_Return(true); 316 } 317 318 CJS_Return CJX_HostPseudoModel::response( 319 CJS_V8* runtime, 320 const std::vector<v8::Local<v8::Value>>& params) { 321 if (params.empty() || params.size() > 4) 322 return CJS_Return(JSGetStringFromID(JSMessage::kParamError)); 323 324 CXFA_FFNotify* pNotify = GetDocument()->GetNotify(); 325 if (!pNotify) 326 return CJS_Return(true); 327 328 WideString question; 329 if (params.size() >= 1) 330 question = runtime->ToWideString(params[0]); 331 332 WideString title; 333 if (params.size() >= 2) 334 title = runtime->ToWideString(params[1]); 335 336 WideString defaultAnswer; 337 if (params.size() >= 3) 338 defaultAnswer = runtime->ToWideString(params[2]); 339 340 bool mark = false; 341 if (params.size() >= 4) 342 mark = runtime->ToInt32(params[3]) != 0; 343 344 WideString answer = 345 pNotify->GetAppProvider()->Response(question, title, defaultAnswer, mark); 346 return CJS_Return(runtime->NewString(answer.UTF8Encode().AsStringView())); 347 } 348 349 CJS_Return CJX_HostPseudoModel::documentInBatch( 350 CJS_V8* runtime, 351 const std::vector<v8::Local<v8::Value>>& params) { 352 return CJS_Return(runtime->NewNumber(0)); 353 } 354 355 CJS_Return CJX_HostPseudoModel::resetData( 356 CJS_V8* runtime, 357 const std::vector<v8::Local<v8::Value>>& params) { 358 if (params.size() > 1) 359 return CJS_Return(JSGetStringFromID(JSMessage::kParamError)); 360 361 CXFA_FFNotify* pNotify = GetDocument()->GetNotify(); 362 if (!pNotify) 363 return CJS_Return(true); 364 365 WideString expression; 366 if (params.size() >= 1) 367 expression = runtime->ToWideString(params[0]); 368 369 if (expression.IsEmpty()) { 370 pNotify->ResetData(); 371 return CJS_Return(true); 372 } 373 374 int32_t iStart = 0; 375 WideString wsName; 376 CXFA_Node* pNode = nullptr; 377 int32_t iExpLength = expression.GetLength(); 378 while (iStart < iExpLength) { 379 iStart = FilterName(expression.AsStringView(), iStart, wsName); 380 CFXJSE_Engine* pScriptContext = GetDocument()->GetScriptContext(); 381 if (!pScriptContext) 382 return CJS_Return(true); 383 384 CXFA_Object* pObject = pScriptContext->GetThisObject(); 385 if (!pObject) 386 return CJS_Return(true); 387 388 uint32_t dwFlag = XFA_RESOLVENODE_Children | XFA_RESOLVENODE_Parent | 389 XFA_RESOLVENODE_Siblings; 390 XFA_RESOLVENODE_RS resolveNodeRS; 391 bool iRet = pScriptContext->ResolveObjects(pObject, wsName.AsStringView(), 392 &resolveNodeRS, dwFlag, nullptr); 393 if (!iRet || !resolveNodeRS.objects.front()->IsNode()) 394 continue; 395 396 pNode = resolveNodeRS.objects.front()->AsNode(); 397 pNotify->ResetData(pNode->GetWidgetAcc()); 398 } 399 if (!pNode) 400 pNotify->ResetData(); 401 402 return CJS_Return(true); 403 } 404 405 CJS_Return CJX_HostPseudoModel::beep( 406 CJS_V8* runtime, 407 const std::vector<v8::Local<v8::Value>>& params) { 408 if (!GetDocument()->GetScriptContext()->IsRunAtClient()) 409 return CJS_Return(true); 410 411 if (params.size() > 1) 412 return CJS_Return(JSGetStringFromID(JSMessage::kParamError)); 413 414 CXFA_FFNotify* pNotify = GetDocument()->GetNotify(); 415 if (!pNotify) 416 return CJS_Return(true); 417 418 uint32_t dwType = 4; 419 if (params.size() >= 1) 420 dwType = runtime->ToInt32(params[0]); 421 422 pNotify->GetAppProvider()->Beep(dwType); 423 return CJS_Return(true); 424 } 425 426 CJS_Return CJX_HostPseudoModel::setFocus( 427 CJS_V8* runtime, 428 const std::vector<v8::Local<v8::Value>>& params) { 429 if (!GetDocument()->GetScriptContext()->IsRunAtClient()) 430 return CJS_Return(true); 431 432 if (params.size() != 1) 433 return CJS_Return(JSGetStringFromID(JSMessage::kParamError)); 434 435 CXFA_FFNotify* pNotify = GetDocument()->GetNotify(); 436 if (!pNotify) 437 return CJS_Return(true); 438 439 CXFA_Node* pNode = nullptr; 440 if (params.size() >= 1) { 441 if (params[0]->IsObject()) { 442 pNode = ToNode(runtime->ToXFAObject(params[0])); 443 } else if (params[0]->IsString()) { 444 CFXJSE_Engine* pScriptContext = GetDocument()->GetScriptContext(); 445 if (!pScriptContext) 446 return CJS_Return(true); 447 448 CXFA_Object* pObject = pScriptContext->GetThisObject(); 449 if (!pObject) 450 return CJS_Return(true); 451 452 uint32_t dwFlag = XFA_RESOLVENODE_Children | XFA_RESOLVENODE_Parent | 453 XFA_RESOLVENODE_Siblings; 454 XFA_RESOLVENODE_RS resolveNodeRS; 455 bool iRet = pScriptContext->ResolveObjects( 456 pObject, runtime->ToWideString(params[0]).AsStringView(), 457 &resolveNodeRS, dwFlag, nullptr); 458 if (!iRet || !resolveNodeRS.objects.front()->IsNode()) 459 return CJS_Return(true); 460 461 pNode = resolveNodeRS.objects.front()->AsNode(); 462 } 463 } 464 pNotify->SetFocusWidgetNode(pNode); 465 return CJS_Return(true); 466 } 467 468 CJS_Return CJX_HostPseudoModel::getFocus( 469 CJS_V8* runtime, 470 const std::vector<v8::Local<v8::Value>>& params) { 471 CXFA_FFNotify* pNotify = GetDocument()->GetNotify(); 472 if (!pNotify) 473 return CJS_Return(true); 474 475 CXFA_Node* pNode = pNotify->GetFocusWidgetNode(); 476 if (!pNode) 477 return CJS_Return(true); 478 479 CFXJSE_Value* value = 480 GetDocument()->GetScriptContext()->GetJSValueFromMap(pNode); 481 if (!value) 482 return CJS_Return(runtime->NewNull()); 483 484 return CJS_Return(value->DirectGetValue().Get(runtime->GetIsolate())); 485 } 486 487 CJS_Return CJX_HostPseudoModel::messageBox( 488 CJS_V8* runtime, 489 const std::vector<v8::Local<v8::Value>>& params) { 490 if (!GetDocument()->GetScriptContext()->IsRunAtClient()) 491 return CJS_Return(true); 492 493 if (params.empty() || params.size() > 4) 494 return CJS_Return(JSGetStringFromID(JSMessage::kParamError)); 495 496 CXFA_FFNotify* pNotify = GetDocument()->GetNotify(); 497 if (!pNotify) 498 return CJS_Return(true); 499 500 WideString message; 501 if (params.size() >= 1) 502 message = runtime->ToWideString(params[0]); 503 504 WideString title; 505 if (params.size() >= 2) 506 title = runtime->ToWideString(params[1]); 507 508 uint32_t messageType = XFA_MBICON_Error; 509 if (params.size() >= 3) { 510 messageType = runtime->ToInt32(params[2]); 511 if (messageType > XFA_MBICON_Status) 512 messageType = XFA_MBICON_Error; 513 } 514 515 uint32_t buttonType = XFA_MB_OK; 516 if (params.size() >= 4) { 517 buttonType = runtime->ToInt32(params[3]); 518 if (buttonType > XFA_MB_YesNoCancel) 519 buttonType = XFA_MB_OK; 520 } 521 522 int32_t iValue = pNotify->GetAppProvider()->MsgBox(message, title, 523 messageType, buttonType); 524 return CJS_Return(runtime->NewNumber(iValue)); 525 } 526 527 CJS_Return CJX_HostPseudoModel::documentCountInBatch( 528 CJS_V8* runtime, 529 const std::vector<v8::Local<v8::Value>>& params) { 530 return CJS_Return(runtime->NewNumber(0)); 531 } 532 533 CJS_Return CJX_HostPseudoModel::print( 534 CJS_V8* runtime, 535 const std::vector<v8::Local<v8::Value>>& params) { 536 if (!GetDocument()->GetScriptContext()->IsRunAtClient()) 537 return CJS_Return(true); 538 539 if (params.size() != 8) 540 return CJS_Return(JSGetStringFromID(JSMessage::kParamError)); 541 542 CXFA_FFNotify* pNotify = GetDocument()->GetNotify(); 543 if (!pNotify) 544 return CJS_Return(true); 545 546 uint32_t dwOptions = 0; 547 if (runtime->ToBoolean(params[0])) 548 dwOptions |= XFA_PRINTOPT_ShowDialog; 549 if (runtime->ToBoolean(params[3])) 550 dwOptions |= XFA_PRINTOPT_CanCancel; 551 if (runtime->ToBoolean(params[4])) 552 dwOptions |= XFA_PRINTOPT_ShrinkPage; 553 if (runtime->ToBoolean(params[5])) 554 dwOptions |= XFA_PRINTOPT_AsImage; 555 if (runtime->ToBoolean(params[6])) 556 dwOptions |= XFA_PRINTOPT_ReverseOrder; 557 if (runtime->ToBoolean(params[7])) 558 dwOptions |= XFA_PRINTOPT_PrintAnnot; 559 560 int32_t nStartPage = runtime->ToInt32(params[1]); 561 int32_t nEndPage = runtime->ToInt32(params[2]); 562 563 pNotify->GetDocEnvironment()->Print(pNotify->GetHDOC(), nStartPage, nEndPage, 564 dwOptions); 565 return CJS_Return(true); 566 } 567 568 CJS_Return CJX_HostPseudoModel::importData( 569 CJS_V8* runtime, 570 const std::vector<v8::Local<v8::Value>>& params) { 571 if (params.empty() || params.size() > 1) 572 return CJS_Return(JSGetStringFromID(JSMessage::kParamError)); 573 574 return CJS_Return(true); 575 } 576 577 CJS_Return CJX_HostPseudoModel::exportData( 578 CJS_V8* runtime, 579 const std::vector<v8::Local<v8::Value>>& params) { 580 if (params.empty() || params.size() > 2) 581 return CJS_Return(JSGetStringFromID(JSMessage::kParamError)); 582 583 CXFA_FFNotify* pNotify = GetDocument()->GetNotify(); 584 if (!pNotify) 585 return CJS_Return(true); 586 587 WideString filePath; 588 if (params.size() >= 1) 589 filePath = runtime->ToWideString(params[0]); 590 591 bool XDP = true; 592 if (params.size() >= 2) 593 XDP = runtime->ToBoolean(params[1]); 594 595 pNotify->GetDocEnvironment()->ExportData(pNotify->GetHDOC(), filePath, XDP); 596 return CJS_Return(true); 597 } 598 599 CJS_Return CJX_HostPseudoModel::pageUp( 600 CJS_V8* runtime, 601 const std::vector<v8::Local<v8::Value>>& params) { 602 CXFA_FFNotify* pNotify = GetDocument()->GetNotify(); 603 if (!pNotify) 604 return CJS_Return(true); 605 606 CXFA_FFDoc* hDoc = pNotify->GetHDOC(); 607 int32_t nCurPage = pNotify->GetDocEnvironment()->GetCurrentPage(hDoc); 608 int32_t nNewPage = 0; 609 if (nCurPage <= 1) 610 return CJS_Return(true); 611 612 nNewPage = nCurPage - 1; 613 pNotify->GetDocEnvironment()->SetCurrentPage(hDoc, nNewPage); 614 return CJS_Return(true); 615 } 616 617 CJS_Return CJX_HostPseudoModel::pageDown( 618 CJS_V8* runtime, 619 const std::vector<v8::Local<v8::Value>>& params) { 620 CXFA_FFNotify* pNotify = GetDocument()->GetNotify(); 621 if (!pNotify) 622 return CJS_Return(true); 623 624 CXFA_FFDoc* hDoc = pNotify->GetHDOC(); 625 int32_t nCurPage = pNotify->GetDocEnvironment()->GetCurrentPage(hDoc); 626 int32_t nPageCount = pNotify->GetDocEnvironment()->CountPages(hDoc); 627 if (!nPageCount || nCurPage == nPageCount) 628 return CJS_Return(true); 629 630 int32_t nNewPage = 0; 631 if (nCurPage >= nPageCount) 632 nNewPage = nPageCount - 1; 633 else 634 nNewPage = nCurPage + 1; 635 636 pNotify->GetDocEnvironment()->SetCurrentPage(hDoc, nNewPage); 637 return CJS_Return(true); 638 } 639