blob: e10cb70ef5313c583471bd9f776161cf26536821 [file] [log] [blame]
// 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_icon_painter.h"
#include "base/numerics/safe_conversions.h"
#include "chrome/browser/ui/color/chrome_color_id.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"
namespace {
// Canvas::DrawRect's stroke can bleed out of |rect|'s bounds, so this draws a
// rectangle inset such that the result is constrained to |rect|'s size.
void DrawRect(gfx::Canvas* canvas,
const gfx::Rect& rect,
const cc::PaintFlags& flags) {
gfx::RectF rect_f(rect);
float stroke_half_width = flags.getStrokeWidth() / 2;
rect_f.Inset(stroke_half_width);
canvas->DrawRect(rect_f, flags);
}
void DrawRoundRect(gfx::Canvas* canvas,
const gfx::Rect& rect,
float radius,
const cc::PaintFlags& flags) {
gfx::RectF rect_f(rect);
float stroke_half_width = flags.getStrokeWidth() / 2;
rect_f.Inset(stroke_half_width);
canvas->DrawRoundRect(rect_f, radius, flags);
}
// Draws a path containing the top and right edges of a rounded rectangle.
void DrawRoundRectEdges(gfx::Canvas* canvas,
const gfx::Rect& rect,
float radius,
const cc::PaintFlags& flags) {
gfx::RectF symbol_rect_f(rect);
float stroke_half_width = flags.getStrokeWidth() / 2;
symbol_rect_f.Inset(stroke_half_width);
SkPath path;
path.moveTo(symbol_rect_f.x(), symbol_rect_f.y());
path.arcTo(symbol_rect_f.right(), symbol_rect_f.y(), symbol_rect_f.right(),
symbol_rect_f.y() + radius, radius);
path.lineTo(symbol_rect_f.right(), symbol_rect_f.bottom());
canvas->DrawPath(path, flags);
}
} // namespace
Windows10IconPainter::Windows10IconPainter() = default;
Windows10IconPainter::~Windows10IconPainter() = default;
void Windows10IconPainter::PaintMinimizeIcon(gfx::Canvas* canvas,
gfx::Rect& symbol_rect,
cc::PaintFlags& flags) {
const int y = symbol_rect.CenterPoint().y();
const gfx::Point p1 = gfx::Point(symbol_rect.x(), y);
const gfx::Point p2 = gfx::Point(symbol_rect.right(), y);
canvas->DrawLine(p1, p2, flags);
}
void Windows10IconPainter::PaintMaximizeIcon(gfx::Canvas* canvas,
gfx::Rect& symbol_rect,
cc::PaintFlags& flags) {
DrawRect(canvas, symbol_rect, flags);
}
void Windows10IconPainter::PaintRestoreIcon(gfx::Canvas* canvas,
gfx::Rect& symbol_rect,
cc::PaintFlags& flags) {
const int separation = base::ClampFloor(2 * canvas->image_scale());
symbol_rect.Inset(gfx::Insets::TLBR(separation, 0, 0, separation));
// Bottom left ("in front") square.
DrawRect(canvas, symbol_rect, flags);
// Top right ("behind") square.
canvas->ClipRect(symbol_rect, SkClipOp::kDifference);
symbol_rect.Offset(separation, -separation);
DrawRect(canvas, symbol_rect, flags);
}
void Windows10IconPainter::PaintCloseIcon(gfx::Canvas* canvas,
gfx::Rect& symbol_rect,
cc::PaintFlags& flags) {
// TODO(bsep): This sometimes draws misaligned at fractional device scales
// because the button's origin isn't necessarily aligned to pixels.
flags.setAntiAlias(true);
canvas->ClipRect(symbol_rect);
SkPath path;
path.moveTo(symbol_rect.x(), symbol_rect.y());
path.lineTo(symbol_rect.right(), symbol_rect.bottom());
path.moveTo(symbol_rect.right(), symbol_rect.y());
path.lineTo(symbol_rect.x(), symbol_rect.bottom());
canvas->DrawPath(path, flags);
}
void Windows10IconPainter::PaintTabSearchIcon(gfx::Canvas* canvas,
gfx::Rect& symbol_rect,
cc::PaintFlags& flags) {
flags.setAntiAlias(true);
canvas->ClipRect(symbol_rect);
// The chevron should occupy the space between the upper and lower quarter
// of the `symbol_rect` bounds.
symbol_rect.Inset(gfx::Insets::VH(symbol_rect.height() / 4, 0));
SkPath path;
path.moveTo(gfx::PointToSkPoint(symbol_rect.origin()));
path.lineTo(gfx::PointToSkPoint(symbol_rect.bottom_center()));
path.lineTo(gfx::PointToSkPoint(symbol_rect.top_right()));
canvas->DrawPath(path, flags);
}
Windows11IconPainter::Windows11IconPainter() = default;
Windows11IconPainter::~Windows11IconPainter() = default;
void Windows11IconPainter::PaintMaximizeIcon(gfx::Canvas* canvas,
gfx::Rect& symbol_rect,
cc::PaintFlags& flags) {
flags.setAntiAlias(true);
const float corner_radius = canvas->image_scale();
DrawRoundRect(canvas, symbol_rect, corner_radius, flags);
}
void Windows11IconPainter::PaintRestoreIcon(gfx::Canvas* canvas,
gfx::Rect& symbol_rect,
cc::PaintFlags& flags) {
const int separation = base::ClampFloor(2 * canvas->image_scale());
symbol_rect.Inset(gfx::Insets::TLBR(separation, 0, 0, separation));
flags.setAntiAlias(true);
// Bottom left ("in front") rounded square.
const float bottom_rect_radius = canvas->image_scale();
DrawRoundRect(canvas, symbol_rect, bottom_rect_radius, flags);
// Top right ("behind") top+right edges of rounded square (2.5x).
symbol_rect.Offset(separation, -separation);
const float top_rect_radius = 2.5f * canvas->image_scale();
DrawRoundRectEdges(canvas, symbol_rect, top_rect_radius, flags);
}