DumpRenderTree.mm 54 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489
  1. /*
  2. * Copyright (C) 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
  3. * (C) 2007 Graham Dennis (graham.dennis@gmail.com)
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions
  7. * are met:
  8. *
  9. * 1. Redistributions of source code must retain the above copyright
  10. * notice, this list of conditions and the following disclaimer.
  11. * 2. Redistributions in binary form must reproduce the above copyright
  12. * notice, this list of conditions and the following disclaimer in the
  13. * documentation and/or other materials provided with the distribution.
  14. * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
  15. * its contributors may be used to endorse or promote products derived
  16. * from this software without specific prior written permission.
  17. *
  18. * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
  19. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  20. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  21. * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
  22. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  23. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  24. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  25. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  26. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  27. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  28. */
  29. #import "config.h"
  30. #import "DumpRenderTree.h"
  31. #import "AccessibilityController.h"
  32. #import "CheckedMalloc.h"
  33. #import "DefaultPolicyDelegate.h"
  34. #import "DumpRenderTreeDraggingInfo.h"
  35. #import "DumpRenderTreePasteboard.h"
  36. #import "DumpRenderTreeWindow.h"
  37. #import "EditingDelegate.h"
  38. #import "EventSendingController.h"
  39. #import "FrameLoadDelegate.h"
  40. #import "HistoryDelegate.h"
  41. #import "JavaScriptThreading.h"
  42. #import "TestRunner.h"
  43. #import "MockGeolocationProvider.h"
  44. #import "MockWebNotificationProvider.h"
  45. #import "NavigationController.h"
  46. #import "ObjCPlugin.h"
  47. #import "ObjCPluginFunction.h"
  48. #import "PixelDumpSupport.h"
  49. #import "PolicyDelegate.h"
  50. #import "ResourceLoadDelegate.h"
  51. #import "StorageTrackerDelegate.h"
  52. #import "UIDelegate.h"
  53. #import "WebArchiveDumpSupport.h"
  54. #import "WebCoreTestSupport.h"
  55. #import "WorkQueue.h"
  56. #import "WorkQueueItem.h"
  57. #import <Carbon/Carbon.h>
  58. #import <CoreFoundation/CoreFoundation.h>
  59. #import <JavaScriptCore/HeapStatistics.h>
  60. #import <JavaScriptCore/Options.h>
  61. #import <WebCore/FoundationExtras.h>
  62. #import <WebKit/DOMElement.h>
  63. #import <WebKit/DOMExtensions.h>
  64. #import <WebKit/DOMRange.h>
  65. #import <WebKit/WebArchive.h>
  66. #import <WebKit/WebBackForwardList.h>
  67. #import <WebKit/WebCache.h>
  68. #import <WebKit/WebCoreStatistics.h>
  69. #import <WebKit/WebDataSourcePrivate.h>
  70. #import <WebKit/WebDatabaseManagerPrivate.h>
  71. #import <WebKit/WebDocumentPrivate.h>
  72. #import <WebKit/WebDeviceOrientationProviderMock.h>
  73. #import <WebKit/WebDynamicScrollBarsView.h>
  74. #import <WebKit/WebEditingDelegate.h>
  75. #import <WebKit/WebFrameView.h>
  76. #import <WebKit/WebHistory.h>
  77. #import <WebKit/WebHistoryItemPrivate.h>
  78. #import <WebKit/WebInspector.h>
  79. #import <WebKit/WebKitNSStringExtras.h>
  80. #import <WebKit/WebPluginDatabase.h>
  81. #import <WebKit/WebPreferences.h>
  82. #import <WebKit/WebPreferencesPrivate.h>
  83. #import <WebKit/WebPreferenceKeysPrivate.h>
  84. #import <WebKit/WebResourceLoadDelegate.h>
  85. #import <WebKit/WebStorageManagerPrivate.h>
  86. #import <WebKit/WebTypesInternal.h>
  87. #import <WebKit/WebViewPrivate.h>
  88. #import <getopt.h>
  89. #import <wtf/Assertions.h>
  90. #import <wtf/FastMalloc.h>
  91. #import <wtf/RetainPtr.h>
  92. #import <wtf/Threading.h>
  93. #import <wtf/ObjcRuntimeExtras.h>
  94. #import <wtf/OwnPtr.h>
  95. extern "C" {
  96. #import <mach-o/getsect.h>
  97. }
  98. using namespace std;
  99. @interface DumpRenderTreeApplication : NSApplication
  100. @end
  101. @interface DumpRenderTreeEvent : NSEvent
  102. @end
  103. @interface NSURLRequest (PrivateThingsWeShouldntReallyUse)
  104. +(void)setAllowsAnyHTTPSCertificate:(BOOL)allow forHost:(NSString *)host;
  105. @end
  106. #if USE(APPKIT)
  107. @interface NSSound (Details)
  108. + (void)_setAlertType:(NSUInteger)alertType;
  109. @end
  110. #endif
  111. static void runTest(const string& testPathOrURL);
  112. // Deciding when it's OK to dump out the state is a bit tricky. All these must be true:
  113. // - There is no load in progress
  114. // - There is no work queued up (see workQueue var, below)
  115. // - waitToDump==NO. This means either waitUntilDone was never called, or it was called
  116. // and notifyDone was called subsequently.
  117. // Note that the call to notifyDone and the end of the load can happen in either order.
  118. volatile bool done;
  119. NavigationController* gNavigationController = 0;
  120. RefPtr<TestRunner> gTestRunner;
  121. WebFrame *mainFrame = 0;
  122. // This is the topmost frame that is loading, during a given load, or nil when no load is
  123. // in progress. Usually this is the same as the main frame, but not always. In the case
  124. // where a frameset is loaded, and then new content is loaded into one of the child frames,
  125. // that child frame is the "topmost frame that is loading".
  126. WebFrame *topLoadingFrame = nil; // !nil iff a load is in progress
  127. CFMutableSetRef disallowedURLs = 0;
  128. static CFRunLoopTimerRef waitToDumpWatchdog = 0;
  129. // Delegates
  130. static FrameLoadDelegate *frameLoadDelegate;
  131. static UIDelegate *uiDelegate;
  132. static EditingDelegate *editingDelegate;
  133. static ResourceLoadDelegate *resourceLoadDelegate;
  134. static HistoryDelegate *historyDelegate;
  135. PolicyDelegate *policyDelegate;
  136. DefaultPolicyDelegate *defaultPolicyDelegate;
  137. StorageTrackerDelegate *storageDelegate;
  138. static int dumpPixelsForAllTests = NO;
  139. static bool dumpPixelsForCurrentTest = false;
  140. static int threaded;
  141. static int dumpTree = YES;
  142. static int useTimeoutWatchdog = YES;
  143. static int forceComplexText;
  144. static int gcBetweenTests;
  145. static BOOL printSeparators;
  146. static RetainPtr<CFStringRef> persistentUserStyleSheetLocation;
  147. static WebHistoryItem *prevTestBFItem = nil; // current b/f item at the end of the previous test
  148. #ifdef __OBJC2__
  149. static void swizzleAllMethods(Class imposter, Class original)
  150. {
  151. unsigned int imposterMethodCount;
  152. Method* imposterMethods = class_copyMethodList(imposter, &imposterMethodCount);
  153. unsigned int originalMethodCount;
  154. Method* originalMethods = class_copyMethodList(original, &originalMethodCount);
  155. for (unsigned int i = 0; i < imposterMethodCount; i++) {
  156. SEL imposterMethodName = method_getName(imposterMethods[i]);
  157. // Attempt to add the method to the original class. If it fails, the method already exists and we should
  158. // instead exchange the implementations.
  159. if (class_addMethod(original, imposterMethodName, method_getImplementation(imposterMethods[i]), method_getTypeEncoding(imposterMethods[i])))
  160. continue;
  161. unsigned int j = 0;
  162. for (; j < originalMethodCount; j++) {
  163. SEL originalMethodName = method_getName(originalMethods[j]);
  164. if (sel_isEqual(imposterMethodName, originalMethodName))
  165. break;
  166. }
  167. // If class_addMethod failed above then the method must exist on the original class.
  168. ASSERT(j < originalMethodCount);
  169. method_exchangeImplementations(imposterMethods[i], originalMethods[j]);
  170. }
  171. free(imposterMethods);
  172. free(originalMethods);
  173. }
  174. #endif
  175. static void poseAsClass(const char* imposter, const char* original)
  176. {
  177. Class imposterClass = objc_getClass(imposter);
  178. Class originalClass = objc_getClass(original);
  179. #ifndef __OBJC2__
  180. class_poseAs(imposterClass, originalClass);
  181. #else
  182. // Swizzle instance methods
  183. swizzleAllMethods(imposterClass, originalClass);
  184. // and then class methods
  185. swizzleAllMethods(object_getClass(imposterClass), object_getClass(originalClass));
  186. #endif
  187. }
  188. void setPersistentUserStyleSheetLocation(CFStringRef url)
  189. {
  190. persistentUserStyleSheetLocation = url;
  191. }
  192. static bool shouldIgnoreWebCoreNodeLeaks(const string& URLString)
  193. {
  194. static char* const ignoreSet[] = {
  195. // Keeping this infrastructure around in case we ever need it again.
  196. };
  197. static const int ignoreSetCount = sizeof(ignoreSet) / sizeof(char*);
  198. for (int i = 0; i < ignoreSetCount; i++) {
  199. // FIXME: ignore case
  200. string curIgnore(ignoreSet[i]);
  201. // Match at the end of the URLString
  202. if (!URLString.compare(URLString.length() - curIgnore.length(), curIgnore.length(), curIgnore))
  203. return true;
  204. }
  205. return false;
  206. }
  207. static NSSet *allowedFontFamilySet()
  208. {
  209. static NSSet *fontFamilySet = [[NSSet setWithObjects:
  210. @"Ahem",
  211. @"Al Bayan",
  212. @"American Typewriter",
  213. @"Andale Mono",
  214. @"Apple Braille",
  215. @"Apple Color Emoji",
  216. @"Apple Chancery",
  217. @"Apple Garamond BT",
  218. @"Apple LiGothic",
  219. @"Apple LiSung",
  220. @"Apple Symbols",
  221. @"AppleGothic",
  222. @"AppleMyungjo",
  223. @"Arial Black",
  224. @"Arial Hebrew",
  225. @"Arial Narrow",
  226. @"Arial Rounded MT Bold",
  227. @"Arial Unicode MS",
  228. @"Arial",
  229. @"Ayuthaya",
  230. @"Baghdad",
  231. @"Baskerville",
  232. @"BiauKai",
  233. @"Big Caslon",
  234. @"Brush Script MT",
  235. @"Chalkboard",
  236. @"Chalkduster",
  237. @"Charcoal CY",
  238. @"Cochin",
  239. @"Comic Sans MS",
  240. @"Copperplate",
  241. @"Corsiva Hebrew",
  242. @"Courier New",
  243. @"Courier",
  244. @"DecoType Naskh",
  245. @"Devanagari MT",
  246. @"Didot",
  247. @"Euphemia UCAS",
  248. @"Futura",
  249. @"GB18030 Bitmap",
  250. @"Geeza Pro",
  251. @"Geneva CY",
  252. @"Geneva",
  253. @"Georgia",
  254. @"Gill Sans",
  255. @"Gujarati MT",
  256. @"GungSeo",
  257. @"Gurmukhi MT",
  258. @"HeadLineA",
  259. @"Hei",
  260. @"Heiti SC",
  261. @"Heiti TC",
  262. @"Helvetica CY",
  263. @"Helvetica Neue",
  264. @"Helvetica",
  265. @"Herculanum",
  266. @"Hiragino Kaku Gothic Pro",
  267. @"Hiragino Kaku Gothic ProN",
  268. @"Hiragino Kaku Gothic Std",
  269. @"Hiragino Kaku Gothic StdN",
  270. @"Hiragino Maru Gothic Monospaced",
  271. @"Hiragino Maru Gothic Pro",
  272. @"Hiragino Maru Gothic ProN",
  273. @"Hiragino Mincho Pro",
  274. @"Hiragino Mincho ProN",
  275. @"Hiragino Sans GB",
  276. @"Hoefler Text",
  277. @"Impact",
  278. @"InaiMathi",
  279. @"Kai",
  280. @"Kailasa",
  281. @"Kokonor",
  282. @"Krungthep",
  283. @"KufiStandardGK",
  284. @"LiHei Pro",
  285. @"LiSong Pro",
  286. @"Lucida Grande",
  287. @"Marker Felt",
  288. @"Menlo",
  289. @"Microsoft Sans Serif",
  290. @"Monaco",
  291. @"Mshtakan",
  292. @"Nadeem",
  293. @"New Peninim MT",
  294. @"Optima",
  295. @"Osaka",
  296. @"Papyrus",
  297. @"PCMyungjo",
  298. @"PilGi",
  299. @"Plantagenet Cherokee",
  300. @"Raanana",
  301. @"Sathu",
  302. @"Silom",
  303. @"Skia",
  304. @"Songti SC",
  305. @"Songti TC",
  306. @"STFangsong",
  307. @"STHeiti",
  308. @"STIXGeneral",
  309. @"STIXSizeOneSym",
  310. @"STKaiti",
  311. @"STSong",
  312. @"Symbol",
  313. @"Tahoma",
  314. @"Thonburi",
  315. @"Times New Roman",
  316. @"Times",
  317. @"Trebuchet MS",
  318. @"Verdana",
  319. @"Webdings",
  320. @"WebKit WeightWatcher",
  321. @"Wingdings 2",
  322. @"Wingdings 3",
  323. @"Wingdings",
  324. @"Zapf Dingbats",
  325. @"Zapfino",
  326. nil] retain];
  327. return fontFamilySet;
  328. }
  329. static NSSet *systemHiddenFontFamilySet()
  330. {
  331. static NSSet *fontFamilySet = [[NSSet setWithObjects:
  332. @".LucidaGrandeUI",
  333. nil] retain];
  334. return fontFamilySet;
  335. }
  336. static IMP appKitAvailableFontFamiliesIMP;
  337. static IMP appKitAvailableFontsIMP;
  338. static NSArray *drt_NSFontManager_availableFontFamilies(id self, SEL _cmd)
  339. {
  340. static NSArray *availableFontFamilies;
  341. if (availableFontFamilies)
  342. return availableFontFamilies;
  343. NSArray *availableFamilies = wtfCallIMP<id>(appKitAvailableFontFamiliesIMP, self, _cmd);
  344. NSMutableSet *prunedFamiliesSet = [NSMutableSet setWithArray:availableFamilies];
  345. [prunedFamiliesSet intersectSet:allowedFontFamilySet()];
  346. availableFontFamilies = [[prunedFamiliesSet allObjects] retain];
  347. return availableFontFamilies;
  348. }
  349. static NSArray *drt_NSFontManager_availableFonts(id self, SEL _cmd)
  350. {
  351. static NSArray *availableFonts;
  352. if (availableFonts)
  353. return availableFonts;
  354. NSSet *allowedFamilies = allowedFontFamilySet();
  355. NSMutableArray *availableFontList = [[NSMutableArray alloc] initWithCapacity:[allowedFamilies count] * 2];
  356. for (NSString *fontFamily in allowedFontFamilySet()) {
  357. NSArray* fontsForFamily = [[NSFontManager sharedFontManager] availableMembersOfFontFamily:fontFamily];
  358. for (NSArray* fontInfo in fontsForFamily) {
  359. // Font name is the first entry in the array.
  360. [availableFontList addObject:[fontInfo objectAtIndex:0]];
  361. }
  362. }
  363. for (NSString *hiddenFontFamily in systemHiddenFontFamilySet()) {
  364. [availableFontList addObject:hiddenFontFamily];
  365. }
  366. availableFonts = availableFontList;
  367. return availableFonts;
  368. }
  369. static void swizzleNSFontManagerMethods()
  370. {
  371. Method availableFontFamiliesMethod = class_getInstanceMethod(objc_getClass("NSFontManager"), @selector(availableFontFamilies));
  372. ASSERT(availableFontFamiliesMethod);
  373. if (!availableFontFamiliesMethod) {
  374. NSLog(@"Failed to swizzle the \"availableFontFamilies\" method on NSFontManager");
  375. return;
  376. }
  377. appKitAvailableFontFamiliesIMP = method_setImplementation(availableFontFamiliesMethod, (IMP)drt_NSFontManager_availableFontFamilies);
  378. Method availableFontsMethod = class_getInstanceMethod(objc_getClass("NSFontManager"), @selector(availableFonts));
  379. ASSERT(availableFontsMethod);
  380. if (!availableFontsMethod) {
  381. NSLog(@"Failed to swizzle the \"availableFonts\" method on NSFontManager");
  382. return;
  383. }
  384. appKitAvailableFontsIMP = method_setImplementation(availableFontsMethod, (IMP)drt_NSFontManager_availableFonts);
  385. }
  386. static void activateTestingFonts()
  387. {
  388. static const char* fontFileNames[] = {
  389. "AHEM____.TTF",
  390. "WebKitWeightWatcher100.ttf",
  391. "WebKitWeightWatcher200.ttf",
  392. "WebKitWeightWatcher300.ttf",
  393. "WebKitWeightWatcher400.ttf",
  394. "WebKitWeightWatcher500.ttf",
  395. "WebKitWeightWatcher600.ttf",
  396. "WebKitWeightWatcher700.ttf",
  397. "WebKitWeightWatcher800.ttf",
  398. "WebKitWeightWatcher900.ttf",
  399. #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1080
  400. "SampleFont.sfont",
  401. #endif
  402. 0
  403. };
  404. NSMutableArray *fontURLs = [NSMutableArray array];
  405. NSURL *resourcesDirectory = [NSURL URLWithString:@"DumpRenderTree.resources" relativeToURL:[[NSBundle mainBundle] executableURL]];
  406. for (unsigned i = 0; fontFileNames[i]; ++i) {
  407. NSURL *fontURL = [resourcesDirectory URLByAppendingPathComponent:[NSString stringWithUTF8String:fontFileNames[i]]];
  408. [fontURLs addObject:[fontURL absoluteURL]];
  409. }
  410. CFArrayRef errors = 0;
  411. if (!CTFontManagerRegisterFontsForURLs((CFArrayRef)fontURLs, kCTFontManagerScopeProcess, &errors)) {
  412. NSLog(@"Failed to activate fonts: %@", errors);
  413. CFRelease(errors);
  414. exit(1);
  415. }
  416. }
  417. static void adjustFonts()
  418. {
  419. swizzleNSFontManagerMethods();
  420. activateTestingFonts();
  421. }
  422. @interface DRTMockScroller : NSScroller
  423. @end
  424. @implementation DRTMockScroller
  425. - (NSRect)rectForPart:(NSScrollerPart)partCode
  426. {
  427. switch (partCode) {
  428. case NSScrollerKnob: {
  429. NSRect frameRect = [self frame];
  430. NSRect bounds = [self bounds];
  431. BOOL isHorizontal = frameRect.size.width > frameRect.size.height;
  432. CGFloat trackLength = isHorizontal ? bounds.size.width : bounds.size.height;
  433. CGFloat minKnobSize = isHorizontal ? bounds.size.height : bounds.size.width;
  434. CGFloat knobLength = max(minKnobSize, static_cast<CGFloat>(round(trackLength * [self knobProportion])));
  435. CGFloat knobPosition = static_cast<CGFloat>((round([self doubleValue] * (trackLength - knobLength))));
  436. if (isHorizontal)
  437. return NSMakeRect(bounds.origin.x + knobPosition, bounds.origin.y, knobLength, bounds.size.height);
  438. return NSMakeRect(bounds.origin.x, bounds.origin.y + + knobPosition, bounds.size.width, knobLength);
  439. }
  440. }
  441. return [super rectForPart:partCode];
  442. }
  443. - (void)drawKnob
  444. {
  445. if (![self isEnabled])
  446. return;
  447. NSRect knobRect = [self rectForPart:NSScrollerKnob];
  448. static NSColor *knobColor = [[NSColor colorWithDeviceRed:0x80 / 255.0 green:0x80 / 255.0 blue:0x80 / 255.0 alpha:1] retain];
  449. [knobColor set];
  450. NSRectFill(knobRect);
  451. }
  452. - (void)drawRect:(NSRect)dirtyRect
  453. {
  454. static NSColor *trackColor = [[NSColor colorWithDeviceRed:0xC0 / 255.0 green:0xC0 / 255.0 blue:0xC0 / 255.0 alpha:1] retain];
  455. static NSColor *disabledTrackColor = [[NSColor colorWithDeviceRed:0xE0 / 255.0 green:0xE0 / 255.0 blue:0xE0 / 255.0 alpha:1] retain];
  456. if ([self isEnabled])
  457. [trackColor set];
  458. else
  459. [disabledTrackColor set];
  460. NSRectFill(dirtyRect);
  461. [self drawKnob];
  462. }
  463. @end
  464. static void registerMockScrollbars()
  465. {
  466. [WebDynamicScrollBarsView setCustomScrollerClass:[DRTMockScroller class]];
  467. }
  468. WebView *createWebViewAndOffscreenWindow()
  469. {
  470. NSRect rect = NSMakeRect(0, 0, TestRunner::viewWidth, TestRunner::viewHeight);
  471. WebView *webView = [[WebView alloc] initWithFrame:rect frameName:nil groupName:@"org.webkit.DumpRenderTree"];
  472. [webView setUIDelegate:uiDelegate];
  473. [webView setFrameLoadDelegate:frameLoadDelegate];
  474. [webView setEditingDelegate:editingDelegate];
  475. [webView setResourceLoadDelegate:resourceLoadDelegate];
  476. [webView _setGeolocationProvider:[MockGeolocationProvider shared]];
  477. [webView _setDeviceOrientationProvider:[WebDeviceOrientationProviderMock shared]];
  478. [webView _setNotificationProvider:[MockWebNotificationProvider shared]];
  479. // Register the same schemes that Safari does
  480. [WebView registerURLSchemeAsLocal:@"feed"];
  481. [WebView registerURLSchemeAsLocal:@"feeds"];
  482. [WebView registerURLSchemeAsLocal:@"feedsearch"];
  483. [webView setContinuousSpellCheckingEnabled:YES];
  484. [webView setAutomaticQuoteSubstitutionEnabled:NO];
  485. [webView setAutomaticLinkDetectionEnabled:NO];
  486. [webView setAutomaticDashSubstitutionEnabled:NO];
  487. [webView setAutomaticTextReplacementEnabled:NO];
  488. [webView setAutomaticSpellingCorrectionEnabled:YES];
  489. [webView setGrammarCheckingEnabled:YES];
  490. [webView setDefersCallbacks:NO];
  491. [webView setInteractiveFormValidationEnabled:YES];
  492. [webView setValidationMessageTimerMagnification:-1];
  493. // To make things like certain NSViews, dragging, and plug-ins work, put the WebView a window, but put it off-screen so you don't see it.
  494. // Put it at -10000, -10000 in "flipped coordinates", since WebCore and the DOM use flipped coordinates.
  495. NSRect windowRect = NSOffsetRect(rect, -10000, [(NSScreen *)[[NSScreen screens] objectAtIndex:0] frame].size.height - rect.size.height + 10000);
  496. DumpRenderTreeWindow *window = [[DumpRenderTreeWindow alloc] initWithContentRect:windowRect styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:YES];
  497. [window setColorSpace:[[NSScreen mainScreen] colorSpace]];
  498. [window setCollectionBehavior:NSWindowCollectionBehaviorStationary];
  499. [[window contentView] addSubview:webView];
  500. [window orderBack:nil];
  501. [window setAutodisplay:NO];
  502. [window _setWindowResolution:1 displayIfChanged:YES];
  503. [window startListeningForAcceleratedCompositingChanges];
  504. // For reasons that are not entirely clear, the following pair of calls makes WebView handle its
  505. // dynamic scrollbars properly. Without it, every frame will always have scrollbars.
  506. NSBitmapImageRep *imageRep = [webView bitmapImageRepForCachingDisplayInRect:[webView bounds]];
  507. [webView cacheDisplayInRect:[webView bounds] toBitmapImageRep:imageRep];
  508. return webView;
  509. }
  510. static NSString *libraryPathForDumpRenderTree()
  511. {
  512. //FIXME: This may not be sufficient to prevent interactions/crashes
  513. //when running more than one copy of DumpRenderTree.
  514. //See https://bugs.webkit.org/show_bug.cgi?id=10906
  515. char* dumpRenderTreeTemp = getenv("DUMPRENDERTREE_TEMP");
  516. if (dumpRenderTreeTemp)
  517. return [[NSFileManager defaultManager] stringWithFileSystemRepresentation:dumpRenderTreeTemp length:strlen(dumpRenderTreeTemp)];
  518. else
  519. return [@"~/Library/Application Support/DumpRenderTree" stringByExpandingTildeInPath];
  520. }
  521. // Called before each test.
  522. static void resetDefaultsToConsistentValues()
  523. {
  524. static const int NoFontSmoothing = 0;
  525. static const int BlueTintedAppearance = 1;
  526. NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
  527. [defaults setInteger:4 forKey:@"AppleAntiAliasingThreshold"]; // smallest font size to CG should perform antialiasing on
  528. [defaults setInteger:NoFontSmoothing forKey:@"AppleFontSmoothing"];
  529. [defaults setInteger:BlueTintedAppearance forKey:@"AppleAquaColorVariant"];
  530. [defaults setObject:@"0.709800 0.835300 1.000000" forKey:@"AppleHighlightColor"];
  531. [defaults setObject:@"0.500000 0.500000 0.500000" forKey:@"AppleOtherHighlightColor"];
  532. [defaults setObject:[NSArray arrayWithObject:@"en"] forKey:@"AppleLanguages"];
  533. [defaults setBool:YES forKey:WebKitEnableFullDocumentTeardownPreferenceKey];
  534. [defaults setBool:YES forKey:WebKitFullScreenEnabledPreferenceKey];
  535. [defaults setBool:YES forKey:@"UseWebKitWebInspector"];
  536. #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
  537. [defaults setObject:[NSDictionary dictionaryWithObjectsAndKeys:
  538. @"notational", @"notationl",
  539. @"message", @"mesage",
  540. @"would", @"wouldn",
  541. @"welcome", @"wellcome",
  542. @"hello\nworld", @"hellolfworld",
  543. nil] forKey:@"NSTestCorrectionDictionary"];
  544. #endif
  545. // Scrollbars are drawn either using AppKit (which uses NSUserDefaults) or using HIToolbox (which uses CFPreferences / kCFPreferencesAnyApplication / kCFPreferencesCurrentUser / kCFPreferencesAnyHost)
  546. [defaults setObject:@"DoubleMax" forKey:@"AppleScrollBarVariant"];
  547. RetainPtr<CFTypeRef> initialValue = CFPreferencesCopyValue(CFSTR("AppleScrollBarVariant"), kCFPreferencesAnyApplication, kCFPreferencesCurrentUser, kCFPreferencesAnyHost);
  548. CFPreferencesSetValue(CFSTR("AppleScrollBarVariant"), CFSTR("DoubleMax"), kCFPreferencesAnyApplication, kCFPreferencesCurrentUser, kCFPreferencesAnyHost);
  549. #ifndef __LP64__
  550. // See <rdar://problem/6347388>.
  551. ThemeScrollBarArrowStyle style;
  552. GetThemeScrollBarArrowStyle(&style); // Force HIToolbox to read from CFPreferences
  553. #endif
  554. #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1080
  555. [defaults setBool:NO forKey:@"NSScrollAnimationEnabled"];
  556. #else
  557. [defaults setBool:NO forKey:@"AppleScrollAnimationEnabled"];
  558. #endif
  559. [defaults setBool:NO forKey:@"NSOverlayScrollersEnabled"];
  560. [defaults setObject:@"Always" forKey:@"AppleShowScrollBars"];
  561. if (initialValue)
  562. CFPreferencesSetValue(CFSTR("AppleScrollBarVariant"), initialValue.get(), kCFPreferencesAnyApplication, kCFPreferencesCurrentUser, kCFPreferencesAnyHost);
  563. NSString *path = libraryPathForDumpRenderTree();
  564. [defaults setObject:[path stringByAppendingPathComponent:@"Databases"] forKey:WebDatabaseDirectoryDefaultsKey];
  565. [defaults setObject:[path stringByAppendingPathComponent:@"LocalStorage"] forKey:WebStorageDirectoryDefaultsKey];
  566. [defaults setObject:[path stringByAppendingPathComponent:@"LocalCache"] forKey:WebKitLocalCacheDefaultsKey];
  567. [defaults setBool:NO forKey:@"WebKitKerningAndLigaturesEnabledByDefault"];
  568. WebPreferences *preferences = [WebPreferences standardPreferences];
  569. [preferences setAllowUniversalAccessFromFileURLs:YES];
  570. [preferences setAllowFileAccessFromFileURLs:YES];
  571. [preferences setStandardFontFamily:@"Times"];
  572. [preferences setFixedFontFamily:@"Courier"];
  573. [preferences setSerifFontFamily:@"Times"];
  574. [preferences setSansSerifFontFamily:@"Helvetica"];
  575. [preferences setCursiveFontFamily:@"Apple Chancery"];
  576. [preferences setFantasyFontFamily:@"Papyrus"];
  577. [preferences setPictographFontFamily:@"Apple Color Emoji"];
  578. [preferences setDefaultFontSize:16];
  579. [preferences setDefaultFixedFontSize:13];
  580. [preferences setMinimumFontSize:0];
  581. [preferences setDefaultTextEncodingName:@"ISO-8859-1"];
  582. [preferences setJavaEnabled:NO];
  583. [preferences setJavaScriptEnabled:YES];
  584. [preferences setEditableLinkBehavior:WebKitEditableLinkOnlyLiveWithShiftKey];
  585. [preferences setTabsToLinks:NO];
  586. [preferences setDOMPasteAllowed:YES];
  587. [preferences setShouldPrintBackgrounds:YES];
  588. [preferences setCacheModel:WebCacheModelDocumentBrowser];
  589. [preferences setXSSAuditorEnabled:NO];
  590. [preferences setExperimentalNotificationsEnabled:NO];
  591. [preferences setPlugInsEnabled:YES];
  592. [preferences setTextAreasAreResizable:YES];
  593. [preferences setPrivateBrowsingEnabled:NO];
  594. [preferences setAuthorAndUserStylesEnabled:YES];
  595. [preferences setJavaScriptCanOpenWindowsAutomatically:YES];
  596. [preferences setJavaScriptCanAccessClipboard:YES];
  597. [preferences setOfflineWebApplicationCacheEnabled:YES];
  598. [preferences setDeveloperExtrasEnabled:NO];
  599. [preferences setJavaScriptExperimentsEnabled:YES];
  600. [preferences setLoadsImagesAutomatically:YES];
  601. [preferences setLoadsSiteIconsIgnoringImageLoadingPreference:NO];
  602. [preferences setFrameFlatteningEnabled:NO];
  603. [preferences setSpatialNavigationEnabled:NO];
  604. if (persistentUserStyleSheetLocation) {
  605. [preferences setUserStyleSheetLocation:[NSURL URLWithString:(NSString *)(persistentUserStyleSheetLocation.get())]];
  606. [preferences setUserStyleSheetEnabled:YES];
  607. } else
  608. [preferences setUserStyleSheetEnabled:NO];
  609. // The back/forward cache is causing problems due to layouts during transition from one page to another.
  610. // So, turn it off for now, but we might want to turn it back on some day.
  611. [preferences setUsesPageCache:NO];
  612. [preferences setAcceleratedCompositingEnabled:YES];
  613. #if USE(CA) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
  614. [preferences setCanvasUsesAcceleratedDrawing:YES];
  615. [preferences setAcceleratedDrawingEnabled:NO];
  616. #endif
  617. [preferences setWebGLEnabled:NO];
  618. [preferences setCSSRegionsEnabled:YES];
  619. [preferences setCSSGridLayoutEnabled:NO];
  620. [preferences setUsePreHTML5ParserQuirks:NO];
  621. [preferences setAsynchronousSpellCheckingEnabled:NO];
  622. [preferences setMockScrollbarsEnabled:YES];
  623. [preferences setSeamlessIFramesEnabled:YES];
  624. #if ENABLE(WEB_AUDIO)
  625. [preferences setWebAudioEnabled:YES];
  626. #endif
  627. [preferences setScreenFontSubstitutionEnabled:YES];
  628. [WebPreferences _setCurrentNetworkLoaderSessionCookieAcceptPolicy:NSHTTPCookieAcceptPolicyOnlyFromMainDocumentDomain];
  629. TestRunner::setSerializeHTTPLoads(false);
  630. setlocale(LC_ALL, "");
  631. }
  632. // Called once on DumpRenderTree startup.
  633. static void setDefaultsToConsistentValuesForTesting()
  634. {
  635. // FIXME: We'd like to start with a clean state for every test, but this function can't be used more than once yet.
  636. [WebPreferences _switchNetworkLoaderToNewTestingSession];
  637. resetDefaultsToConsistentValues();
  638. NSString *path = libraryPathForDumpRenderTree();
  639. NSURLCache *sharedCache =
  640. [[NSURLCache alloc] initWithMemoryCapacity:1024 * 1024
  641. diskCapacity:0
  642. diskPath:[path stringByAppendingPathComponent:@"URLCache"]];
  643. [NSURLCache setSharedURLCache:sharedCache];
  644. [sharedCache release];
  645. }
  646. static void runThread(void* arg)
  647. {
  648. static ThreadIdentifier previousId = 0;
  649. ThreadIdentifier currentId = currentThread();
  650. // Verify 2 successive threads do not get the same Id.
  651. ASSERT(previousId != currentId);
  652. previousId = currentId;
  653. }
  654. static void* runPthread(void* arg)
  655. {
  656. runThread(arg);
  657. return 0;
  658. }
  659. static void testThreadIdentifierMap()
  660. {
  661. // Imitate 'foreign' threads that are not created by WTF.
  662. pthread_t pthread;
  663. pthread_create(&pthread, 0, &runPthread, 0);
  664. pthread_join(pthread, 0);
  665. pthread_create(&pthread, 0, &runPthread, 0);
  666. pthread_join(pthread, 0);
  667. // Now create another thread using WTF. On OSX, it will have the same pthread handle
  668. // but should get a different ThreadIdentifier.
  669. createThread(runThread, 0, "DumpRenderTree: test");
  670. }
  671. static void allocateGlobalControllers()
  672. {
  673. // FIXME: We should remove these and move to the ObjC standard [Foo sharedInstance] model
  674. gNavigationController = [[NavigationController alloc] init];
  675. frameLoadDelegate = [[FrameLoadDelegate alloc] init];
  676. uiDelegate = [[UIDelegate alloc] init];
  677. editingDelegate = [[EditingDelegate alloc] init];
  678. resourceLoadDelegate = [[ResourceLoadDelegate alloc] init];
  679. policyDelegate = [[PolicyDelegate alloc] init];
  680. historyDelegate = [[HistoryDelegate alloc] init];
  681. storageDelegate = [[StorageTrackerDelegate alloc] init];
  682. defaultPolicyDelegate = [[DefaultPolicyDelegate alloc] init];
  683. }
  684. // ObjC++ doens't seem to let me pass NSObject*& sadly.
  685. static inline void releaseAndZero(NSObject** object)
  686. {
  687. [*object release];
  688. *object = nil;
  689. }
  690. static void releaseGlobalControllers()
  691. {
  692. releaseAndZero(&gNavigationController);
  693. releaseAndZero(&frameLoadDelegate);
  694. releaseAndZero(&editingDelegate);
  695. releaseAndZero(&resourceLoadDelegate);
  696. releaseAndZero(&uiDelegate);
  697. releaseAndZero(&policyDelegate);
  698. releaseAndZero(&storageDelegate);
  699. }
  700. static void initializeGlobalsFromCommandLineOptions(int argc, const char *argv[])
  701. {
  702. struct option options[] = {
  703. {"notree", no_argument, &dumpTree, NO},
  704. {"pixel-tests", no_argument, &dumpPixelsForAllTests, YES},
  705. {"tree", no_argument, &dumpTree, YES},
  706. {"threaded", no_argument, &threaded, YES},
  707. {"complex-text", no_argument, &forceComplexText, YES},
  708. {"gc-between-tests", no_argument, &gcBetweenTests, YES},
  709. {"no-timeout", no_argument, &useTimeoutWatchdog, NO},
  710. {NULL, 0, NULL, 0}
  711. };
  712. int option;
  713. while ((option = getopt_long(argc, (char * const *)argv, "", options, NULL)) != -1) {
  714. switch (option) {
  715. case '?': // unknown or ambiguous option
  716. case ':': // missing argument
  717. exit(1);
  718. break;
  719. }
  720. }
  721. }
  722. static void addTestPluginsToPluginSearchPath(const char* executablePath)
  723. {
  724. NSString *pwd = [[NSString stringWithUTF8String:executablePath] stringByDeletingLastPathComponent];
  725. [WebPluginDatabase setAdditionalWebPlugInPaths:[NSArray arrayWithObject:pwd]];
  726. [[WebPluginDatabase sharedDatabase] refresh];
  727. }
  728. static bool useLongRunningServerMode(int argc, const char *argv[])
  729. {
  730. // This assumes you've already called getopt_long
  731. return (argc == optind+1 && strcmp(argv[optind], "-") == 0);
  732. }
  733. static void runTestingServerLoop()
  734. {
  735. // When DumpRenderTree run in server mode, we just wait around for file names
  736. // to be passed to us and read each in turn, passing the results back to the client
  737. char filenameBuffer[2048];
  738. while (fgets(filenameBuffer, sizeof(filenameBuffer), stdin)) {
  739. char *newLineCharacter = strchr(filenameBuffer, '\n');
  740. if (newLineCharacter)
  741. *newLineCharacter = '\0';
  742. if (strlen(filenameBuffer) == 0)
  743. continue;
  744. runTest(filenameBuffer);
  745. }
  746. }
  747. static void prepareConsistentTestingEnvironment()
  748. {
  749. poseAsClass("DumpRenderTreePasteboard", "NSPasteboard");
  750. poseAsClass("DumpRenderTreeEvent", "NSEvent");
  751. setDefaultsToConsistentValuesForTesting();
  752. adjustFonts();
  753. registerMockScrollbars();
  754. allocateGlobalControllers();
  755. makeLargeMallocFailSilently();
  756. #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
  757. NSActivityOptions options = (NSActivityUserInitiatedAllowingIdleSystemSleep | NSActivityLatencyCritical) & ~(NSActivitySuddenTerminationDisabled | NSActivityAutomaticTerminationDisabled);
  758. static id assertion = [[[NSProcessInfo processInfo] beginActivityWithOptions:options reason:@"DumpRenderTree should not be subject to process suppression"] retain];
  759. ASSERT_UNUSED(assertion, assertion);
  760. #endif
  761. }
  762. void dumpRenderTree(int argc, const char *argv[])
  763. {
  764. initializeGlobalsFromCommandLineOptions(argc, argv);
  765. prepareConsistentTestingEnvironment();
  766. addTestPluginsToPluginSearchPath(argv[0]);
  767. if (forceComplexText)
  768. [WebView _setAlwaysUsesComplexTextCodePath:YES];
  769. #if USE(APPKIT)
  770. [NSSound _setAlertType:0];
  771. #endif
  772. WebView *webView = createWebViewAndOffscreenWindow();
  773. mainFrame = [webView mainFrame];
  774. [[NSURLCache sharedURLCache] removeAllCachedResponses];
  775. [WebCache empty];
  776. [NSURLRequest setAllowsAnyHTTPSCertificate:YES forHost:@"localhost"];
  777. [NSURLRequest setAllowsAnyHTTPSCertificate:YES forHost:@"127.0.0.1"];
  778. // http://webkit.org/b/32689
  779. testThreadIdentifierMap();
  780. if (threaded)
  781. startJavaScriptThreads();
  782. if (useLongRunningServerMode(argc, argv)) {
  783. printSeparators = YES;
  784. runTestingServerLoop();
  785. } else {
  786. printSeparators = optind < argc - 1;
  787. for (int i = optind; i != argc; ++i)
  788. runTest(argv[i]);
  789. }
  790. if (threaded)
  791. stopJavaScriptThreads();
  792. NSWindow *window = [webView window];
  793. [webView close];
  794. mainFrame = nil;
  795. // Work around problem where registering drag types leaves an outstanding
  796. // "perform selector" on the window, which retains the window. It's a bit
  797. // inelegant and perhaps dangerous to just blow them all away, but in practice
  798. // it probably won't cause any trouble (and this is just a test tool, after all).
  799. [NSObject cancelPreviousPerformRequestsWithTarget:window];
  800. [window close]; // releases when closed
  801. [webView release];
  802. releaseGlobalControllers();
  803. [DumpRenderTreePasteboard releaseLocalPasteboards];
  804. // FIXME: This should be moved onto TestRunner and made into a HashSet
  805. if (disallowedURLs) {
  806. CFRelease(disallowedURLs);
  807. disallowedURLs = 0;
  808. }
  809. }
  810. int main(int argc, const char *argv[])
  811. {
  812. NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
  813. [DumpRenderTreeApplication sharedApplication]; // Force AppKit to init itself
  814. dumpRenderTree(argc, argv);
  815. [WebCoreStatistics garbageCollectJavaScriptObjects];
  816. [WebCoreStatistics emptyCache]; // Otherwise SVGImages trigger false positives for Frame/Node counts
  817. if (JSC::Options::logHeapStatisticsAtExit())
  818. JSC::HeapStatistics::reportSuccess();
  819. [pool release];
  820. return 0;
  821. }
  822. static NSInteger compareHistoryItems(id item1, id item2, void *context)
  823. {
  824. return [[item1 target] caseInsensitiveCompare:[item2 target]];
  825. }
  826. static NSData *dumpAudio()
  827. {
  828. const char *encodedAudioData = gTestRunner->encodedAudioData().c_str();
  829. NSData *data = [NSData dataWithBytes:encodedAudioData length:gTestRunner->encodedAudioData().length()];
  830. return data;
  831. }
  832. static void dumpHistoryItem(WebHistoryItem *item, int indent, BOOL current)
  833. {
  834. int start = 0;
  835. if (current) {
  836. printf("curr->");
  837. start = 6;
  838. }
  839. for (int i = start; i < indent; i++)
  840. putchar(' ');
  841. NSString *urlString = [item URLString];
  842. if ([[NSURL URLWithString:urlString] isFileURL]) {
  843. NSRange range = [urlString rangeOfString:@"/LayoutTests/"];
  844. urlString = [@"(file test):" stringByAppendingString:[urlString substringFromIndex:(range.length + range.location)]];
  845. }
  846. printf("%s", [urlString UTF8String]);
  847. NSString *target = [item target];
  848. if (target && [target length] > 0)
  849. printf(" (in frame \"%s\")", [target UTF8String]);
  850. if ([item isTargetItem])
  851. printf(" **nav target**");
  852. putchar('\n');
  853. NSArray *kids = [item children];
  854. if (kids) {
  855. // must sort to eliminate arbitrary result ordering which defeats reproducible testing
  856. kids = [kids sortedArrayUsingFunction:&compareHistoryItems context:nil];
  857. for (unsigned i = 0; i < [kids count]; i++)
  858. dumpHistoryItem([kids objectAtIndex:i], indent+4, NO);
  859. }
  860. }
  861. static void dumpFrameScrollPosition(WebFrame *f)
  862. {
  863. WebScriptObject* scriptObject = [f windowObject];
  864. NSPoint scrollPosition = NSMakePoint(
  865. [[scriptObject valueForKey:@"pageXOffset"] floatValue],
  866. [[scriptObject valueForKey:@"pageYOffset"] floatValue]);
  867. if (ABS(scrollPosition.x) > 0.00000001 || ABS(scrollPosition.y) > 0.00000001) {
  868. if ([f parentFrame] != nil)
  869. printf("frame '%s' ", [[f name] UTF8String]);
  870. printf("scrolled to %.f,%.f\n", scrollPosition.x, scrollPosition.y);
  871. }
  872. if (gTestRunner->dumpChildFrameScrollPositions()) {
  873. NSArray *kids = [f childFrames];
  874. if (kids)
  875. for (unsigned i = 0; i < [kids count]; i++)
  876. dumpFrameScrollPosition([kids objectAtIndex:i]);
  877. }
  878. }
  879. static NSString *dumpFramesAsText(WebFrame *frame)
  880. {
  881. DOMDocument *document = [frame DOMDocument];
  882. DOMElement *documentElement = [document documentElement];
  883. if (!documentElement)
  884. return @"";
  885. NSMutableString *result = [[[NSMutableString alloc] init] autorelease];
  886. // Add header for all but the main frame.
  887. if ([frame parentFrame])
  888. result = [NSMutableString stringWithFormat:@"\n--------\nFrame: '%@'\n--------\n", [frame name]];
  889. [result appendFormat:@"%@\n", [documentElement innerText]];
  890. if (gTestRunner->dumpChildFramesAsText()) {
  891. NSArray *kids = [frame childFrames];
  892. if (kids) {
  893. for (unsigned i = 0; i < [kids count]; i++)
  894. [result appendString:dumpFramesAsText([kids objectAtIndex:i])];
  895. }
  896. }
  897. return result;
  898. }
  899. static NSData *dumpFrameAsPDF(WebFrame *frame)
  900. {
  901. if (!frame)
  902. return nil;
  903. // Sadly we have to dump to a file and then read from that file again
  904. // +[NSPrintOperation PDFOperationWithView:insideRect:] requires a rect and prints to a single page
  905. // likewise +[NSView dataWithPDFInsideRect:] also prints to a single continuous page
  906. // The goal of this function is to test "real" printing across multiple pages.
  907. // FIXME: It's possible there might be printing SPI to let us print a multi-page PDF to an NSData object
  908. NSString *path = [libraryPathForDumpRenderTree() stringByAppendingPathComponent:@"test.pdf"];
  909. NSMutableDictionary *printInfoDict = [NSMutableDictionary dictionaryWithDictionary:[[NSPrintInfo sharedPrintInfo] dictionary]];
  910. [printInfoDict setObject:NSPrintSaveJob forKey:NSPrintJobDisposition];
  911. [printInfoDict setObject:path forKey:NSPrintSavePath];
  912. NSPrintInfo *printInfo = [[NSPrintInfo alloc] initWithDictionary:printInfoDict];
  913. [printInfo setHorizontalPagination:NSAutoPagination];
  914. [printInfo setVerticalPagination:NSAutoPagination];
  915. [printInfo setVerticallyCentered:NO];
  916. NSPrintOperation *printOperation = [NSPrintOperation printOperationWithView:[frame frameView] printInfo:printInfo];
  917. [printOperation setShowPanels:NO];
  918. [printOperation runOperation];
  919. [printInfo release];
  920. NSData *pdfData = [NSData dataWithContentsOfFile:path];
  921. [[NSFileManager defaultManager] removeFileAtPath:path handler:nil];
  922. return pdfData;
  923. }
  924. static void dumpBackForwardListForWebView(WebView *view)
  925. {
  926. printf("\n============== Back Forward List ==============\n");
  927. WebBackForwardList *bfList = [view backForwardList];
  928. // Print out all items in the list after prevTestBFItem, which was from the previous test
  929. // Gather items from the end of the list, the print them out from oldest to newest
  930. NSMutableArray *itemsToPrint = [[NSMutableArray alloc] init];
  931. for (int i = [bfList forwardListCount]; i > 0; i--) {
  932. WebHistoryItem *item = [bfList itemAtIndex:i];
  933. // something is wrong if the item from the last test is in the forward part of the b/f list
  934. assert(item != prevTestBFItem);
  935. [itemsToPrint addObject:item];
  936. }
  937. assert([bfList currentItem] != prevTestBFItem);
  938. [itemsToPrint addObject:[bfList currentItem]];
  939. int currentItemIndex = [itemsToPrint count] - 1;
  940. for (int i = -1; i >= -[bfList backListCount]; i--) {
  941. WebHistoryItem *item = [bfList itemAtIndex:i];
  942. if (item == prevTestBFItem)
  943. break;
  944. [itemsToPrint addObject:item];
  945. }
  946. for (int i = [itemsToPrint count]-1; i >= 0; i--)
  947. dumpHistoryItem([itemsToPrint objectAtIndex:i], 8, i == currentItemIndex);
  948. [itemsToPrint release];
  949. printf("===============================================\n");
  950. }
  951. static void sizeWebViewForCurrentTest()
  952. {
  953. // W3C SVG tests expect to be 480x360
  954. bool isSVGW3CTest = (gTestRunner->testPathOrURL().find("svg/W3C-SVG-1.1") != string::npos);
  955. if (isSVGW3CTest)
  956. [[mainFrame webView] setFrameSize:NSMakeSize(TestRunner::w3cSVGViewWidth, TestRunner::w3cSVGViewHeight)];
  957. else
  958. [[mainFrame webView] setFrameSize:NSMakeSize(TestRunner::viewWidth, TestRunner::viewHeight)];
  959. }
  960. static const char *methodNameStringForFailedTest()
  961. {
  962. const char *errorMessage;
  963. if (gTestRunner->dumpAsText())
  964. errorMessage = "[documentElement innerText]";
  965. else if (gTestRunner->dumpDOMAsWebArchive())
  966. errorMessage = "[[mainFrame DOMDocument] webArchive]";
  967. else if (gTestRunner->dumpSourceAsWebArchive())
  968. errorMessage = "[[mainFrame dataSource] webArchive]";
  969. else
  970. errorMessage = "[mainFrame renderTreeAsExternalRepresentation]";
  971. return errorMessage;
  972. }
  973. static void dumpBackForwardListForAllWindows()
  974. {
  975. CFArrayRef openWindows = (CFArrayRef)[DumpRenderTreeWindow openWindows];
  976. unsigned count = CFArrayGetCount(openWindows);
  977. for (unsigned i = 0; i < count; i++) {
  978. NSWindow *window = (NSWindow *)CFArrayGetValueAtIndex(openWindows, i);
  979. WebView *webView = [[[window contentView] subviews] objectAtIndex:0];
  980. dumpBackForwardListForWebView(webView);
  981. }
  982. }
  983. static void invalidateAnyPreviousWaitToDumpWatchdog()
  984. {
  985. if (waitToDumpWatchdog) {
  986. CFRunLoopTimerInvalidate(waitToDumpWatchdog);
  987. CFRelease(waitToDumpWatchdog);
  988. waitToDumpWatchdog = 0;
  989. }
  990. }
  991. void setWaitToDumpWatchdog(CFRunLoopTimerRef timer)
  992. {
  993. ASSERT(timer);
  994. ASSERT(shouldSetWaitToDumpWatchdog());
  995. waitToDumpWatchdog = timer;
  996. CFRunLoopAddTimer(CFRunLoopGetCurrent(), waitToDumpWatchdog, kCFRunLoopCommonModes);
  997. }
  998. bool shouldSetWaitToDumpWatchdog()
  999. {
  1000. return !waitToDumpWatchdog && useTimeoutWatchdog;
  1001. }
  1002. void dump()
  1003. {
  1004. invalidateAnyPreviousWaitToDumpWatchdog();
  1005. ASSERT(!gTestRunner->hasPendingWebNotificationClick());
  1006. if (dumpTree) {
  1007. NSString *resultString = nil;
  1008. NSData *resultData = nil;
  1009. NSString *resultMimeType = @"text/plain";
  1010. if ([[[mainFrame dataSource] _responseMIMEType] isEqualToString:@"text/plain"]) {
  1011. gTestRunner->setDumpAsText(true);
  1012. gTestRunner->setGeneratePixelResults(false);
  1013. }
  1014. if (gTestRunner->dumpAsAudio()) {
  1015. resultData = dumpAudio();
  1016. resultMimeType = @"audio/wav";
  1017. } else if (gTestRunner->dumpAsText()) {
  1018. resultString = dumpFramesAsText(mainFrame);
  1019. } else if (gTestRunner->dumpAsPDF()) {
  1020. resultData = dumpFrameAsPDF(mainFrame);
  1021. resultMimeType = @"application/pdf";
  1022. } else if (gTestRunner->dumpDOMAsWebArchive()) {
  1023. WebArchive *webArchive = [[mainFrame DOMDocument] webArchive];
  1024. resultString = HardAutorelease(createXMLStringFromWebArchiveData((CFDataRef)[webArchive data]));
  1025. resultMimeType = @"application/x-webarchive";
  1026. } else if (gTestRunner->dumpSourceAsWebArchive()) {
  1027. WebArchive *webArchive = [[mainFrame dataSource] webArchive];
  1028. resultString = HardAutorelease(createXMLStringFromWebArchiveData((CFDataRef)[webArchive data]));
  1029. resultMimeType = @"application/x-webarchive";
  1030. } else
  1031. resultString = [mainFrame renderTreeAsExternalRepresentationForPrinting:gTestRunner->isPrinting()];
  1032. if (resultString && !resultData)
  1033. resultData = [resultString dataUsingEncoding:NSUTF8StringEncoding];
  1034. printf("Content-Type: %s\n", [resultMimeType UTF8String]);
  1035. if (gTestRunner->dumpAsAudio())
  1036. printf("Content-Transfer-Encoding: base64\n");
  1037. WTF::FastMallocStatistics mallocStats = WTF::fastMallocStatistics();
  1038. printf("DumpMalloc: %li\n", mallocStats.committedVMBytes);
  1039. if (resultData) {
  1040. fwrite([resultData bytes], 1, [resultData length], stdout);
  1041. if (!gTestRunner->dumpAsText() && !gTestRunner->dumpDOMAsWebArchive() && !gTestRunner->dumpSourceAsWebArchive())
  1042. dumpFrameScrollPosition(mainFrame);
  1043. if (gTestRunner->dumpBackForwardList())
  1044. dumpBackForwardListForAllWindows();
  1045. } else
  1046. printf("ERROR: nil result from %s", methodNameStringForFailedTest());
  1047. // Stop the watchdog thread before we leave this test to make sure it doesn't
  1048. // fire in between tests causing the next test to fail.
  1049. // This is a speculative fix for: https://bugs.webkit.org/show_bug.cgi?id=32339
  1050. invalidateAnyPreviousWaitToDumpWatchdog();
  1051. if (printSeparators) {
  1052. puts("#EOF"); // terminate the content block
  1053. fputs("#EOF\n", stderr);
  1054. }
  1055. }
  1056. if (dumpPixelsForCurrentTest && gTestRunner->generatePixelResults())
  1057. // FIXME: when isPrinting is set, dump the image with page separators.
  1058. dumpWebViewAsPixelsAndCompareWithExpected(gTestRunner->expectedPixelHash());
  1059. puts("#EOF"); // terminate the (possibly empty) pixels block
  1060. fflush(stdout);
  1061. fflush(stderr);
  1062. done = YES;
  1063. }
  1064. static bool shouldLogFrameLoadDelegates(const char* pathOrURL)
  1065. {
  1066. return strstr(pathOrURL, "loading/");
  1067. }
  1068. static bool shouldLogHistoryDelegates(const char* pathOrURL)
  1069. {
  1070. return strstr(pathOrURL, "globalhistory/");
  1071. }
  1072. static bool shouldOpenWebInspector(const char* pathOrURL)
  1073. {
  1074. return strstr(pathOrURL, "inspector/");
  1075. }
  1076. static bool shouldDumpAsText(const char* pathOrURL)
  1077. {
  1078. return strstr(pathOrURL, "dumpAsText/");
  1079. }
  1080. static bool shouldEnableDeveloperExtras(const char* pathOrURL)
  1081. {
  1082. return true;
  1083. }
  1084. static void resetWebViewToConsistentStateBeforeTesting()
  1085. {
  1086. WebView *webView = [mainFrame webView];
  1087. [webView setEditable:NO];
  1088. [(EditingDelegate *)[webView editingDelegate] setAcceptsEditing:YES];
  1089. [webView makeTextStandardSize:nil];
  1090. [webView resetPageZoom:nil];
  1091. [webView _scaleWebView:1.0 atOrigin:NSZeroPoint];
  1092. [webView _setCustomBackingScaleFactor:0];
  1093. [webView setTabKeyCyclesThroughElements:YES];
  1094. [webView setPolicyDelegate:defaultPolicyDelegate];
  1095. [policyDelegate setPermissive:NO];
  1096. [policyDelegate setControllerToNotifyDone:0];
  1097. [frameLoadDelegate resetToConsistentState];
  1098. [webView _setDashboardBehavior:WebDashboardBehaviorUseBackwardCompatibilityMode to:NO];
  1099. [webView _clearMainFrameName];
  1100. [[webView undoManager] removeAllActions];
  1101. [WebView _removeAllUserContentFromGroup:[webView groupName]];
  1102. [[webView window] setAutodisplay:NO];
  1103. [webView setTracksRepaints:NO];
  1104. resetDefaultsToConsistentValues();
  1105. if (gTestRunner) {
  1106. WebCoreTestSupport::resetInternalsObject([mainFrame globalContext]);
  1107. // in the case that a test using the chrome input field failed, be sure to clean up for the next test
  1108. gTestRunner->removeChromeInputField();
  1109. }
  1110. [webView setContinuousSpellCheckingEnabled:YES];
  1111. [webView setAutomaticQuoteSubstitutionEnabled:NO];
  1112. [webView setAutomaticLinkDetectionEnabled:NO];
  1113. [webView setAutomaticDashSubstitutionEnabled:NO];
  1114. [webView setAutomaticTextReplacementEnabled:NO];
  1115. [webView setAutomaticSpellingCorrectionEnabled:YES];
  1116. [webView setGrammarCheckingEnabled:YES];
  1117. [WebView _setUsesTestModeFocusRingColor:YES];
  1118. [WebView _resetOriginAccessWhitelists];
  1119. [WebView _setAllowsRoundingHacks:NO];
  1120. [[MockGeolocationProvider shared] stopTimer];
  1121. [[MockWebNotificationProvider shared] reset];
  1122. // Clear the contents of the general pasteboard
  1123. [[NSPasteboard generalPasteboard] declareTypes:[NSArray arrayWithObject:NSStringPboardType] owner:nil];
  1124. [mainFrame _clearOpener];
  1125. }
  1126. static void runTest(const string& inputLine)
  1127. {
  1128. ASSERT(!inputLine.empty());
  1129. TestCommand command = parseInputLine(inputLine);
  1130. const string& pathOrURL = command.pathOrURL;
  1131. dumpPixelsForCurrentTest = command.shouldDumpPixels || dumpPixelsForAllTests;
  1132. NSString *pathOrURLString = [NSString stringWithUTF8String:pathOrURL.c_str()];
  1133. if (!pathOrURLString) {
  1134. fprintf(stderr, "Failed to parse \"%s\" as UTF-8\n", pathOrURL.c_str());
  1135. return;
  1136. }
  1137. NSURL *url;
  1138. if ([pathOrURLString hasPrefix:@"http://"] || [pathOrURLString hasPrefix:@"https://"] || [pathOrURLString hasPrefix:@"file://"])
  1139. url = [NSURL URLWithString:pathOrURLString];
  1140. else
  1141. url = [NSURL fileURLWithPath:pathOrURLString];
  1142. if (!url) {
  1143. fprintf(stderr, "Failed to parse \"%s\" as a URL\n", pathOrURL.c_str());
  1144. return;
  1145. }
  1146. const string testURL([[url absoluteString] UTF8String]);
  1147. resetWebViewToConsistentStateBeforeTesting();
  1148. gTestRunner = TestRunner::create(testURL, command.expectedPixelHash);
  1149. topLoadingFrame = nil;
  1150. ASSERT(!draggingInfo); // the previous test should have called eventSender.mouseUp to drop!
  1151. releaseAndZero(&draggingInfo);
  1152. done = NO;
  1153. sizeWebViewForCurrentTest();
  1154. gTestRunner->setIconDatabaseEnabled(false);
  1155. if (disallowedURLs)
  1156. CFSetRemoveAllValues(disallowedURLs);
  1157. if (shouldLogFrameLoadDelegates(pathOrURL.c_str()))
  1158. gTestRunner->setDumpFrameLoadCallbacks(true);
  1159. if (shouldLogHistoryDelegates(pathOrURL.c_str()))
  1160. [[mainFrame webView] setHistoryDelegate:historyDelegate];
  1161. else
  1162. [[mainFrame webView] setHistoryDelegate:nil];
  1163. if (shouldEnableDeveloperExtras(pathOrURL.c_str())) {
  1164. gTestRunner->setDeveloperExtrasEnabled(true);
  1165. if (shouldOpenWebInspector(pathOrURL.c_str()))
  1166. gTestRunner->showWebInspector();
  1167. if (shouldDumpAsText(pathOrURL.c_str())) {
  1168. gTestRunner->setDumpAsText(true);
  1169. gTestRunner->setGeneratePixelResults(false);
  1170. }
  1171. }
  1172. if ([WebHistory optionalSharedHistory])
  1173. [WebHistory setOptionalSharedHistory:nil];
  1174. lastMousePosition = NSZeroPoint;
  1175. lastClickPosition = NSZeroPoint;
  1176. [prevTestBFItem release];
  1177. prevTestBFItem = [[[[mainFrame webView] backForwardList] currentItem] retain];
  1178. WorkQueue::shared()->clear();
  1179. WorkQueue::shared()->setFrozen(false);
  1180. bool ignoreWebCoreNodeLeaks = shouldIgnoreWebCoreNodeLeaks(testURL);
  1181. if (ignoreWebCoreNodeLeaks)
  1182. [WebCoreStatistics startIgnoringWebCoreNodeLeaks];
  1183. NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
  1184. [mainFrame loadRequest:[NSURLRequest requestWithURL:url]];
  1185. [pool release];
  1186. while (!done) {
  1187. pool = [[NSAutoreleasePool alloc] init];
  1188. [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantPast]];
  1189. [pool release];
  1190. }
  1191. pool = [[NSAutoreleasePool alloc] init];
  1192. [EventSendingController clearSavedEvents];
  1193. [[mainFrame webView] setSelectedDOMRange:nil affinity:NSSelectionAffinityDownstream];
  1194. WorkQueue::shared()->clear();
  1195. if (gTestRunner->closeRemainingWindowsWhenComplete()) {
  1196. NSArray* array = [DumpRenderTreeWindow openWindows];
  1197. unsigned count = [array count];
  1198. for (unsigned i = 0; i < count; i++) {
  1199. NSWindow *window = [array objectAtIndex:i];
  1200. // Don't try to close the main window
  1201. if (window == [[mainFrame webView] window])
  1202. continue;
  1203. WebView *webView = [[[window contentView] subviews] objectAtIndex:0];
  1204. [webView close];
  1205. [window close];
  1206. }
  1207. }
  1208. // If developer extras enabled Web Inspector may have been open by the test.
  1209. if (shouldEnableDeveloperExtras(pathOrURL.c_str())) {
  1210. gTestRunner->closeWebInspector();
  1211. gTestRunner->setDeveloperExtrasEnabled(false);
  1212. }
  1213. resetWebViewToConsistentStateBeforeTesting();
  1214. [mainFrame loadHTMLString:@"<html></html>" baseURL:[NSURL URLWithString:@"about:blank"]];
  1215. [mainFrame stopLoading];
  1216. [pool release];
  1217. // We should only have our main window left open when we're done
  1218. ASSERT(CFArrayGetCount(openWindowsRef) == 1);
  1219. ASSERT(CFArrayGetValueAtIndex(openWindowsRef, 0) == [[mainFrame webView] window]);
  1220. gTestRunner.clear();
  1221. if (ignoreWebCoreNodeLeaks)
  1222. [WebCoreStatistics stopIgnoringWebCoreNodeLeaks];
  1223. if (gcBetweenTests)
  1224. [WebCoreStatistics garbageCollectJavaScriptObjects];
  1225. }
  1226. void displayWebView()
  1227. {
  1228. WebView *webView = [mainFrame webView];
  1229. [webView display];
  1230. [webView setTracksRepaints:YES];
  1231. [webView resetTrackedRepaints];
  1232. }
  1233. @implementation DumpRenderTreeEvent
  1234. + (NSPoint)mouseLocation
  1235. {
  1236. return [[[mainFrame webView] window] convertBaseToScreen:lastMousePosition];
  1237. }
  1238. @end
  1239. @implementation DumpRenderTreeApplication
  1240. - (BOOL)isRunning
  1241. {
  1242. // <rdar://problem/7686123> Java plug-in freezes unless NSApplication is running
  1243. return YES;
  1244. }
  1245. @end