color_transform.cc 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  1. // Copyright 2019 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "ui/color/color_transform.h"
  5. #include "base/bind.h"
  6. #include "base/logging.h"
  7. #include "base/strings/string_number_conversions.h"
  8. #include "third_party/skia/include/core/SkColor.h"
  9. #include "ui/color/color_mixer.h"
  10. #include "ui/color/color_provider_utils.h"
  11. namespace ui {
  12. ColorTransform::ColorTransform(Callback callback)
  13. : callback_(std::move(callback)) {}
  14. ColorTransform::ColorTransform(SkColor color) {
  15. const auto generator = [](SkColor color, SkColor input_color,
  16. const ColorMixer& mixer) {
  17. DVLOG(2) << "ColorTransform From Color:"
  18. << " Input Color:" << SkColorName(input_color)
  19. << " Color: " << SkColorName(color)
  20. << " Result Color: " << SkColorName(color);
  21. return color;
  22. };
  23. callback_ = base::BindRepeating(generator, color);
  24. }
  25. ColorTransform::ColorTransform(ColorId id) {
  26. const auto generator = [](ColorId id, SkColor input_color,
  27. const ColorMixer& mixer) {
  28. SkColor result_color = mixer.GetResultColor(id);
  29. DVLOG(2) << "ColorTransform FromMixer:"
  30. << " Input Color:" << SkColorName(input_color)
  31. << " Color Id: " << ColorIdName(id)
  32. << " Result Color: " << SkColorName(result_color);
  33. return result_color;
  34. };
  35. callback_ = base::BindRepeating(generator, id);
  36. }
  37. ColorTransform::ColorTransform(const ColorTransform&) = default;
  38. ColorTransform& ColorTransform::operator=(const ColorTransform&) = default;
  39. ColorTransform::~ColorTransform() = default;
  40. SkColor ColorTransform::Run(SkColor input_color,
  41. const ColorMixer& mixer) const {
  42. return callback_.Run(input_color, mixer);
  43. }
  44. ColorTransform AlphaBlend(ColorTransform foreground_transform,
  45. ColorTransform background_transform,
  46. SkAlpha alpha) {
  47. const auto generator = [](ColorTransform foreground_transform,
  48. ColorTransform background_transform, SkAlpha alpha,
  49. SkColor input_color, const ColorMixer& mixer) {
  50. const SkColor foreground_color =
  51. foreground_transform.Run(input_color, mixer);
  52. const SkColor background_color =
  53. background_transform.Run(input_color, mixer);
  54. const SkColor result_color =
  55. color_utils::AlphaBlend(foreground_color, background_color, alpha);
  56. DVLOG(2) << "ColorTransform AlphaBlend:"
  57. << " Input Color: " << SkColorName(input_color)
  58. << " FG Transform: " << SkColorName(foreground_color)
  59. << " BG Transform: " << SkColorName(background_color)
  60. << " Alpha: " << base::NumberToString(alpha)
  61. << " Result Color: " << SkColorName(result_color);
  62. return result_color;
  63. };
  64. return base::BindRepeating(generator, std::move(foreground_transform),
  65. std::move(background_transform), alpha);
  66. }
  67. ColorTransform BlendForMinContrast(
  68. ColorTransform foreground_transform,
  69. ColorTransform background_transform,
  70. absl::optional<ColorTransform> high_contrast_foreground_transform,
  71. float contrast_ratio) {
  72. const auto generator =
  73. [](ColorTransform foreground_transform,
  74. ColorTransform background_transform,
  75. absl::optional<ColorTransform> high_contrast_foreground_transform,
  76. float contrast_ratio, SkColor input_color, const ColorMixer& mixer) {
  77. const SkColor foreground_color =
  78. foreground_transform.Run(input_color, mixer);
  79. const SkColor background_color =
  80. background_transform.Run(input_color, mixer);
  81. const absl::optional<SkColor> high_contrast_foreground =
  82. high_contrast_foreground_transform.has_value()
  83. ? absl::make_optional(
  84. high_contrast_foreground_transform.value().Run(
  85. input_color, mixer))
  86. : absl::nullopt;
  87. const SkColor result_color =
  88. color_utils::BlendForMinContrast(foreground_color, background_color,
  89. high_contrast_foreground,
  90. contrast_ratio)
  91. .color;
  92. DVLOG(2) << "ColorTransform BlendForMinContrast:"
  93. << " FG Transform Color: " << SkColorName(foreground_color)
  94. << " BG Transform Color: " << SkColorName(background_color)
  95. << " High Contrast Foreground: "
  96. << (high_contrast_foreground.has_value()
  97. ? SkColorName(high_contrast_foreground.value())
  98. : "<none>")
  99. << " Contrast Ratio: " << base::NumberToString(contrast_ratio)
  100. << " Result Color: " << SkColorName(result_color);
  101. return result_color;
  102. };
  103. return base::BindRepeating(generator, std::move(foreground_transform),
  104. std::move(background_transform),
  105. std::move(high_contrast_foreground_transform),
  106. contrast_ratio);
  107. }
  108. ColorTransform BlendForMinContrastWithSelf(ColorTransform transform,
  109. float contrast_ratio) {
  110. return BlendForMinContrast(transform, transform, absl::nullopt,
  111. contrast_ratio);
  112. }
  113. ColorTransform BlendTowardMaxContrast(ColorTransform transform, SkAlpha alpha) {
  114. const auto generator = [](ColorTransform transform, SkAlpha alpha,
  115. SkColor input_color, const ColorMixer& mixer) {
  116. const SkColor transform_color = transform.Run(input_color, mixer);
  117. const SkColor result_color =
  118. color_utils::BlendTowardMaxContrast(transform_color, alpha);
  119. DVLOG(2) << "ColorTransform BlendTowardMaxContrast:"
  120. << " Input Color:" << SkColorName(input_color)
  121. << " Transform Color: " << SkColorName(transform_color)
  122. << " Alpha: " << base::NumberToString(alpha)
  123. << " Result Color: " << SkColorName(result_color);
  124. return result_color;
  125. };
  126. return base::BindRepeating(generator, std::move(transform), alpha);
  127. }
  128. ColorTransform ContrastInvert(ColorTransform transform) {
  129. const auto generator = [](ColorTransform transform, SkColor input_color,
  130. const ColorMixer& mixer) {
  131. const SkColor foreground = transform.Run(input_color, mixer);
  132. const SkColor far_endpoint =
  133. color_utils::GetColorWithMaxContrast(foreground);
  134. const SkColor near_endpoint =
  135. color_utils::GetEndpointColorWithMinContrast(foreground);
  136. const float contrast_ratio =
  137. color_utils::GetContrastRatio(foreground, far_endpoint);
  138. const SkColor result_color =
  139. color_utils::BlendForMinContrast(foreground, near_endpoint,
  140. absl::nullopt, contrast_ratio)
  141. .color;
  142. DVLOG(2) << "ColorTransform ContrastInvert:"
  143. << " Input Color: " << SkColorName(input_color)
  144. << " Foreground: " << SkColorName(foreground)
  145. << " Far End: " << SkColorName(far_endpoint)
  146. << " Near End: " << SkColorName(near_endpoint)
  147. << " Contrast Ratio: " << base::NumberToString(contrast_ratio)
  148. << " Result Color: " << SkColorName(result_color);
  149. return result_color;
  150. };
  151. return base::BindRepeating(generator, std::move(transform));
  152. }
  153. ColorTransform DeriveDefaultIconColor(ColorTransform transform) {
  154. const auto generator = [](ColorTransform transform, SkColor input_color,
  155. const ColorMixer& mixer) {
  156. const SkColor transform_color = transform.Run(input_color, mixer);
  157. const SkColor result_color =
  158. color_utils::DeriveDefaultIconColor(transform_color);
  159. DVLOG(2) << "ColorTransform DeriveDefaultIconColor:"
  160. << " Input Color: " << SkColorName(input_color)
  161. << " Transform Color: " << SkColorName(transform_color)
  162. << " Result Color: " << SkColorName(result_color);
  163. return result_color;
  164. };
  165. return base::BindRepeating(generator, std::move(transform));
  166. }
  167. ColorTransform FromTransformInput() {
  168. const auto generator = [](SkColor input_color, const ColorMixer& mixer) {
  169. DVLOG(2) << "ColorTransform FromTransformInput: "
  170. << " Input/Result Color: " << SkColorName(input_color);
  171. return input_color;
  172. };
  173. return base::BindRepeating(generator);
  174. }
  175. ColorTransform GetColorWithMaxContrast(ColorTransform transform) {
  176. const auto generator = [](ColorTransform transform, SkColor input_color,
  177. const ColorMixer& mixer) {
  178. const SkColor transform_color = transform.Run(input_color, mixer);
  179. const SkColor result_color =
  180. color_utils::GetColorWithMaxContrast(transform_color);
  181. DVLOG(2) << "ColorTransform GetColorWithMaxContrast:"
  182. << " Input Color: " << SkColorName(input_color)
  183. << " Transform Color: " << SkColorName(transform_color)
  184. << " Result Color: " << SkColorName(result_color);
  185. return result_color;
  186. };
  187. return base::BindRepeating(generator, std::move(transform));
  188. }
  189. ColorTransform GetEndpointColorWithMinContrast(ColorTransform transform) {
  190. const auto generator = [](ColorTransform transform, SkColor input_color,
  191. const ColorMixer& mixer) {
  192. const SkColor transform_color = transform.Run(input_color, mixer);
  193. const SkColor result_color =
  194. color_utils::GetEndpointColorWithMinContrast(transform_color);
  195. DVLOG(2) << "ColorTransform GetEndPointColorWithMinContrast:"
  196. << " Input Color: " << SkColorName(input_color)
  197. << " Transform Color: " << SkColorName(transform_color)
  198. << " Result Color: " << SkColorName(result_color);
  199. return result_color;
  200. };
  201. return base::BindRepeating(generator, std::move(transform));
  202. }
  203. ColorTransform GetResultingPaintColor(ColorTransform foreground_transform,
  204. ColorTransform background_transform) {
  205. const auto generator = [](ColorTransform foreground_transform,
  206. ColorTransform background_transform,
  207. SkColor input_color, const ColorMixer& mixer) {
  208. const SkColor foreground_color =
  209. foreground_transform.Run(input_color, mixer);
  210. const SkColor background_color =
  211. background_transform.Run(input_color, mixer);
  212. const SkColor result_color =
  213. color_utils::GetResultingPaintColor(foreground_color, background_color);
  214. DVLOG(2) << "ColorTransform GetResultingPaintColor:"
  215. << " Input Color: " << SkColorName(input_color)
  216. << " FG Transform Color: " << SkColorName(foreground_color)
  217. << " BG Transform Color: " << SkColorName(background_color)
  218. << " Result Color: " << SkColorName(result_color);
  219. return result_color;
  220. };
  221. return base::BindRepeating(generator, std::move(foreground_transform),
  222. std::move(background_transform));
  223. }
  224. ColorTransform SelectBasedOnDarkInput(
  225. ColorTransform input_transform,
  226. ColorTransform output_transform_for_dark_input,
  227. ColorTransform output_transform_for_light_input) {
  228. const auto generator = [](ColorTransform input_transform,
  229. ColorTransform output_transform_for_dark_input,
  230. ColorTransform output_transform_for_light_input,
  231. SkColor input_color, const ColorMixer& mixer) {
  232. const SkColor color = input_transform.Run(input_color, mixer);
  233. const auto& output_transform = color_utils::IsDark(color)
  234. ? output_transform_for_dark_input
  235. : output_transform_for_light_input;
  236. const SkColor result_color = output_transform.Run(input_color, mixer);
  237. DVLOG(2) << "ColorTransform SelectBasedOnDarkInput:"
  238. << " Input Color: " << SkColorName(input_color)
  239. << " Input Transform: " << SkColorName(color)
  240. << " IsDark: " << (color_utils::IsDark(color) ? "true" : "false")
  241. << " Result Color: " << SkColorName(result_color);
  242. return result_color;
  243. };
  244. return base::BindRepeating(generator, std::move(input_transform),
  245. std::move(output_transform_for_dark_input),
  246. std::move(output_transform_for_light_input));
  247. }
  248. ColorTransform SetAlpha(ColorTransform transform, SkAlpha alpha) {
  249. const auto generator = [](ColorTransform transform, SkAlpha alpha,
  250. SkColor input_color, const ColorMixer& mixer) {
  251. const SkColor transform_color = transform.Run(input_color, mixer);
  252. const SkColor result_color = SkColorSetA(transform_color, alpha);
  253. DVLOG(2) << "ColorTransform SetAlpha:"
  254. << " Input Color: " << SkColorName(input_color)
  255. << " Transform Color: " << SkColorName(transform_color)
  256. << " Alpha: " << base::NumberToString(alpha)
  257. << " Result Color: " << SkColorName(result_color);
  258. return result_color;
  259. };
  260. return base::BindRepeating(generator, std::move(transform), alpha);
  261. }
  262. ColorTransform PickGoogleColor(ColorTransform color,
  263. ColorTransform background_color,
  264. float min_contrast) {
  265. const auto generator =
  266. [](ColorTransform transform, ColorTransform background_transform,
  267. float min_contrast, SkColor input_color, const ColorMixer& mixer) {
  268. const SkColor transform_color = transform.Run(input_color, mixer);
  269. const SkColor background_color =
  270. background_transform.Run(input_color, mixer);
  271. const SkColor result_color = color_utils::PickGoogleColor(
  272. transform_color, background_color, min_contrast);
  273. DVLOG(2) << "ColorTransform PickGoogleColor:"
  274. << " Input Color: " << SkColorName(input_color)
  275. << " Transform Color: " << SkColorName(transform_color)
  276. << " Background Color: " << SkColorName(background_color)
  277. << " Min Contrast: " << base::NumberToString(min_contrast)
  278. << " Result Color: " << SkColorName(result_color);
  279. return result_color;
  280. };
  281. return base::BindRepeating(generator, std::move(color),
  282. std::move(background_color), min_contrast);
  283. }
  284. ColorTransform HSLShift(ColorTransform color, color_utils::HSL hsl) {
  285. const auto generator = [](ColorTransform transform, color_utils::HSL hsl,
  286. SkColor input_color, const ColorMixer& mixer) {
  287. const SkColor transform_color = transform.Run(input_color, mixer);
  288. const SkColor result_color = color_utils::HSLShift(transform_color, hsl);
  289. DVLOG(2) << "ColorTransform HSLShift:"
  290. << " Input Color: " << SkColorName(input_color)
  291. << " Transform Color: " << SkColorName(transform_color)
  292. << " HSL: {" << base::NumberToString(hsl.h) << ", "
  293. << base::NumberToString(hsl.s) << ", "
  294. << base::NumberToString(hsl.l) << "}"
  295. << " Result Color: " << SkColorName(result_color);
  296. return result_color;
  297. };
  298. return base::BindRepeating(generator, std::move(color), hsl);
  299. }
  300. } // namespace ui