Commit 04077658 authored by Peter Kasting's avatar Peter Kasting Committed by Commit Bot

Draw theme frames starting at 16 DIP above tabs regardless of frame height.

This provides a consistent alignment point for theme authors, makes some themes
(e.g. Dots) look correct (other themes want other values, e.g. 0, so there's no
one "right way" here), and prevents mirroring above the top of the frame image
in Refresh, since no mode has a frame height above the tabs > 16 DIP.

Bug: 866671
Change-Id: I1d79627e2735d54a332013ee70a2c71f107a898f
Reviewed-on: https://chromium-review.googlesource.com/1157878
Commit-Queue: Peter Kasting <pkasting@chromium.org>
Reviewed-by: default avatarEvan Stade <estade@chromium.org>
Reviewed-by: default avatarTom Sepez <tsepez@chromium.org>
Reviewed-by: default avatarScott Violet <sky@chromium.org>
Reviewed-by: default avatarBret Sepulveda <bsep@chromium.org>
Cr-Commit-Position: refs/heads/master@{#580615}
parent cc684999
......@@ -55,7 +55,8 @@ void PaintFrameImagesInRoundRect(gfx::Canvas* canvas,
SkColor opaque_background_color,
const gfx::Rect& bounds,
int corner_radius,
int image_inset_x) {
int image_inset_x,
int image_inset_y) {
SkPath frame_path = MakeRoundRectPath(bounds, corner_radius, corner_radius);
bool antialias = corner_radius > 0;
......@@ -76,41 +77,32 @@ void PaintFrameImagesInRoundRect(gfx::Canvas* canvas,
// and the background color. In this case we use a SaveLayerWithFlags() call
// to draw all 2-3 components into a single layer then apply the alpha to them
// together.
if (alpha < 0xFF ||
(!frame_image.isNull() && !frame_overlay_image.isNull())) {
const bool blending_required =
alpha < 0xFF || (!frame_image.isNull() && !frame_overlay_image.isNull());
if (blending_required) {
cc::PaintFlags flags;
// We use kPlus blending mode so that between the active and inactive
// background colors, the result is 255 alpha (i.e. opaque).
flags.setBlendMode(SkBlendMode::kPlus);
flags.setAlpha(alpha);
canvas->SaveLayerWithFlags(flags);
// Images can be transparent and we expect the background color to be
// present behind them. Here the |alpha| will be applied to the background
// color by the SaveLayer call, so use |opaque_background_color|.
canvas->DrawColor(opaque_background_color);
if (!frame_image.isNull()) {
canvas->TileImageInt(frame_image, image_inset_x, 0, 0, 0, bounds.width(),
bounds.height(), 1.0f, SkShader::kRepeat_TileMode,
SkShader::kMirror_TileMode);
}
if (!frame_overlay_image.isNull())
canvas->DrawImageInt(frame_overlay_image, 0, 0);
canvas->Restore();
return;
}
// Images can be transparent and we expect the background color to be
// present behind them.
// Images can be transparent and we expect the background color to be present
// behind them. Here the |alpha| will be applied to the background color by
// the SaveLayer call, so use |opaque_background_color|.
canvas->DrawColor(opaque_background_color);
if (!frame_image.isNull()) {
canvas->TileImageInt(frame_image, image_inset_x, 0, 0, 0, bounds.width(),
bounds.height());
canvas->TileImageInt(frame_image, image_inset_x, image_inset_y, 0, 0,
bounds.width(), bounds.height(), 1.0f,
SkShader::kRepeat_TileMode,
SkShader::kMirror_TileMode);
}
if (!frame_overlay_image.isNull())
canvas->DrawImageInt(frame_overlay_image, 0, 0);
if (blending_required)
canvas->Restore();
}
} // namespace
......@@ -186,10 +178,11 @@ void CustomFrameHeader::PaintFrameImages(gfx::Canvas* canvas, bool active) {
if (!target_widget()->IsMaximized() && !target_widget()->IsFullscreen())
corner_radius = FrameHeaderUtil::GetTopCornerRadiusWhenRestored();
PaintFrameImagesInRoundRect(canvas, frame_image, frame_overlay_image, alpha,
opaque_background_color, GetPaintedBounds(),
corner_radius,
FrameHeaderUtil::GetThemeBackgroundXInset());
PaintFrameImagesInRoundRect(
canvas, frame_image, frame_overlay_image, alpha, opaque_background_color,
GetPaintedBounds(), corner_radius,
FrameHeaderUtil::GetThemeBackgroundXInset(),
appearance_provider_->GetFrameHeaderImageYInset());
}
} // namespace ash
......@@ -23,6 +23,7 @@ class ASH_EXPORT CustomFrameHeader : public FrameHeader {
virtual SkColor GetTitleColor() = 0;
virtual SkColor GetFrameHeaderColor(bool active) = 0;
virtual gfx::ImageSkia GetFrameHeaderImage(bool active) = 0;
virtual int GetFrameHeaderImageYInset() = 0;
virtual gfx::ImageSkia GetFrameHeaderOverlayImage(bool active) = 0;
virtual bool IsTabletMode() const = 0;
};
......
......@@ -50,6 +50,10 @@ class WindowPropertyAppearanceProvider
: kFrameImageInactiveKey);
}
int GetFrameHeaderImageYInset() override {
return window_->GetProperty(kFrameImageYInsetKey);
}
gfx::ImageSkia GetFrameHeaderOverlayImage(bool active) override {
return LookUpImageForProperty(active ? kFrameImageOverlayActiveKey
: kFrameImageOverlayInactiveKey);
......@@ -255,7 +259,7 @@ void HeaderView::OnWindowPropertyChanged(aura::Window* window,
DCHECK_EQ(target_widget_->GetNativeWindow(), window);
if (key == kFrameImageActiveKey || key == kFrameImageInactiveKey ||
key == kFrameImageOverlayActiveKey ||
key == kFrameImageOverlayInactiveKey) {
key == kFrameImageOverlayInactiveKey || key == kFrameImageYInsetKey) {
SchedulePaint();
} else if (key == aura::client::kAvatarIconKey) {
gfx::ImageSkia* const avatar_icon =
......
......@@ -87,6 +87,9 @@ void MusPropertyMirrorAsh::MirrorPropertyFromWidgetWindowToRootWindow(
MirrorOwnedProperty(window, root_window, kFrameImageOverlayActiveKey);
} else if (key == kFrameImageOverlayInactiveKey) {
MirrorOwnedProperty(window, root_window, kFrameImageOverlayInactiveKey);
} else if (key == kFrameImageYInsetKey) {
root_window->SetProperty(kFrameImageYInsetKey,
window->GetProperty(kFrameImageYInsetKey));
} else if (key == kFrameIsThemedByHostedAppKey) {
root_window->SetProperty(kFrameIsThemedByHostedAppKey,
window->GetProperty(kFrameIsThemedByHostedAppKey));
......
......@@ -57,6 +57,9 @@ void RegisterWindowProperties(aura::PropertyConverter* property_converter) {
kFrameImageActiveKey, mojom::kFrameImageOverlayActive_Property);
property_converter->RegisterUnguessableTokenProperty(
kFrameImageActiveKey, mojom::kFrameImageOverlayInactive_Property);
property_converter->RegisterPrimitiveProperty(
kFrameImageYInsetKey, mojom::kFrameImageYInset_Property,
aura::PropertyConverter::CreateAcceptAnyValueCallback());
property_converter->RegisterPrimitiveProperty(
kFrameInactiveColorKey,
ui::mojom::WindowManager::kFrameInactiveColor_Property,
......@@ -125,6 +128,7 @@ DEFINE_OWNED_UI_CLASS_PROPERTY_KEY(base::UnguessableToken,
DEFINE_OWNED_UI_CLASS_PROPERTY_KEY(base::UnguessableToken,
kFrameImageOverlayInactiveKey,
nullptr);
DEFINE_UI_CLASS_PROPERTY_KEY(int, kFrameImageYInsetKey, 0);
DEFINE_UI_CLASS_PROPERTY_KEY(bool, kHideInOverviewKey, false);
DEFINE_UI_CLASS_PROPERTY_KEY(bool, kHideShelfWhenFullscreenKey, true);
DEFINE_UI_CLASS_PROPERTY_KEY(bool,
......
......@@ -96,6 +96,10 @@ ASH_PUBLIC_EXPORT extern const aura::WindowProperty<
ASH_PUBLIC_EXPORT extern const aura::WindowProperty<
base::UnguessableToken*>* const kFrameImageOverlayInactiveKey;
// A property that controls where a themed window's image is painted.
ASH_PUBLIC_EXPORT extern const aura::WindowProperty<int>* const
kFrameImageYInsetKey;
// A property key to indicate whether we should hide this window in overview
// mode and Alt + Tab.
ASH_PUBLIC_EXPORT extern const aura::WindowProperty<bool>* const
......
......@@ -31,6 +31,9 @@ const string kFrameImageOverlayActive_Property =
const string kFrameImageOverlayInactive_Property =
"ash:frame-image-overlay-inactive";
// A property that controls where a themed window's image is painted.
const string kFrameImageYInset_Property = "ash:frame-image-y-inset";
// A boolean that tells Ash whether the frame's colors come from a PWA manifest.
const string kFrameIsThemedByHostedApp_Property =
"ash:frame-is-themed-by-hosted-app";
......
......@@ -51,7 +51,7 @@ constexpr int kTallestTabHeight = 41;
// theme packs that aren't int-equal to this. Increment this number if you
// change default theme assets or if you need themes to recreate their generated
// images (which are cached).
const int kThemePackVersion = 54;
const int kThemePackVersion = 55;
// IDs that are in the DataPack won't clash with the positive integer
// uint16_t. kHeaderID should always have the maximum value because we want the
......@@ -1386,21 +1386,10 @@ void BrowserThemePack::CreateTabBackgroundImagesAndColors(ImageCache* images) {
if (tab_it != images->end())
overlay = tab_it->second.AsImageSkia();
// The height of the frame above the tabstrip in restored mode.
// Offsetting by this allows using semitransparent tab background images
// that will appear to overlay the frame at the correct position.
// Offsetting in all cases, and not just when there is an overlay, allows
// the tab painting code to avoid conditional positioning.
// TODO(pkasting): https://crbug.com/866671 For backwards-compat with
// existing themes, we should probably force this to 16 and update the
// frame and tab drawing code to match. This might make themes with art
// right at the top of the frame look bad, though.
constexpr int kRestoredTabVerticalOffset = 8;
auto source = std::make_unique<TabBackgroundImageSource>(
frame_color, image_to_tint, overlay,
GetTintInternal(ThemeProperties::TINT_BACKGROUND_TAB),
kRestoredTabVerticalOffset);
ThemeProperties::kFrameHeightAboveTabs);
gfx::Size dest_size = image_to_tint.size();
dest_size.SetToMax(gfx::Size(0, kTallestTabHeight));
const gfx::Image dest_image(gfx::ImageSkia(std::move(source), dest_size));
......
......@@ -197,6 +197,9 @@ base::Optional<SkColor> MaybeGetDefaultColorForNewerMaterialUi(int id,
} // namespace
// static
constexpr int ThemeProperties::kFrameHeightAboveTabs;
// static
int ThemeProperties::StringToAlignment(const std::string& alignment) {
int alignment_mask = 0;
......
......@@ -171,6 +171,15 @@ class ThemeProperties {
#endif // OS_WIN
};
// Themes are hardcoded to draw frame images as if they start this many DIPs
// above the top of the tabstrip, no matter how much space actually exists.
// This aids with backwards compatibility (for some themes; Chrome's behavior
// has been inconsistent over time), provides a consistent alignment point for
// theme authors, and ensures the frame image won't need to be mirrored above
// the tabs in Refresh (since frame heights above the tabs are never greater
// than this).
static constexpr int kFrameHeightAboveTabs = 16;
// Used by the browser theme pack to parse alignments from something like
// "top left" into a bitmask of Alignment.
static int StringToAlignment(const std::string& alignment);
......
......@@ -26,6 +26,7 @@
#include "base/strings/utf_string_conversions.h"
#include "chrome/app/chrome_command_ids.h"
#include "chrome/browser/profiles/profiles_state.h"
#include "chrome/browser/themes/theme_properties.h"
#include "chrome/browser/ui/ash/multi_user/multi_user_window_manager.h"
#include "chrome/browser/ui/ash/tablet_mode_client.h"
#include "chrome/browser/ui/browser.h"
......@@ -530,6 +531,9 @@ void BrowserNonClientFrameViewAsh::Layout() {
BrowserNonClientFrameView::Layout();
UpdateClientArea();
frame()->GetNativeWindow()->SetProperty(ash::kFrameImageYInsetKey,
GetFrameHeaderImageYInset());
return;
}
......@@ -661,6 +665,10 @@ gfx::ImageSkia BrowserNonClientFrameViewAsh::GetFrameHeaderImage(bool active) {
return GetFrameImage(active);
}
int BrowserNonClientFrameViewAsh::GetFrameHeaderImageYInset() {
return ThemeProperties::kFrameHeightAboveTabs - GetTopInset(false);
}
gfx::ImageSkia BrowserNonClientFrameViewAsh::GetFrameHeaderOverlayImage(
bool active) {
DCHECK(!IsMash());
......
......@@ -92,6 +92,7 @@ class BrowserNonClientFrameViewAsh
SkColor GetTitleColor() override;
SkColor GetFrameHeaderColor(bool active) override;
gfx::ImageSkia GetFrameHeaderImage(bool active) override;
int GetFrameHeaderImageYInset() override;
gfx::ImageSkia GetFrameHeaderOverlayImage(bool active) override;
bool IsTabletMode() const override;
......
......@@ -754,10 +754,13 @@ void GlassBrowserFrameView::PaintTitlebar(gfx::Canvas* canvas) const {
canvas->DrawRect(titlebar_rect, flags);
const gfx::ImageSkia frame_image = GetFrameImage();
if (!frame_image.isNull()) {
canvas->TileImageInt(
frame_image, 0, 0, titlebar_rect.x(), titlebar_rect.y(),
titlebar_rect.width(), titlebar_rect.height(), scale,
SkShader::kRepeat_TileMode, SkShader::kMirror_TileMode);
canvas->TileImageInt(frame_image, 0,
ThemeProperties::kFrameHeightAboveTabs -
GetTopInset(false) + titlebar_rect.y(),
titlebar_rect.x(), titlebar_rect.y(),
titlebar_rect.width(), titlebar_rect.height(), scale,
SkShader::kRepeat_TileMode,
SkShader::kMirror_TileMode);
}
const gfx::ImageSkia frame_overlay_image = GetFrameOverlayImage();
if (!frame_overlay_image.isNull()) {
......
......@@ -477,16 +477,12 @@ gfx::Size OpaqueBrowserFrameView::GetNewTabButtonPreferredSize() const {
}
int OpaqueBrowserFrameView::GetTopAreaHeight() const {
const gfx::ImageSkia frame_image = GetFrameImage();
int top_area_height =
std::max(frame_image.height(), layout_->NonClientTopHeight(false));
if (browser_view()->IsTabStripVisible()) {
top_area_height =
std::max(top_area_height,
GetBoundsForTabStrip(browser_view()->tabstrip()).bottom() -
GetLayoutConstant(TABSTRIP_TOOLBAR_OVERLAP));
}
return top_area_height;
const int non_client_top_height = layout_->NonClientTopHeight(false);
if (!browser_view()->IsTabStripVisible())
return non_client_top_height;
return std::max(non_client_top_height,
GetBoundsForTabStrip(browser_view()->tabstrip()).bottom() -
GetLayoutConstant(TABSTRIP_TOOLBAR_OVERLAP));
}
bool OpaqueBrowserFrameView::UseCustomFrame() const {
......@@ -509,8 +505,17 @@ void OpaqueBrowserFrameView::OnPaint(gfx::Canvas* canvas) {
frame_background_->set_is_active(ShouldPaintAsActive());
frame_background_->set_incognito(browser_view()->IsIncognito());
frame_background_->set_theme_image(GetFrameImage());
const int y_inset =
browser_view()->IsTabStripVisible()
? (ThemeProperties::kFrameHeightAboveTabs - GetTopInset(false))
: 0;
frame_background_->set_theme_image_y_inset(y_inset);
frame_background_->set_theme_overlay_image(GetFrameOverlayImage());
frame_background_->set_top_area_height(GetTopAreaHeight());
const int visible_image_height = GetFrameImage().height() -
ThemeProperties::kFrameHeightAboveTabs +
GetTopInset(false);
frame_background_->set_top_area_height(
std::max(GetTopAreaHeight(), visible_image_height));
if (layout_->IsTitleBarCondensed())
PaintMaximizedFrameBorder(canvas);
......
......@@ -1243,15 +1243,15 @@ void Tab::MaybeAdjustLeftForPinnedTab(gfx::Rect* bounds,
void Tab::PaintTab(gfx::Canvas* canvas, const gfx::Path& clip) {
int active_tab_fill_id = 0;
int active_tab_y_offset = 0;
int active_tab_y_inset = 0;
if (GetThemeProvider()->HasCustomImage(IDR_THEME_TOOLBAR)) {
active_tab_fill_id = IDR_THEME_TOOLBAR;
active_tab_y_offset = -GetStrokeHeight();
active_tab_y_inset = GetStrokeHeight();
}
if (IsActive()) {
PaintTabBackground(canvas, true /* active */, active_tab_fill_id,
active_tab_y_offset, nullptr /* clip */);
active_tab_y_inset, nullptr /* clip */);
} else {
PaintInactiveTabBackground(canvas, clip);
......@@ -1260,7 +1260,7 @@ void Tab::PaintTab(gfx::Canvas* canvas, const gfx::Path& clip) {
canvas->SaveLayerAlpha(gfx::ToRoundedInt(throb_value * 0xff),
GetLocalBounds());
PaintTabBackground(canvas, true /* active */, active_tab_fill_id,
active_tab_y_offset, nullptr /* clip */);
active_tab_y_inset, nullptr /* clip */);
canvas->Restore();
}
}
......@@ -1280,10 +1280,10 @@ void Tab::PaintInactiveTabBackground(gfx::Canvas* canvas,
void Tab::PaintTabBackground(gfx::Canvas* canvas,
bool active,
int fill_id,
int y_offset,
int y_inset,
const gfx::Path* clip) {
// |y_offset| is only set when |fill_id| is being used.
DCHECK(!y_offset || fill_id);
// |y_inset| is only set when |fill_id| is being used.
DCHECK(!y_inset || fill_id);
const SkColor active_color = controller_->GetTabBackgroundColor(TAB_ACTIVE);
const SkColor inactive_color =
......@@ -1308,7 +1308,7 @@ void Tab::PaintTabBackground(gfx::Canvas* canvas,
(MD::IsRefreshUi() && (std::trunc(scale) != scale))) {
gfx::Path fill_path = GetInteriorPath(scale, bounds());
PaintTabBackgroundFill(canvas, fill_path, active, paint_hover_effect,
active_color, inactive_color, fill_id, y_offset);
active_color, inactive_color, fill_id, y_inset);
if (TabStrip::ShouldDrawStrokes()) {
gfx::Path stroke_path = GetBorderPath(scale, false, false, bounds());
gfx::ScopedCanvas scoped_canvas(clip ? canvas : nullptr);
......@@ -1331,7 +1331,7 @@ void Tab::PaintTabBackground(gfx::Canvas* canvas,
recorder.beginRecording(size().width(), size().height()), scale);
PaintTabBackgroundFill(&cache_canvas, fill_path, active,
paint_hover_effect, active_color, inactive_color,
fill_id, y_offset);
fill_id, y_inset);
cache.fill_record = recorder.finishRecordingAsPicture();
}
if (TabStrip::ShouldDrawStrokes()) {
......@@ -1365,7 +1365,7 @@ void Tab::PaintTabBackgroundFill(gfx::Canvas* canvas,
SkColor active_color,
SkColor inactive_color,
int fill_id,
int y_offset) {
int y_inset) {
gfx::ScopedCanvas scoped_canvas(canvas);
const float scale = canvas->UndoDeviceScaleFactor();
......@@ -1374,8 +1374,8 @@ void Tab::PaintTabBackgroundFill(gfx::Canvas* canvas,
gfx::ScopedCanvas scale_scoper(canvas);
canvas->sk_canvas()->scale(scale, scale);
canvas->TileImageInt(*GetThemeProvider()->GetImageSkiaNamed(fill_id),
GetMirroredX() + background_offset_, y_offset, 0,
0, width(), height());
GetMirroredX() + background_offset_, 0, 0, y_inset,
width(), height());
} else {
cc::PaintFlags flags;
flags.setAntiAlias(true);
......
......@@ -256,7 +256,7 @@ class Tab : public gfx::AnimationDelegate,
void PaintTabBackground(gfx::Canvas* canvas,
bool active,
int fill_id,
int y_offset,
int y_inset,
const gfx::Path* clip);
// Helper methods for PaintTabBackground.
......@@ -267,7 +267,7 @@ class Tab : public gfx::AnimationDelegate,
SkColor active_color,
SkColor inactive_color,
int fill_id,
int y_offset);
int y_inset);
void PaintTabBackgroundStroke(gfx::Canvas* canvas,
const gfx::Path& fill_path,
const gfx::Path& stroke_path,
......
......@@ -19,6 +19,7 @@ FrameBackground::FrameBackground()
use_custom_frame_(true),
is_active_(true),
incognito_(false),
theme_image_y_inset_(0),
top_area_height_(0),
left_edge_(nullptr),
top_edge_(nullptr),
......@@ -138,7 +139,7 @@ void FrameBackground::PaintMaximized(gfx::Canvas* canvas,
// Draw the theme frame and overlay, if available.
if (!theme_image_.isNull()) {
canvas->TileImageInt(theme_image_, 0, 0, 0, -maximized_top_inset_,
canvas->TileImageInt(theme_image_, 0, theme_image_y_inset_, 0, 0,
view->width(), top_area_height_, 1.0f,
SkShader::kRepeat_TileMode,
SkShader::kMirror_TileMode);
......
......@@ -43,6 +43,9 @@ class VIEWS_EXPORT FrameBackground {
// Memory is owned by the caller.
void set_theme_image(const gfx::ImageSkia& image) { theme_image_ = image; }
// Sets an inset into the theme image to begin painting at.
void set_theme_image_y_inset(int y_inset) { theme_image_y_inset_ = y_inset; }
// Sets an image that overlays the top window image. Usually used to add
// edge highlighting to provide the illusion of depth. May be null (empty).
// Memory is owned by the caller.
......@@ -89,6 +92,7 @@ class VIEWS_EXPORT FrameBackground {
bool is_active_;
bool incognito_;
gfx::ImageSkia theme_image_;
int theme_image_y_inset_;
gfx::ImageSkia theme_overlay_image_;
int top_area_height_;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment