Commit b2270914 authored by Evan Stade's avatar Evan Stade Committed by Commit Bot

OopAsh: improve immersive mode reveal widget.

1. Make sure located events go to the top container when it's revealed.
This is accomplished with an EventRewriter which clears the target
window, which had been provided by the window service, from the event.
Without this, clicks on the top container are targeted to the
web contents window because the Window Service doesn't know about the
top container's window. In the long term, we may be able to remove this
EventRewriter with a more general solution (e.g. improving how the window
service targets the event in the first place).

2. Instead of mirroring the top container's layers, make the widget
completely transparent except for the ash-provided window controls.
Mirroring doesn't update the reveal widget in response to changes in
the top container's layers, such as when a button is hovered and an ink
drop is added.

3. Allow the reveal widget to accept events so that it's possible to
interact with the window controls. Resize the reveal widget to be just
big enough for the window controls so that clicks anywhere else will
go straight through to the underlying top container view.

4. Make the browser-side non client frame view paint the frame bg. This
is necessary because the reveal widget (i.e. window controls) is now on
top of the container view and has no client-side rendering (what the
mirroring view used to provide).

Future issues to address:
- the cursor is not updated (e.g. when hovering the omnibox) presumably
  because the cursor is coming from the window that the WS thinks is
  underneath the pointer, i.e. the web contents.

Alternatives considered:
- update the mirrored layers every time the layer tree changes. This
  doesn't seem to be easy to accomplish or likely to be very performant.
- move the top container into the reveal widget. This somewhat works
  with a few tweaks here and there to code that assumes the top container
  is always in the browser widget, but ultimately it seems that making
  the reveal widget focusable causes difficulties with window activation
  and focus traversal.

