File: windows_caption_button.cc

package info (click to toggle)
chromium 139.0.7258.138-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 6,120,676 kB
  • sloc: cpp: 35,100,869; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (256 lines) | stat: -rw-r--r-- 9,291 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/ui/views/frame/windows_caption_button.h"

#include <memory>

#include "base/numerics/safe_conversions.h"
#include "base/win/windows_version.h"
#include "chrome/browser/themes/theme_properties.h"
#include "chrome/browser/ui/color/chrome_color_id.h"
#include "chrome/browser/ui/frame/window_frame_util.h"
#include "chrome/browser/ui/layout_constants.h"
#include "chrome/browser/ui/views/frame/browser_frame_view_win.h"
#include "chrome/browser/ui/views/frame/browser_view.h"
#include "chrome/browser/ui/views/frame/tab_strip_region_view.h"
#include "chrome/grit/theme_resources.h"
#include "ui/base/metadata/metadata_impl_macros.h"
#include "ui/base/theme_provider.h"
#include "ui/base/ui_base_features.h"
#include "ui/gfx/animation/tween.h"
#include "ui/gfx/color_utils.h"
#include "ui/gfx/geometry/rect_conversions.h"
#include "ui/gfx/geometry/skia_conversions.h"
#include "ui/gfx/scoped_canvas.h"

WindowsCaptionButton::WindowsCaptionButton(
    PressedCallback callback,
    BrowserFrameViewWin* frame_view,
    ViewID button_type,
    const std::u16string& accessible_name)
    : views::Button(std::move(callback)),
      frame_view_(frame_view),
      icon_painter_(CreateIconPainter()),
      button_type_(button_type) {
  SetAnimateOnStateChange(true);
  // Not focusable by default, only for accessibility.
  SetFocusBehavior(FocusBehavior::ACCESSIBLE_ONLY);
  GetViewAccessibility().SetName(accessible_name);
  SetID(button_type);
}

WindowsCaptionButton::~WindowsCaptionButton() = default;

std::unique_ptr<Windows10IconPainter>
WindowsCaptionButton::CreateIconPainter() {
  if (base::win::GetVersion() >= base::win::Version::WIN11) {
    return std::make_unique<Windows11IconPainter>();
  }
  return std::make_unique<Windows10IconPainter>();
}

gfx::Size WindowsCaptionButton::CalculatePreferredSize(
    const views::SizeBounds& available_size) const {
  const int width =
      WindowFrameUtil::kWindowsCaptionButtonWidth + GetBetweenButtonSpacing();

  // TODO(bsep): The sizes in this function are for 1x device scale and don't
  // match Windows button sizes at hidpi.
  int height = WindowFrameUtil::kWindowsCaptionButtonHeightRestored;
  if (!frame_view_->browser_view()->webui_tab_strip() &&
      frame_view_->IsMaximized()) {
    int maximized_height =
        frame_view_->browser_view()->ShouldDrawTabStrip()
            ? frame_view_->browser_view()->GetTabStripHeight()
            : frame_view_->TitlebarMaximizedVisualHeight();
    constexpr int kMaximizedBottomMargin = 2;
    maximized_height -= kMaximizedBottomMargin;
    height = std::min(height, maximized_height);
  }
  return gfx::Size(width, height);
}

SkColor WindowsCaptionButton::GetBaseForegroundColor() const {
  return GetColorProvider()->GetColor(
      GetWidget()->ShouldPaintAsActive()
          ? kColorCaptionButtonForegroundActive
          : kColorCaptionButtonForegroundInactive);
}

void WindowsCaptionButton::OnPaintBackground(gfx::Canvas* canvas) {
  // Paint the background of the button (the semi-transparent rectangle that
  // appears when you hover or press the button).
  const ui::ThemeProvider* theme_provider = GetThemeProvider();
  const SkColor bg_color =
      GetColorProvider()->GetColor(kColorCaptionButtonBackground);
  const SkAlpha theme_alpha = SkColorGetA(bg_color);
  gfx::Rect bounds = GetContentsBounds();
  bounds.Inset(gfx::Insets::TLBR(0, GetBetweenButtonSpacing(), 0, 0));

  if (theme_alpha > 0) {
    canvas->FillRect(
        bounds,
        SkColorSetA(
            bg_color,
            WindowFrameUtil::CalculateWindowsCaptionButtonBackgroundAlpha(
                theme_alpha)));
  }
  if (theme_provider->HasCustomImage(IDR_THEME_WINDOW_CONTROL_BACKGROUND)) {
    // Figure out what portion of the background image to display
    const int button_display_order = GetButtonDisplayOrderIndex();
    const int base_button_width = WindowFrameUtil::kWindowsCaptionButtonWidth;
    const int base_visual_spacing =
        WindowFrameUtil::kWindowsCaptionButtonVisualSpacing;
    const int src_x =
        button_display_order * (base_button_width + base_visual_spacing);
    const int src_y = 0;

    canvas->TileImageInt(
        *theme_provider->GetImageSkiaNamed(IDR_THEME_WINDOW_CONTROL_BACKGROUND),
        src_x, src_y, bounds.x(), bounds.y(), bounds.width(), bounds.height());
  }

  SkColor base_color;
  SkAlpha hovered_alpha, pressed_alpha;
  if (button_type_ == VIEW_ID_CLOSE_BUTTON) {
    base_color =
        GetColorProvider()->GetColor(kColorCaptionCloseButtonBackgroundHovered);
    hovered_alpha = SK_AlphaOPAQUE;
    pressed_alpha = 0x98;
  } else {
    // Match the native buttons.
    base_color = GetBaseForegroundColor();
    hovered_alpha = 0x1A;
    pressed_alpha = 0x33;

    if (theme_alpha > 0) {
      // Theme buttons have slightly increased opacity to make them stand out
      // against a visually-busy frame image.
      constexpr float kAlphaScale = 1.3f;
      hovered_alpha = base::ClampRound<SkAlpha>(hovered_alpha * kAlphaScale);
      pressed_alpha = base::ClampRound<SkAlpha>(pressed_alpha * kAlphaScale);
    }
  }

  SkAlpha alpha;
  if (GetState() == STATE_PRESSED) {
    alpha = pressed_alpha;
  } else {
    alpha = gfx::Tween::IntValueBetween(hover_animation().GetCurrentValue(),
                                        SK_AlphaTRANSPARENT, hovered_alpha);
  }
  canvas->FillRect(bounds, SkColorSetA(base_color, alpha));
}

