0

Initial implementation of Color Pipeline classes.

Design doc:
https://docs.google.com/document/d/1rpNjGg0762tnjfChkA1WJwHalDUQ0ZwkcXsgwwuCuQE/edit?usp=sharing

This implements the core types:
* ColorId
* ColorMixer
* ColorModifier
* ColorProvider
* ColorRecipe
* ColorSet
* ColorSetId
* ColorVariant

It also adds a new "color_unittests" target with unittests that should provide
full coverage of the above, except for ColorVariant (which is not yet used).

Still unimplemented:
* ColorVariant support, including thought about how things like incognito and
  dark mode should work, whether ColorVariant is really the right primitive, and
  whether "inactive" deserves to be a variant.
* A fleshed-out ownership/lifetime model for ColorProfile, which affects what
  constructors or factory functions we expose, as well as the APIs for modifying
  the color pipeline.

This does not include this code anywhere in Chrome.

*.json are autogenerated and do not need review.

Bug: 1003612
Change-Id: I6edf603b407a4cc25315e383974ec0fc0718d9c1
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1807135
Commit-Queue: Peter Kasting <pkasting@chromium.org>
Reviewed-by: Allen Bauer <kylixrd@chromium.org>
Reviewed-by: Scott Violet <sky@chromium.org>
Cr-Commit-Position: refs/heads/master@{#698262}
This commit is contained in:
Peter Kasting
2019-09-20 00:16:09 +00:00
committed by Commit Bot
parent ff850b92cf
commit 8d5c4d6132
36 changed files with 2975 additions and 0 deletions

@ -182,10 +182,12 @@ group("gn_all") {
"//third_party/blink/renderer/platform/heap:blink_heap_unittests",
"//third_party/blink/renderer/platform/wtf:wtf_unittests",
"//tools/imagediff",
"//ui/color:color_unittests",
"//ui/display:display_unittests",
"//ui/events:events_unittests",
"//ui/gl:gl_unittests",
"//ui/latency:latency_unittests",
"//ui/native_theme:native_theme_unittests",
"//ui/touch_selection:ui_touch_selection_unittests",
"//url/ipc:url_ipc_unittests",
"//v8:gn_all",

@ -121,6 +121,23 @@
},
"test": "chrome_all_tast_tests"
},
{
"merge": {
"args": [],
"script": "//testing/merge_scripts/standard_gtest_merge.py"
},
"swarming": {
"can_use_on_swarming_builders": true,
"dimension_sets": [
{
"kvm": "1",
"os": "Ubuntu-16.04",
"pool": "chrome.tests.cros-vm"
}
]
},
"test": "color_unittests"
},
{
"merge": {
"args": [],
@ -641,6 +658,23 @@
},
"test": "chrome_all_tast_tests"
},
{
"merge": {
"args": [],
"script": "//testing/merge_scripts/standard_gtest_merge.py"
},
"swarming": {
"can_use_on_swarming_builders": true,
"dimension_sets": [
{
"kvm": "1",
"os": "Ubuntu-16.04",
"pool": "chrome.tests.cros-vm"
}
]
},
"test": "color_unittests"
},
{
"merge": {
"args": [],
@ -1582,6 +1616,23 @@
},
"test": "chromeos_unittests"
},
{
"merge": {
"args": [],
"script": "//testing/merge_scripts/standard_gtest_merge.py"
},
"swarming": {
"can_use_on_swarming_builders": true,
"dimension_sets": [
{
"os": "Ubuntu-16.04",
"pool": "chrome.tests",
"ssd": "0"
}
]
},
"test": "color_unittests"
},
{
"merge": {
"args": [],

@ -1589,6 +1589,62 @@
},
"test": "chrome_public_test_apk"
},
{
"args": [
"--gs-results-bucket=chromium-result-details",
"--recover-devices",
"--avd-name=20190903T160000Z_android_23_google_apis_x86",
"--emulator-home=../../.android"
],
"merge": {
"args": [
"--bucket",
"chromium-result-details",
"--test-name",
"color_unittests"
],
"script": "//build/android/pylib/results/presentation/test_results_presentation.py"
},
"swarming": {
"can_use_on_swarming_builders": true,
"cipd_packages": [
{
"cipd_package": "chromium/third_party/android_sdk/public/avds/android-23/google_apis/x86",
"location": ".android",
"revision": "cfoclSzHrFOS_AcwBL09RQ5PvJByQHu3MX6EbC5aWZIC"
},
{
"cipd_package": "chromium/third_party/android_sdk/public/emulator",
"location": "third_party/android_sdk/public",
"revision": "f4WdgkPvDdVCE8zBWPzcSIj4N9WFhKp3CSKDWylXuLEC"
},
{
"cipd_package": "chromium/third_party/android_sdk/public/system-images/android-23/google_apis/x86",
"location": "third_party/android_sdk/public",
"revision": "npuCAATVbhmywZwGhI3tMoECTrBBzzyJLpjAPXqtmYYC"
}
],
"dimension_sets": [
{
"cpu": "x86-64",
"device_os": null,
"device_type": null,
"os": "Ubuntu-16.04"
}
],
"output_links": [
{
"link": [
"https://luci-logdog.appspot.com/v/?s",
"=android%2Fswarming%2Flogcats%2F",
"${TASK_ID}%2F%2B%2Funified_logcats"
],
"name": "shard #${SHARD_INDEX} logcats"
}
]
},
"test": "color_unittests"
},
{
"args": [
"--gs-results-bucket=chromium-result-details",
@ -5543,6 +5599,62 @@
},
"test": "chrome_public_test_apk"
},
{
"args": [
"--gs-results-bucket=chromium-result-details",
"--recover-devices",
"--avd-name=20190716T160000Z_android_28_google_apis_x86",
"--emulator-home=../../.android"
],
"merge": {
"args": [
"--bucket",
"chromium-result-details",
"--test-name",
"color_unittests"
],
"script": "//build/android/pylib/results/presentation/test_results_presentation.py"
},
"swarming": {
"can_use_on_swarming_builders": true,
"cipd_packages": [
{
"cipd_package": "chromium/third_party/android_sdk/public/avds/android-28/google_apis/x86",
"location": ".android",
"revision": "J5MFTg7OhekLKsOX7bmkVTSCDzohydCvXrn4sJzy0xsC"
},
{
"cipd_package": "chromium/third_party/android_sdk/public/emulator",
"location": "third_party/android_sdk/public",
"revision": "xhyuoquVvBTcJelgRjMKZeoBVSQRjB7pLVJPt5C9saIC"
},
{
"cipd_package": "chromium/third_party/android_sdk/public/system-images/android-28/google_apis/x86",
"location": "third_party/android_sdk/public",
"revision": "LDa0XkTjgGYx7Amzg5qjIRgCfc4F_pq7rKMJVdACYx8C"
}
],
"dimension_sets": [
{
"cpu": "x86-64",
"device_os": null,
"device_type": null,
"os": "Ubuntu-16.04"
}
],
"output_links": [
{
"link": [
"https://luci-logdog.appspot.com/v/?s",
"=android%2Fswarming%2Flogcats%2F",
"${TASK_ID}%2F%2B%2Funified_logcats"
],
"name": "shard #${SHARD_INDEX} logcats"
}
]
},
"test": "color_unittests"
},
{
"args": [
"--gs-results-bucket=chromium-result-details",

@ -2869,6 +2869,50 @@
},
"test": "chrome_public_test_vr_apk"
},
{
"args": [
"--gs-results-bucket=chromium-result-details",
"--recover-devices"
],
"merge": {
"args": [
"--bucket",
"chromium-result-details",
"--test-name",
"color_unittests"
],
"script": "//build/android/pylib/results/presentation/test_results_presentation.py"
},
"swarming": {
"can_use_on_swarming_builders": true,
"cipd_packages": [
{
"cipd_package": "infra/tools/luci/logdog/butler/${platform}",
"location": "bin",
"revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
}
],
"dimension_sets": [
{
"device_os": "KTU84P",
"device_os_type": "userdebug",
"device_type": "hammerhead",
"os": "Android"
}
],
"output_links": [
{
"link": [
"https://luci-logdog.appspot.com/v/?s",
"=android%2Fswarming%2Flogcats%2F",
"${TASK_ID}%2F%2B%2Funified_logcats"
],
"name": "shard #${SHARD_INDEX} logcats"
}
]
},
"test": "color_unittests"
},
{
"args": [
"--gs-results-bucket=chromium-result-details",
@ -5771,6 +5815,51 @@
},
"test": "chrome_public_test_apk"
},
{
"args": [
"--gs-results-bucket=chromium-result-details",
"--recover-devices"
],
"merge": {
"args": [
"--bucket",
"chromium-result-details",
"--test-name",
"color_unittests"
],
"script": "//build/android/pylib/results/presentation/test_results_presentation.py"
},
"swarming": {
"can_use_on_swarming_builders": true,
"cipd_packages": [
{
"cipd_package": "infra/tools/luci/logdog/butler/${platform}",
"location": "bin",
"revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
}
],
"dimension_sets": [
{
"device_os": "KTU84Z",
"device_os_type": "userdebug",
"device_type": "flo",
"os": "Android"
}
],
"expiration": 10800,
"output_links": [
{
"link": [
"https://luci-logdog.appspot.com/v/?s",
"=android%2Fswarming%2Flogcats%2F",
"${TASK_ID}%2F%2B%2Funified_logcats"
],
"name": "shard #${SHARD_INDEX} logcats"
}
]
},
"test": "color_unittests"
},
{
"args": [
"--gs-results-bucket=chromium-result-details",
@ -8810,6 +8899,51 @@
},
"test": "chrome_public_test_vr_apk"
},
{
"args": [
"--gs-results-bucket=chromium-result-details",
"--recover-devices"
],
"merge": {
"args": [
"--bucket",
"chromium-result-details",
"--test-name",
"color_unittests"
],
"script": "//build/android/pylib/results/presentation/test_results_presentation.py"
},
"swarming": {
"can_use_on_swarming_builders": true,
"cipd_packages": [
{
"cipd_package": "infra/tools/luci/logdog/butler/${platform}",
"location": "bin",
"revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
}
],
"dimension_sets": [
{
"device_os": "LMY48I",
"device_os_type": "userdebug",
"device_type": "hammerhead",
"os": "Android"
}
],
"expiration": 10800,
"output_links": [
{
"link": [
"https://luci-logdog.appspot.com/v/?s",
"=android%2Fswarming%2Flogcats%2F",
"${TASK_ID}%2F%2B%2Funified_logcats"
],
"name": "shard #${SHARD_INDEX} logcats"
}
]
},
"test": "color_unittests"
},
{
"args": [
"--gs-results-bucket=chromium-result-details",
@ -11991,6 +12125,51 @@
},
"test": "chrome_public_test_apk"
},
{
"args": [
"--gs-results-bucket=chromium-result-details",
"--recover-devices"
],
"merge": {
"args": [
"--bucket",
"chromium-result-details",
"--test-name",
"color_unittests"
],
"script": "//build/android/pylib/results/presentation/test_results_presentation.py"
},
"swarming": {
"can_use_on_swarming_builders": true,
"cipd_packages": [
{
"cipd_package": "infra/tools/luci/logdog/butler/${platform}",
"location": "bin",
"revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
}
],
"dimension_sets": [
{
"device_os": "LMY49B",
"device_os_type": "userdebug",
"device_type": "flo",
"os": "Android"
}
],
"expiration": 10800,
"output_links": [
{
"link": [
"https://luci-logdog.appspot.com/v/?s",
"=android%2Fswarming%2Flogcats%2F",
"${TASK_ID}%2F%2B%2Funified_logcats"
],
"name": "shard #${SHARD_INDEX} logcats"
}
]
},
"test": "color_unittests"
},
{
"args": [
"--gs-results-bucket=chromium-result-details",
@ -15055,6 +15234,50 @@
},
"test": "chrome_public_test_vr_apk"
},
{
"args": [
"--gs-results-bucket=chromium-result-details",
"--recover-devices"
],
"merge": {
"args": [
"--bucket",
"chromium-result-details",
"--test-name",
"color_unittests"
],
"script": "//build/android/pylib/results/presentation/test_results_presentation.py"
},
"swarming": {
"can_use_on_swarming_builders": true,
"cipd_packages": [
{
"cipd_package": "infra/tools/luci/logdog/butler/${platform}",
"location": "bin",
"revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
}
],
"dimension_sets": [
{
"device_os": "MMB29Q",
"device_os_type": "userdebug",
"device_type": "bullhead",
"os": "Android"
}
],
"output_links": [
{
"link": [
"https://luci-logdog.appspot.com/v/?s",
"=android%2Fswarming%2Flogcats%2F",
"${TASK_ID}%2F%2B%2Funified_logcats"
],
"name": "shard #${SHARD_INDEX} logcats"
}
]
},
"test": "color_unittests"
},
{
"args": [
"--gs-results-bucket=chromium-result-details",
@ -18185,6 +18408,51 @@
},
"test": "chrome_public_test_apk"
},
{
"args": [
"--gs-results-bucket=chromium-result-details",
"--recover-devices"
],
"merge": {
"args": [
"--bucket",
"chromium-result-details",
"--test-name",
"color_unittests"
],
"script": "//build/android/pylib/results/presentation/test_results_presentation.py"
},
"swarming": {
"can_use_on_swarming_builders": true,
"cipd_packages": [
{
"cipd_package": "infra/tools/luci/logdog/butler/${platform}",
"location": "bin",
"revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
}
],
"dimension_sets": [
{
"device_os": "MRA58Z",
"device_os_type": "userdebug",
"device_type": "flo",
"os": "Android"
}
],
"expiration": 10800,
"output_links": [
{
"link": [
"https://luci-logdog.appspot.com/v/?s",
"=android%2Fswarming%2Flogcats%2F",
"${TASK_ID}%2F%2B%2Funified_logcats"
],
"name": "shard #${SHARD_INDEX} logcats"
}
]
},
"test": "color_unittests"
},
{
"args": [
"--gs-results-bucket=chromium-result-details",
@ -23386,6 +23654,50 @@
},
"test": "chrome_public_test_vr_apk"
},
{
"args": [
"--gs-results-bucket=chromium-result-details",
"--recover-devices"
],
"merge": {
"args": [
"--bucket",
"chromium-result-details",
"--test-name",
"color_unittests"
],
"script": "//build/android/pylib/results/presentation/test_results_presentation.py"
},
"swarming": {
"can_use_on_swarming_builders": true,
"cipd_packages": [
{
"cipd_package": "infra/tools/luci/logdog/butler/${platform}",
"location": "bin",
"revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
}
],
"dimension_sets": [
{
"device_os": "KTU84P",
"device_os_type": "userdebug",
"device_type": "hammerhead",
"os": "Android"
}
],
"output_links": [
{
"link": [
"https://luci-logdog.appspot.com/v/?s",
"=android%2Fswarming%2Flogcats%2F",
"${TASK_ID}%2F%2B%2Funified_logcats"
],
"name": "shard #${SHARD_INDEX} logcats"
}
]
},
"test": "color_unittests"
},
{
"args": [
"--gs-results-bucket=chromium-result-details",
@ -26447,6 +26759,50 @@
},
"test": "chrome_public_test_vr_apk"
},
{
"args": [
"--gs-results-bucket=chromium-result-details",
"--recover-devices"
],
"merge": {
"args": [
"--bucket",
"chromium-result-details",
"--test-name",
"color_unittests"
],
"script": "//build/android/pylib/results/presentation/test_results_presentation.py"
},
"swarming": {
"can_use_on_swarming_builders": true,
"cipd_packages": [
{
"cipd_package": "infra/tools/luci/logdog/butler/${platform}",
"location": "bin",
"revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
}
],
"dimension_sets": [
{
"device_os": "MMB29Q",
"device_os_type": "userdebug",
"device_type": "bullhead",
"os": "Android"
}
],
"output_links": [
{
"link": [
"https://luci-logdog.appspot.com/v/?s",
"=android%2Fswarming%2Flogcats%2F",
"${TASK_ID}%2F%2B%2Funified_logcats"
],
"name": "shard #${SHARD_INDEX} logcats"
}
]
},
"test": "color_unittests"
},
{
"args": [
"--gs-results-bucket=chromium-result-details",

@ -126,6 +126,23 @@
},
"test": "chrome_all_tast_tests"
},
{
"merge": {
"args": [],
"script": "//testing/merge_scripts/standard_gtest_merge.py"
},
"swarming": {
"can_use_on_swarming_builders": true,
"dimension_sets": [
{
"kvm": "1",
"os": "Ubuntu-16.04",
"pool": "Chrome-CrOS-VM"
}
]
},
"test": "color_unittests"
},
{
"merge": {
"args": [],
@ -1127,6 +1144,22 @@
},
"test": "chromeos_unittests"
},
{
"isolate_coverage_data": true,
"merge": {
"args": [],
"script": "//testing/merge_scripts/standard_gtest_merge.py"
},
"swarming": {
"can_use_on_swarming_builders": true,
"dimension_sets": [
{
"os": "Ubuntu-16.04"
}
]
},
"test": "color_unittests"
},
{
"isolate_coverage_data": true,
"merge": {
@ -2713,6 +2746,21 @@
},
"test": "chromeos_unittests"
},
{
"merge": {
"args": [],
"script": "//testing/merge_scripts/standard_gtest_merge.py"
},
"swarming": {
"can_use_on_swarming_builders": true,
"dimension_sets": [
{
"os": "Ubuntu-16.04"
}
]
},
"test": "color_unittests"
},
{
"merge": {
"args": [],
@ -4216,6 +4264,21 @@
},
"test": "chromeos_unittests"
},
{
"merge": {
"args": [],
"script": "//testing/merge_scripts/standard_gtest_merge.py"
},
"swarming": {
"can_use_on_swarming_builders": true,
"dimension_sets": [
{
"os": "Ubuntu-16.04"
}
]
},
"test": "color_unittests"
},
{
"merge": {
"args": [],

@ -328,6 +328,21 @@
},
"test": "chromedriver_unittests"
},
{
"merge": {
"args": [],
"script": "//testing/merge_scripts/standard_gtest_merge.py"
},
"swarming": {
"can_use_on_swarming_builders": true,
"dimension_sets": [
{
"os": "Ubuntu-16.04"
}
]
},
"test": "color_unittests"
},
{
"merge": {
"args": [],
@ -1765,6 +1780,22 @@
},
"test": "chromedriver_unittests"
},
{
"merge": {
"args": [],
"script": "//testing/merge_scripts/standard_gtest_merge.py"
},
"swarming": {
"can_use_on_swarming_builders": true,
"dimension_sets": [
{
"cpu": "x86-64",
"os": "Windows-10-15063"
}
]
},
"test": "color_unittests"
},
{
"merge": {
"args": [],
@ -3388,6 +3419,22 @@
},
"test": "chromedriver_unittests"
},
{
"merge": {
"args": [],
"script": "//testing/merge_scripts/standard_gtest_merge.py"
},
"swarming": {
"can_use_on_swarming_builders": true,
"dimension_sets": [
{
"cpu": "x86-64",
"os": "Windows-10-15063"
}
]
},
"test": "color_unittests"
},
{
"merge": {
"args": [],
@ -5420,6 +5467,50 @@
},
"test": "chrome_public_test_apk"
},
{
"args": [
"--gs-results-bucket=chromium-result-details",
"--recover-devices"
],
"merge": {
"args": [
"--bucket",
"chromium-result-details",
"--test-name",
"color_unittests"
],
"script": "//build/android/pylib/results/presentation/test_results_presentation.py"
},
"swarming": {
"can_use_on_swarming_builders": true,
"cipd_packages": [
{
"cipd_package": "infra/tools/luci/logdog/butler/${platform}",
"location": "bin",
"revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
}
],
"dimension_sets": [
{
"device_os": "KTU84P",
"device_os_type": "userdebug",
"device_type": "hammerhead",
"os": "Android"
}
],
"output_links": [
{
"link": [
"https://luci-logdog.appspot.com/v/?s",
"=android%2Fswarming%2Flogcats%2F",
"${TASK_ID}%2F%2B%2Funified_logcats"
],
"name": "shard #${SHARD_INDEX} logcats"
}
]
},
"test": "color_unittests"
},
{
"args": [
"--gs-results-bucket=chromium-result-details",
@ -8591,6 +8682,50 @@
},
"test": "chrome_public_test_apk"
},
{
"args": [
"--gs-results-bucket=chromium-result-details",
"--recover-devices"
],
"merge": {
"args": [
"--bucket",
"chromium-result-details",
"--test-name",
"color_unittests"
],
"script": "//build/android/pylib/results/presentation/test_results_presentation.py"
},
"swarming": {
"can_use_on_swarming_builders": true,
"cipd_packages": [
{
"cipd_package": "infra/tools/luci/logdog/butler/${platform}",
"location": "bin",
"revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
}
],
"dimension_sets": [
{
"device_os": "MMB29Q",
"device_os_type": "userdebug",
"device_type": "bullhead",
"os": "Android"
}
],
"output_links": [
{
"link": [
"https://luci-logdog.appspot.com/v/?s",
"=android%2Fswarming%2Flogcats%2F",
"${TASK_ID}%2F%2B%2Funified_logcats"
],
"name": "shard #${SHARD_INDEX} logcats"
}
]
},
"test": "color_unittests"
},
{
"args": [
"--gs-results-bucket=chromium-result-details",
@ -11099,6 +11234,21 @@
},
"test": "chromedriver_unittests"
},
{
"merge": {
"args": [],
"script": "//testing/merge_scripts/standard_gtest_merge.py"
},
"swarming": {
"can_use_on_swarming_builders": true,
"dimension_sets": [
{
"os": "Ubuntu-16.04"
}
]
},
"test": "color_unittests"
},
{
"merge": {
"args": [],
@ -12563,6 +12713,24 @@
},
"test": "chromedriver_unittests"
},
{
"args": [
"--test-launcher-print-test-stdio=always"
],
"merge": {
"args": [],
"script": "//testing/merge_scripts/standard_gtest_merge.py"
},
"swarming": {
"can_use_on_swarming_builders": true,
"dimension_sets": [
{
"os": "Ubuntu-16.04"
}
]
},
"test": "color_unittests"
},
{
"args": [
"--test-launcher-print-test-stdio=always"
@ -14151,6 +14319,21 @@
},
"test": "chromedriver_unittests"
},
{
"merge": {
"args": [],
"script": "//testing/merge_scripts/standard_gtest_merge.py"
},
"swarming": {
"can_use_on_swarming_builders": true,
"dimension_sets": [
{
"os": "Ubuntu-16.04"
}
]
},
"test": "color_unittests"
},
{
"merge": {
"args": [],
@ -15533,6 +15716,21 @@
},
"test": "chromedriver_unittests"
},
{
"merge": {
"args": [],
"script": "//testing/merge_scripts/standard_gtest_merge.py"
},
"swarming": {
"can_use_on_swarming_builders": true,
"dimension_sets": [
{
"os": "Ubuntu-16.04"
}
]
},
"test": "color_unittests"
},
{
"merge": {
"args": [],
@ -16917,6 +17115,21 @@
},
"test": "chromedriver_unittests"
},
{
"merge": {
"args": [],
"script": "//testing/merge_scripts/standard_gtest_merge.py"
},
"swarming": {
"can_use_on_swarming_builders": true,
"dimension_sets": [
{
"os": "Ubuntu-16.04"
}
]
},
"test": "color_unittests"
},
{
"merge": {
"args": [],
@ -18301,6 +18514,21 @@
},
"test": "chromedriver_unittests"
},
{
"merge": {
"args": [],
"script": "//testing/merge_scripts/standard_gtest_merge.py"
},
"swarming": {
"can_use_on_swarming_builders": true,
"dimension_sets": [
{
"os": "Ubuntu-16.04"
}
]
},
"test": "color_unittests"
},
{
"merge": {
"args": [],
@ -19701,6 +19929,21 @@
},
"test": "chromedriver_unittests"
},
{
"merge": {
"args": [],
"script": "//testing/merge_scripts/standard_gtest_merge.py"
},
"swarming": {
"can_use_on_swarming_builders": true,
"dimension_sets": [
{
"os": "Ubuntu-16.04"
}
]
},
"test": "color_unittests"
},
{
"merge": {
"args": [],
@ -20987,6 +21230,16 @@
},
"test": "chromedriver_unittests"
},
{
"merge": {
"args": [],
"script": "//testing/merge_scripts/standard_gtest_merge.py"
},
"swarming": {
"can_use_on_swarming_builders": true
},
"test": "color_unittests"
},
{
"merge": {
"args": [],
@ -22066,6 +22319,19 @@
},
"test": "chromedriver_unittests"
},
{
"args": [
"--test-launcher-print-test-stdio=always"
],
"merge": {
"args": [],
"script": "//testing/merge_scripts/standard_gtest_merge.py"
},
"swarming": {
"can_use_on_swarming_builders": true
},
"test": "color_unittests"
},
{
"args": [
"--test-launcher-print-test-stdio=always"
@ -23068,6 +23334,16 @@
},
"test": "chromedriver_unittests"
},
{
"merge": {
"args": [],
"script": "//testing/merge_scripts/standard_gtest_merge.py"
},
"swarming": {
"can_use_on_swarming_builders": true
},
"test": "color_unittests"
},
{
"merge": {
"args": [],
@ -24129,6 +24405,16 @@
},
"test": "chromedriver_unittests"
},
{
"merge": {
"args": [],
"script": "//testing/merge_scripts/standard_gtest_merge.py"
},
"swarming": {
"can_use_on_swarming_builders": true
},
"test": "color_unittests"
},
{
"merge": {
"args": [],
@ -25180,6 +25466,16 @@
},
"test": "chromedriver_unittests"
},
{
"merge": {
"args": [],
"script": "//testing/merge_scripts/standard_gtest_merge.py"
},
"swarming": {
"can_use_on_swarming_builders": true
},
"test": "color_unittests"
},
{
"merge": {
"args": [],
@ -26231,6 +26527,16 @@
},
"test": "chromedriver_unittests"
},
{
"merge": {
"args": [],
"script": "//testing/merge_scripts/standard_gtest_merge.py"
},
"swarming": {
"can_use_on_swarming_builders": true
},
"test": "color_unittests"
},
{
"merge": {
"args": [],
@ -27426,6 +27732,22 @@
},
"test": "chromedriver_unittests"
},
{
"merge": {
"args": [],
"script": "//testing/merge_scripts/standard_gtest_merge.py"
},
"swarming": {
"can_use_on_swarming_builders": true,
"dimension_sets": [
{
"cpu": "x86-64",
"os": "Windows-10-15063"
}
]
},
"test": "color_unittests"
},
{
"merge": {
"args": [],
@ -29071,6 +29393,22 @@
},
"test": "chromedriver_unittests"
},
{
"merge": {
"args": [],
"script": "//testing/merge_scripts/standard_gtest_merge.py"
},
"swarming": {
"can_use_on_swarming_builders": true,
"dimension_sets": [
{
"cpu": "x86-64",
"os": "Windows-10-15063"
}
]
},
"test": "color_unittests"
},
{
"merge": {
"args": [],
@ -30716,6 +31054,22 @@
},
"test": "chromedriver_unittests"
},
{
"merge": {
"args": [],
"script": "//testing/merge_scripts/standard_gtest_merge.py"
},
"swarming": {
"can_use_on_swarming_builders": true,
"dimension_sets": [
{
"cpu": "x86-64",
"os": "Windows-10-15063"
}
]
},
"test": "color_unittests"
},
{
"merge": {
"args": [],
@ -32217,6 +32571,16 @@
},
"test": "chromedriver_unittests"
},
{
"merge": {
"args": [],
"script": "//testing/merge_scripts/standard_gtest_merge.py"
},
"swarming": {
"can_use_on_swarming_builders": true
},
"test": "color_unittests"
},
{
"merge": {
"args": [],
@ -33268,6 +33632,16 @@
},
"test": "chromedriver_unittests"
},
{
"merge": {
"args": [],
"script": "//testing/merge_scripts/standard_gtest_merge.py"
},
"swarming": {
"can_use_on_swarming_builders": true
},
"test": "color_unittests"
},
{
"merge": {
"args": [],
@ -34319,6 +34693,16 @@
},
"test": "chromedriver_unittests"
},
{
"merge": {
"args": [],
"script": "//testing/merge_scripts/standard_gtest_merge.py"
},
"swarming": {
"can_use_on_swarming_builders": true
},
"test": "color_unittests"
},
{
"merge": {
"args": [],
@ -35370,6 +35754,16 @@
},
"test": "chromedriver_unittests"
},
{
"merge": {
"args": [],
"script": "//testing/merge_scripts/standard_gtest_merge.py"
},
"swarming": {
"can_use_on_swarming_builders": true
},
"test": "color_unittests"
},
{
"merge": {
"args": [],
@ -36421,6 +36815,16 @@
},
"test": "chromedriver_unittests"
},
{
"merge": {
"args": [],
"script": "//testing/merge_scripts/standard_gtest_merge.py"
},
"swarming": {
"can_use_on_swarming_builders": true
},
"test": "color_unittests"
},
{
"merge": {
"args": [],
@ -37547,6 +37951,21 @@
},
"test": "chromedriver_unittests"
},
{
"merge": {
"args": [],
"script": "//testing/merge_scripts/standard_gtest_merge.py"
},
"swarming": {
"can_use_on_swarming_builders": true,
"dimension_sets": [
{
"os": "Ubuntu-16.04"
}
]
},
"test": "color_unittests"
},
{
"merge": {
"args": [],
@ -38973,6 +39392,21 @@
},
"test": "chromedriver_unittests"
},
{
"merge": {
"args": [],
"script": "//testing/merge_scripts/standard_gtest_merge.py"
},
"swarming": {
"can_use_on_swarming_builders": true,
"dimension_sets": [
{
"os": "Windows-10-15063"
}
]
},
"test": "color_unittests"
},
{
"merge": {
"args": [],

@ -1394,6 +1394,16 @@
},
"test": "chromedriver_unittests"
},
{
"merge": {
"args": [],
"script": "//testing/merge_scripts/standard_gtest_merge.py"
},
"swarming": {
"can_use_on_swarming_builders": false
},
"test": "color_unittests"
},
{
"merge": {
"args": [],
@ -2647,6 +2657,22 @@
},
"test": "chromedriver_unittests"
},
{
"merge": {
"args": [],
"script": "//testing/merge_scripts/standard_gtest_merge.py"
},
"swarming": {
"can_use_on_swarming_builders": true,
"dimension_sets": [
{
"cpu": "x86-64",
"os": "Windows-10-17134"
}
]
},
"test": "color_unittests"
},
{
"merge": {
"args": [],
@ -5273,6 +5299,51 @@
},
"test": "chrome_public_test_vr_apk"
},
{
"args": [
"--gs-results-bucket=chromium-result-details",
"--recover-devices"
],
"isolate_coverage_data": true,
"merge": {
"args": [
"--bucket",
"chromium-result-details",
"--test-name",
"color_unittests"
],
"script": "//build/android/pylib/results/presentation/test_results_presentation.py"
},
"swarming": {
"can_use_on_swarming_builders": true,
"cipd_packages": [
{
"cipd_package": "infra/tools/luci/logdog/butler/${platform}",
"location": "bin",
"revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
}
],
"dimension_sets": [
{
"device_os": "MMB29Q",
"device_os_type": "userdebug",
"device_type": "bullhead",
"os": "Android"
}
],
"output_links": [
{
"link": [
"https://luci-logdog.appspot.com/v/?s",
"=android%2Fswarming%2Flogcats%2F",
"${TASK_ID}%2F%2B%2Funified_logcats"
],
"name": "shard #${SHARD_INDEX} logcats"
}
]
},
"test": "color_unittests"
},
{
"args": [
"--gs-results-bucket=chromium-result-details",
@ -8277,6 +8348,26 @@
},
"test": "chrome_all_tast_tests"
},
{
"isolate_coverage_data": true,
"merge": {
"args": [],
"script": "//testing/merge_scripts/standard_gtest_merge.py"
},
"swarming": {
"can_use_on_swarming_builders": true,
"dimension_sets": [
{
"kvm": "1",
"os": "Ubuntu-16.04",
"pool": "Chrome-CrOS-VM"
}
],
"hard_timeout": 3600,
"io_timeout": 3600
},
"test": "color_unittests"
},
{
"isolate_coverage_data": true,
"merge": {
@ -10709,6 +10800,21 @@
},
"test": "cast_unittests"
},
{
"merge": {
"args": [],
"script": "//testing/merge_scripts/standard_gtest_merge.py"
},
"swarming": {
"can_use_on_swarming_builders": true,
"dimension_sets": [
{
"os": "Ubuntu-16.04"
}
]
},
"test": "color_unittests"
},
{
"merge": {
"args": [],
@ -11443,6 +11549,24 @@
},
"test": "cast_unittests"
},
{
"args": [
"--enable-features=BlinkHeapConcurrentMarking"
],
"merge": {
"args": [],
"script": "//testing/merge_scripts/standard_gtest_merge.py"
},
"swarming": {
"can_use_on_swarming_builders": true,
"dimension_sets": [
{
"os": "Ubuntu-16.04"
}
]
},
"test": "color_unittests"
},
{
"args": [
"--enable-features=BlinkHeapConcurrentMarking"
@ -12211,6 +12335,21 @@
},
"test": "cast_unittests"
},
{
"merge": {
"args": [],
"script": "//testing/merge_scripts/standard_gtest_merge.py"
},
"swarming": {
"can_use_on_swarming_builders": true,
"dimension_sets": [
{
"os": "Ubuntu-16.04"
}
]
},
"test": "color_unittests"
},
{
"merge": {
"args": [],
@ -13206,6 +13345,22 @@
},
"test": "chromeos_unittests"
},
{
"isolate_coverage_data": true,
"merge": {
"args": [],
"script": "//testing/merge_scripts/standard_gtest_merge.py"
},
"swarming": {
"can_use_on_swarming_builders": true,
"dimension_sets": [
{
"os": "Ubuntu-16.04"
}
]
},
"test": "color_unittests"
},
{
"isolate_coverage_data": true,
"merge": {
@ -14723,6 +14878,21 @@
},
"test": "chromedriver_unittests"
},
{
"merge": {
"args": [],
"script": "//testing/merge_scripts/standard_gtest_merge.py"
},
"swarming": {
"can_use_on_swarming_builders": true,
"dimension_sets": [
{
"os": "Ubuntu-16.04"
}
]
},
"test": "color_unittests"
},
{
"merge": {
"args": [],
@ -16508,6 +16678,22 @@
},
"test": "chromedriver_unittests"
},
{
"isolate_coverage_data": true,
"merge": {
"args": [],
"script": "//testing/merge_scripts/standard_gtest_merge.py"
},
"swarming": {
"can_use_on_swarming_builders": true,
"dimension_sets": [
{
"os": "Ubuntu-16.04"
}
]
},
"test": "color_unittests"
},
{
"isolate_coverage_data": true,
"merge": {
@ -22307,6 +22493,23 @@
},
"test": "chromedriver_unittests"
},
{
"merge": {
"args": [],
"script": "//testing/merge_scripts/standard_gtest_merge.py"
},
"swarming": {
"can_use_on_swarming_builders": true,
"dimension_sets": [
{
"gpu": "8086:0a2e",
"os": "Mac-10.15"
}
],
"expiration": 21600
},
"test": "color_unittests"
},
{
"merge": {
"args": [],

@ -282,6 +282,21 @@
},
"test": "cast_unittests"
},
{
"merge": {
"args": [],
"script": "//testing/merge_scripts/standard_gtest_merge.py"
},
"swarming": {
"can_use_on_swarming_builders": true,
"dimension_sets": [
{
"os": "Ubuntu-16.04"
}
]
},
"test": "color_unittests"
},
{
"merge": {
"args": [],
@ -1084,6 +1099,21 @@
},
"test": "cast_unittests"
},
{
"merge": {
"args": [],
"script": "//testing/merge_scripts/standard_gtest_merge.py"
},
"swarming": {
"can_use_on_swarming_builders": true,
"dimension_sets": [
{
"os": "Ubuntu-16.04"
}
]
},
"test": "color_unittests"
},
{
"merge": {
"args": [],
@ -2582,6 +2612,22 @@
},
"test": "chromedriver_unittests"
},
{
"isolate_coverage_data": true,
"merge": {
"args": [],
"script": "//testing/merge_scripts/standard_gtest_merge.py"
},
"swarming": {
"can_use_on_swarming_builders": true,
"dimension_sets": [
{
"os": "Ubuntu-16.04"
}
]
},
"test": "color_unittests"
},
{
"isolate_coverage_data": true,
"merge": {
@ -4448,6 +4494,21 @@
},
"test": "chromedriver_unittests"
},
{
"merge": {
"args": [],
"script": "//testing/merge_scripts/standard_gtest_merge.py"
},
"swarming": {
"can_use_on_swarming_builders": true,
"dimension_sets": [
{
"os": "Ubuntu-16.04"
}
]
},
"test": "color_unittests"
},
{
"merge": {
"args": [],
@ -6219,6 +6280,21 @@
},
"test": "chromedriver_unittests"
},
{
"merge": {
"args": [],
"script": "//testing/merge_scripts/standard_gtest_merge.py"
},
"swarming": {
"can_use_on_swarming_builders": true,
"dimension_sets": [
{
"os": "Ubuntu-14.04"
}
]
},
"test": "color_unittests"
},
{
"merge": {
"args": [],

@ -347,6 +347,22 @@
},
"test": "chromedriver_unittests"
},
{
"merge": {
"args": [],
"script": "//testing/merge_scripts/standard_gtest_merge.py"
},
"swarming": {
"can_use_on_swarming_builders": true,
"dimension_sets": [
{
"gpu": "none",
"os": "Mac-10.10"
}
]
},
"test": "color_unittests"
},
{
"merge": {
"args": [],
@ -1900,6 +1916,22 @@
},
"test": "chromedriver_unittests"
},
{
"merge": {
"args": [],
"script": "//testing/merge_scripts/standard_gtest_merge.py"
},
"swarming": {
"can_use_on_swarming_builders": true,
"dimension_sets": [
{
"gpu": "none",
"os": "Mac-10.11"
}
]
},
"test": "color_unittests"
},
{
"merge": {
"args": [],
@ -3453,6 +3485,22 @@
},
"test": "chromedriver_unittests"
},
{
"merge": {
"args": [],
"script": "//testing/merge_scripts/standard_gtest_merge.py"
},
"swarming": {
"can_use_on_swarming_builders": true,
"dimension_sets": [
{
"gpu": "8086:0a2e",
"os": "Mac-10.12.6"
}
]
},
"test": "color_unittests"
},
{
"merge": {
"args": [],
@ -5051,6 +5099,22 @@
},
"test": "chromedriver_unittests"
},
{
"merge": {
"args": [],
"script": "//testing/merge_scripts/standard_gtest_merge.py"
},
"swarming": {
"can_use_on_swarming_builders": true,
"dimension_sets": [
{
"gpu": "none",
"os": "Mac-10.13.6"
}
]
},
"test": "color_unittests"
},
{
"merge": {
"args": [],
@ -6639,6 +6703,22 @@
},
"test": "chromedriver_unittests"
},
{
"merge": {
"args": [],
"script": "//testing/merge_scripts/standard_gtest_merge.py"
},
"swarming": {
"can_use_on_swarming_builders": true,
"dimension_sets": [
{
"gpu": "none",
"os": "Mac-10.13.6"
}
]
},
"test": "color_unittests"
},
{
"merge": {
"args": [],

@ -894,6 +894,50 @@
},
"test": "chrome_public_test_vr_apk"
},
{
"args": [
"--gs-results-bucket=chromium-result-details",
"--recover-devices"
],
"merge": {
"args": [
"--bucket",
"chromium-result-details",
"--test-name",
"color_unittests"
],
"script": "//build/android/pylib/results/presentation/test_results_presentation.py"
},
"swarming": {
"can_use_on_swarming_builders": true,
"cipd_packages": [
{
"cipd_package": "infra/tools/luci/logdog/butler/${platform}",
"location": "bin",
"revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
}
],
"dimension_sets": [
{
"device_os": "MMB29Q",
"device_os_type": "userdebug",
"device_type": "bullhead",
"os": "Android"
}
],
"output_links": [
{
"link": [
"https://luci-logdog.appspot.com/v/?s",
"=android%2Fswarming%2Flogcats%2F",
"${TASK_ID}%2F%2B%2Funified_logcats"
],
"name": "shard #${SHARD_INDEX} logcats"
}
]
},
"test": "color_unittests"
},
{
"args": [
"--gs-results-bucket=chromium-result-details",
@ -3458,6 +3502,24 @@
},
"test": "chromedriver_unittests"
},
{
"args": [
"--test-launcher-print-test-stdio=always"
],
"merge": {
"args": [],
"script": "//testing/merge_scripts/standard_gtest_merge.py"
},
"swarming": {
"can_use_on_swarming_builders": true,
"dimension_sets": [
{
"os": "Ubuntu-16.04"
}
]
},
"test": "color_unittests"
},
{
"args": [
"--test-launcher-print-test-stdio=always"
@ -5125,6 +5187,21 @@
},
"test": "chromedriver_unittests"
},
{
"merge": {
"args": [],
"script": "//testing/merge_scripts/standard_gtest_merge.py"
},
"swarming": {
"can_use_on_swarming_builders": true,
"dimension_sets": [
{
"os": "Ubuntu-16.04"
}
]
},
"test": "color_unittests"
},
{
"merge": {
"args": [],
@ -6667,6 +6744,24 @@
},
"test": "chromeos_unittests"
},
{
"args": [
"--test-launcher-print-test-stdio=always"
],
"merge": {
"args": [],
"script": "//testing/merge_scripts/standard_gtest_merge.py"
},
"swarming": {
"can_use_on_swarming_builders": true,
"dimension_sets": [
{
"os": "Ubuntu-16.04"
}
]
},
"test": "color_unittests"
},
{
"args": [
"--test-launcher-print-test-stdio=always"
@ -8470,6 +8565,25 @@
},
"test": "chromeos_unittests"
},
{
"args": [
"--test-launcher-print-test-stdio=always"
],
"merge": {
"args": [],
"script": "//testing/merge_scripts/standard_gtest_merge.py"
},
"swarming": {
"can_use_on_swarming_builders": true,
"dimension_sets": [
{
"cpu": "x86-64",
"os": "Ubuntu-16.04"
}
]
},
"test": "color_unittests"
},
{
"args": [
"--test-launcher-print-test-stdio=always"
@ -10227,6 +10341,25 @@
},
"test": "chromedriver_unittests"
},
{
"args": [
"--test-launcher-print-test-stdio=always"
],
"merge": {
"args": [],
"script": "//testing/merge_scripts/standard_gtest_merge.py"
},
"swarming": {
"can_use_on_swarming_builders": true,
"dimension_sets": [
{
"cpu": "x86-64",
"os": "Ubuntu-16.04"
}
]
},
"test": "color_unittests"
},
{
"args": [
"--test-launcher-print-test-stdio=always"
@ -11896,6 +12029,24 @@
},
"test": "chromedriver_unittests"
},
{
"args": [
"--test-launcher-print-test-stdio=always"
],
"merge": {
"args": [],
"script": "//testing/merge_scripts/standard_gtest_merge.py"
},
"swarming": {
"can_use_on_swarming_builders": true,
"dimension_sets": [
{
"os": "Ubuntu-16.04"
}
]
},
"test": "color_unittests"
},
{
"args": [
"--test-launcher-print-test-stdio=always"
@ -13421,6 +13572,19 @@
},
"test": "chromedriver_unittests"
},
{
"args": [
"--test-launcher-print-test-stdio=always"
],
"merge": {
"args": [],
"script": "//testing/merge_scripts/standard_gtest_merge.py"
},
"swarming": {
"can_use_on_swarming_builders": true
},
"test": "color_unittests"
},
{
"args": [
"--test-launcher-print-test-stdio=always"
@ -15064,6 +15228,50 @@
},
"test": "chrome_public_smoke_test"
},
{
"args": [
"--gs-results-bucket=chromium-result-details",
"--recover-devices"
],
"merge": {
"args": [
"--bucket",
"chromium-result-details",
"--test-name",
"color_unittests"
],
"script": "//build/android/pylib/results/presentation/test_results_presentation.py"
},
"swarming": {
"can_use_on_swarming_builders": true,
"cipd_packages": [
{
"cipd_package": "infra/tools/luci/logdog/butler/${platform}",
"location": "bin",
"revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
}
],
"dimension_sets": [
{
"device_os": "KTU84P",
"device_os_type": "userdebug",
"device_type": "hammerhead",
"os": "Android"
}
],
"output_links": [
{
"link": [
"https://luci-logdog.appspot.com/v/?s",
"=android%2Fswarming%2Flogcats%2F",
"${TASK_ID}%2F%2B%2Funified_logcats"
],
"name": "shard #${SHARD_INDEX} logcats"
}
]
},
"test": "color_unittests"
},
{
"args": [
"--gs-results-bucket=chromium-result-details",
@ -17296,6 +17504,21 @@
},
"test": "chromedriver_unittests"
},
{
"merge": {
"args": [],
"script": "//testing/merge_scripts/standard_gtest_merge.py"
},
"swarming": {
"can_use_on_swarming_builders": true,
"dimension_sets": [
{
"os": "Windows-10-15063"
}
]
},
"test": "color_unittests"
},
{
"merge": {
"args": [],

@ -269,6 +269,16 @@
},
"test": "chromedriver_unittests"
},
{
"merge": {
"args": [],
"script": "//testing/merge_scripts/standard_gtest_merge.py"
},
"swarming": {
"can_use_on_swarming_builders": true
},
"test": "color_unittests"
},
{
"merge": {
"args": [],
@ -1673,6 +1683,22 @@
},
"test": "chromedriver_unittests"
},
{
"merge": {
"args": [],
"script": "//testing/merge_scripts/standard_gtest_merge.py"
},
"swarming": {
"can_use_on_swarming_builders": true,
"dimension_sets": [
{
"cpu": "x86-64",
"os": "Windows-10-15063"
}
]
},
"test": "color_unittests"
},
{
"merge": {
"args": [],
@ -3518,6 +3544,22 @@
},
"test": "chromedriver_unittests"
},
{
"merge": {
"args": [],
"script": "//testing/merge_scripts/standard_gtest_merge.py"
},
"swarming": {
"can_use_on_swarming_builders": true,
"dimension_sets": [
{
"cpu": "x86-64",
"os": "Windows-10-15063"
}
]
},
"test": "color_unittests"
},
{
"merge": {
"args": [],
@ -5335,6 +5377,16 @@
},
"test": "chromedriver_unittests"
},
{
"merge": {
"args": [],
"script": "//testing/merge_scripts/standard_gtest_merge.py"
},
"swarming": {
"can_use_on_swarming_builders": true
},
"test": "color_unittests"
},
{
"merge": {
"args": [],
@ -6594,6 +6646,16 @@
},
"test": "chromedriver_unittests"
},
{
"merge": {
"args": [],
"script": "//testing/merge_scripts/standard_gtest_merge.py"
},
"swarming": {
"can_use_on_swarming_builders": true
},
"test": "color_unittests"
},
{
"merge": {
"args": [],

@ -735,6 +735,10 @@
"label": "//ui/gfx:color_transform_fuzzer",
"type": "fuzzer",
},
"color_unittests": {
"label": "//ui/color:color_unittests",
"type": "console_test_launcher",
},
"comfort_noise_decoder_fuzzer": {
"label": "//third_party/webrtc/test/fuzzers:comfort_noise_decoder_fuzzer",
"type": "fuzzer",

@ -375,6 +375,7 @@
'idempotent': False, # https://crbug.com/923426#c27
},
},
'color_unittests': {},
'cros_browser_sanity_test': {},
'crypto_unittests': {},
'display_unittests': {},
@ -2283,6 +2284,7 @@
],
},
'cast_unittests': {},
'color_unittests': {},
'components_browsertests': {},
'components_unittests': {
'android_swarming': {

@ -824,6 +824,51 @@
},
"test": "chrome_public_test_vr_apk"
},
{
"args": [
"--gs-results-bucket=chromium-result-details",
"--recover-devices"
],
"isolate_coverage_data": true,
"merge": {
"args": [
"--bucket",
"chromium-result-details",
"--test-name",
"color_unittests"
],
"script": "//build/android/pylib/results/presentation/test_results_presentation.py"
},
"swarming": {
"can_use_on_swarming_builders": true,
"cipd_packages": [
{
"cipd_package": "infra/tools/luci/logdog/butler/${platform}",
"location": "bin",
"revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
}
],
"dimension_sets": [
{
"device_os": "KTU84P",
"device_os_type": "userdebug",
"device_type": "hammerhead",
"os": "Android"
}
],
"output_links": [
{
"link": [
"https://luci-logdog.appspot.com/v/?s",
"=android%2Fswarming%2Flogcats%2F",
"${TASK_ID}%2F%2B%2Funified_logcats"
],
"name": "shard #${SHARD_INDEX} logcats"
}
]
},
"test": "color_unittests"
},
{
"args": [
"--gs-results-bucket=chromium-result-details",

@ -17,6 +17,7 @@ capture_unittests
cast_unittests
cc_unittests
chrome_app_unittests
color_unittests
components_browsertests
components_unittests
compositor_unittests

48
ui/color/BUILD.gn Normal file

@ -0,0 +1,48 @@
# Copyright 2019 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import("//build/config/jumbo.gni")
import("//testing/test.gni")
jumbo_component("color") {
sources = [
"color_id.h",
"color_mixer.cc",
"color_mixer.h",
"color_provider.cc",
"color_provider.h",
"color_recipe.cc",
"color_recipe.h",
"color_set.cc",
"color_set.h",
"color_transform.cc",
"color_transform.h",
"color_variant.h",
]
defines = [ "IS_COLOR_IMPL" ]
public_deps = [
"//base",
"//skia",
"//ui/gfx:color_utils",
]
}
test("color_unittests") {
sources = [
"color_mixer_unittest.cc",
"color_provider_unittest.cc",
"color_recipe_unittest.cc",
"color_transform_unittest.cc",
"color_unittest_utils.h",
"run_all_unittests.cc",
]
deps = [
":color",
"//base/test:test_support",
"//testing/gtest",
]
}

4
ui/color/DEPS Normal file

@ -0,0 +1,4 @@
include_rules = [
"+third_party/skia/include",
"+ui/gfx",
]

3
ui/color/OWNERS Normal file

@ -0,0 +1,3 @@
pkasting@chromium.org
# COMPONENT: UI

56
ui/color/color_id.h Normal file

@ -0,0 +1,56 @@
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_COLOR_COLOR_ID_H_
#define UI_COLOR_COLOR_ID_H_
namespace ui {
// ColorId contains identifiers for all input, intermediary, and output colors
// known to the core UI layer. Embedders can extend this enum with additional
// values that are understood by the ColorProvider implementation. Embedders
// define enum values from kUiColorsEnd. Values named beginning with "kColor"
// represent the actual colors; the rest are markers.
using ColorId = int;
enum ColorIds : ColorId {
kUiColorsStart = 0,
// TODO(pkasting): Define this list.
kColorX = kUiColorsStart,
// Embedders must start color IDs from this value.
kUiColorsEnd,
// Embedders must not assign IDs larger than this value. This is used to
// verify that color IDs and color set IDs are not interchanged.
kUiColorsLast = 0xffff
};
// ColorSetId contains identifiers for all distinct color sets known to the core
// UI layer. As with ColorId, embedders can extend this enum with additional
// values that are understood by the ColorProvider implementation. Embedders
// define enum values from kUiColorSetsEnd. Values named beginning with
// "kColorSet" represent the actual colors; the rest are markers.
using ColorSetId = int;
enum ColorSetIds : ColorSetId {
kUiColorSetsStart = kUiColorsLast + 1,
// TODO(pkasting): Define this list.
kColorSetX = kUiColorSetsStart,
// Embedders must start color set IDs from this value.
kUiColorSetsEnd,
};
// Verifies that |id| is a color ID, not a color set ID.
#define DCHECK_COLOR_ID_VALID(id) \
DCHECK_GE(id, kUiColorsStart); \
DCHECK_LE(id, kUiColorsLast)
// Verifies that |id| is a color set ID, not a color ID.
#define DCHECK_COLOR_SET_ID_VALID(id) DCHECK_GE(id, kUiColorSetsStart)
} // namespace ui
#endif // UI_COLOR_COLOR_ID_H_

72
ui/color/color_mixer.cc Normal file

@ -0,0 +1,72 @@
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/color/color_mixer.h"
#include "base/containers/adapters.h"
#include "base/stl_util.h"
#include "ui/color/color_recipe.h"
#include "ui/gfx/color_palette.h"
namespace ui {
ColorMixer::ColorMixer(const ColorMixer* previous_mixer)
: previous_mixer_(previous_mixer) {}
ColorMixer::ColorMixer(ColorMixer&&) noexcept = default;
ColorMixer& ColorMixer::operator=(ColorMixer&&) noexcept = default;
ColorMixer::~ColorMixer() = default;
void ColorMixer::AddSet(ColorSet&& set) {
DCHECK(FindSetWithId(set.id) == sets_.cend());
sets_.push_front(std::move(set));
}
ColorRecipe& ColorMixer::AddRecipe(ColorId id) {
DCHECK_COLOR_ID_VALID(id);
DCHECK(!base::Contains(recipes_, id));
return recipes_[id];
}
SkColor ColorMixer::GetInputColor(ColorId id) const {
DCHECK_COLOR_ID_VALID(id);
for (const auto& set : sets_) {
const auto i = set.colors.find(id);
if (i != set.colors.end())
return i->second;
}
return previous_mixer_ ? previous_mixer_->GetResultColor(id)
: gfx::kPlaceholderColor;
}
SkColor ColorMixer::GetOriginalColorFromSet(ColorId id,
ColorSetId set_id) const {
DCHECK_COLOR_ID_VALID(id);
DCHECK_COLOR_SET_ID_VALID(set_id);
const auto i = FindSetWithId(set_id);
if (i != sets_.end()) {
const auto j = i->colors.find(id);
if (j != i->colors.end())
return j->second;
}
return previous_mixer_ ? previous_mixer_->GetOriginalColorFromSet(id, set_id)
: gfx::kPlaceholderColor;
}
SkColor ColorMixer::GetResultColor(ColorId id) const {
DCHECK_COLOR_ID_VALID(id);
const SkColor color = GetInputColor(id);
const auto i = recipes_.find(id);
return (i == recipes_.end()) ? color : i->second.GenerateResult(color, *this);
}
ColorMixer::ColorSets::const_iterator ColorMixer::FindSetWithId(
ColorSetId id) const {
return std::find_if(sets_.cbegin(), sets_.cend(),
[id](const auto& set) { return set.id == id; });
}
} // namespace ui

86
ui/color/color_mixer.h Normal file

@ -0,0 +1,86 @@
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_COLOR_COLOR_MIXER_H_
#define UI_COLOR_COLOR_MIXER_H_
#include <forward_list>
#include <map>
#include "base/component_export.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/color/color_id.h"
#include "ui/color/color_set.h"
namespace ui {
class ColorRecipe;
// ColorMixer represents a single conceptual mapping of a set of inputs, via a
// collection of transforms, to a set of outputs. Examples of plausible
// ColorMixers are "the UI element colors, as constructed from core color
// primitive values", "the way a set of high contrast colors overwrites default
// values", "the final output colors for all parts of a single UI area", or
// "a layer that enforces contrast minima on a variety of inputs". ColorMixers
// are chained together into a pipeline by a ColorProvider, and thus may rely
// completely, partly, or not at all on the inputs and outputs of previous
// mixers in the pipeline.
class COMPONENT_EXPORT(COLOR) ColorMixer {
public:
// Having each ColorMixer know about the |previous_mixer| in the pipeline
// allows mixers to implement the pipeline directly and simplifies the API,
// compared to having each mixer report results (via e.g. Optional<SkColor>)
// to the ColorProvider, which would need to query different mixers in order.
explicit ColorMixer(const ColorMixer* previous_mixer = nullptr);
// ColorMixer is movable since it holds both sets and recipes, each of which
// might be expensive to copy.
ColorMixer(ColorMixer&&) noexcept;
ColorMixer& operator=(ColorMixer&&) noexcept;
~ColorMixer();
// Adds |set| to |sets_|. |set| must not have the same ID as any previously
// added sets, though it may contain colors with the same IDs as colors in
// those sets; in such cases, the last-added set takes priority.
void AddSet(ColorSet&& set);
// Adds a recipe for |id|, which must not already have an existing recipe.
// Returns a non-const ref to allow chaining calls to
// ColorRecipe::AddTransform().
ColorRecipe& AddRecipe(ColorId id);
// Returns the input color for |id|. First searches all |sets_| in reverse
// order; if not found, asks the previous mixer for the result color. If
// there is no previous mixer, returns gfx::kPlaceholderColor.
SkColor GetInputColor(ColorId id) const;
// Returns the color for |id| from |set_id|. If this mixer does not have that
// set, the request will be forwarded to the previous mixer. If there is no
// previous mixer, returns gfx::kPlaceholderColor.
SkColor GetOriginalColorFromSet(ColorId id, ColorSetId set_id) const;
// Returns the result color for |id|, that is, the result of applying any
// applicable recipe from |recipes_| to the relevant input color.
SkColor GetResultColor(ColorId id) const;
private:
using ColorSets = std::forward_list<ColorSet>;
// Returns an iterator to the set in |sets_| with ID |id|, or sets_.cend().
ColorSets::const_iterator FindSetWithId(ColorSetId id) const;
const ColorMixer* previous_mixer_;
ColorSets sets_;
// This uses std::map instead of base::flat_map since the recipes are inserted
// one at a time instead of all at once, and there may be a lot of them.
// TODO(pkasting): Consider unifying how sets and recipes are specified:
// either both at construction (at which point this can use a flat_map) or
// both built piecemeal (which would mean ColorSets should probably become a
// std::map as well).
std::map<ColorId, ColorRecipe> recipes_;
};
} // namespace ui
#endif // UI_COLOR_COLOR_MIXER_H_

@ -0,0 +1,240 @@
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/color/color_mixer.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/color/color_recipe.h"
#include "ui/color/color_unittest_utils.h"
#include "ui/gfx/color_palette.h"
namespace ui {
namespace {
// Tests that AddSet() changes the result of various other functions.
TEST(ColorMixerTest, AddSet) {
ColorMixer mixer;
EXPECT_EQ(gfx::kPlaceholderColor, mixer.GetInputColor(kColorTest0));
EXPECT_EQ(gfx::kPlaceholderColor,
mixer.GetOriginalColorFromSet(kColorTest0, kColorSetTest0));
EXPECT_EQ(gfx::kPlaceholderColor, mixer.GetResultColor(kColorTest0));
mixer.AddSet({kColorSetTest0, {{kColorTest0, SK_ColorGREEN}}});
EXPECT_EQ(SK_ColorGREEN, mixer.GetInputColor(kColorTest0));
EXPECT_EQ(SK_ColorGREEN,
mixer.GetOriginalColorFromSet(kColorTest0, kColorSetTest0));
EXPECT_EQ(SK_ColorGREEN, mixer.GetResultColor(kColorTest0));
}
// Tests that the recipe returned by AddRecipe() is respected by the mixer.
TEST(ColorMixerTest, AddRecipe) {
ColorMixer mixer;
mixer.AddRecipe(kColorTest0).AddTransform(FromColor(SK_ColorGREEN));
EXPECT_EQ(SK_ColorGREEN, mixer.GetResultColor(kColorTest0));
}
// Tests that GetInputColor() returns a placeholder color if the mixer has no
// recipes.
TEST(ColorMixerTest, GetInputColorNoInput) {
EXPECT_EQ(gfx::kPlaceholderColor, ColorMixer().GetInputColor(kColorTest0));
}
// Tests that GetInputColor() will find the color in a single input set and
// return a placeholder color for a color not in that set.
TEST(ColorMixerTest, GetInputColorOneSet) {
ColorMixer mixer;
mixer.AddSet({kColorSetTest0, {{kColorTest0, SK_ColorGREEN}}});
EXPECT_EQ(SK_ColorGREEN, mixer.GetInputColor(kColorTest0));
EXPECT_EQ(gfx::kPlaceholderColor, mixer.GetInputColor(kColorTest1));
}
// Tests that GetInputColor() will find the colors in multiple non-overlapping
// input sets.
TEST(ColorMixerTest, GetInputColorTwoSetsNonOverlapping) {
ColorMixer mixer;
mixer.AddSet({kColorSetTest0, {{kColorTest0, SK_ColorGREEN}}});
mixer.AddSet({kColorSetTest1, {{kColorTest1, SK_ColorRED}}});
EXPECT_EQ(SK_ColorGREEN, mixer.GetInputColor(kColorTest0));
EXPECT_EQ(SK_ColorRED, mixer.GetInputColor(kColorTest1));
}
// Tests that when multiple input sets specify the same ID, the last set added
// wins.
TEST(ColorMixerTest, GetInputColorTwoSetsOverlapping) {
ColorMixer mixer;
// These sets are intentionally added out of numeric order to ensure the set
// ID ordering is ignored.
mixer.AddSet({kColorSetTest0, {{kColorTest0, SK_ColorRED}}});
mixer.AddSet({kColorSetTest2, {{kColorTest0, SK_ColorBLUE}}});
mixer.AddSet({kColorSetTest1, {{kColorTest0, SK_ColorGREEN}}});
EXPECT_EQ(SK_ColorGREEN, mixer.GetInputColor(kColorTest0));
}
// Tests that when a mixer does not have a requested color for GetInputColor(),
// it forwards the request to the previous mixer.
TEST(ColorMixerTest, GetInputColorPreviousMixer) {
ColorMixer mixer0;
mixer0.AddSet({kColorSetTest0, {{kColorTest0, SK_ColorGREEN}}});
ColorMixer mixer1(&mixer0);
mixer1.AddSet({kColorSetTest1, {{kColorTest1, SK_ColorRED}}});
EXPECT_EQ(SK_ColorGREEN, mixer1.GetInputColor(kColorTest0));
}
// Tests that GetInputColor() on a given mixer ignores any recipe that mixer has
// for that color.
TEST(ColorMixerTest, GetInputColorIgnoresRecipe) {
ColorMixer mixer;
mixer.AddSet({kColorSetTest0, {{kColorTest0, SK_ColorGREEN}}});
mixer.AddRecipe(kColorTest0).AddTransform(GetColorWithMaxContrast());
EXPECT_EQ(SK_ColorGREEN, mixer.GetInputColor(kColorTest0));
}
// Tests that if GetInputColor() needs to reference the output of a previous
// mixer, it will reference the result color (i.e. after applying any recipe)
// rather than referencing that mixer's input color.
TEST(ColorMixerTest, GetInputColorRespectsRecipePreviousMixer) {
ColorMixer mixer0;
mixer0.AddSet({kColorSetTest0, {{kColorTest0, SK_ColorGREEN}}});
mixer0.AddRecipe(kColorTest0).AddTransform(GetColorWithMaxContrast());
ColorMixer mixer1(&mixer0);
mixer1.AddSet({kColorSetTest1, {{kColorTest1, SK_ColorRED}}});
EXPECT_EQ(color_utils::GetColorWithMaxContrast(SK_ColorGREEN),
mixer1.GetInputColor(kColorTest0));
}
// Tests that GetOriginalColorFromSet() returns a placeholder color when there
// are no ColorSets.
TEST(ColorMixerTest, GetOriginalColorFromSetNoSets) {
EXPECT_EQ(gfx::kPlaceholderColor,
ColorMixer().GetOriginalColorFromSet(kColorTest0, kColorSetTest0));
}
// Tests that GetOriginalColorFromSet() will find the color in a single input
// set and return a placeholder color for a color not in that set.
TEST(ColorMixerTest, GetOriginalColorFromSetOneSet) {
ColorMixer mixer;
mixer.AddSet({kColorSetTest0, {{kColorTest0, SK_ColorGREEN}}});
EXPECT_EQ(SK_ColorGREEN,
mixer.GetOriginalColorFromSet(kColorTest0, kColorSetTest0));
EXPECT_EQ(gfx::kPlaceholderColor,
mixer.GetOriginalColorFromSet(kColorTest1, kColorSetTest0));
EXPECT_EQ(gfx::kPlaceholderColor,
mixer.GetOriginalColorFromSet(kColorTest0, kColorSetTest1));
}
// Tests that GetOriginalColorFromSet() will find the colors in multiple
// non-overlapping input sets.
TEST(ColorMixerTest, GetOriginalColorFromSetTwoSetsNonOverlapping) {
ColorMixer mixer;
mixer.AddSet({kColorSetTest0, {{kColorTest0, SK_ColorGREEN}}});
mixer.AddSet({kColorSetTest1, {{kColorTest1, SK_ColorRED}}});
EXPECT_EQ(SK_ColorGREEN,
mixer.GetOriginalColorFromSet(kColorTest0, kColorSetTest0));
EXPECT_EQ(gfx::kPlaceholderColor,
mixer.GetOriginalColorFromSet(kColorTest1, kColorSetTest0));
EXPECT_EQ(gfx::kPlaceholderColor,
mixer.GetOriginalColorFromSet(kColorTest0, kColorSetTest1));
EXPECT_EQ(SK_ColorRED,
mixer.GetOriginalColorFromSet(kColorTest1, kColorSetTest1));
}
// Tests that when two input sets specify the same ID, GetOriginalColorFromSet()
// can retrieve either color, depending on the requested set.
TEST(ColorMixerTest, GetOriginalColorFromSetTwoSetsOverlapping) {
ColorMixer mixer;
mixer.AddSet({kColorSetTest0, {{kColorTest0, SK_ColorGREEN}}});
mixer.AddSet({kColorSetTest1, {{kColorTest0, SK_ColorRED}}});
EXPECT_EQ(SK_ColorGREEN,
mixer.GetOriginalColorFromSet(kColorTest0, kColorSetTest0));
EXPECT_EQ(SK_ColorRED,
mixer.GetOriginalColorFromSet(kColorTest0, kColorSetTest1));
}
// Tests that when a mixer does not have a requested color for
// GetOriginalColorFromSet(), it forwards the request to the previous mixer.
TEST(ColorMixerTest, GetOriginalColorFromSetPreviousMixer) {
ColorMixer mixer0;
mixer0.AddSet({kColorSetTest0, {{kColorTest0, SK_ColorGREEN}}});
ColorMixer mixer1(&mixer0);
mixer1.AddSet({kColorSetTest1, {{kColorTest1, SK_ColorRED}}});
EXPECT_EQ(SK_ColorGREEN,
mixer1.GetOriginalColorFromSet(kColorTest0, kColorSetTest0));
}
// Tests that GetOriginalColorFromSet() on a given mixer ignores any recipe that
// mixer has for that color.
TEST(ColorMixerTest, GetOriginalColorFromSetIgnoresRecipe) {
ColorMixer mixer;
mixer.AddSet({kColorSetTest0, {{kColorTest0, SK_ColorGREEN}}});
mixer.AddRecipe(kColorTest0).AddTransform(GetColorWithMaxContrast());
EXPECT_EQ(SK_ColorGREEN,
mixer.GetOriginalColorFromSet(kColorTest0, kColorSetTest0));
}
// Tests that if GetOriginalColorFromSet() needs to reference the input of a
// previous mixer, it will reference the input color (i.e. without applying any
// recipe) rather than referencing that mixer's result color.
TEST(ColorMixerTest, GetOriginalColorFromSetIgnoresRecipePreviousMixer) {
ColorMixer mixer0;
mixer0.AddSet({kColorSetTest0, {{kColorTest0, SK_ColorGREEN}}});
mixer0.AddRecipe(kColorTest0).AddTransform(GetColorWithMaxContrast());
ColorMixer mixer1(&mixer0);
mixer1.AddSet({kColorSetTest1, {{kColorTest1, SK_ColorRED}}});
EXPECT_EQ(SK_ColorGREEN,
mixer1.GetOriginalColorFromSet(kColorTest0, kColorSetTest0));
}
// Tests that GetResultColor() returns a placeholder color when there are no
// ColorSets or recipes.
TEST(ColorMixerTest, GetResultColorNoInput) {
EXPECT_EQ(gfx::kPlaceholderColor, ColorMixer().GetResultColor(kColorTest0));
}
// Tests that GetResultColor() returns its input color when there are no
// recipes.
TEST(ColorMixerTest, GetResultColorNoRecipe) {
ColorMixer mixer;
mixer.AddSet({kColorSetTest0, {{kColorTest0, SK_ColorGREEN}}});
EXPECT_EQ(SK_ColorGREEN, mixer.GetResultColor(kColorTest0));
}
// Tests that GetResultColor() does not require an input set to provide an
// initial value for its requested color.
TEST(ColorMixerTest, GetResultColorNoSet) {
ColorMixer mixer;
mixer.AddRecipe(kColorTest0).AddTransform(FromColor(SK_ColorGREEN));
mixer.AddRecipe(kColorTest1).AddTransform(GetColorWithMaxContrast());
EXPECT_EQ(SK_ColorGREEN, mixer.GetResultColor(kColorTest0));
EXPECT_NE(gfx::kPlaceholderColor, mixer.GetResultColor(kColorTest1));
}
// Tests that having an initial value for a requested color will not affect the
// output of GetResultColor() if its recipe overrides it.
TEST(ColorMixerTest, GetResultColorIgnoresSet) {
ColorMixer mixer;
mixer.AddSet({kColorSetTest0,
{{kColorTest0, SK_ColorWHITE}, {kColorTest1, SK_ColorBLACK}}});
mixer.AddRecipe(kColorTest0).AddTransform(FromColor(SK_ColorGREEN));
mixer.AddRecipe(kColorTest1).AddTransform(FromColor(SK_ColorGREEN));
EXPECT_EQ(SK_ColorGREEN, mixer.GetResultColor(kColorTest0));
EXPECT_EQ(SK_ColorGREEN, mixer.GetResultColor(kColorTest1));
}
// Tests that GetResultColor() can reference other result colors, each of which
// will have its recipe applied.
TEST(ColorMixerTest, GetResultColorChained) {
ColorMixer mixer;
mixer.AddSet({kColorSetTest0, {{kColorTest1, SK_ColorWHITE}}});
mixer.AddRecipe(kColorTest0).AddTransform(FromColor(gfx::kGoogleBlue050));
mixer.AddRecipe(kColorTest1)
.AddTransform(GetColorWithMaxContrast())
.AddTransform(BlendTowardMaxContrast(0x29));
mixer.AddRecipe(kColorTest2)
.AddTransform(FromColor(gfx::kGoogleBlue500))
.AddTransform(BlendForMinContrast(kColorTest1, kColorTest0));
EXPECT_EQ(SkColorSetRGB(0x89, 0xB3, 0xF8), mixer.GetResultColor(kColorTest2));
}
} // namespace
} // namespace ui

@ -0,0 +1,44 @@
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/color/color_provider.h"
#include <utility>
#include "ui/color/color_mixer.h"
#include "ui/gfx/color_palette.h"
namespace ui {
ColorMixer* ColorProvider::AddMixer() {
// Adding a mixer could change any of the result colors.
cache_.clear();
// Supply each new mixer with the previous mixer in the pipeline; this way
// GetColor() need not query each mixer in order, but simply ask the last
// mixer for its result, and trust mixers to query each other back up the
// chain as needed.
mixers_.emplace_front(mixers_.empty() ? nullptr : &mixers_.front());
return &mixers_.front();
}
SkColor ColorProvider::GetColor(ColorId id, ColorVariant variant) const {
DCHECK_COLOR_ID_VALID(id);
if (mixers_.empty())
return gfx::kPlaceholderColor;
// Only compute the result color when it's not already in the cache.
auto i = cache_.find(id);
if (i == cache_.end())
i = cache_.insert({id, mixers_.front().GetResultColor(id)}).first;
return i->second;
}
ColorProvider::ColorProvider() = default;
ColorProvider::~ColorProvider() = default;
} // namespace ui

57
ui/color/color_provider.h Normal file

@ -0,0 +1,57 @@
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_COLOR_COLOR_PROVIDER_H_
#define UI_COLOR_COLOR_PROVIDER_H_
#include <forward_list>
#include <map>
#include "base/component_export.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/color/color_id.h"
#include "ui/color/color_mixer.h"
#include "ui/color/color_variant.h"
namespace ui {
// A ColorProvider holds the complete pipeline of ColorMixers that compute
// result colors for UI elements. ColorProvider is meant to be a long-lived
// object whose internal list of mixers does not change after initial
// construction. Separate ColorProviders should be instantiated for e.g.
// windows with different themes.
// TODO(pkasting): Figure out ownership model and lifetime.
class COMPONENT_EXPORT(COLOR) ColorProvider {
public:
ColorProvider();
// There should be no reason to copy or move a ColorProvider.
ColorProvider(const ColorProvider&) = delete;
ColorProvider& operator=(const ColorProvider&) = delete;
~ColorProvider();
// Adds a mixer to the end of the current color pipeline. Returns a pointer
// to the added mixer so callers can subsequently add sets and/or recipes.
ColorMixer* AddMixer();
// Returns the result color for |id| by applying the effects of each mixer in
// order. Returns gfx::kPlaceholderColor if no mixer knows how to construct
// |id|.
// TODO(pkasting): Current |variant| has no effect; figure out how to support
// it.
SkColor GetColor(ColorId id, ColorVariant variant = ColorVariant()) const;
private:
// The entire color pipeline, in reverse order (that is, the "last" mixer is
// at the front).
std::forward_list<ColorMixer> mixers_;
// Caches the results of calls to GetColor(). This is invalidated by
// AddMixer(). Uses a std::map rather than a base::flat_map since it has
// frequent inserts and could grow very large.
mutable std::map<ColorId, SkColor> cache_;
};
} // namespace ui
#endif // UI_COLOR_COLOR_PROVIDER_H_

@ -0,0 +1,67 @@
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/color/color_provider.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/color/color_unittest_utils.h"
#include "ui/gfx/color_palette.h"
namespace ui {
namespace {
// Tests that AddMixer() returns non-null pointers, implying addition was
// successful. (Other tests below will verify the mixers have an effect.)
TEST(ColorProviderTest, AddMixer) {
ColorProvider provider;
EXPECT_NE(nullptr, provider.AddMixer());
EXPECT_NE(nullptr, provider.AddMixer());
}
// Tests that when there are no mixers, GetColor() returns a placeholder value.
TEST(ColorProviderTest, GetColorNoMixers) {
EXPECT_EQ(gfx::kPlaceholderColor, ColorProvider().GetColor(kColorTest0));
}
// Tests that when there is a single mixer, GetColor() makes use of it where
// possible.
TEST(ColorProviderTest, SingleMixer) {
ColorProvider provider;
provider.AddMixer()->AddSet({kColorSetTest0, {{kColorTest0, SK_ColorGREEN}}});
EXPECT_EQ(SK_ColorGREEN, provider.GetColor(kColorTest0));
EXPECT_EQ(gfx::kPlaceholderColor, provider.GetColor(kColorTest1));
}
// Tests that when there are multiple non-overlapping mixers, GetColor() makes
// use of both.
TEST(ColorProviderTest, NonOverlappingMixers) {
ColorProvider provider;
provider.AddMixer()->AddSet({kColorSetTest0, {{kColorTest0, SK_ColorGREEN}}});
provider.AddMixer()->AddSet({kColorSetTest1, {{kColorTest1, SK_ColorRED}}});
EXPECT_EQ(SK_ColorGREEN, provider.GetColor(kColorTest0));
EXPECT_EQ(SK_ColorRED, provider.GetColor(kColorTest1));
}
// Tests that when mixers supply overlapping color specifications, the last one
// added takes priority.
TEST(ColorProviderTest, OverlappingMixers) {
ColorProvider provider;
provider.AddMixer()->AddSet({kColorSetTest0, {{kColorTest0, SK_ColorGREEN}}});
provider.AddMixer()->AddSet({kColorSetTest0, {{kColorTest0, SK_ColorRED}}});
EXPECT_EQ(SK_ColorRED, provider.GetColor(kColorTest0));
}
// Tests that repeated calls for the same color do not produce incorrect values.
// This attempts to verify that nothing is badly wrong with color caching.
TEST(ColorProviderTest, Caching) {
ColorProvider provider;
provider.AddMixer()->AddSet({kColorSetTest0, {{kColorTest0, SK_ColorGREEN}}});
EXPECT_EQ(SK_ColorGREEN, provider.GetColor(kColorTest0));
EXPECT_EQ(SK_ColorGREEN, provider.GetColor(kColorTest0));
provider.AddMixer()->AddSet({kColorSetTest0, {{kColorTest0, SK_ColorRED}}});
EXPECT_EQ(SK_ColorRED, provider.GetColor(kColorTest0));
}
} // namespace
} // namespace ui

33
ui/color/color_recipe.cc Normal file

@ -0,0 +1,33 @@
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/color/color_recipe.h"
#include <utility>
#include "ui/color/color_mixer.h"
namespace ui {
ColorRecipe::ColorRecipe() = default;
ColorRecipe::ColorRecipe(ColorRecipe&&) noexcept = default;
ColorRecipe& ColorRecipe::operator=(ColorRecipe&&) noexcept = default;
ColorRecipe::~ColorRecipe() = default;
ColorRecipe& ColorRecipe::AddTransform(ColorTransform&& transform) {
transforms_.push_back(std::move(transform));
return *this;
}
SkColor ColorRecipe::GenerateResult(SkColor input,
const ColorMixer& mixer) const {
for (const auto& transform : transforms_)
input = transform.Run(input, mixer);
return input;
}
} // namespace ui

45
ui/color/color_recipe.h Normal file

@ -0,0 +1,45 @@
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_COLOR_COLOR_RECIPE_H_
#define UI_COLOR_COLOR_RECIPE_H_
#include <list>
#include "base/component_export.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/color/color_transform.h"
namespace ui {
class ColorMixer;
// A ColorRecipe describes how to construct an output color from a series of
// transforms. Recipes take an input color and mixer, then apply their
// transforms in order to produce the output. This means that a recipe with no
// transforms will return its input color unchanged.
class COMPONENT_EXPORT(COLOR) ColorRecipe {
public:
ColorRecipe();
// ColorRecipe is movable since it holds the full list of transforms, which
// might be expensive to copy.
ColorRecipe(ColorRecipe&&) noexcept;
ColorRecipe& operator=(ColorRecipe&&) noexcept;
~ColorRecipe();
// Adds a transform to the end of the current recipe. Returns a non-const ref
// to allow chaining calls.
ColorRecipe& AddTransform(ColorTransform&& transform);
// Generates the output color for |input| by applying all transforms. |mixer|
// is passed to each transform, since it might need to request other colors.
SkColor GenerateResult(SkColor input, const ColorMixer& mixer) const;
private:
std::list<ColorTransform> transforms_;
};
} // namespace ui
#endif // UI_COLOR_COLOR_RECIPE_H_

@ -0,0 +1,65 @@
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/color/color_recipe.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/color/color_mixer.h"
#include "ui/color/color_set.h"
#include "ui/color/color_unittest_utils.h"
#include "ui/gfx/color_palette.h"
namespace ui {
namespace {
// Tests that a recipe with no transforms passes through its input color
// unchanged.
TEST(ColorRecipeTest, EmptyRecipeIsPassthrough) {
const ColorRecipe recipe;
const auto verify_passthrough = [&](SkColor input) {
EXPECT_EQ(input, recipe.GenerateResult(input, ColorMixer()));
};
verify_passthrough(SK_ColorBLACK);
verify_passthrough(SK_ColorWHITE);
verify_passthrough(SK_ColorRED);
}
// Tests that a transform in a recipe has an effect.
TEST(ColorRecipeTest, OneTransform) {
constexpr SkColor kOutput = SK_ColorGREEN;
ColorRecipe recipe;
recipe.AddTransform(FromColor(kOutput));
const auto verify_transform = [&](SkColor input) {
EXPECT_EQ(kOutput, recipe.GenerateResult(input, ColorMixer()));
};
verify_transform(SK_ColorBLACK);
verify_transform(SK_ColorWHITE);
verify_transform(SK_ColorRED);
}
// Tests that in a recipe with multiple transforms, each is applied.
TEST(ColorRecipeTest, ChainedTransforms) {
ColorRecipe recipe;
recipe.AddTransform(DeriveDefaultIconColor())
.AddTransform(BlendForMinContrast(kColorTest0));
constexpr SkColor kBackground = SK_ColorWHITE;
ColorMixer mixer;
mixer.AddSet({kColorSetTest0, {{kColorTest0, kBackground}}});
const auto verify_chain = [&](SkColor input) {
const SkColor color = recipe.GenerateResult(input, mixer);
// The DeriveDefaultIconColor transform should change the output color even
// when the BlendForMinContrast transform takes no action.
EXPECT_NE(input, color);
// The BlendForMinContrast transform should always be able to guarantee
// readable contrast against white.
EXPECT_GE(color_utils::GetContrastRatio(color, kBackground),
color_utils::kMinimumReadableContrastRatio);
};
verify_chain(SK_ColorBLACK);
verify_chain(SK_ColorWHITE);
verify_chain(SK_ColorRED);
}
} // namespace
} // namespace ui

18
ui/color/color_set.cc Normal file

@ -0,0 +1,18 @@
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/color/color_set.h"
namespace ui {
ColorSet::ColorSet(ColorSetId id, ColorMap&& colors)
: id(id), colors(std::move(colors)) {}
ColorSet::ColorSet(ColorSet&&) noexcept = default;
ColorSet& ColorSet::operator=(ColorSet&&) noexcept = default;
ColorSet::~ColorSet() = default;
} // namespace ui

41
ui/color/color_set.h Normal file

@ -0,0 +1,41 @@
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_COLOR_COLOR_SET_H_
#define UI_COLOR_COLOR_SET_H_
#include "base/component_export.h"
#include "base/containers/flat_map.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/color/color_id.h"
namespace ui {
// A ColorSet is a collection of identifiers mapped to actual SkColors, tagged
// with an overarching set ID. This is intended to be used as input to a
// ColorMixer, where it can be referenced by ColorRecipes. ColorSets are used
// to capture colors whose source is some external set of values. Examples of
// plausible ColorSets are "the system native colors on this platform", "the
// core Chrome colors", "custom theme colors", and "native high-contrast
// colors". ColorSets should consist of conceptually-related, orthogonal
// colors, and the ColorIds in them should be chosen to map well to the origin
// concepts, not to how those colors will be used in browser UI; use recipes to
// map input values from ColorSets to IDs that are referenced by UI elements, or
// to construct "pseudo-colors", transition values, and other colors that don't
// actually originate with an external source.
struct COMPONENT_EXPORT(COLOR) ColorSet {
using ColorMap = base::flat_map<ColorId, SkColor>;
ColorSet(ColorSetId id, ColorMap&& colors);
ColorSet(ColorSet&&) noexcept;
ColorSet& operator=(ColorSet&&) noexcept;
~ColorSet();
ColorSetId id;
ColorMap colors;
};
} // namespace ui
#endif // UI_COLOR_COLOR_SET_H_

@ -0,0 +1,82 @@
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/color/color_transform.h"
#include "base/bind.h"
#include "ui/color/color_mixer.h"
namespace ui {
ColorTransform BlendForMinContrast(
ColorId background_id,
base::Optional<ColorId> high_contrast_foreground_id,
float contrast_ratio) {
DCHECK_COLOR_ID_VALID(background_id);
const auto generator = [](ColorId background_id,
base::Optional<ColorId> high_contrast_foreground_id,
float contrast_ratio, SkColor input_color,
const ColorMixer& mixer) {
const SkColor background_color = mixer.GetResultColor(background_id);
const base::Optional<SkColor> foreground_color =
high_contrast_foreground_id.has_value()
? base::make_optional(
mixer.GetResultColor(high_contrast_foreground_id.value()))
: base::nullopt;
return color_utils::BlendForMinContrast(input_color, background_color,
foreground_color, contrast_ratio)
.color;
};
return base::Bind(generator, background_id, high_contrast_foreground_id,
contrast_ratio);
}
ColorTransform BlendTowardMaxContrast(SkAlpha alpha) {
const auto generator = [](SkAlpha alpha, SkColor input_color,
const ColorMixer& mixer) {
return color_utils::BlendTowardMaxContrast(input_color, alpha);
};
return base::Bind(generator, alpha);
}
ColorTransform DeriveDefaultIconColor() {
const auto generator = [](SkColor input_color, const ColorMixer& mixer) {
return color_utils::DeriveDefaultIconColor(input_color);
};
return base::Bind(generator);
}
ColorTransform FromColor(SkColor color) {
const auto generator = [](SkColor color, SkColor input_color,
const ColorMixer& mixer) { return color; };
return base::Bind(generator, color);
}
ColorTransform FromOriginalColorFromSet(ColorId id, ColorSetId set_id) {
DCHECK_COLOR_ID_VALID(id);
DCHECK_COLOR_SET_ID_VALID(set_id);
const auto generator = [](ColorId id, ColorSetId set_id, SkColor input_color,
const ColorMixer& mixer) {
return mixer.GetOriginalColorFromSet(id, set_id);
};
return base::Bind(generator, id, set_id);
}
ColorTransform FromInputColor(ColorId id) {
DCHECK_COLOR_ID_VALID(id);
const auto generator = [](ColorId id, SkColor input_color,
const ColorMixer& mixer) {
return mixer.GetInputColor(id);
};
return base::Bind(generator, id);
}
ColorTransform GetColorWithMaxContrast() {
const auto generator = [](SkColor input_color, const ColorMixer& mixer) {
return color_utils::GetColorWithMaxContrast(input_color);
};
return base::Bind(generator);
}
} // namespace ui

@ -0,0 +1,60 @@
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_COLOR_COLOR_TRANSFORM_H_
#define UI_COLOR_COLOR_TRANSFORM_H_
#include "base/callback.h"
#include "base/component_export.h"
#include "base/optional.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/color/color_id.h"
#include "ui/gfx/color_utils.h"
namespace ui {
class ColorMixer;
// ColorTransform is a function which transforms an |input| color, optionally
// using a |mixer| (to obtain other colors). ColorTransforms can be chained
// together in ColorRecipes, where each will be applied to the preceding
// transform's output.
using ColorTransform =
base::RepeatingCallback<SkColor(SkColor input, const ColorMixer& mixer)>;
// Functions to create common transform:
// A transform which modifies the input color to contrast with result color
// |background_id| by at least |contrast_ratio|, if possible. If
// |high_contrast_foreground_id| is non-null, it is used as the blend target.
COMPONENT_EXPORT(COLOR)
ColorTransform BlendForMinContrast(
ColorId background_id,
base::Optional<ColorId> high_contrast_foreground_id = base::nullopt,
float contrast_ratio = color_utils::kMinimumReadableContrastRatio);
// A transform which blends the input color toward the color with max contrast
// by |alpha|.
COMPONENT_EXPORT(COLOR) ColorTransform BlendTowardMaxContrast(SkAlpha alpha);
// A transform which returns the default icon color for the input color.
COMPONENT_EXPORT(COLOR) ColorTransform DeriveDefaultIconColor();
// A transform which outputs |color|.
COMPONENT_EXPORT(COLOR) ColorTransform FromColor(SkColor color);
// A transform which returns the color |id| from set |set_id|.
COMPONENT_EXPORT(COLOR)
ColorTransform FromOriginalColorFromSet(ColorId id, ColorSetId set_id);
// A transform which returns the input color |id|.
COMPONENT_EXPORT(COLOR) ColorTransform FromInputColor(ColorId id);
// A transform which returns the color with max contrast against the input
// color.
COMPONENT_EXPORT(COLOR) ColorTransform GetColorWithMaxContrast();
} // namespace ui
#endif // UI_COLOR_COLOR_TRANSFORM_H_

@ -0,0 +1,142 @@
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/color/color_transform.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/color/color_mixer.h"
#include "ui/color/color_unittest_utils.h"
#include "ui/gfx/color_palette.h"
namespace ui {
namespace {
// Tests that BlendForMinContrast(), with the default args, produces a transform
// that blends its input color to produce readable contrast against the
// specified background color.
TEST(ColorTransformTest, BlendForMinContrast) {
const ColorTransform transform = BlendForMinContrast(kColorTest0);
constexpr SkColor kBackground = SK_ColorWHITE;
ColorMixer mixer;
mixer.AddSet({kColorSetTest0, {{kColorTest0, kBackground}}});
const auto verify_contrast = [&](SkColor input) {
EXPECT_GE(
color_utils::GetContrastRatio(transform.Run(input, mixer), kBackground),
color_utils::kMinimumReadableContrastRatio);
};
verify_contrast(SK_ColorBLACK);
verify_contrast(SK_ColorWHITE);
verify_contrast(SK_ColorRED);
}
// Tests that BlendForMinContrast() supports optional args, which can be used to
// blend toward a specific foreground color and with a specific minimum contrast
// ratio.
TEST(ColorTransformTest, BlendForMinContrastOptionalArgs) {
constexpr float kMinContrast = 6.0f;
const ColorTransform transform =
BlendForMinContrast(kColorTest0, kColorTest1, kMinContrast);
constexpr SkColor kBackground = SK_ColorWHITE;
ColorMixer mixer;
mixer.AddSet(
{kColorSetTest0,
{{kColorTest0, kBackground}, {kColorTest1, gfx::kGoogleBlue900}}});
const auto verify_contrast = [&](SkColor input) {
EXPECT_GE(
color_utils::GetContrastRatio(transform.Run(input, mixer), kBackground),
kMinContrast);
};
verify_contrast(SK_ColorBLACK);
verify_contrast(SK_ColorWHITE);
verify_contrast(gfx::kGoogleBlue500);
}
// Tests that BlendTowardMaxContrast() produces a transform that blends its
// input color towards the color with max contrast.
TEST(ColorTransformTest, BlendTowardMaxContrast) {
constexpr SkAlpha kAlpha = 0x20;
const ColorTransform transform = BlendTowardMaxContrast(kAlpha);
const auto verify_blend = [&](SkColor input) {
const SkColor target = color_utils::GetColorWithMaxContrast(input);
EXPECT_LT(color_utils::GetContrastRatio(transform.Run(input, ColorMixer()),
target),
color_utils::GetContrastRatio(input, target));
};
verify_blend(SK_ColorBLACK);
verify_blend(SK_ColorWHITE);
verify_blend(SK_ColorRED);
}
// Tests that DeriveDefaultIconColor() produces a transform that changes its
// input color.
TEST(ColorTransformTest, DeriveDefaultIconColor) {
const ColorTransform transform = DeriveDefaultIconColor();
const auto verify_derive = [&](SkColor input) {
EXPECT_NE(input, transform.Run(input, ColorMixer()));
};
verify_derive(SK_ColorBLACK);
verify_derive(SK_ColorWHITE);
verify_derive(SK_ColorRED);
}
// Tests that FromColor() produces a transform that ignores the input color and
// always outputs a specified SkColor.
TEST(ColorTransformTest, FromColor) {
constexpr SkColor kOutput = SK_ColorGREEN;
const ColorTransform transform = FromColor(kOutput);
const auto verify_color = [&](SkColor input) {
EXPECT_EQ(kOutput, transform.Run(input, ColorMixer()));
};
verify_color(SK_ColorBLACK);
verify_color(SK_ColorWHITE);
verify_color(SK_ColorRED);
}
// Tests that FromOriginalColorFromSet() produces a transform that ignores the
// input color and always outputs a specified color from a specified color set.
TEST(ColorTransformTest, FromOriginalColorFromSet) {
const ColorTransform transform =
FromOriginalColorFromSet(kColorTest0, kColorSetTest0);
constexpr SkColor kSet0Test0Color = SK_ColorGREEN;
ColorMixer mixer;
mixer.AddSet({kColorSetTest0, {{kColorTest0, kSet0Test0Color}}});
mixer.AddSet({kColorSetTest1, {{kColorTest0, SK_ColorRED}}});
const auto verify_color = [&](SkColor input) {
EXPECT_EQ(kSet0Test0Color, transform.Run(input, mixer));
};
verify_color(SK_ColorBLACK);
verify_color(SK_ColorWHITE);
verify_color(SK_ColorRED);
}
// Tests that FromInputColor() produces a transform that ignores
// the input color and always outputs a specified color.
TEST(ColorTransformTest, FromInputColor) {
const ColorTransform transform = FromInputColor(kColorTest0);
constexpr SkColor kTest0Color = SK_ColorGREEN;
ColorMixer mixer;
mixer.AddSet({kColorSetTest0,
{{kColorTest0, kTest0Color}, {kColorTest1, SK_ColorRED}}});
const auto verify_color = [&](SkColor input) {
EXPECT_EQ(kTest0Color, transform.Run(input, mixer));
};
verify_color(SK_ColorBLACK);
verify_color(SK_ColorWHITE);
verify_color(SK_ColorRED);
} // namespace
// Tests that GetColorWithMaxContrast transforms white to the darkest color.
TEST(ColorTransformTest, GetColorWithMaxContrast) {
const ColorTransform transform = GetColorWithMaxContrast();
constexpr SkColor kNewDarkestColor = gfx::kGoogleGrey500;
const SkColor default_darkest_color =
color_utils::SetDarkestColorForTesting(kNewDarkestColor);
constexpr SkColor kLightestColor = SK_ColorWHITE;
EXPECT_EQ(kNewDarkestColor, transform.Run(kLightestColor, ColorMixer()));
color_utils::SetDarkestColorForTesting(default_darkest_color);
EXPECT_EQ(default_darkest_color, transform.Run(kLightestColor, ColorMixer()));
}
} // namespace
} // namespace ui

@ -0,0 +1,36 @@
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_COLOR_COLOR_UNITTEST_UTILS_H_
#define UI_COLOR_COLOR_UNITTEST_UTILS_H_
#include "ui/color/color_id.h"
namespace ui {
// Test-only color IDs.
enum TestColorIds : ColorId {
kTestColorsStart = kUiColorsEnd,
kColorTest0 = kTestColorsStart,
kColorTest1,
kColorTest2,
kTestColorsEnd,
};
// Test-only color set IDs.
enum TestColorSetIds : ColorSetId {
kTestColorSetsStart = kUiColorSetsEnd,
kColorSetTest0 = kTestColorSetsStart,
kColorSetTest1,
kColorSetTest2,
kTestColorSetsEnd,
};
} // namespace ui
#endif // UI_COLOR_COLOR_UNITTEST_UTILS_H_

47
ui/color/color_variant.h Normal file

@ -0,0 +1,47 @@
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_COLOR_COLOR_VARIANT_H_
#define UI_COLOR_COLOR_VARIANT_H_
#include "base/component_export.h"
namespace ui {
// ColorVariant represents common not-mutually-exclusive properties that affect
// many colors, such as "inactive" or "incognito". This does not cover process-
// or theme-wide attributes (such as "dark mode enabled"), which should be
// handled by the code that fills in ColorSets or in individual ColorRecipes;
// nor does it cover more narrowly-scoped, mutually-exclusive properties (such
// as "pressed" vs. "hovered"), which should be tracked with separate ColorIds.
class COMPONENT_EXPORT(COLOR) ColorVariant {
public:
ColorVariant() = default;
// ColorVariant is copyable because its underlying representation is small and
// integral.
ColorVariant(const ColorVariant&) = default;
ColorVariant& operator=(const ColorVariant&) = default;
~ColorVariant() = default;
// Setters return a non-const ref to allow chaining at construction.
ColorVariant& set_inactive(bool inactive) {
inactive_ = inactive;
return *this;
}
ColorVariant& set_incognito(bool incognito) {
incognito_ = incognito;
return *this;
}
bool inactive() const { return inactive_; }
bool incognito() const { return incognito_; }
private:
bool inactive_ = false;
bool incognito_ = false;
};
} // namespace ui
#endif // UI_COLOR_COLOR_VARIANT_H_

@ -0,0 +1,15 @@
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/bind.h"
#include "base/test/launcher/unit_test_launcher.h"
#include "base/test/test_suite.h"
int main(int argc, char* argv[]) {
base::TestSuite test_suite(argc, argv);
return base::LaunchUnitTests(
argc, argv,
base::BindRepeating(&base::TestSuite::Run,
base::Unretained(&test_suite)));
}