/platform/external/webkit/WebCore/bindings/js/JSDOMBinding.cpp

https://github.com/aharish/totoro-gb-opensource-update2 · C++ · 863 lines · 672 code · 125 blank · 66 comment · 121 complexity · 5b1a3a5fab8e52428538d5f8c1ba0416 MD5 · raw file

  1. /*
  2. * Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
  3. * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
  4. * Copyright (C) 2007 Samuel Weinig <sam@webkit.org>
  5. *
  6. * This library is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 2 of the License, or (at your option) any later version.
  10. *
  11. * This library is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public
  17. * License along with this library; if not, write to the Free Software
  18. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  19. */
  20. #include "config.h"
  21. #include "JSDOMBinding.h"
  22. #include "debugger/DebuggerCallFrame.h"
  23. #include "ActiveDOMObject.h"
  24. #include "DOMCoreException.h"
  25. #include "Document.h"
  26. #include "EventException.h"
  27. #include "ExceptionBase.h"
  28. #include "ExceptionCode.h"
  29. #include "Frame.h"
  30. #include "HTMLAudioElement.h"
  31. #include "HTMLCanvasElement.h"
  32. #include "HTMLImageElement.h"
  33. #include "HTMLScriptElement.h"
  34. #include "HTMLNames.h"
  35. #include "JSDOMCoreException.h"
  36. #include "JSDOMWindowCustom.h"
  37. #include "JSEventException.h"
  38. #include "JSExceptionBase.h"
  39. #include "JSNode.h"
  40. #include "JSRangeException.h"
  41. #include "JSXMLHttpRequestException.h"
  42. #include "KURL.h"
  43. #include "MessagePort.h"
  44. #include "RangeException.h"
  45. #include "ScriptCachedFrameData.h"
  46. #include "ScriptController.h"
  47. #include "Settings.h"
  48. #include "XMLHttpRequestException.h"
  49. #include <runtime/DateInstance.h>
  50. #include <runtime/Error.h>
  51. #include <runtime/JSFunction.h>
  52. #include <runtime/PrototypeFunction.h>
  53. #include <wtf/MathExtras.h>
  54. #include <wtf/StdLibExtras.h>
  55. #if ENABLE(SVG)
  56. #include "JSSVGException.h"
  57. #include "SVGException.h"
  58. #endif
  59. #if ENABLE(XPATH)
  60. #include "JSXPathException.h"
  61. #include "XPathException.h"
  62. #endif
  63. #if ENABLE(WORKERS)
  64. #include <wtf/ThreadSpecific.h>
  65. using namespace WTF;
  66. #endif
  67. using namespace JSC;
  68. namespace WebCore {
  69. using namespace HTMLNames;
  70. typedef Document::JSWrapperCache JSWrapperCache;
  71. typedef Document::JSWrapperCacheMap JSWrapperCacheMap;
  72. inline JSWrapperCache* Document::getWrapperCache(DOMWrapperWorld* world)
  73. {
  74. if (world->isNormal()) {
  75. if (JSWrapperCache* wrapperCache = m_normalWorldWrapperCache)
  76. return wrapperCache;
  77. ASSERT(!m_wrapperCacheMap.contains(world));
  78. } else if (JSWrapperCache* wrapperCache = m_wrapperCacheMap.get(world))
  79. return wrapperCache;
  80. return createWrapperCache(world);
  81. }
  82. // For debugging, keep a set of wrappers currently cached, and check that
  83. // all are uncached before they are destroyed. This helps us catch bugs like:
  84. // - wrappers being deleted without being removed from the cache
  85. // - wrappers being cached twice
  86. static void willCacheWrapper(DOMObject* wrapper);
  87. static void didUncacheWrapper(DOMObject* wrapper);
  88. #ifdef NDEBUG
  89. static inline void willCacheWrapper(DOMObject*)
  90. {
  91. }
  92. static inline void didUncacheWrapper(DOMObject*)
  93. {
  94. }
  95. #else
  96. static HashSet<DOMObject*>& wrapperSet()
  97. {
  98. #if ENABLE(WORKERS)
  99. DEFINE_STATIC_LOCAL(ThreadSpecific<HashSet<DOMObject*> >, staticWrapperSet, ());
  100. return *staticWrapperSet;
  101. #else
  102. DEFINE_STATIC_LOCAL(HashSet<DOMObject*>, staticWrapperSet, ());
  103. return staticWrapperSet;
  104. #endif
  105. }
  106. static void willCacheWrapper(DOMObject* wrapper)
  107. {
  108. ASSERT(!wrapperSet().contains(wrapper));
  109. wrapperSet().add(wrapper);
  110. }
  111. static void didUncacheWrapper(DOMObject* wrapper)
  112. {
  113. if (!wrapper)
  114. return;
  115. ASSERT(wrapperSet().contains(wrapper));
  116. wrapperSet().remove(wrapper);
  117. }
  118. DOMObject::~DOMObject()
  119. {
  120. ASSERT(!wrapperSet().contains(this));
  121. }
  122. #endif
  123. DOMWrapperWorld::DOMWrapperWorld(JSC::JSGlobalData* globalData, bool isNormal)
  124. : m_globalData(globalData)
  125. , m_isNormal(isNormal)
  126. {
  127. }
  128. DOMWrapperWorld::~DOMWrapperWorld()
  129. {
  130. if (m_globalData) {
  131. JSGlobalData::ClientData* clientData = m_globalData->clientData;
  132. ASSERT(clientData);
  133. static_cast<WebCoreJSClientData*>(clientData)->forgetWorld(this);
  134. }
  135. for (HashSet<Document*>::iterator iter = documentsWithWrappers.begin(); iter != documentsWithWrappers.end(); ++iter)
  136. forgetWorldOfDOMNodesForDocument(*iter, this);
  137. }
  138. class JSGlobalDataWorldIterator {
  139. public:
  140. JSGlobalDataWorldIterator(JSGlobalData* globalData)
  141. : m_pos(static_cast<WebCoreJSClientData*>(globalData->clientData)->m_worldSet.begin())
  142. , m_end(static_cast<WebCoreJSClientData*>(globalData->clientData)->m_worldSet.end())
  143. {
  144. }
  145. operator bool()
  146. {
  147. return m_pos != m_end;
  148. }
  149. DOMWrapperWorld* operator*()
  150. {
  151. ASSERT(m_pos != m_end);
  152. return *m_pos;
  153. }
  154. DOMWrapperWorld* operator->()
  155. {
  156. ASSERT(m_pos != m_end);
  157. return *m_pos;
  158. }
  159. JSGlobalDataWorldIterator& operator++()
  160. {
  161. ++m_pos;
  162. return *this;
  163. }
  164. private:
  165. HashSet<DOMWrapperWorld*>::iterator m_pos;
  166. HashSet<DOMWrapperWorld*>::iterator m_end;
  167. };
  168. DOMWrapperWorld* normalWorld(JSC::JSGlobalData& globalData)
  169. {
  170. JSGlobalData::ClientData* clientData = globalData.clientData;
  171. ASSERT(clientData);
  172. return static_cast<WebCoreJSClientData*>(clientData)->normalWorld();
  173. }
  174. DOMWrapperWorld* mainThreadNormalWorld()
  175. {
  176. ASSERT(isMainThread());
  177. static DOMWrapperWorld* cachedNormalWorld = normalWorld(*JSDOMWindow::commonJSGlobalData());
  178. return cachedNormalWorld;
  179. }
  180. DOMObjectHashTableMap& DOMObjectHashTableMap::mapFor(JSGlobalData& globalData)
  181. {
  182. JSGlobalData::ClientData* clientData = globalData.clientData;
  183. ASSERT(clientData);
  184. return static_cast<WebCoreJSClientData*>(clientData)->hashTableMap;
  185. }
  186. const JSC::HashTable* getHashTableForGlobalData(JSGlobalData& globalData, const JSC::HashTable* staticTable)
  187. {
  188. return DOMObjectHashTableMap::mapFor(globalData).get(staticTable);
  189. }
  190. static inline DOMObjectWrapperMap& DOMObjectWrapperMapFor(JSC::ExecState* exec)
  191. {
  192. return currentWorld(exec)->m_wrappers;
  193. }
  194. bool hasCachedDOMObjectWrapperUnchecked(JSGlobalData* globalData, void* objectHandle)
  195. {
  196. for (JSGlobalDataWorldIterator worldIter(globalData); worldIter; ++worldIter) {
  197. if (worldIter->m_wrappers.uncheckedGet(objectHandle))
  198. return true;
  199. }
  200. return false;
  201. }
  202. bool hasCachedDOMObjectWrapper(JSGlobalData* globalData, void* objectHandle)
  203. {
  204. for (JSGlobalDataWorldIterator worldIter(globalData); worldIter; ++worldIter) {
  205. if (worldIter->m_wrappers.get(objectHandle))
  206. return true;
  207. }
  208. return false;
  209. }
  210. DOMObject* getCachedDOMObjectWrapper(JSC::ExecState* exec, void* objectHandle)
  211. {
  212. return DOMObjectWrapperMapFor(exec).get(objectHandle);
  213. }
  214. void cacheDOMObjectWrapper(JSC::ExecState* exec, void* objectHandle, DOMObject* wrapper)
  215. {
  216. willCacheWrapper(wrapper);
  217. DOMObjectWrapperMapFor(exec).set(objectHandle, wrapper);
  218. }
  219. bool hasCachedDOMNodeWrapperUnchecked(Document* document, Node* node)
  220. {
  221. if (!document)
  222. return hasCachedDOMObjectWrapperUnchecked(JSDOMWindow::commonJSGlobalData(), node);
  223. JSWrapperCacheMap& wrapperCacheMap = document->wrapperCacheMap();
  224. for (JSWrapperCacheMap::iterator iter = wrapperCacheMap.begin(); iter != wrapperCacheMap.end(); ++iter) {
  225. if (iter->second->uncheckedGet(node))
  226. return true;
  227. }
  228. return false;
  229. }
  230. JSNode* getCachedDOMNodeWrapper(JSC::ExecState* exec, Document* document, Node* node)
  231. {
  232. if (document)
  233. return document->getWrapperCache(currentWorld(exec))->get(node);
  234. return static_cast<JSNode*>(DOMObjectWrapperMapFor(exec).get(node));
  235. }
  236. void forgetDOMObject(DOMObject* wrapper, void* objectHandle)
  237. {
  238. JSC::JSGlobalData* globalData = Heap::heap(wrapper)->globalData();
  239. // Check the normal world first!
  240. JSGlobalData::ClientData* clientData = globalData->clientData;
  241. ASSERT(clientData);
  242. DOMObjectWrapperMap& wrappers = static_cast<WebCoreJSClientData*>(clientData)->normalWorld()->m_wrappers;
  243. if (wrappers.uncheckedRemove(objectHandle, wrapper)) {
  244. didUncacheWrapper(wrapper);
  245. return;
  246. }
  247. // We can't guarantee that a wrapper is in the cache when it uncaches itself,
  248. // since a new wrapper may be cached before the old wrapper's destructor runs.
  249. for (JSGlobalDataWorldIterator worldIter(globalData); worldIter; ++worldIter) {
  250. if (worldIter->m_wrappers.uncheckedRemove(objectHandle, wrapper))
  251. break;
  252. }
  253. didUncacheWrapper(wrapper);
  254. }
  255. void forgetDOMNode(JSNode* wrapper, Node* node, Document* document)
  256. {
  257. if (!document) {
  258. forgetDOMObject(wrapper, node);
  259. return;
  260. }
  261. // We can't guarantee that a wrapper is in the cache when it uncaches itself,
  262. // since a new wrapper may be cached before the old wrapper's destructor runs.
  263. JSWrapperCacheMap& wrapperCacheMap = document->wrapperCacheMap();
  264. for (JSWrapperCacheMap::iterator wrappersIter = wrapperCacheMap.begin(); wrappersIter != wrapperCacheMap.end(); ++wrappersIter) {
  265. if (wrappersIter->second->uncheckedRemove(node, wrapper))
  266. break;
  267. }
  268. didUncacheWrapper(wrapper);
  269. }
  270. void cacheDOMNodeWrapper(JSC::ExecState* exec, Document* document, Node* node, JSNode* wrapper)
  271. {
  272. if (!document) {
  273. willCacheWrapper(wrapper);
  274. DOMObjectWrapperMapFor(exec).set(node, wrapper);
  275. return;
  276. }
  277. willCacheWrapper(wrapper);
  278. document->getWrapperCache(currentWorld(exec))->set(node, wrapper);
  279. }
  280. void forgetAllDOMNodesForDocument(Document* document)
  281. {
  282. ASSERT(document);
  283. JSWrapperCacheMap& wrapperCacheMap = document->wrapperCacheMap();
  284. JSWrapperCacheMap::const_iterator wrappersMapEnd = wrapperCacheMap.end();
  285. for (JSWrapperCacheMap::const_iterator wrappersMapIter = wrapperCacheMap.begin(); wrappersMapIter != wrappersMapEnd; ++wrappersMapIter) {
  286. delete wrappersMapIter->second;
  287. wrappersMapIter->first->forgetDocument(document);
  288. }
  289. }
  290. void forgetWorldOfDOMNodesForDocument(Document* document, DOMWrapperWorld* world)
  291. {
  292. JSWrapperCache* wrappers = document->wrapperCacheMap().take(world);
  293. ASSERT(wrappers); // 'world' should only know about 'document' if 'document' knows about 'world'!
  294. delete wrappers;
  295. }
  296. static inline bool isObservableThroughDOM(JSNode* jsNode, DOMWrapperWorld* world)
  297. {
  298. // Certain conditions implicitly make a JS DOM node wrapper observable
  299. // through the DOM, even if no explicit reference to it remains.
  300. Node* node = jsNode->impl();
  301. if (node->inDocument()) {
  302. // If a node is in the document, and its wrapper has custom properties,
  303. // the wrapper is observable because future access to the node through the
  304. // DOM must reflect those properties.
  305. if (jsNode->hasCustomProperties())
  306. return true;
  307. // If a node is in the document, and has event listeners, its wrapper is
  308. // observable because its wrapper is responsible for marking those event listeners.
  309. if (node->hasEventListeners())
  310. return true; // Technically, we may overzealously mark a wrapper for a node that has only non-JS event listeners. Oh well.
  311. // If a node owns another object with a wrapper with custom properties,
  312. // the wrapper must be treated as observable, because future access to
  313. // those objects through the DOM must reflect those properties.
  314. // FIXME: It would be better if this logic could be in the node next to
  315. // the custom markChildren functions rather than here.
  316. if (node->isElementNode()) {
  317. if (NamedNodeMap* attributes = static_cast<Element*>(node)->attributeMap()) {
  318. if (DOMObject* wrapper = world->m_wrappers.uncheckedGet(attributes)) {
  319. if (wrapper->hasCustomProperties())
  320. return true;
  321. }
  322. }
  323. if (node->isStyledElement()) {
  324. if (CSSMutableStyleDeclaration* style = static_cast<StyledElement*>(node)->inlineStyleDecl()) {
  325. if (DOMObject* wrapper = world->m_wrappers.uncheckedGet(style)) {
  326. if (wrapper->hasCustomProperties())
  327. return true;
  328. }
  329. }
  330. }
  331. if (static_cast<Element*>(node)->hasTagName(canvasTag)) {
  332. if (CanvasRenderingContext* context = static_cast<HTMLCanvasElement*>(node)->renderingContext()) {
  333. if (DOMObject* wrapper = world->m_wrappers.uncheckedGet(context)) {
  334. if (wrapper->hasCustomProperties())
  335. return true;
  336. }
  337. }
  338. }
  339. }
  340. } else {
  341. // If a wrapper is the last reference to an image or script element
  342. // that is loading but not in the document, the wrapper is observable
  343. // because it is the only thing keeping the image element alive, and if
  344. // the image element is destroyed, its load event will not fire.
  345. // FIXME: The DOM should manage this issue without the help of JavaScript wrappers.
  346. if (node->hasTagName(imgTag) && !static_cast<HTMLImageElement*>(node)->haveFiredLoadEvent())
  347. return true;
  348. if (node->hasTagName(scriptTag) && !static_cast<HTMLScriptElement*>(node)->haveFiredLoadEvent())
  349. return true;
  350. #if ENABLE(VIDEO)
  351. if (node->hasTagName(audioTag) && !static_cast<HTMLAudioElement*>(node)->paused())
  352. return true;
  353. #endif
  354. }
  355. // If a node is firing event listeners, its wrapper is observable because
  356. // its wrapper is responsible for marking those event listeners.
  357. if (node->isFiringEventListeners())
  358. return true;
  359. return false;
  360. }
  361. void markDOMNodesForDocument(MarkStack& markStack, Document* document)
  362. {
  363. JSWrapperCacheMap& wrapperCacheMap = document->wrapperCacheMap();
  364. for (JSWrapperCacheMap::iterator wrappersIter = wrapperCacheMap.begin(); wrappersIter != wrapperCacheMap.end(); ++wrappersIter) {
  365. DOMWrapperWorld* world = wrappersIter->first;
  366. JSWrapperCache* nodeDict = wrappersIter->second;
  367. JSWrapperCache::iterator nodeEnd = nodeDict->uncheckedEnd();
  368. for (JSWrapperCache::iterator nodeIt = nodeDict->uncheckedBegin(); nodeIt != nodeEnd; ++nodeIt) {
  369. JSNode* jsNode = nodeIt->second;
  370. if (isObservableThroughDOM(jsNode, world))
  371. markStack.append(jsNode);
  372. }
  373. }
  374. }
  375. void markActiveObjectsForContext(MarkStack& markStack, JSGlobalData& globalData, ScriptExecutionContext* scriptExecutionContext)
  376. {
  377. // If an element has pending activity that may result in event listeners being called
  378. // (e.g. an XMLHttpRequest), we need to keep JS wrappers alive.
  379. const HashMap<ActiveDOMObject*, void*>& activeObjects = scriptExecutionContext->activeDOMObjects();
  380. HashMap<ActiveDOMObject*, void*>::const_iterator activeObjectsEnd = activeObjects.end();
  381. for (HashMap<ActiveDOMObject*, void*>::const_iterator iter = activeObjects.begin(); iter != activeObjectsEnd; ++iter) {
  382. if (iter->first->hasPendingActivity()) {
  383. // Generally, an active object with pending activity must have a wrapper to mark its listeners.
  384. // However, some ActiveDOMObjects don't have JS wrappers.
  385. markDOMObjectWrapper(markStack, globalData, iter->second);
  386. }
  387. }
  388. const HashSet<MessagePort*>& messagePorts = scriptExecutionContext->messagePorts();
  389. HashSet<MessagePort*>::const_iterator portsEnd = messagePorts.end();
  390. for (HashSet<MessagePort*>::const_iterator iter = messagePorts.begin(); iter != portsEnd; ++iter) {
  391. // If the message port is remotely entangled, then always mark it as in-use because we can't determine reachability across threads.
  392. if (!(*iter)->locallyEntangledPort() || (*iter)->hasPendingActivity())
  393. markDOMObjectWrapper(markStack, globalData, *iter);
  394. }
  395. }
  396. typedef std::pair<JSNode*, DOMWrapperWorld*> WrapperAndWorld;
  397. typedef WTF::Vector<WrapperAndWorld, 8> WrapperSet;
  398. static inline void takeWrappers(Node* node, Document* document, WrapperSet& wrapperSet)
  399. {
  400. if (document) {
  401. JSWrapperCacheMap& wrapperCacheMap = document->wrapperCacheMap();
  402. for (JSWrapperCacheMap::iterator iter = wrapperCacheMap.begin(); iter != wrapperCacheMap.end(); ++iter) {
  403. if (JSNode* wrapper = iter->second->take(node)) {
  404. didUncacheWrapper(wrapper);
  405. wrapperSet.append(WrapperAndWorld(wrapper, iter->first));
  406. }
  407. }
  408. } else {
  409. for (JSGlobalDataWorldIterator worldIter(JSDOMWindow::commonJSGlobalData()); worldIter; ++worldIter) {
  410. DOMWrapperWorld* world = *worldIter;
  411. if (JSNode* wrapper = static_cast<JSNode*>(world->m_wrappers.take(node))) {
  412. didUncacheWrapper(wrapper);
  413. wrapperSet.append(WrapperAndWorld(wrapper, world));
  414. }
  415. }
  416. }
  417. }
  418. void updateDOMNodeDocument(Node* node, Document* oldDocument, Document* newDocument)
  419. {
  420. ASSERT(oldDocument != newDocument);
  421. WrapperSet wrapperSet;
  422. takeWrappers(node, oldDocument, wrapperSet);
  423. for (unsigned i = 0; i < wrapperSet.size(); ++i) {
  424. JSNode* wrapper = wrapperSet[i].first;
  425. willCacheWrapper(wrapper);
  426. if (newDocument)
  427. newDocument->getWrapperCache(wrapperSet[i].second)->set(node, wrapper);
  428. else
  429. wrapperSet[i].second->m_wrappers.set(node, wrapper);
  430. }
  431. }
  432. void markDOMObjectWrapper(MarkStack& markStack, JSGlobalData& globalData, void* object)
  433. {
  434. // FIXME: This could be changed to only mark wrappers that are "observable"
  435. // as markDOMNodesForDocument does, allowing us to collect more wrappers,
  436. // but doing this correctly would be challenging.
  437. if (!object)
  438. return;
  439. for (JSGlobalDataWorldIterator worldIter(&globalData); worldIter; ++worldIter) {
  440. if (DOMObject* wrapper = worldIter->m_wrappers.uncheckedGet(object))
  441. markStack.append(wrapper);
  442. }
  443. }
  444. void markDOMNodeWrapper(MarkStack& markStack, Document* document, Node* node)
  445. {
  446. if (document) {
  447. JSWrapperCacheMap& wrapperCacheMap = document->wrapperCacheMap();
  448. for (JSWrapperCacheMap::iterator iter = wrapperCacheMap.begin(); iter != wrapperCacheMap.end(); ++iter) {
  449. if (JSNode* wrapper = iter->second->uncheckedGet(node))
  450. markStack.append(wrapper);
  451. }
  452. return;
  453. }
  454. for (JSGlobalDataWorldIterator worldIter(JSDOMWindow::commonJSGlobalData()); worldIter; ++worldIter) {
  455. if (DOMObject* wrapper = worldIter->m_wrappers.uncheckedGet(node))
  456. markStack.append(wrapper);
  457. }
  458. }
  459. static void stringWrapperDestroyed(JSString* str, void* context)
  460. {
  461. StringImpl* cacheKey = static_cast<StringImpl*>(context);
  462. JSC::JSGlobalData* globalData = Heap::heap(str)->globalData();
  463. // Check the normal world first!
  464. JSGlobalData::ClientData* clientData = globalData->clientData;
  465. ASSERT(clientData);
  466. JSStringCache& cache = static_cast<WebCoreJSClientData*>(clientData)->normalWorld()->m_stringCache;
  467. if (cache.uncheckedRemove(cacheKey, str)) {
  468. cacheKey->deref();
  469. return;
  470. }
  471. for (JSGlobalDataWorldIterator worldIter(globalData); worldIter; ++worldIter) {
  472. if (worldIter->m_stringCache.uncheckedRemove(cacheKey, str))
  473. break;
  474. }
  475. cacheKey->deref();
  476. }
  477. JSValue jsStringSlowCase(ExecState* exec, JSStringCache& stringCache, StringImpl* stringImpl)
  478. {
  479. // If there is a stale entry, we have to explicitly remove it to avoid
  480. // problems down the line.
  481. if (JSString* wrapper = stringCache.uncheckedGet(stringImpl))
  482. stringCache.uncheckedRemove(stringImpl, wrapper);
  483. JSString* wrapper = jsStringWithFinalizer(exec, stringImpl->ustring(), stringWrapperDestroyed, stringImpl);
  484. stringCache.set(stringImpl, wrapper);
  485. // ref explicitly instead of using a RefPtr-keyed hashtable because the wrapper can
  486. // outlive the cache, so the stringImpl has to match the wrapper's lifetime.
  487. stringImpl->ref();
  488. return wrapper;
  489. }
  490. JSValue jsStringOrNull(ExecState* exec, const String& s)
  491. {
  492. if (s.isNull())
  493. return jsNull();
  494. return jsString(exec, s);
  495. }
  496. JSValue jsOwnedStringOrNull(ExecState* exec, const UString& s)
  497. {
  498. if (s.isNull())
  499. return jsNull();
  500. return jsOwnedString(exec, s);
  501. }
  502. JSValue jsStringOrUndefined(ExecState* exec, const String& s)
  503. {
  504. if (s.isNull())
  505. return jsUndefined();
  506. return jsString(exec, s);
  507. }
  508. JSValue jsStringOrFalse(ExecState* exec, const String& s)
  509. {
  510. if (s.isNull())
  511. return jsBoolean(false);
  512. return jsString(exec, s);
  513. }
  514. JSValue jsString(ExecState* exec, const KURL& url)
  515. {
  516. return jsString(exec, url.string());
  517. }
  518. JSValue jsStringOrNull(ExecState* exec, const KURL& url)
  519. {
  520. if (url.isNull())
  521. return jsNull();
  522. return jsString(exec, url.string());
  523. }
  524. JSValue jsStringOrUndefined(ExecState* exec, const KURL& url)
  525. {
  526. if (url.isNull())
  527. return jsUndefined();
  528. return jsString(exec, url.string());
  529. }
  530. JSValue jsStringOrFalse(ExecState* exec, const KURL& url)
  531. {
  532. if (url.isNull())
  533. return jsBoolean(false);
  534. return jsString(exec, url.string());
  535. }
  536. UString valueToStringWithNullCheck(ExecState* exec, JSValue value)
  537. {
  538. if (value.isNull())
  539. return UString();
  540. return value.toString(exec);
  541. }
  542. UString valueToStringWithUndefinedOrNullCheck(ExecState* exec, JSValue value)
  543. {
  544. if (value.isUndefinedOrNull())
  545. return UString();
  546. return value.toString(exec);
  547. }
  548. JSValue jsDateOrNull(ExecState* exec, double value)
  549. {
  550. if (!isfinite(value))
  551. return jsNull();
  552. return new (exec) DateInstance(exec, value);
  553. }
  554. double valueToDate(ExecState* exec, JSValue value)
  555. {
  556. if (value.isNumber())
  557. return value.uncheckedGetNumber();
  558. if (!value.inherits(&DateInstance::info))
  559. return std::numeric_limits<double>::quiet_NaN();
  560. return static_cast<DateInstance*>(value.toObject(exec))->internalNumber();
  561. }
  562. void reportException(ExecState* exec, JSValue exception)
  563. {
  564. UString errorMessage = exception.toString(exec);
  565. JSObject* exceptionObject = exception.toObject(exec);
  566. int lineNumber = exceptionObject->get(exec, Identifier(exec, "line")).toInt32(exec);
  567. UString exceptionSourceURL = exceptionObject->get(exec, Identifier(exec, "sourceURL")).toString(exec);
  568. exec->clearException();
  569. if (ExceptionBase* exceptionBase = toExceptionBase(exception))
  570. errorMessage = exceptionBase->message() + ": " + exceptionBase->description();
  571. ScriptExecutionContext* scriptExecutionContext = static_cast<JSDOMGlobalObject*>(exec->lexicalGlobalObject())->scriptExecutionContext();
  572. ASSERT(scriptExecutionContext);
  573. // Crash data indicates null-dereference crashes at this point in the Safari 4 Public Beta.
  574. // It's harmless to return here without reporting the exception to the log and the debugger in this case.
  575. if (!scriptExecutionContext)
  576. return;
  577. scriptExecutionContext->reportException(errorMessage, lineNumber, exceptionSourceURL);
  578. }
  579. void reportCurrentException(ExecState* exec)
  580. {
  581. JSValue exception = exec->exception();
  582. exec->clearException();
  583. reportException(exec, exception);
  584. }
  585. void setDOMException(ExecState* exec, ExceptionCode ec)
  586. {
  587. if (!ec || exec->hadException())
  588. return;
  589. // FIXME: All callers to setDOMException need to pass in the right global object
  590. // for now, we're going to assume the lexicalGlobalObject. Which is wrong in cases like this:
  591. // frames[0].document.createElement(null, null); // throws an exception which should have the subframes prototypes.
  592. JSDOMGlobalObject* globalObject = deprecatedGlobalObjectForPrototype(exec);
  593. ExceptionCodeDescription description;
  594. getExceptionCodeDescription(ec, description);
  595. JSValue errorObject;
  596. switch (description.type) {
  597. case DOMExceptionType:
  598. errorObject = toJS(exec, globalObject, DOMCoreException::create(description));
  599. break;
  600. case RangeExceptionType:
  601. errorObject = toJS(exec, globalObject, RangeException::create(description));
  602. break;
  603. case EventExceptionType:
  604. errorObject = toJS(exec, globalObject, EventException::create(description));
  605. break;
  606. case XMLHttpRequestExceptionType:
  607. errorObject = toJS(exec, globalObject, XMLHttpRequestException::create(description));
  608. break;
  609. #if ENABLE(SVG)
  610. case SVGExceptionType:
  611. errorObject = toJS(exec, globalObject, SVGException::create(description).get(), 0 /* no context on purpose */);
  612. break;
  613. #endif
  614. #if ENABLE(XPATH)
  615. case XPathExceptionType:
  616. errorObject = toJS(exec, globalObject, XPathException::create(description));
  617. break;
  618. #endif
  619. }
  620. ASSERT(errorObject);
  621. exec->setException(errorObject);
  622. }
  623. bool checkNodeSecurity(ExecState* exec, Node* node)
  624. {
  625. return node && allowsAccessFromFrame(exec, node->document()->frame());
  626. }
  627. bool allowsAccessFromFrame(ExecState* exec, Frame* frame)
  628. {
  629. if (!frame)
  630. return false;
  631. JSDOMWindow* window = toJSDOMWindow(frame, currentWorld(exec));
  632. return window && window->allowsAccessFrom(exec);
  633. }
  634. bool allowsAccessFromFrame(ExecState* exec, Frame* frame, String& message)
  635. {
  636. if (!frame)
  637. return false;
  638. JSDOMWindow* window = toJSDOMWindow(frame, currentWorld(exec));
  639. return window && window->allowsAccessFrom(exec, message);
  640. }
  641. bool shouldAllowNavigation(ExecState* exec, Frame* frame)
  642. {
  643. Frame* lexicalFrame = toLexicalFrame(exec);
  644. return lexicalFrame && lexicalFrame->loader()->shouldAllowNavigation(frame);
  645. }
  646. void printErrorMessageForFrame(Frame* frame, const String& message)
  647. {
  648. if (!frame)
  649. return;
  650. if (message.isEmpty())
  651. return;
  652. Settings* settings = frame->settings();
  653. if (!settings)
  654. return;
  655. if (settings->privateBrowsingEnabled())
  656. return;
  657. frame->domWindow()->console()->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, message, 1, String()); // FIXME: provide a real line number and source URL.
  658. }
  659. Frame* toLexicalFrame(ExecState* exec)
  660. {
  661. return asJSDOMWindow(exec->lexicalGlobalObject())->impl()->frame();
  662. }
  663. Frame* toDynamicFrame(ExecState* exec)
  664. {
  665. return asJSDOMWindow(exec->dynamicGlobalObject())->impl()->frame();
  666. }
  667. bool processingUserGesture(ExecState* exec)
  668. {
  669. Frame* frame = toDynamicFrame(exec);
  670. return frame && frame->script()->processingUserGesture(currentWorld(exec));
  671. }
  672. KURL completeURL(ExecState* exec, const String& relativeURL)
  673. {
  674. // For historical reasons, we need to complete the URL using the dynamic frame.
  675. Frame* frame = toDynamicFrame(exec);
  676. if (!frame)
  677. return KURL();
  678. return frame->loader()->completeURL(relativeURL);
  679. }
  680. JSValue objectToStringFunctionGetter(ExecState* exec, const Identifier& propertyName, const PropertySlot&)
  681. {
  682. return new (exec) NativeFunctionWrapper(exec, exec->lexicalGlobalObject()->prototypeFunctionStructure(), 0, propertyName, objectProtoFuncToString);
  683. }
  684. Structure* getCachedDOMStructure(JSDOMGlobalObject* globalObject, const ClassInfo* classInfo)
  685. {
  686. JSDOMStructureMap& structures = globalObject->structures();
  687. return structures.get(classInfo).get();
  688. }
  689. Structure* cacheDOMStructure(JSDOMGlobalObject* globalObject, NonNullPassRefPtr<Structure> structure, const ClassInfo* classInfo)
  690. {
  691. JSDOMStructureMap& structures = globalObject->structures();
  692. ASSERT(!structures.contains(classInfo));
  693. return structures.set(classInfo, structure).first->second.get();
  694. }
  695. Structure* getCachedDOMStructure(ExecState* exec, const ClassInfo* classInfo)
  696. {
  697. return getCachedDOMStructure(static_cast<JSDOMGlobalObject*>(exec->lexicalGlobalObject()), classInfo);
  698. }
  699. Structure* cacheDOMStructure(ExecState* exec, NonNullPassRefPtr<Structure> structure, const ClassInfo* classInfo)
  700. {
  701. return cacheDOMStructure(static_cast<JSDOMGlobalObject*>(exec->lexicalGlobalObject()), structure, classInfo);
  702. }
  703. JSObject* getCachedDOMConstructor(ExecState* exec, const ClassInfo* classInfo)
  704. {
  705. JSDOMConstructorMap& constructors = static_cast<JSDOMGlobalObject*>(exec->lexicalGlobalObject())->constructors();
  706. return constructors.get(classInfo);
  707. }
  708. void cacheDOMConstructor(ExecState* exec, const ClassInfo* classInfo, JSObject* constructor)
  709. {
  710. JSDOMConstructorMap& constructors = static_cast<JSDOMGlobalObject*>(exec->lexicalGlobalObject())->constructors();
  711. ASSERT(!constructors.contains(classInfo));
  712. constructors.set(classInfo, constructor);
  713. }
  714. JSC::JSObject* toJSSequence(ExecState* exec, JSValue value, unsigned& length)
  715. {
  716. JSObject* object = value.getObject();
  717. if (!object) {
  718. throwError(exec, TypeError);
  719. return 0;
  720. }
  721. JSValue lengthValue = object->get(exec, exec->propertyNames().length);
  722. if (exec->hadException())
  723. return 0;
  724. if (lengthValue.isUndefinedOrNull()) {
  725. throwError(exec, TypeError);
  726. return 0;
  727. }
  728. length = lengthValue.toUInt32(exec);
  729. if (exec->hadException())
  730. return 0;
  731. return object;
  732. }
  733. bool DOMObject::defineOwnProperty(ExecState* exec, const Identifier&, PropertyDescriptor&, bool)
  734. {
  735. throwError(exec, TypeError, "defineProperty is not supported on DOM Objects");
  736. return false;
  737. }
  738. } // namespace WebCore