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 32 #import <AvailabilityMacros.h> 33 #import <AppKit/AppKit.h> 34 #include <signal.h> 35 #include <stdio.h> 36 #include <stdlib.h> 37 38 // This is a simple helper app that changes the color sync profile to the 39 // generic profile and back when done. This program is managed by the layout 40 // test script, so it can do the job for multiple DumpRenderTree while they are 41 // running layout tests. 42 43 namespace { 44 45 #if defined(MAC_OS_X_VERSION_10_7) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7 46 47 CFURLRef sUserColorProfileURL; 48 49 void installLayoutTestColorProfile() 50 { 51 // To make sure we get consistent colors (not dependent on the chosen color 52 // space of the main display), we force the generic RGB color profile. 53 // This causes a change the user can see. 54 55 CFUUIDRef mainDisplayID = CGDisplayCreateUUIDFromDisplayID(CGMainDisplayID()); 56 57 if (!sUserColorProfileURL) { 58 CFDictionaryRef deviceInfo = ColorSyncDeviceCopyDeviceInfo(kColorSyncDisplayDeviceClass, mainDisplayID); 59 60 if (!deviceInfo) { 61 NSLog(@"No display attached to system; not setting main display's color profile."); 62 CFRelease(mainDisplayID); 63 return; 64 } 65 66 CFDictionaryRef profileInfo = (CFDictionaryRef)CFDictionaryGetValue(deviceInfo, kColorSyncCustomProfiles); 67 if (profileInfo) { 68 sUserColorProfileURL = (CFURLRef)CFDictionaryGetValue(profileInfo, CFSTR("1")); 69 CFRetain(sUserColorProfileURL); 70 } else { 71 profileInfo = (CFDictionaryRef)CFDictionaryGetValue(deviceInfo, kColorSyncFactoryProfiles); 72 CFDictionaryRef factoryProfile = (CFDictionaryRef)CFDictionaryGetValue(profileInfo, CFSTR("1")); 73 sUserColorProfileURL = (CFURLRef)CFDictionaryGetValue(factoryProfile, kColorSyncDeviceProfileURL); 74 CFRetain(sUserColorProfileURL); 75 } 76 77 CFRelease(deviceInfo); 78 } 79 80 ColorSyncProfileRef genericRGBProfile = ColorSyncProfileCreateWithName(kColorSyncGenericRGBProfile); 81 CFErrorRef error; 82 CFURLRef profileURL = ColorSyncProfileGetURL(genericRGBProfile, &error); 83 if (!profileURL) { 84 NSLog(@"Failed to get URL of Generic RGB color profile! Many pixel tests may fail as a result. Error: %@", error); 85 86 if (sUserColorProfileURL) { 87 CFRelease(sUserColorProfileURL); 88 sUserColorProfileURL = 0; 89 } 90 91 CFRelease(genericRGBProfile); 92 CFRelease(mainDisplayID); 93 return; 94 } 95 96 CFMutableDictionaryRef profileInfo = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 97 CFDictionarySetValue(profileInfo, kColorSyncDeviceDefaultProfileID, profileURL); 98 99 if (!ColorSyncDeviceSetCustomProfiles(kColorSyncDisplayDeviceClass, mainDisplayID, profileInfo)) { 100 NSLog(@"Failed to set color profile for main display! Many pixel tests may fail as a result."); 101 102 if (sUserColorProfileURL) { 103 CFRelease(sUserColorProfileURL); 104 sUserColorProfileURL = 0; 105 } 106 } 107 108 CFRelease(profileInfo); 109 CFRelease(genericRGBProfile); 110 CFRelease(mainDisplayID); 111 } 112 113 void restoreUserColorProfile(void) 114 { 115 // This is used as a signal handler, and thus the calls into ColorSync are unsafe. 116 // But we might as well try to restore the user's color profile, we're going down anyway... 117 118 if (!sUserColorProfileURL) 119 return; 120 121 CFUUIDRef mainDisplayID = CGDisplayCreateUUIDFromDisplayID(CGMainDisplayID()); 122 CFMutableDictionaryRef profileInfo = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 123 CFDictionarySetValue(profileInfo, kColorSyncDeviceDefaultProfileID, sUserColorProfileURL); 124 ColorSyncDeviceSetCustomProfiles(kColorSyncDisplayDeviceClass, mainDisplayID, profileInfo); 125 CFRelease(mainDisplayID); 126 CFRelease(profileInfo); 127 } 128 129 #else // For Snow Leopard and before, use older CM* API. 130 131 const char colorProfilePath[] = "/System/Library/ColorSync/Profiles/Generic RGB Profile.icc"; 132 133 CMProfileLocation initialColorProfileLocation; // The locType field is initialized to 0 which is the same as cmNoProfileBase. 134 135 void installLayoutTestColorProfile() 136 { 137 // To make sure we get consistent colors (not dependent on the Main display), 138 // we force the generic rgb color profile. This cases a change the user can 139 // see. 140 const CMDeviceScope scope = { kCFPreferencesCurrentUser, kCFPreferencesCurrentHost }; 141 142 CMProfileRef profile = 0; 143 int error = CMGetProfileByAVID((CMDisplayIDType)kCGDirectMainDisplay, &profile); 144 if (!error) { 145 UInt32 size = sizeof(initialColorProfileLocation); 146 error = NCMGetProfileLocation(profile, &initialColorProfileLocation, &size); 147 CMCloseProfile(profile); 148 } 149 if (error) { 150 NSLog(@"failed to get the current color profile, pixmaps won't match. Error: %d", (int)error); 151 initialColorProfileLocation.locType = cmNoProfileBase; 152 return; 153 } 154 155 CMProfileLocation location; 156 location.locType = cmPathBasedProfile; 157 strncpy(location.u.pathLoc.path, colorProfilePath, sizeof(location.u.pathLoc.path)); 158 error = CMSetDeviceProfile(cmDisplayDeviceClass, (CMDeviceID)kCGDirectMainDisplay, &scope, cmDefaultProfileID, &location); 159 if (error) { 160 NSLog(@"failed install the generic color profile, pixmaps won't match. Error: %d", (int)error); 161 initialColorProfileLocation.locType = cmNoProfileBase; 162 } 163 } 164 165 void restoreUserColorProfile(void) 166 { 167 // This is used as a signal handler, and thus the calls into ColorSync are unsafe. 168 // But we might as well try to restore the user's color profile, we're going down anyway... 169 if (initialColorProfileLocation.locType != cmNoProfileBase) { 170 const CMDeviceScope scope = { kCFPreferencesCurrentUser, kCFPreferencesCurrentHost }; 171 int error = CMSetDeviceProfile(cmDisplayDeviceClass, (CMDeviceID)kCGDirectMainDisplay, &scope, cmDefaultProfileID, &initialColorProfileLocation); 172 if (error) { 173 NSLog(@"Failed to restore color profile, use System Preferences -> Displays -> Color to reset. Error: %d", (int)error); 174 } 175 initialColorProfileLocation.locType = cmNoProfileBase; 176 } 177 } 178 179 #endif 180 181 void simpleSignalHandler(int sig) 182 { 183 // Try to restore the color profile and try to go down cleanly 184 restoreUserColorProfile(); 185 exit(128 + sig); 186 } 187 188 } // namespace 189 190 int main(int argc, char* argv[]) 191 { 192 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; 193 194 // Hooks the ways we might get told to clean up... 195 signal(SIGINT, simpleSignalHandler); 196 signal(SIGHUP, simpleSignalHandler); 197 signal(SIGTERM, simpleSignalHandler); 198 199 // Save off the current profile, and then install the layout test profile. 200 installLayoutTestColorProfile(); 201 202 // Let the script know we're ready 203 printf("ready\n"); 204 fflush(stdout); 205 206 // Wait for any key (or signal) 207 getchar(); 208 209 // Restore the profile 210 restoreUserColorProfile(); 211 212 [pool release]; 213 return 0; 214 } 215