DOMWindowExtensionNoCache_Bundle.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. /*
  2. * Copyright (C) 2012 Apple Inc. All rights reserved.
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions
  6. * are met:
  7. * 1. Redistributions of source code must retain the above copyright
  8. * notice, this list of conditions and the following disclaimer.
  9. * 2. Redistributions in binary form must reproduce the above copyright
  10. * notice, this list of conditions and the following disclaimer in the
  11. * documentation and/or other materials provided with the distribution.
  12. *
  13. * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
  14. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  15. * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  16. * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
  17. * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  18. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  19. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  20. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  21. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  22. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
  23. * THE POSSIBILITY OF SUCH DAMAGE.
  24. */
  25. #include "config.h"
  26. #include "InjectedBundleTest.h"
  27. #include <WebKit2/WKBundleDOMWindowExtension.h>
  28. #include <WebKit2/WKBundleFrame.h>
  29. #include <WebKit2/WKBundlePage.h>
  30. #include <WebKit2/WKBundlePageGroup.h>
  31. #include <WebKit2/WKBundlePrivate.h>
  32. #include <WebKit2/WKBundleScriptWorld.h>
  33. #include <WebKit2/WKRetainPtr.h>
  34. #include <wtf/HashMap.h>
  35. #include <assert.h>
  36. namespace TestWebKitAPI {
  37. static void didFinishLoadForFrameCallback(WKBundlePageRef, WKBundleFrameRef, WKTypeRef*, const void* clientInfo);
  38. static void globalObjectIsAvailableForFrameCallback(WKBundlePageRef, WKBundleFrameRef, WKBundleScriptWorldRef, const void* clientInfo);
  39. static void willDisconnectDOMWindowExtensionFromGlobalObjectCallback(WKBundlePageRef, WKBundleDOMWindowExtensionRef, const void* clientInfo);
  40. static void didReconnectDOMWindowExtensionToGlobalObjectCallback(WKBundlePageRef, WKBundleDOMWindowExtensionRef, const void* clientInfo);
  41. static void willDestroyGlobalObjectForDOMWindowExtensionCallback(WKBundlePageRef, WKBundleDOMWindowExtensionRef, const void* clientInfo);
  42. enum ExtensionState {
  43. Uncreated = 0, Connected, Disconnected, Destroyed, Removed
  44. };
  45. const char* states[5] = {
  46. "Uncreated",
  47. "Connected",
  48. "Disconnected",
  49. "Destroyed",
  50. "Removed"
  51. };
  52. typedef struct {
  53. const char* name;
  54. ExtensionState state;
  55. } ExtensionRecord;
  56. class DOMWindowExtensionNoCache : public InjectedBundleTest {
  57. public:
  58. DOMWindowExtensionNoCache(const std::string& identifier);
  59. virtual void initialize(WKBundleRef, WKTypeRef userData);
  60. virtual void didCreatePage(WKBundleRef, WKBundlePageRef);
  61. virtual void willDestroyPage(WKBundleRef, WKBundlePageRef);
  62. void globalObjectIsAvailableForFrame(WKBundleFrameRef, WKBundleScriptWorldRef);
  63. void willDisconnectDOMWindowExtensionFromGlobalObject(WKBundleDOMWindowExtensionRef);
  64. void didReconnectDOMWindowExtensionToGlobalObject(WKBundleDOMWindowExtensionRef);
  65. void willDestroyGlobalObjectForDOMWindowExtension(WKBundleDOMWindowExtensionRef);
  66. void frameLoadFinished(WKBundleFrameRef);
  67. private:
  68. void updateExtensionStateRecord(WKBundleDOMWindowExtensionRef, ExtensionState);
  69. void sendExtensionStateMessage();
  70. void sendBundleMessage(const char*);
  71. WKBundleRef m_bundle;
  72. ExtensionRecord m_extensionRecords[10];
  73. HashMap<WKBundleDOMWindowExtensionRef, int> m_extensionToRecordMap;
  74. int m_numberMainFrameLoads;
  75. };
  76. static InjectedBundleTest::Register<DOMWindowExtensionNoCache> registrar("DOMWindowExtensionNoCache");
  77. DOMWindowExtensionNoCache::DOMWindowExtensionNoCache(const std::string& identifier)
  78. : InjectedBundleTest(identifier)
  79. , m_numberMainFrameLoads(0)
  80. {
  81. m_extensionRecords[0].name = "First page, main frame, standard world";
  82. m_extensionRecords[1].name = "First page, main frame, non-standard world";
  83. m_extensionRecords[2].name = "First page, subframe, standard world";
  84. m_extensionRecords[3].name = "First page, subframe, non-standard world";
  85. m_extensionRecords[4].name = "Second page, main frame, standard world";
  86. m_extensionRecords[5].name = "Second page, main frame, non-standard world";
  87. m_extensionRecords[6].name = "First page, main frame, standard world";
  88. m_extensionRecords[7].name = "First page, main frame, non-standard world";
  89. m_extensionRecords[8].name = "First page, subframe, standard world";
  90. m_extensionRecords[9].name = "First page, subframe, non-standard world";
  91. for (size_t i = 0; i < 10; ++i)
  92. m_extensionRecords[i].state = Uncreated;
  93. }
  94. void DOMWindowExtensionNoCache::frameLoadFinished(WKBundleFrameRef frame)
  95. {
  96. bool mainFrame = !WKBundleFrameGetParentFrame(frame);
  97. if (mainFrame)
  98. m_numberMainFrameLoads++;
  99. char body[16384];
  100. sprintf(body, "%s finished loading", mainFrame ? "Main frame" : "Subframe");
  101. // Only consider load finished for the main frame
  102. const char* name = mainFrame ? "DidFinishLoadForMainFrame" : "DidFinishLoadForFrame";
  103. WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString(name));
  104. WKRetainPtr<WKStringRef> messageBody = adoptWK(WKStringCreateWithUTF8CString(body));
  105. WKBundlePostMessage(m_bundle, messageName.get(), messageBody.get());
  106. sendExtensionStateMessage();
  107. }
  108. void DOMWindowExtensionNoCache::sendExtensionStateMessage()
  109. {
  110. char body[16384];
  111. sprintf(body, "Extension states:\n%s - %s\n%s - %s\n%s - %s\n%s - %s\n%s - %s\n%s - %s\n%s - %s\n%s - %s\n%s - %s\n%s - %s",
  112. m_extensionRecords[0].name, states[m_extensionRecords[0].state],
  113. m_extensionRecords[1].name, states[m_extensionRecords[1].state],
  114. m_extensionRecords[2].name, states[m_extensionRecords[2].state],
  115. m_extensionRecords[3].name, states[m_extensionRecords[3].state],
  116. m_extensionRecords[4].name, states[m_extensionRecords[4].state],
  117. m_extensionRecords[5].name, states[m_extensionRecords[5].state],
  118. m_extensionRecords[6].name, states[m_extensionRecords[6].state],
  119. m_extensionRecords[7].name, states[m_extensionRecords[7].state],
  120. m_extensionRecords[8].name, states[m_extensionRecords[8].state],
  121. m_extensionRecords[9].name, states[m_extensionRecords[9].state]);
  122. WKRetainPtr<WKStringRef> messageName = adoptWK(WKStringCreateWithUTF8CString("ExtensionStates"));
  123. WKRetainPtr<WKStringRef> messageBody = adoptWK(WKStringCreateWithUTF8CString(body));
  124. WKBundlePostMessage(m_bundle, messageName.get(), messageBody.get());
  125. }
  126. void DOMWindowExtensionNoCache::initialize(WKBundleRef bundle, WKTypeRef userData)
  127. {
  128. assert(WKGetTypeID(userData) == WKBundlePageGroupGetTypeID());
  129. WKBundlePageGroupRef pageGroup = static_cast<WKBundlePageGroupRef>(userData);
  130. WKRetainPtr<WKStringRef> source(AdoptWK, WKStringCreateWithUTF8CString("alert('Unimportant alert');"));
  131. WKBundleAddUserScript(bundle, pageGroup, WKBundleScriptWorldCreateWorld(), source.get(), 0, 0, 0, kWKInjectAtDocumentStart, kWKInjectInAllFrames);
  132. }
  133. void DOMWindowExtensionNoCache::didCreatePage(WKBundleRef bundle, WKBundlePageRef page)
  134. {
  135. m_bundle = bundle;
  136. WKBundlePageLoaderClient pageLoaderClient;
  137. memset(&pageLoaderClient, 0, sizeof(pageLoaderClient));
  138. pageLoaderClient.version = kWKBundlePageLoaderClientCurrentVersion;
  139. pageLoaderClient.clientInfo = this;
  140. pageLoaderClient.didFinishLoadForFrame = didFinishLoadForFrameCallback;
  141. pageLoaderClient.globalObjectIsAvailableForFrame = globalObjectIsAvailableForFrameCallback;
  142. pageLoaderClient.willDisconnectDOMWindowExtensionFromGlobalObject = willDisconnectDOMWindowExtensionFromGlobalObjectCallback;
  143. pageLoaderClient.didReconnectDOMWindowExtensionToGlobalObject = didReconnectDOMWindowExtensionToGlobalObjectCallback;
  144. pageLoaderClient.willDestroyGlobalObjectForDOMWindowExtension = willDestroyGlobalObjectForDOMWindowExtensionCallback;
  145. WKBundlePageSetPageLoaderClient(page, &pageLoaderClient);
  146. }
  147. void DOMWindowExtensionNoCache::willDestroyPage(WKBundleRef, WKBundlePageRef)
  148. {
  149. HashMap<WKBundleDOMWindowExtensionRef, int>::iterator it = m_extensionToRecordMap.begin();
  150. HashMap<WKBundleDOMWindowExtensionRef, int>::iterator end = m_extensionToRecordMap.end();
  151. for (; it != end; ++it) {
  152. updateExtensionStateRecord(it->key, Removed);
  153. WKRelease(it->key);
  154. }
  155. m_extensionToRecordMap.clear();
  156. sendExtensionStateMessage();
  157. sendBundleMessage("TestComplete");
  158. }
  159. void DOMWindowExtensionNoCache::updateExtensionStateRecord(WKBundleDOMWindowExtensionRef extension, ExtensionState state)
  160. {
  161. int index = m_extensionToRecordMap.get(extension);
  162. m_extensionRecords[index].state = state;
  163. }
  164. void DOMWindowExtensionNoCache::sendBundleMessage(const char* message)
  165. {
  166. WKRetainPtr<WKStringRef> wkMessage = adoptWK(WKStringCreateWithUTF8CString(message));
  167. WKBundlePostMessage(m_bundle, wkMessage.get(), wkMessage.get());
  168. }
  169. void DOMWindowExtensionNoCache::globalObjectIsAvailableForFrame(WKBundleFrameRef frame, WKBundleScriptWorldRef world)
  170. {
  171. WKBundleDOMWindowExtensionRef extension = WKBundleDOMWindowExtensionCreate(frame, world);
  172. int index;
  173. bool standard;
  174. standard = world == WKBundleScriptWorldNormalWorld();
  175. bool mainFrame = !WKBundleFrameGetParentFrame(frame);
  176. switch (m_numberMainFrameLoads) {
  177. case 0:
  178. index = mainFrame ? (standard ? 0 : 1) : (standard ? 2 : 3);
  179. break;
  180. case 1:
  181. index = standard ? 4 : 5;
  182. break;
  183. case 2:
  184. index = mainFrame ? (standard ? 6 : 7) : (standard ? 8 : 9);
  185. break;
  186. default:
  187. ASSERT_NOT_REACHED();
  188. break;
  189. }
  190. m_extensionToRecordMap.set(extension, index);
  191. updateExtensionStateRecord(extension, Connected);
  192. sendBundleMessage("GlobalObjectIsAvailableForFrame called");
  193. }
  194. void DOMWindowExtensionNoCache::willDisconnectDOMWindowExtensionFromGlobalObject(WKBundleDOMWindowExtensionRef extension)
  195. {
  196. // No items should be going into a 0-capacity page cache.
  197. ASSERT_NOT_REACHED();
  198. }
  199. void DOMWindowExtensionNoCache::didReconnectDOMWindowExtensionToGlobalObject(WKBundleDOMWindowExtensionRef)
  200. {
  201. // No items should be coming out of a 0-capacity page cache.
  202. ASSERT_NOT_REACHED();
  203. }
  204. void DOMWindowExtensionNoCache::willDestroyGlobalObjectForDOMWindowExtension(WKBundleDOMWindowExtensionRef extension)
  205. {
  206. sendBundleMessage("WillDestroyDOMWindowExtensionToGlobalObject called");
  207. updateExtensionStateRecord(extension, Destroyed);
  208. m_extensionToRecordMap.remove(extension);
  209. WKRelease(extension);
  210. }
  211. static void didFinishLoadForFrameCallback(WKBundlePageRef, WKBundleFrameRef frame, WKTypeRef*, const void *clientInfo)
  212. {
  213. ((DOMWindowExtensionNoCache*)clientInfo)->frameLoadFinished(frame);
  214. }
  215. static void globalObjectIsAvailableForFrameCallback(WKBundlePageRef, WKBundleFrameRef frame, WKBundleScriptWorldRef world, const void* clientInfo)
  216. {
  217. ((DOMWindowExtensionNoCache*)clientInfo)->globalObjectIsAvailableForFrame(frame, world);
  218. }
  219. static void willDisconnectDOMWindowExtensionFromGlobalObjectCallback(WKBundlePageRef, WKBundleDOMWindowExtensionRef extension, const void* clientInfo)
  220. {
  221. ((DOMWindowExtensionNoCache*)clientInfo)->willDisconnectDOMWindowExtensionFromGlobalObject(extension);
  222. }
  223. static void didReconnectDOMWindowExtensionToGlobalObjectCallback(WKBundlePageRef, WKBundleDOMWindowExtensionRef extension, const void* clientInfo)
  224. {
  225. ((DOMWindowExtensionNoCache*)clientInfo)->didReconnectDOMWindowExtensionToGlobalObject(extension);
  226. }
  227. static void willDestroyGlobalObjectForDOMWindowExtensionCallback(WKBundlePageRef, WKBundleDOMWindowExtensionRef extension , const void* clientInfo)
  228. {
  229. ((DOMWindowExtensionNoCache*)clientInfo)->willDestroyGlobalObjectForDOMWindowExtension(extension);
  230. }
  231. } // namespace TestWebKitAPI