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
|
// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chromeos/ui/frame/default_frame_header.h"
#include "base/check.h"
#include "chromeos/ui/base/app_types.h"
#include "chromeos/ui/base/chromeos_ui_constants.h"
#include "chromeos/ui/base/window_properties.h"
#include "chromeos/ui/frame/caption_buttons/frame_caption_button_container_view.h"
#include "chromeos/ui/wm/window_util.h"
#include "third_party/skia/include/core/SkPath.h"
#include "ui/color/color_id.h"
#include "ui/color/color_provider.h"
#include "ui/compositor/layer.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/color_utils.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/views/view.h"
#include "ui/views/widget/native_widget_aura.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_delegate.h"
#include "ui/views/window/caption_button_layout_constants.h"
using views::Widget;
namespace {
// Tiles an image into an area, rounding the top corners.
void TileRoundRect(gfx::Canvas* canvas,
const cc::PaintFlags& flags,
const gfx::Rect& bounds,
int corner_radius) {
SkRect rect = gfx::RectToSkRect(bounds);
const SkScalar corner_radius_scalar = SkIntToScalar(corner_radius);
SkScalar radii[8] = {corner_radius_scalar,
corner_radius_scalar, // top-left
corner_radius_scalar,
corner_radius_scalar, // top-right
0,
0, // bottom-right
0,
0}; // bottom-left
// Antialiasing can result in blending a transparent pixel and
// leave non opaque alpha between the frame and the client area.
// Extend 1dp to make sure it's fully opaque.
rect.fBottom += 1;
SkPath path;
path.addRoundRect(rect, radii, SkPathDirection::kCW);
canvas->DrawPath(path, flags);
}
// For now, we should only apply dynamic color to the default frame header if
// the window is a system web app.
bool ShouldApplyDynamicColor(aura::Window* window) {
return window->GetProperty(chromeos::kAppTypeKey) ==
chromeos::AppType::SYSTEM_APP;
}
} // namespace
namespace chromeos {
///////////////////////////////////////////////////////////////////////////////
// DefaultFrameHeader, public:
DefaultFrameHeader::DefaultFrameHeader(
views::Widget* target_widget,
views::View* header_view,
chromeos::FrameCaptionButtonContainerView* caption_button_container)
: FrameHeader(target_widget, header_view) {
DCHECK(caption_button_container);
SetCaptionButtonContainer(caption_button_container);
}
DefaultFrameHeader::~DefaultFrameHeader() = default;
void DefaultFrameHeader::SetWidthInPixels(int width_in_pixels) {
if (width_in_pixels_ == width_in_pixels)
return;
width_in_pixels_ = width_in_pixels;
SchedulePaintForTitle();
}
void DefaultFrameHeader::UpdateFrameColors() {
aura::Window* target_window = GetTargetWindow();
if (!target_window) {
// b/302708285: This codepath is run during Widget teardown. In that
// situation, `target_window` might be null and we won't display the
// updated colors anyway.
return;
}
const SkColor active_frame_color =
target_window->GetProperty(kFrameActiveColorKey);
const SkColor inactive_frame_color =
target_window->GetProperty(kFrameInactiveColorKey);
bool updated = false;
// Update the frame if the frame color for the current active state changes.
if (active_frame_color_ != active_frame_color) {
active_frame_color_ = active_frame_color;
updated = mode() == Mode::MODE_ACTIVE;
}
if (inactive_frame_color_ != inactive_frame_color) {
inactive_frame_color_ = inactive_frame_color;
updated |= mode() == Mode::MODE_INACTIVE;
}
if (updated) {
StartTransitionAnimation(kDefaultFrameColorChangeAnimationDuration);
}
if (ShouldApplyDynamicColor(GetTargetWindow())) {
UpdateCaptionButtonColors(mode() == MODE_ACTIVE
? ui::kColorSysPrimary
: ui::kColorFrameCaptionButtonUnfocused);
} else {
UpdateCaptionButtonColors(std::nullopt);
}
}
///////////////////////////////////////////////////////////////////////////////
// DefaultFrameHeader, protected:
void DefaultFrameHeader::DoPaintHeader(gfx::Canvas* canvas) {
cc::PaintFlags flags;
if (ShouldApplyDynamicColor(GetTargetWindow())) {
flags.setColor(target_widget()->GetColorProvider()->GetColor(
GetColorIdForCurrentMode()));
} else {
flags.setColor(mode() == Mode::MODE_ACTIVE ? active_frame_color_
: inactive_frame_color_);
}
const int corner_radius = header_corner_radius();
flags.setAntiAlias(corner_radius > 0);
if (width_in_pixels_ > 0) {
canvas->Save();
float layer_scale =
target_widget()->GetNativeWindow()->layer()->device_scale_factor();
float canvas_scale = canvas->UndoDeviceScaleFactor();
gfx::Rect rect =
ScaleToEnclosingRect(GetPaintedBounds(), canvas_scale, canvas_scale);
rect.set_width(width_in_pixels_ * canvas_scale / layer_scale);
TileRoundRect(canvas, flags, rect,
static_cast<int>(corner_radius * canvas_scale));
canvas->Restore();
} else {
TileRoundRect(canvas, flags, GetPaintedBounds(), corner_radius);
}
PaintTitleBar(canvas);
}
views::CaptionButtonLayoutSize DefaultFrameHeader::GetButtonLayoutSize() const {
return views::CaptionButtonLayoutSize::kNonBrowserCaption;
}
SkColor DefaultFrameHeader::GetTitleColor() const {
// Use IsDark() to change target colors instead of PickContrastingColor(), so
// that FrameCaptionButton::GetButtonColor() (which uses different target
// colors) can change between light/dark targets at the same time. It looks
// bad when the title and caption buttons disagree about whether to be light
// or dark.
const SkColor frame_color = GetCurrentFrameColor();
const SkColor desired_color = color_utils::IsDark(frame_color)
? SK_ColorWHITE
: SkColorSetRGB(40, 40, 40);
return color_utils::BlendForMinContrast(desired_color, frame_color).color;
}
///////////////////////////////////////////////////////////////////////////////
// DefaultFrameHeader, private:
aura::Window* DefaultFrameHeader::GetTargetWindow() {
return target_widget()->GetNativeWindow();
}
SkColor DefaultFrameHeader::GetCurrentFrameColor() const {
return mode() == MODE_ACTIVE ? active_frame_color_ : inactive_frame_color_;
}
} // namespace chromeos
|