battery_image_source.cc 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. // Copyright 2020 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 "ash/system/power/battery_image_source.h"
  5. #include "ash/constants/ash_features.h"
  6. #include "ash/resources/vector_icons/vector_icons.h"
  7. #include "ash/style/ash_color_provider.h"
  8. #include "base/cxx17_backports.h"
  9. #include "ui/gfx/canvas.h"
  10. #include "ui/gfx/geometry/rect_conversions.h"
  11. #include "ui/gfx/geometry/rect_f.h"
  12. #include "ui/gfx/geometry/skia_conversions.h"
  13. #include "ui/gfx/paint_vector_icon.h"
  14. namespace {
  15. // The minimum height (in dp) of the charged region of the battery icon when the
  16. // battery is present and has a charge greater than 0.
  17. const int kMinVisualChargeLevel = 1;
  18. // These dimensions specify the largest possible rectangle that is fully
  19. // encompassed by the battery icon |kBatteryIcon|. This rectangle is the area
  20. // that is "filled" to show battery charge percentage.
  21. constexpr gfx::RectF kDefaultFillRect = gfx::RectF(7, 6, 6, 10);
  22. inline SkColor GetBatteryBadgeColor() {
  23. return ash::AshColorProvider::Get()->GetContentLayerColor(
  24. ash::AshColorProvider::ContentLayerType::kBatteryBadgeColor);
  25. }
  26. inline SkColor GetAlertColor() {
  27. return ash::AshColorProvider::Get()->GetContentLayerColor(
  28. ash::AshColorProvider::ContentLayerType::kIconColorAlert);
  29. }
  30. } // namespace
  31. namespace ash {
  32. BatteryImageSource::BatteryImageSource(
  33. const PowerStatus::BatteryImageInfo& info,
  34. int height,
  35. SkColor bg_color,
  36. SkColor fg_color,
  37. absl::optional<SkColor> badge_color)
  38. : gfx::CanvasImageSource(gfx::Size(height, height)),
  39. info_(info),
  40. bg_color_(bg_color),
  41. fg_color_(fg_color),
  42. badge_color_(badge_color.value_or(
  43. info.charge_percent > 50 ? GetBatteryBadgeColor() : fg_color)) {}
  44. BatteryImageSource::~BatteryImageSource() = default;
  45. void BatteryImageSource::Draw(gfx::Canvas* canvas) {
  46. // Draw the solid outline of the battery icon.
  47. PaintVectorIcon(canvas, kBatteryIcon, size().height(), fg_color_);
  48. canvas->Save();
  49. const float dsf = canvas->UndoDeviceScaleFactor();
  50. // All constants below are expressed relative to a canvas size of 20. The
  51. // actual canvas size (i.e. |size()|) may not be 20.
  52. const float kAssumedCanvasSize = 20;
  53. const float const_scale = dsf * size().height() / kAssumedCanvasSize;
  54. SkPath path;
  55. gfx::RectF fill_rect = kDefaultFillRect;
  56. fill_rect.Scale(const_scale);
  57. path.addRect(gfx::RectToSkRect(gfx::ToEnclosingRect(fill_rect)));
  58. cc::PaintFlags flags;
  59. SkRect icon_bounds = path.getBounds();
  60. // |charge_level| is a value between 0 and the visual height of the icon
  61. // representing the number of device pixels the battery image should be
  62. // shown charged. The exception is when |charge_level| is very low; in this
  63. // case, still draw 1dip of charge.
  64. float charge_level =
  65. std::floor(info_.charge_percent / 100.0 * icon_bounds.height());
  66. const float min_charge_level = dsf * kMinVisualChargeLevel;
  67. charge_level =
  68. base::clamp(charge_level, min_charge_level, icon_bounds.height());
  69. const float charge_y = icon_bounds.bottom() - charge_level;
  70. gfx::RectF clip_rect(0, charge_y, size().width() * dsf,
  71. size().height() * dsf);
  72. canvas->ClipRect(clip_rect);
  73. const SkColor alert_color = GetAlertColor();
  74. const bool use_alert_color =
  75. charge_level == min_charge_level && info_.alert_if_low;
  76. flags.setColor(use_alert_color ? alert_color : fg_color_);
  77. canvas->DrawPath(path, flags);
  78. canvas->Restore();
  79. if (info_.badge_outline) {
  80. if (ash::features::IsDarkLightModeEnabled()) {
  81. // The outline is always a vector icon with PATH_MODE_CLEAR. This means it
  82. // masks out anything previously drawn to the canvas. Give it any opaque
  83. // color so it will properly mask the rest of the battery icon. NOTE: The
  84. // view which renders this canvas must paint to its own non-opaque layer,
  85. // otherwise this outline will show up SK_ColorBlue instead of
  86. // transparent.
  87. PaintVectorIcon(canvas, *info_.badge_outline, size().height(),
  88. SK_ColorBLUE);
  89. } else {
  90. // The outline is a colored outline, so give it a color meant to be seen
  91. // by the user.
  92. const SkColor outline_color =
  93. info_.charge_percent > 50 ? fg_color_ : bg_color_;
  94. PaintVectorIcon(canvas, *info_.badge_outline, size().height(),
  95. outline_color);
  96. }
  97. }
  98. // Paint the badge over top of the battery, if applicable.
  99. if (info_.icon_badge) {
  100. const SkColor default_color =
  101. ash::features::IsDarkLightModeEnabled() ? fg_color_ : badge_color_;
  102. const SkColor badge_color = use_alert_color ? alert_color : default_color;
  103. PaintVectorIcon(canvas, *info_.icon_badge, size().height(), badge_color);
  104. }
  105. }
  106. bool BatteryImageSource::HasRepresentationAtAllScales() const {
  107. return true;
  108. }
  109. } // namespace ash