(Reland) Switch builds to clang by default for Linux and OS X.
[pdfium.git] / fpdfsdk / src / javascript / JS_Runtime.cpp
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 "JS_Runtime.h"
8
9 #include "../../include/fsdk_mgr.h"  // For CPDFDoc_Environment.
10 #include "../../include/javascript/IJavaScript.h"
11 #include "Consts.h"
12 #include "Document.h"
13 #include "Field.h"
14 #include "Icon.h"
15 #include "JS_Context.h"
16 #include "JS_Define.h"
17 #include "JS_EventHandler.h"
18 #include "JS_GlobalData.h"
19 #include "JS_Object.h"
20 #include "JS_Value.h"
21 #include "PublicMethods.h"
22 #include "app.h"
23 #include "color.h"
24 #include "console.h"
25 #include "event.h"
26 #include "global.h"
27 #include "report.h"
28 #include "util.h"
29
30 // static
31 void IJS_Runtime::Initialize(unsigned int slot, void* isolate) {
32   FXJS_Initialize(slot, reinterpret_cast<v8::Isolate*>(isolate));
33 }
34
35 // static
36 IJS_Runtime* IJS_Runtime::Create(CPDFDoc_Environment* pEnv) {
37   return new CJS_Runtime(pEnv);
38 }
39
40 // static
41 CJS_Runtime* CJS_Runtime::FromContext(const IJS_Context* cc) {
42   const CJS_Context* pContext = static_cast<const CJS_Context*>(cc);
43   return pContext->GetJSRuntime();
44 }
45
46 CJS_Runtime::CJS_Runtime(CPDFDoc_Environment* pApp)
47     : m_pApp(pApp),
48       m_pDocument(NULL),
49       m_bBlocking(FALSE),
50       m_isolate(NULL),
51       m_isolateManaged(false) {
52   IPDF_JSPLATFORM* pPlatform = m_pApp->GetFormFillInfo()->m_pJsPlatform;
53   if (pPlatform->version <= 2) {
54     unsigned int embedderDataSlot = 0;
55     v8::Isolate* pExternalIsolate = nullptr;
56     if (pPlatform->version == 2) {
57       pExternalIsolate = reinterpret_cast<v8::Isolate*>(pPlatform->m_isolate);
58       embedderDataSlot = pPlatform->m_v8EmbedderSlot;
59     }
60     FXJS_Initialize(embedderDataSlot, pExternalIsolate);
61   }
62   m_isolateManaged = FXJS_GetIsolate(&m_isolate);
63   if (m_isolateManaged || FXJS_GlobalIsolateRefCount() == 0)
64     DefineJSObjects();
65
66   CJS_Context* pContext = (CJS_Context*)NewContext();
67   FXJS_InitializeRuntime(GetIsolate(), this, m_context);
68   ReleaseContext(pContext);
69 }
70
71 CJS_Runtime::~CJS_Runtime() {
72   for (auto* obs : m_observers)
73     obs->OnDestroyed();
74
75   for (int i = 0, sz = m_ContextArray.GetSize(); i < sz; i++)
76     delete m_ContextArray.GetAt(i);
77
78   m_ContextArray.RemoveAll();
79   FXJS_ReleaseRuntime(GetIsolate(), m_context);
80
81   m_pApp = NULL;
82   m_pDocument = NULL;
83   m_context.Reset();
84
85   if (m_isolateManaged)
86     m_isolate->Dispose();
87 }
88
89 void CJS_Runtime::DefineJSObjects() {
90   v8::Isolate::Scope isolate_scope(GetIsolate());
91   v8::HandleScope handle_scope(GetIsolate());
92   v8::Local<v8::Context> context = v8::Context::New(GetIsolate());
93   v8::Context::Scope context_scope(context);
94
95   // The call order determines the "ObjDefID" assigned to each class.
96   // ObjDefIDs 0 - 2
97   CJS_Border::DefineJSObjects(GetIsolate(), FXJSOBJTYPE_STATIC);
98   CJS_Display::DefineJSObjects(GetIsolate(), FXJSOBJTYPE_STATIC);
99   CJS_Font::DefineJSObjects(GetIsolate(), FXJSOBJTYPE_STATIC);
100
101   // ObjDefIDs 3 - 5
102   CJS_Highlight::DefineJSObjects(GetIsolate(), FXJSOBJTYPE_STATIC);
103   CJS_Position::DefineJSObjects(GetIsolate(), FXJSOBJTYPE_STATIC);
104   CJS_ScaleHow::DefineJSObjects(GetIsolate(), FXJSOBJTYPE_STATIC);
105
106   // ObjDefIDs 6 - 8
107   CJS_ScaleWhen::DefineJSObjects(GetIsolate(), FXJSOBJTYPE_STATIC);
108   CJS_Style::DefineJSObjects(GetIsolate(), FXJSOBJTYPE_STATIC);
109   CJS_Zoomtype::DefineJSObjects(GetIsolate(), FXJSOBJTYPE_STATIC);
110
111   // ObjDefIDs 9 - 11
112   CJS_App::DefineJSObjects(GetIsolate(), FXJSOBJTYPE_STATIC);
113   CJS_Color::DefineJSObjects(GetIsolate(), FXJSOBJTYPE_STATIC);
114   CJS_Console::DefineJSObjects(GetIsolate(), FXJSOBJTYPE_STATIC);
115
116   // ObjDefIDs 12 - 14
117   CJS_Document::DefineJSObjects(GetIsolate(), FXJSOBJTYPE_GLOBAL);
118   CJS_Event::DefineJSObjects(GetIsolate(), FXJSOBJTYPE_STATIC);
119   CJS_Field::DefineJSObjects(GetIsolate(), FXJSOBJTYPE_DYNAMIC);
120
121   // ObjDefIDs 15 - 17
122   CJS_Global::DefineJSObjects(GetIsolate(), FXJSOBJTYPE_STATIC);
123   CJS_Icon::DefineJSObjects(GetIsolate(), FXJSOBJTYPE_DYNAMIC);
124   CJS_Util::DefineJSObjects(GetIsolate(), FXJSOBJTYPE_STATIC);
125
126   // ObjDefIDs 18 - 20 (these can't fail, return void).
127   CJS_PublicMethods::DefineJSObjects(GetIsolate());
128   CJS_GlobalConsts::DefineJSObjects(this);
129   CJS_GlobalArrays::DefineJSObjects(this);
130
131   // ObjDefIDs 21 - 22.
132   CJS_TimerObj::DefineJSObjects(GetIsolate(), FXJSOBJTYPE_DYNAMIC);
133   CJS_PrintParamsObj::DefineJSObjects(GetIsolate(), FXJSOBJTYPE_DYNAMIC);
134 }
135
136 IJS_Context* CJS_Runtime::NewContext() {
137   CJS_Context* p = new CJS_Context(this);
138   m_ContextArray.Add(p);
139   return p;
140 }
141
142 void CJS_Runtime::ReleaseContext(IJS_Context* pContext) {
143   CJS_Context* pJSContext = (CJS_Context*)pContext;
144
145   for (int i = 0, sz = m_ContextArray.GetSize(); i < sz; i++) {
146     if (pJSContext == m_ContextArray.GetAt(i)) {
147       delete pJSContext;
148       m_ContextArray.RemoveAt(i);
149       break;
150     }
151   }
152 }
153
154 IJS_Context* CJS_Runtime::GetCurrentContext() {
155   if (!m_ContextArray.GetSize())
156     return NULL;
157   return m_ContextArray.GetAt(m_ContextArray.GetSize() - 1);
158 }
159
160 void CJS_Runtime::SetReaderDocument(CPDFSDK_Document* pReaderDoc) {
161   if (m_pDocument != pReaderDoc) {
162     v8::Isolate::Scope isolate_scope(m_isolate);
163     v8::HandleScope handle_scope(m_isolate);
164     v8::Local<v8::Context> context =
165         v8::Local<v8::Context>::New(m_isolate, m_context);
166     v8::Context::Scope context_scope(context);
167
168     m_pDocument = pReaderDoc;
169     if (pReaderDoc) {
170       v8::Local<v8::Object> pThis = FXJS_GetThisObj(GetIsolate());
171       if (!pThis.IsEmpty()) {
172         if (FXJS_GetObjDefnID(pThis) == CJS_Document::g_nObjDefnID) {
173           if (CJS_Document* pJSDocument =
174                   (CJS_Document*)FXJS_GetPrivate(GetIsolate(), pThis)) {
175             if (Document* pDocument = (Document*)pJSDocument->GetEmbedObject())
176               pDocument->AttachDoc(pReaderDoc);
177           }
178         }
179       }
180     }
181   }
182 }
183
184 int CJS_Runtime::Execute(IJS_Context* cc,
185                          const wchar_t* script,
186                          CFX_WideString* info) {
187   FXJSErr error = {};
188   int nRet = FXJS_Execute(m_isolate, cc, script, &error);
189   if (nRet < 0) {
190     info->Format(L"[ Line: %05d { %s } ] : %s", error.linnum - 1, error.srcline,
191                  error.message);
192   }
193   return nRet;
194 }
195
196 bool CJS_Runtime::AddEventToSet(const FieldEvent& event) {
197   return m_FieldEventSet.insert(event).second;
198 }
199
200 void CJS_Runtime::RemoveEventFromSet(const FieldEvent& event) {
201   m_FieldEventSet.erase(event);
202 }
203
204 v8::Local<v8::Context> CJS_Runtime::NewJSContext() {
205   return v8::Local<v8::Context>::New(m_isolate, m_context);
206 }
207
208 void CJS_Runtime::AddObserver(Observer* observer) {
209   ASSERT(m_observers.find(observer) == m_observers.end());
210   m_observers.insert(observer);
211 }
212
213 void CJS_Runtime::RemoveObserver(Observer* observer) {
214   ASSERT(m_observers.find(observer) != m_observers.end());
215   m_observers.erase(observer);
216 }
217
218 CFX_WideString ChangeObjName(const CFX_WideString& str) {
219   CFX_WideString sRet = str;
220   sRet.Replace(L"_", L".");
221   return sRet;
222 }