Bug: 640365
Change-Id: I03956c07354e20dadc2919f9a0402ce1f7b4a672
Reviewed-on: https://chromium-review.googlesource.com/1171547
Commit-Queue: Evan Stade <estade@chromium.org>
Reviewed-by: default avatarScott Violet <sky@chromium.org>
Cr-Commit-Position: refs/heads/master@{#585649}
parent c2ed26d4
...@@ -5,8 +5,10 @@ ...@@ -5,8 +5,10 @@
#include "ash/frame/custom_frame_header.h" #include "ash/frame/custom_frame_header.h"
#include "ash/frame/caption_buttons/frame_caption_button_container_view.h" #include "ash/frame/caption_buttons/frame_caption_button_container_view.h"
#include "ash/frame/detached_title_area_renderer.h"
#include "ash/frame/frame_header_util.h" #include "ash/frame/frame_header_util.h"
#include "ash/public/cpp/ash_layout_constants.h" #include "ash/public/cpp/ash_layout_constants.h"
#include "ash/public/cpp/frame_utils.h"
#include "ash/public/cpp/vector_icons/vector_icons.h" #include "ash/public/cpp/vector_icons/vector_icons.h"
#include "base/logging.h" #include "base/logging.h"
#include "third_party/skia/include/core/SkCanvas.h" #include "third_party/skia/include/core/SkCanvas.h"
...@@ -51,58 +53,20 @@ SkPath MakeRoundRectPath(const gfx::Rect& bounds, ...@@ -51,58 +53,20 @@ SkPath MakeRoundRectPath(const gfx::Rect& bounds,
void PaintFrameImagesInRoundRect(gfx::Canvas* canvas, void PaintFrameImagesInRoundRect(gfx::Canvas* canvas,
const gfx::ImageSkia& frame_image, const gfx::ImageSkia& frame_image,
const gfx::ImageSkia& frame_overlay_image, const gfx::ImageSkia& frame_overlay_image,
int alpha, SkColor background_color,
SkColor opaque_background_color,
const gfx::Rect& bounds, const gfx::Rect& bounds,
int corner_radius,
int image_inset_x, int image_inset_x,
int image_inset_y) { int image_inset_y,
int alpha,
int corner_radius) {
SkPath frame_path = MakeRoundRectPath(bounds, corner_radius, corner_radius); SkPath frame_path = MakeRoundRectPath(bounds, corner_radius, corner_radius);
bool antialias = corner_radius > 0; bool antialias = corner_radius > 0;
gfx::ScopedCanvas scoped_save(canvas); gfx::ScopedCanvas scoped_save(canvas);
canvas->ClipPath(frame_path, antialias); canvas->ClipPath(frame_path, antialias);
// When no images are used, just draw a color, with the animation |alpha| PaintThemedFrame(canvas, frame_image, frame_overlay_image, background_color,
// applied. bounds, image_inset_x, image_inset_y, alpha);
if (frame_image.isNull() && frame_overlay_image.isNull()) {
// We use kPlus blending mode so that between the active and inactive
// background colors, the result is 255 alpha (i.e. opaque).
canvas->DrawColor(SkColorSetA(opaque_background_color, alpha),
SkBlendMode::kPlus);
return;
}
// This handles the case where blending is required between one or more images
// 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.
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, 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 } // namespace
...@@ -129,9 +93,14 @@ CustomFrameHeader::~CustomFrameHeader() = default; ...@@ -129,9 +93,14 @@ CustomFrameHeader::~CustomFrameHeader() = default;
// CustomFrameHeader, protected: // CustomFrameHeader, protected:
void CustomFrameHeader::DoPaintHeader(gfx::Canvas* canvas) { void CustomFrameHeader::DoPaintHeader(gfx::Canvas* canvas) {
PaintFrameImages(canvas, false /* active */); // If this is a detached title area renderer (i.e. for client-controlled
PaintFrameImages(canvas, true /* active */); // immersive mode), then Mash only needs to render the window caption buttons.
PaintTitleBar(canvas); if (!DetachedTitleAreaRendererForClient::ForWindow(
view()->GetWidget()->GetNativeView())) {
PaintFrameImages(canvas, false /* active */);
PaintFrameImages(canvas, true /* active */);
PaintTitleBar(canvas);
}
} }
AshLayoutSize CustomFrameHeader::GetButtonLayoutSize() const { AshLayoutSize CustomFrameHeader::GetButtonLayoutSize() const {
...@@ -170,19 +139,16 @@ void CustomFrameHeader::PaintFrameImages(gfx::Canvas* canvas, bool active) { ...@@ -170,19 +139,16 @@ void CustomFrameHeader::PaintFrameImages(gfx::Canvas* canvas, bool active) {
appearance_provider_->GetFrameHeaderImage(active); appearance_provider_->GetFrameHeaderImage(active);
gfx::ImageSkia frame_overlay_image = gfx::ImageSkia frame_overlay_image =
appearance_provider_->GetFrameHeaderOverlayImage(active); appearance_provider_->GetFrameHeaderOverlayImage(active);
// We ensure that the background color is opaque.
SkColor opaque_background_color =
SkColorSetA(appearance_provider_->GetFrameHeaderColor(active), 0xFF);
int corner_radius = 0; int corner_radius = 0;
if (!target_widget()->IsMaximized() && !target_widget()->IsFullscreen()) if (!target_widget()->IsMaximized() && !target_widget()->IsFullscreen())
corner_radius = FrameHeaderUtil::GetTopCornerRadiusWhenRestored(); corner_radius = FrameHeaderUtil::GetTopCornerRadiusWhenRestored();
PaintFrameImagesInRoundRect( PaintFrameImagesInRoundRect(
canvas, frame_image, frame_overlay_image, alpha, opaque_background_color, canvas, frame_image, frame_overlay_image,
GetPaintedBounds(), corner_radius, appearance_provider_->GetFrameHeaderColor(active), GetPaintedBounds(),
FrameHeaderUtil::GetThemeBackgroundXInset(), FrameHeaderUtil::GetThemeBackgroundXInset(),
appearance_provider_->GetFrameHeaderImageYInset()); appearance_provider_->GetFrameHeaderImageYInset(), alpha, corner_radius);
} }
} // namespace ash } // namespace ash
...@@ -43,12 +43,13 @@ namespace ash { ...@@ -43,12 +43,13 @@ namespace ash {
// the immersive logic, including positioning of the reveal window. // the immersive logic, including positioning of the reveal window.
// //
// DetachedTitleAreaRenderer comes in two variants. // DetachedTitleAreaRenderer comes in two variants.
// DetachedTitleAreaRendererForClient is used for clients that need to draw // 1. DetachedTitleAreaRendererForClient is used for clients that need to draw
// into the non-client area of the widget (case 2). For example, Chrome browser // into the non-client area of the widget (case 2). For example, Chrome browser
// windows draw into the non-client area of tabbed browser widgets (the tab // windows draw into the non-client area of tabbed browser widgets (the tab
// strip is in the non-client area). In such a case // strip is in the non-client area). In such a case
// DetachedTitleAreaRendererForClient is used. // DetachedTitleAreaRendererForClient is used. For these, Mash only draws the
// If the client does not need to draw to the non-client area (case 1) then // window controls --- the frame is rendered by the client.
// 2. If the client does not need to draw to the non-client area (case 1) then
// DetachedTitleAreaRendererInternal is used (and ash controls the whole // DetachedTitleAreaRendererInternal is used (and ash controls the whole
// immersive experience). Which is used is determined by // immersive experience). Which is used is determined by
// |kRenderParentTitleArea_Property|. If |kRenderParentTitleArea_Property| is // |kRenderParentTitleArea_Property|. If |kRenderParentTitleArea_Property| is
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
#include "ash/frame/default_frame_header.h" #include "ash/frame/default_frame_header.h"
#include "ash/frame/header_view.h" #include "ash/frame/header_view.h"
#include "ash/public/cpp/ash_constants.h" #include "ash/public/cpp/ash_constants.h"
#include "ash/public/cpp/frame_border_hit_test.h" #include "ash/public/cpp/frame_utils.h"
#include "ash/public/cpp/immersive/immersive_fullscreen_controller.h" #include "ash/public/cpp/immersive/immersive_fullscreen_controller.h"
#include "ash/public/cpp/immersive/immersive_fullscreen_controller_delegate.h" #include "ash/public/cpp/immersive/immersive_fullscreen_controller_delegate.h"
#include "ash/public/cpp/window_properties.h" #include "ash/public/cpp/window_properties.h"
......
...@@ -46,8 +46,8 @@ component("cpp") { ...@@ -46,8 +46,8 @@ component("cpp") {
"ash_typography.h", "ash_typography.h",
"ash_view_ids.h", "ash_view_ids.h",
"config.h", "config.h",
"frame_border_hit_test.cc", "frame_utils.cc",
"frame_border_hit_test.h", "frame_utils.h",
"immersive/immersive_context.cc", "immersive/immersive_context.cc",
"immersive/immersive_context.h", "immersive/immersive_context.h",
"immersive/immersive_focus_watcher.h", "immersive/immersive_focus_watcher.h",
......
// Copyright 2016 The Chromium Authors. All rights reserved. // Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#include "ash/public/cpp/frame_border_hit_test.h" #include "ash/public/cpp/frame_utils.h"
#include "ash/public/cpp/ash_constants.h" #include "ash/public/cpp/ash_constants.h"
#include "ui/aura/env.h" #include "ui/aura/env.h"
#include "ui/aura/window.h" #include "ui/aura/window.h"
#include "ui/base/hit_test.h" #include "ui/base/hit_test.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/image/image_skia.h"
#include "ui/views/view_properties.h" #include "ui/views/view_properties.h"
#include "ui/views/widget/widget.h" #include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_delegate.h" #include "ui/views/widget/widget_delegate.h"
...@@ -61,4 +64,57 @@ int FrameBorderNonClientHitTest(views::NonClientFrameView* view, ...@@ -61,4 +64,57 @@ int FrameBorderNonClientHitTest(views::NonClientFrameView* view,
return HTCAPTION; return HTCAPTION;
} }
void PaintThemedFrame(gfx::Canvas* canvas,
const gfx::ImageSkia& frame_image,
const gfx::ImageSkia& frame_overlay_image,
SkColor background_color,
const gfx::Rect& bounds,
int image_inset_x,
int image_inset_y,
int alpha) {
SkColor opaque_background_color =
SkColorSetA(background_color, SK_AlphaOPAQUE);
// When no images are used, just draw a color, with the animation |alpha|
// applied.
if (frame_image.isNull() && frame_overlay_image.isNull()) {
// We use kPlus blending mode so that between the active and inactive
// background colors, the result is 255 alpha (i.e. opaque).
canvas->DrawColor(SkColorSetA(opaque_background_color, alpha),
SkBlendMode::kPlus);
return;
}
// This handles the case where blending is required between one or more images
// 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.
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, 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 ash } // namespace ash
// Copyright 2016 The Chromium Authors. All rights reserved. // Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#ifndef ASH_PUBLIC_CPP_FRAME_BORDER_HIT_TEST_H_ #ifndef ASH_PUBLIC_CPP_FRAME_UTILS_H_
#define ASH_PUBLIC_CPP_FRAME_BORDER_HIT_TEST_H_ #define ASH_PUBLIC_CPP_FRAME_UTILS_H_
#include "ash/public/cpp/ash_public_export.h" #include "ash/public/cpp/ash_public_export.h"
#include "third_party/skia/include/core/SkColor.h"
namespace gfx { namespace gfx {
class Canvas;
class ImageSkia;
class Point; class Point;
} class Rect;
} // namespace gfx
namespace views { namespace views {
class NonClientFrameView; class NonClientFrameView;
} // namespace views }
namespace ash { namespace ash {
...@@ -22,6 +26,18 @@ ASH_PUBLIC_EXPORT int FrameBorderNonClientHitTest( ...@@ -22,6 +26,18 @@ ASH_PUBLIC_EXPORT int FrameBorderNonClientHitTest(
views::NonClientFrameView* view, views::NonClientFrameView* view,
const gfx::Point& point_in_widget); const gfx::Point& point_in_widget);
// Paints the frame header images and background color for custom themes (i.e.
// browser themes) into a canvas.
ASH_PUBLIC_EXPORT void PaintThemedFrame(
gfx::Canvas* canvas,
const gfx::ImageSkia& frame_image,
const gfx::ImageSkia& frame_overlay_image,
SkColor background_color,
const gfx::Rect& bounds,
int image_inset_x,
int image_inset_y,
int alpha);
} // namespace ash } // namespace ash
#endif // ASH_PUBLIC_CPP_FRAME_BORDER_HIT_TEST_H_ #endif // ASH_PUBLIC_CPP_FRAME_UTILS_H_
...@@ -8,14 +8,14 @@ ...@@ -8,14 +8,14 @@
#include "ash/frame/caption_buttons/frame_back_button.h" // mash-ok #include "ash/frame/caption_buttons/frame_back_button.h" // mash-ok
#include "ash/frame/caption_buttons/frame_caption_button_container_view.h" // mash-ok #include "ash/frame/caption_buttons/frame_caption_button_container_view.h" // mash-ok
#include "ash/frame/default_frame_header.h" // mash-ok #include "ash/frame/default_frame_header.h" // mash-ok
#include "ash/frame/frame_header_util.h" // mash-ok #include "ash/frame/frame_header_util.h" // mash-ok
#include "ash/public/cpp/app_list/app_list_features.h" #include "ash/public/cpp/app_list/app_list_features.h"
#include "ash/public/cpp/app_types.h" #include "ash/public/cpp/app_types.h"
#include "ash/public/cpp/ash_constants.h" #include "ash/public/cpp/ash_constants.h"
#include "ash/public/cpp/ash_layout_constants.h" #include "ash/public/cpp/ash_layout_constants.h"
#include "ash/public/cpp/ash_switches.h" #include "ash/public/cpp/ash_switches.h"
#include "ash/public/cpp/frame_border_hit_test.h" #include "ash/public/cpp/frame_utils.h"
#include "ash/public/cpp/window_properties.h" #include "ash/public/cpp/window_properties.h"
#include "ash/public/interfaces/constants.mojom.h" #include "ash/public/interfaces/constants.mojom.h"
#include "ash/public/interfaces/window_state_type.mojom.h" #include "ash/public/interfaces/window_state_type.mojom.h"
...@@ -55,6 +55,7 @@ ...@@ -55,6 +55,7 @@
#include "ui/base/ui_base_features.h" #include "ui/base/ui_base_features.h"
#include "ui/gfx/canvas.h" #include "ui/gfx/canvas.h"
#include "ui/gfx/image/image_skia.h" #include "ui/gfx/image/image_skia.h"
#include "ui/gfx/scoped_canvas.h"
#include "ui/views/controls/label.h" #include "ui/views/controls/label.h"
#include "ui/views/layout/box_layout.h" #include "ui/views/layout/box_layout.h"
#include "ui/views/mus/desktop_window_tree_host_mus.h" #include "ui/views/mus/desktop_window_tree_host_mus.h"
...@@ -397,7 +398,7 @@ void BrowserNonClientFrameViewAsh::UpdateClientArea() { ...@@ -397,7 +398,7 @@ void BrowserNonClientFrameViewAsh::UpdateClientArea() {
// clicks in the frame decoration. // clicks in the frame decoration.
static_cast<aura::WindowTreeHostMus*>( static_cast<aura::WindowTreeHostMus*>(
reveal_widget->GetNativeWindow()->GetHost()) reveal_widget->GetNativeWindow()->GetHost())
->SetClientArea(client_area_insets, additional_client_area); ->SetClientArea(client_area_insets, {});
} }
} else { } else {
window_tree_host_mus->SetClientArea(gfx::Insets(), additional_client_area); window_tree_host_mus->SetClientArea(gfx::Insets(), additional_client_area);
...@@ -508,12 +509,24 @@ void BrowserNonClientFrameViewAsh::OnPaint(gfx::Canvas* canvas) { ...@@ -508,12 +509,24 @@ void BrowserNonClientFrameViewAsh::OnPaint(gfx::Canvas* canvas) {
if (!ShouldPaint()) if (!ShouldPaint())
return; return;
ImmersiveModeController* immersive_mode_controller =
browser_view()->immersive_mode_controller();
if (frame_header_) { if (frame_header_) {
DCHECK(!IsMash()); DCHECK(!IsMash());
const ash::FrameHeader::Mode header_mode = const ash::FrameHeader::Mode header_mode =
ShouldPaintAsActive() ? ash::FrameHeader::MODE_ACTIVE ShouldPaintAsActive() ? ash::FrameHeader::MODE_ACTIVE
: ash::FrameHeader::MODE_INACTIVE; : ash::FrameHeader::MODE_INACTIVE;
frame_header_->PaintHeader(canvas, header_mode); frame_header_->PaintHeader(canvas, header_mode);
} else if (IsMash() && immersive_mode_controller->IsEnabled() &&
immersive_mode_controller->IsRevealed()) {
// TODO(estade): GetTopInset() ignores its parameter in Mash. Fix for this
// case, where we truly want to force |restored| to true.
ash::PaintThemedFrame(canvas, GetFrameImage(kActive),
GetFrameOverlayImage(kActive), GetFrameColor(kActive),
gfx::Rect(width(), GetTopInset(false)),
GetThemeBackgroundXInset(),
GetFrameHeaderImageYInset(), SK_AlphaOPAQUE);
} }
if (browser_view()->IsToolbarVisible() && if (browser_view()->IsToolbarVisible() &&
......
...@@ -23,21 +23,56 @@ ...@@ -23,21 +23,56 @@
#include "ui/aura/mus/mus_types.h" #include "ui/aura/mus/mus_types.h"
#include "ui/aura/mus/property_converter.h" #include "ui/aura/mus/property_converter.h"
#include "ui/aura/mus/window_port_mus.h" #include "ui/aura/mus/window_port_mus.h"
#include "ui/aura/mus/window_tree_host_mus.h"
#include "ui/aura/window.h" #include "ui/aura/window.h"
#include "ui/base/ui_base_features.h" #include "ui/base/ui_base_features.h"
#include "ui/compositor/layer.h" #include "ui/compositor/layer.h"
#include "ui/compositor/paint_context.h" #include "ui/compositor/paint_context.h"
#include "ui/compositor/paint_recorder.h" #include "ui/compositor/paint_recorder.h"
#include "ui/events/event_rewriter.h"
#include "ui/views/background.h" #include "ui/views/background.h"
#include "ui/views/mus/mus_client.h" #include "ui/views/mus/mus_client.h"
#include "ui/views/view.h" #include "ui/views/view.h"
#include "ui/views/widget/native_widget_aura.h" #include "ui/views/widget/native_widget_aura.h"
#include "ui/views/widget/widget.h" #include "ui/views/widget/widget.h"
#include "ui/views/window/non_client_view.h" #include "ui/views/window/non_client_view.h"
#include "ui/wm/core/window_util.h"
namespace { namespace {
// This class rewrites located events to have no target so the target will be
// found via local process hit testing instead of the window service, which is
// unaware of the browser's top container that is on top of the web contents. An
// instance is active whenever the Mash reveal widget is active.
class LocatedEventRetargeter : public ui::EventRewriter {
public:
LocatedEventRetargeter() {}
~LocatedEventRetargeter() override {}
ui::EventRewriteStatus RewriteEvent(
const ui::Event& event,
std::unique_ptr<ui::Event>* rewritten_event) override {
if (!event.IsLocatedEvent())
return ui::EVENT_REWRITE_CONTINUE;
// Before being sent to the rewriters, the event is already cloned which
// strips its EventTarget. The only goal of this EventRewriter is to null
// the target, so there's no need to do anything extra here.
DCHECK(!event.target());
*rewritten_event = ui::Event::Clone(event);
return ui::EVENT_REWRITE_REWRITTEN;
}
ui::EventRewriteStatus NextDispatchEvent(
const ui::Event& last_event,
std::unique_ptr<ui::Event>* new_event) override {
return ui::EVENT_REWRITE_CONTINUE;
}
private:
DISALLOW_COPY_AND_ASSIGN(LocatedEventRetargeter);
};
// Converts from ImmersiveModeController::AnimateReveal to // Converts from ImmersiveModeController::AnimateReveal to
// ash::ImmersiveFullscreenController::AnimateReveal. // ash::ImmersiveFullscreenController::AnimateReveal.
ash::ImmersiveFullscreenController::AnimateReveal ash::ImmersiveFullscreenController::AnimateReveal
...@@ -64,46 +99,12 @@ class ImmersiveRevealedLockAsh : public ImmersiveRevealedLock { ...@@ -64,46 +99,12 @@ class ImmersiveRevealedLockAsh : public ImmersiveRevealedLock {
DISALLOW_COPY_AND_ASSIGN(ImmersiveRevealedLockAsh); DISALLOW_COPY_AND_ASSIGN(ImmersiveRevealedLockAsh);
}; };
// View responsible for mirroring the content of the TopContainer. This is done
// by way of mirroring the actual layers.
class TopContainerMirrorView : public views::View {
public:
explicit TopContainerMirrorView(views::View* view) : view_(view) {
DCHECK(view_->layer());
SetPaintToLayer();
layer()->SetFillsBoundsOpaquely(false);
// At this point we have no size. Wait for the first resize before we
// create the mirrored layer.
}
~TopContainerMirrorView() override {}
// views::View:
void OnBoundsChanged(const gfx::Rect& previous_bounds) override {
if (mirrored_layer_tree_owner_ &&
mirrored_layer_tree_owner_->root()->size() == size()) {
return;
}
mirrored_layer_tree_owner_.reset();
DCHECK(view_->layer()); // SetPaintToLayer() should have been called.
mirrored_layer_tree_owner_ = wm::MirrorLayers(view_, false);
mirrored_layer_tree_owner_->root()->SetBounds(gfx::Rect(size()));
layer()->Add(mirrored_layer_tree_owner_->root());
}
private:
views::View* view_;
std::unique_ptr<ui::LayerTreeOwner> mirrored_layer_tree_owner_;
DISALLOW_COPY_AND_ASSIGN(TopContainerMirrorView);
};
} // namespace } // namespace
ImmersiveModeControllerAsh::ImmersiveModeControllerAsh() ImmersiveModeControllerAsh::ImmersiveModeControllerAsh()
: ImmersiveModeController(Type::ASH), : ImmersiveModeController(Type::ASH),
controller_(new ash::ImmersiveFullscreenController) {} controller_(new ash::ImmersiveFullscreenController),
event_rewriter_(std::make_unique<LocatedEventRetargeter>()) {}
ImmersiveModeControllerAsh::~ImmersiveModeControllerAsh() = default; ImmersiveModeControllerAsh::~ImmersiveModeControllerAsh() = default;
...@@ -220,28 +221,34 @@ void ImmersiveModeControllerAsh::CreateMashRevealWidget() { ...@@ -220,28 +221,34 @@ void ImmersiveModeControllerAsh::CreateMashRevealWidget() {
[ui::mojom::WindowManager::kWindowIgnoredByShelf_InitProperty] = [ui::mojom::WindowManager::kWindowIgnoredByShelf_InitProperty] =
mojo::ConvertTo<std::vector<uint8_t>>(true); mojo::ConvertTo<std::vector<uint8_t>>(true);
init_params.name = "ChromeImmersiveRevealWindow"; init_params.name = "ChromeImmersiveRevealWindow";
// We want events to fall through to the real views.
init_params.accept_events = false;
init_params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; init_params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
init_params.activatable = views::Widget::InitParams::ACTIVATABLE_NO; init_params.activatable = views::Widget::InitParams::ACTIVATABLE_NO;
init_params.parent = browser_view_->GetNativeWindow()->GetRootWindow(); init_params.parent = browser_view_->GetNativeWindow()->GetRootWindow();
// The widget needs to be translucent so the frame decorations drawn by the // The widget needs to be translucent so the frame decorations drawn by the
// window manager are visible. // window manager are visible.
init_params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; init_params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
const gfx::Rect& top_container_bounds = init_params.bounds = GetScreenBoundsForRevealWidget();
browser_view_->top_container()->bounds();
init_params.bounds =
gfx::Rect(0, -top_container_bounds.height(), top_container_bounds.width(),
top_container_bounds.height());
mash_reveal_widget_->Init(init_params); mash_reveal_widget_->Init(init_params);
mash_reveal_widget_->SetContentsView(
new TopContainerMirrorView(browser_view_->top_container()));
mash_reveal_widget_->StackAtTop(); mash_reveal_widget_->StackAtTop();
mash_reveal_widget_->Show(); mash_reveal_widget_->Show();
browser_view_->GetWidget()
->GetNativeWindow()
->GetHost()
->GetEventSource()
->AddEventRewriter(event_rewriter_.get());
} }
void ImmersiveModeControllerAsh::DestroyMashRevealWidget() { void ImmersiveModeControllerAsh::DestroyMashRevealWidget() {
mash_reveal_widget_.reset(); if (mash_reveal_widget_) {
browser_view_->GetWidget()
->GetNativeWindow()
->GetHost()
->GetEventSource()
->RemoveEventRewriter(event_rewriter_.get());
mash_reveal_widget_.reset();
}
} }
void ImmersiveModeControllerAsh::OnImmersiveRevealStarted() { void ImmersiveModeControllerAsh::OnImmersiveRevealStarted() {
...@@ -283,11 +290,8 @@ void ImmersiveModeControllerAsh::SetVisibleFraction(double visible_fraction) { ...@@ -283,11 +290,8 @@ void ImmersiveModeControllerAsh::SetVisibleFraction(double visible_fraction) {
browser_view_->Layout(); browser_view_->Layout();
browser_view_->frame()->GetFrameView()->UpdateClientArea(); browser_view_->frame()->GetFrameView()->UpdateClientArea();
if (mash_reveal_widget_) { if (mash_reveal_widget_)
gfx::Rect bounds = mash_reveal_widget_->GetNativeWindow()->bounds(); mash_reveal_widget_->SetBounds(GetScreenBoundsForRevealWidget());
bounds.set_y(visible_fraction * bounds.height() - bounds.height());
mash_reveal_widget_->SetBounds(bounds);
}
} }
std::vector<gfx::Rect> std::vector<gfx::Rect>
...@@ -351,3 +355,17 @@ void ImmersiveModeControllerAsh::OnWindowDestroying(aura::Window* window) { ...@@ -351,3 +355,17 @@ void ImmersiveModeControllerAsh::OnWindowDestroying(aura::Window* window) {
observed_windows_.Remove(window); observed_windows_.Remove(window);
DCHECK(!observed_windows_.IsObservingSources()); DCHECK(!observed_windows_.IsObservingSources());
} }
gfx::Rect ImmersiveModeControllerAsh::GetScreenBoundsForRevealWidget() {
const gfx::Rect* inverted_caption_button_bounds =
browser_view_->GetWidget()
->GetNativeWindow()
->GetRootWindow()
->GetProperty(ash::kCaptionButtonBoundsKey);
if (!inverted_caption_button_bounds)
return gfx::Rect();
gfx::Rect top_container_bounds =
browser_view_->top_container()->GetBoundsInScreen();
return *inverted_caption_button_bounds +
gfx::Vector2d(top_container_bounds.right(), top_container_bounds.y());
}
...@@ -21,6 +21,10 @@ namespace aura { ...@@ -21,6 +21,10 @@ namespace aura {
class Window; class Window;
} }
namespace ui {
class EventRewriter;
}
// See ash/mus/frame/README.md for description of how immersive mode works in // See ash/mus/frame/README.md for description of how immersive mode works in
// mash. This code works with both classic ash, and mash. // mash. This code works with both classic ash, and mash.
class ImmersiveModeControllerAsh class ImmersiveModeControllerAsh
...@@ -80,6 +84,8 @@ class ImmersiveModeControllerAsh ...@@ -80,6 +84,8 @@ class ImmersiveModeControllerAsh
intptr_t old) override; intptr_t old) override;
void OnWindowDestroying(aura::Window* window) override; void OnWindowDestroying(aura::Window* window) override;
gfx::Rect GetScreenBoundsForRevealWidget();
std::unique_ptr<ash::ImmersiveFullscreenController> controller_; std::unique_ptr<ash::ImmersiveFullscreenController> controller_;
BrowserView* browser_view_ = nullptr; BrowserView* browser_view_ = nullptr;
...@@ -92,10 +98,13 @@ class ImmersiveModeControllerAsh ...@@ -92,10 +98,13 @@ class ImmersiveModeControllerAsh
// the top-of-window views are not revealed. // the top-of-window views are not revealed.
double visible_fraction_ = 1.0; double visible_fraction_ = 1.0;
// When running in mash a widget is created to draw the top container. This // When running in mash a widget is created to draw window controls on top of
// widget does not actually contain the top container, it just renders it. // the browser's |top_container|.
std::unique_ptr<views::Widget> mash_reveal_widget_; std::unique_ptr<views::Widget> mash_reveal_widget_;
// See comment above LocatedEventRetargeter.
std::unique_ptr<ui::EventRewriter> event_rewriter_;
content::NotificationRegistrar registrar_; content::NotificationRegistrar registrar_;
ScopedObserver<aura::Window, aura::WindowObserver> observed_windows_{this}; ScopedObserver<aura::Window, aura::WindowObserver> observed_windows_{this};
......
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