void WindowsCaptionButton::PaintButtonContents(gfx::Canvas* canvas) {
  PaintSymbol(canvas);
}

int WindowsCaptionButton::GetBetweenButtonSpacing() const {
  const int display_order_index = GetButtonDisplayOrderIndex();
  return display_order_index == 0
             ? 0
             : WindowFrameUtil::kWindowsCaptionButtonVisualSpacing;
}

int WindowsCaptionButton::GetButtonDisplayOrderIndex() const {
  int button_display_order = 0;
  switch (button_type_) {
    case VIEW_ID_MINIMIZE_BUTTON:
      button_display_order = 0;
      break;
    case VIEW_ID_MAXIMIZE_BUTTON:
    case VIEW_ID_RESTORE_BUTTON:
      button_display_order = 1;
      break;
    case VIEW_ID_CLOSE_BUTTON:
      button_display_order = 2;
      break;
    default:
      NOTREACHED();
  }

  // Reverse the ordering if we're in RTL mode
  if (base::i18n::IsRTL()) {
    const int max_index = 2;
    button_display_order = max_index - button_display_order;
  }

  return button_display_order;
}

void WindowsCaptionButton::PaintSymbol(gfx::Canvas* canvas) {
  SkColor symbol_color = GetBaseForegroundColor();
  const SkColor hovered_color =
      GetColorProvider()->GetColor(kColorCaptionCloseButtonForegroundHovered);
  if (!GetEnabled() ||
      (!GetWidget()->ShouldPaintAsActive() && GetState() != STATE_HOVERED &&
       GetState() != STATE_PRESSED)) {
    symbol_color =
        SkColorSetA(symbol_color, SkColorGetA(GetColorProvider()->GetColor(
                                      kColorCaptionForegroundInactive)));
  } else if (button_type_ == VIEW_ID_CLOSE_BUTTON &&
             hover_animation().is_animating()) {
    symbol_color = gfx::Tween::ColorValueBetween(
        hover_animation().GetCurrentValue(), symbol_color, hovered_color);
  } else if (button_type_ == VIEW_ID_CLOSE_BUTTON &&
             (GetState() == STATE_HOVERED || GetState() == STATE_PRESSED)) {
    symbol_color = hovered_color;
  }

  gfx::ScopedCanvas scoped_canvas(canvas);
  const float scale = canvas->UndoDeviceScaleFactor();

  const int symbol_size_pixels = base::ClampRound(10 * scale);
  gfx::RectF bounds_rect(GetContentsBounds());
  bounds_rect.Scale(scale);
  gfx::Rect symbol_rect(gfx::ToEnclosingRect(bounds_rect));
  symbol_rect.ClampToCenteredSize(
      gfx::Size(symbol_size_pixels, symbol_size_pixels));

  cc::PaintFlags flags;
  flags.setAntiAlias(false);
  flags.setColor(symbol_color);
  flags.setStyle(cc::PaintFlags::kStroke_Style);
  const int stroke_width = base::ClampRound(scale);
  flags.setStrokeWidth(stroke_width);

  switch (button_type_) {
    case VIEW_ID_MINIMIZE_BUTTON:
      icon_painter_->PaintMinimizeIcon(canvas, symbol_rect, flags);
      return;

    case VIEW_ID_MAXIMIZE_BUTTON:
      icon_painter_->PaintMaximizeIcon(canvas, symbol_rect, flags);
      return;

    case VIEW_ID_RESTORE_BUTTON:
      icon_painter_->PaintRestoreIcon(canvas, symbol_rect, flags);
      return;

    case VIEW_ID_CLOSE_BUTTON: {
      // The close button's X is surrounded by a "halo" of transparent pixels.
      // When the X is white, the transparent pixels need to be a bit brighter
      // to be visible.
      const float stroke_halo =
          stroke_width * (symbol_color == hovered_color ? 0.1f : 0.05f);
      flags.setStrokeWidth(stroke_width + stroke_halo);

      icon_painter_->PaintCloseIcon(canvas, symbol_rect, flags);
      return;
    }

    default:
      NOTREACHED();
  }
}

BEGIN_METADATA(WindowsCaptionButton)
ADD_READONLY_PROPERTY_METADATA(int, BetweenButtonSpacing)
ADD_READONLY_PROPERTY_METADATA(int, ButtonDisplayOrderIndex)
ADD_READONLY_PROPERTY_METADATA(SkColor,
                               BaseForegroundColor,
                               ui::metadata::SkColorConverter)
END_METADATA