LayoutTestHelper.m 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. /*
  2. * Copyright (C) 2010 Google Inc. All rights reserved.
  3. * Copyright (C) 2012 Apple Inc.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are
  7. * met:
  8. *
  9. * * Redistributions of source code must retain the above copyright
  10. * notice, this list of conditions and the following disclaimer.
  11. * * Redistributions in binary form must reproduce the above
  12. * copyright notice, this list of conditions and the following disclaimer
  13. * in the documentation and/or other materials provided with the
  14. * distribution.
  15. * * Neither the name of Google Inc. nor the names of its
  16. * contributors may be used to endorse or promote products derived from
  17. * this software without specific prior written permission.
  18. *
  19. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  20. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  21. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  22. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  23. * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  24. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  25. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  26. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  27. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  28. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  29. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  30. */
  31. #import <AppKit/AppKit.h>
  32. #import <ApplicationServices/ApplicationServices.h>
  33. #import <signal.h>
  34. #import <stdio.h>
  35. #import <stdlib.h>
  36. // This is a simple helper app that changes the color profile of the main display
  37. // to GenericRGB and back when done. This program is managed by the layout
  38. // test script, so it can do the job for multiple DumpRenderTree while they are
  39. // running layout tests.
  40. #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
  41. static CFURLRef sUserColorProfileURL;
  42. static void installLayoutTestColorProfile()
  43. {
  44. // To make sure we get consistent colors (not dependent on the chosen color
  45. // space of the main display), we force the generic RGB color profile.
  46. // This causes a change the user can see.
  47. CFUUIDRef mainDisplayID = CGDisplayCreateUUIDFromDisplayID(CGMainDisplayID());
  48. if (!sUserColorProfileURL) {
  49. CFDictionaryRef deviceInfo = ColorSyncDeviceCopyDeviceInfo(kColorSyncDisplayDeviceClass, mainDisplayID);
  50. if (!deviceInfo) {
  51. NSLog(@"No display attached to system; not setting main display's color profile.");
  52. CFRelease(mainDisplayID);
  53. return;
  54. }
  55. CFDictionaryRef profileInfo = (CFDictionaryRef)CFDictionaryGetValue(deviceInfo, kColorSyncCustomProfiles);
  56. if (profileInfo) {
  57. sUserColorProfileURL = (CFURLRef)CFDictionaryGetValue(profileInfo, CFSTR("1"));
  58. CFRetain(sUserColorProfileURL);
  59. } else {
  60. profileInfo = (CFDictionaryRef)CFDictionaryGetValue(deviceInfo, kColorSyncFactoryProfiles);
  61. CFDictionaryRef factoryProfile = (CFDictionaryRef)CFDictionaryGetValue(profileInfo, CFSTR("1"));
  62. sUserColorProfileURL = (CFURLRef)CFDictionaryGetValue(factoryProfile, kColorSyncDeviceProfileURL);
  63. CFRetain(sUserColorProfileURL);
  64. }
  65. CFRelease(deviceInfo);
  66. }
  67. ColorSyncProfileRef genericRGBProfile = ColorSyncProfileCreateWithName(kColorSyncGenericRGBProfile);
  68. CFErrorRef error;
  69. CFURLRef profileURL = ColorSyncProfileGetURL(genericRGBProfile, &error);
  70. if (!profileURL) {
  71. NSLog(@"Failed to get URL of Generic RGB color profile! Many pixel tests may fail as a result. Error: %@", error);
  72. if (sUserColorProfileURL) {
  73. CFRelease(sUserColorProfileURL);
  74. sUserColorProfileURL = 0;
  75. }
  76. CFRelease(genericRGBProfile);
  77. CFRelease(mainDisplayID);
  78. return;
  79. }
  80. CFMutableDictionaryRef profileInfo = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
  81. CFDictionarySetValue(profileInfo, kColorSyncDeviceDefaultProfileID, profileURL);
  82. if (!ColorSyncDeviceSetCustomProfiles(kColorSyncDisplayDeviceClass, mainDisplayID, profileInfo)) {
  83. NSLog(@"Failed to set color profile for main display! Many pixel tests may fail as a result.");
  84. if (sUserColorProfileURL) {
  85. CFRelease(sUserColorProfileURL);
  86. sUserColorProfileURL = 0;
  87. }
  88. }
  89. CFRelease(profileInfo);
  90. CFRelease(genericRGBProfile);
  91. CFRelease(mainDisplayID);
  92. }
  93. static void restoreUserColorProfile(void)
  94. {
  95. // This is used as a signal handler, and thus the calls into ColorSync are unsafe.
  96. // But we might as well try to restore the user's color profile, we're going down anyway...
  97. if (!sUserColorProfileURL)
  98. return;
  99. CFUUIDRef mainDisplayID = CGDisplayCreateUUIDFromDisplayID(CGMainDisplayID());
  100. CFMutableDictionaryRef profileInfo = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
  101. CFDictionarySetValue(profileInfo, kColorSyncDeviceDefaultProfileID, sUserColorProfileURL);
  102. ColorSyncDeviceSetCustomProfiles(kColorSyncDisplayDeviceClass, mainDisplayID, profileInfo);
  103. CFRelease(mainDisplayID);
  104. CFRelease(profileInfo);
  105. }
  106. #else // For Snow Leopard and before, use older CM* API.
  107. const char colorProfilePath[] = "/System/Library/ColorSync/Profiles/Generic RGB Profile.icc";
  108. CMProfileLocation initialColorProfileLocation; // The locType field is initialized to 0 which is the same as cmNoProfileBase.
  109. static void installLayoutTestColorProfile()
  110. {
  111. // To make sure we get consistent colors (not dependent on the chosen color
  112. // space of the main display), we force the generic RGB color profile.
  113. // This causes a change the user can see.
  114. const CMDeviceScope scope = { kCFPreferencesCurrentUser, kCFPreferencesCurrentHost };
  115. CMProfileRef profile = 0;
  116. int error = CMGetProfileByAVID((CMDisplayIDType)kCGDirectMainDisplay, &profile);
  117. if (!error) {
  118. UInt32 size = sizeof(initialColorProfileLocation);
  119. error = NCMGetProfileLocation(profile, &initialColorProfileLocation, &size);
  120. CMCloseProfile(profile);
  121. }
  122. if (error) {
  123. NSLog(@"Failed to get the current color profile. Many pixel tests may fail as a result. Error: %d", (int)error);
  124. initialColorProfileLocation.locType = cmNoProfileBase;
  125. return;
  126. }
  127. CMProfileLocation location;
  128. location.locType = cmPathBasedProfile;
  129. strncpy(location.u.pathLoc.path, colorProfilePath, sizeof(location.u.pathLoc.path));
  130. error = CMSetDeviceProfile(cmDisplayDeviceClass, (CMDeviceID)kCGDirectMainDisplay, &scope, cmDefaultProfileID, &location);
  131. if (error) {
  132. NSLog(@"Failed install the GenericRGB color profile. Many pixel tests may fail as a result. Error: %d", (int)error);
  133. initialColorProfileLocation.locType = cmNoProfileBase;
  134. }
  135. }
  136. static void restoreUserColorProfile(void)
  137. {
  138. // This is used as a signal handler, and thus the calls into ColorSync are unsafe.
  139. // But we might as well try to restore the user's color profile, we're going down anyway...
  140. if (initialColorProfileLocation.locType != cmNoProfileBase) {
  141. const CMDeviceScope scope = { kCFPreferencesCurrentUser, kCFPreferencesCurrentHost };
  142. int error = CMSetDeviceProfile(cmDisplayDeviceClass, (CMDeviceID)kCGDirectMainDisplay, &scope, cmDefaultProfileID, &initialColorProfileLocation);
  143. if (error) {
  144. NSLog(@"Failed to restore color profile, use System Preferences -> Displays -> Color to reset. Error: %d", (int)error);
  145. }
  146. initialColorProfileLocation.locType = cmNoProfileBase;
  147. }
  148. }
  149. #endif
  150. static void simpleSignalHandler(int sig)
  151. {
  152. // Try to restore the color profile and try to go down cleanly
  153. restoreUserColorProfile();
  154. exit(128 + sig);
  155. }
  156. int main(int argc, char* argv[])
  157. {
  158. NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
  159. // Hooks the ways we might get told to clean up...
  160. signal(SIGINT, simpleSignalHandler);
  161. signal(SIGHUP, simpleSignalHandler);
  162. signal(SIGTERM, simpleSignalHandler);
  163. // Save off the current profile, and then install the layout test profile.
  164. installLayoutTestColorProfile();
  165. // Let the script know we're ready
  166. printf("ready\n");
  167. fflush(stdout);
  168. // Wait for any key (or signal)
  169. getchar();
  170. // Restore the profile
  171. restoreUserColorProfile();
  172. [pool release];
  173. return 0;
  174. }