1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95

content / test / gpu / gpu_tests / color_profile_manager_mac.py [blame]

# Copyright 2017 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

# Variables will be pulled into globals() from the ColorSync framework, and will
# trigger undefined-variables.
# pylint: disable=undefined-variable
# pytype: disable=name-error


from gpu_tests.util import host_information

if host_information.IsMac():
  # pylint: disable=import-error
  # pytype: disable=import-error
  import Foundation
  import Quartz
  import objc
  # pytype: enable=import-error
  # pylint: enable=import-error
  # There is no module for the ColorSync framework, so synthesize one using
  # bridge # support.
  color_sync_framework = '/System/Library/Frameworks/ApplicationServices.' \
                         'framework/Versions/A/Frameworks/ColorSync.framework'
  # This string is the output of running gen_bridge_metadata on the ColorSync
  # headers.
  color_sync_bridge_string = """<?xml version='1.0'?>
    <signatures version='1.0'>
      <constant name='kColorSyncDeviceDefaultProfileID' type='^{__CFString=}'/>
      <constant name='kColorSyncDisplayDeviceClass' type='^{__CFString=}'/>
      <constant name='kColorSyncProfileUserScope' type='^{__CFString=}'/>
      <function name='CGDisplayCreateUUIDFromDisplayID'>
        <arg type='I'/>
        <retval already_retained='true' type='^{__CFUUID=}'/>
      </function>
      <function name='ColorSyncDeviceCopyDeviceInfo'>
        <arg type='^{__CFString=}'/>
        <arg type='^{__CFUUID=}'/>
        <retval already_retained='true' type='^{__CFDictionary=}'/>
      </function>
      <function name='ColorSyncDeviceSetCustomProfiles'>
        <arg type='^{__CFString=}'/>
        <arg type='^{__CFUUID=}'/>
        <arg type='^{__CFDictionary=}'/>
        <retval type='B'/>
      </function>
    </signatures>"""
  objc.parseBridgeSupport(color_sync_bridge_string, globals(),
                          color_sync_framework)


# Set |display_id| to use the color profile specified in |profile_url|. If
# |profile_url| is None, then use the factor default.
def SetDisplayCustomProfile(device_id: int, profile_url: str) -> None:
  if profile_url is None:
    profile_url = Foundation.kCFNull
  profile_info = {
      kColorSyncDeviceDefaultProfileID: profile_url,
      kColorSyncProfileUserScope: Foundation.kCFPreferencesCurrentUser
  }
  result = ColorSyncDeviceSetCustomProfiles(kColorSyncDisplayDeviceClass,
                                            device_id, profile_info)
  if not result:
    raise Exception('Failed to set display custom profile')


# Returns the URL for the system's sRGB color profile.
def GetSRGBProfileURL() -> str:
  srgb_profile_path = '/System/Library/ColorSync/Profiles/sRGB Profile.icc'
  srgb_profile_url = Foundation.CFURLCreateFromFileSystemRepresentation(
      None, srgb_profile_path.encode('utf-8'), len(srgb_profile_path), False)
  return srgb_profile_url


# Return a map from display ID to custom color profiles set on the display or
# None if no custom color profile is set.
def GetDisplaysToProfileURLMap() -> dict:
  display_profile_url_map = {}
  online_display_list_result = Quartz.CGGetOnlineDisplayList(32, None, None)
  error = online_display_list_result[0]
  if error != Quartz.kCGErrorSuccess:
    raise Exception('Failed to get online displays from Quartz')
  online_displays = online_display_list_result[1]
  for display_id in online_displays:
    device_info = ColorSyncDeviceCopyDeviceInfo(
        kColorSyncDisplayDeviceClass,
        CGDisplayCreateUUIDFromDisplayID(display_id))
    if not device_info:
      raise Exception('KVM connection on bot is broken, please file a bug')
    device_id = device_info['DeviceID']
    custom_profile_url = None
    if 'CustomProfiles' in device_info and '1' in device_info['CustomProfiles']:
      custom_profile_url = device_info['CustomProfiles']['1']
    display_profile_url_map[device_id] = custom_profile_url
  return display_profile_url_map