Commit a8745244 authored by Sidney San Martín's avatar Sidney San Martín Committed by Commit Bot

Use the regular layer tree for fullscreen low power detachment on Mac.

Fixes an issue where fullscreen video wasn't positioned correctly in the
low power tree for some sites, and a longstanding issue where clipped
videos become un-clipped in the fullscreen low power tree.

Made possible by two changes:

- Black and transparent backgrounds are no longer rendered as IOSurfaces
  for color correction. For macOS to consider a layer solid black, it
  needs to actually have a black background color (and no contents).
  Note: I think we can avoid IOSurface replacement by setting a flag or
  two on the CAContext. See https://crrev.com/c/742663.

- Instead of constructing a new layer tree for fullscreen low power,
  just make the root layer black and match its size to the background to
  meet the "opaque black superlayer" requirement for detachment. A nicer
  solution could be to send the browser a color, since it already has a
  solid color superlayer, in which case no special handling for
  fullscreen layer detachment would be needed at all, it would "just
  work". It still needs to be determined whether that would comply with
  the HTML fullscreen spec. See https://crbug.com/785001.

Bug: 781637
Change-Id: I94abb1ade9c58c218296a27f9a7bc3630d4a0c64
Reviewed-on: https://chromium-review.googlesource.com/775139
Commit-Queue: Sidney San Martín <sdy@chromium.org>
Reviewed-by: default avatarccameron <ccameron@chromium.org>
Cr-Commit-Position: refs/heads/master@{#517879}
parent 7fb06bca
...@@ -94,20 +94,17 @@ class ACCELERATED_WIDGET_MAC_EXPORT CARendererLayerTree { ...@@ -94,20 +94,17 @@ class ACCELERATED_WIDGET_MAC_EXPORT CARendererLayerTree {
RootLayer* old_layer, RootLayer* old_layer,
float scale_factor); float scale_factor);
// Check to see if the CALayer tree can be represented entirely by a video // Check to see if the CALayer tree is just a video layer on a black
// layer on a black background. If so, then commit the layer, assign it to // background. If so, return true and set background_rect to the
// |low_power_layer|, and return true. Otherwise return false. This is to // background's bounding rect, otherwise return false. CommitToCA() calls
// be called by CommitToCA(). // this function and, based on its return value, either gives the root
bool CommitFullscreenLowPowerLayer(ContentLayer* old_low_power_layer, // layer this frame and a black background color or clears them.
float scale_factor); bool WantsFullcreenLowPowerBackdrop(float scale_factor,
gfx::RectF* background_rect);
std::vector<ClipAndSortingLayer> clip_and_sorting_layers; std::vector<ClipAndSortingLayer> clip_and_sorting_layers;
base::scoped_nsobject<CALayer> ca_layer; base::scoped_nsobject<CALayer> ca_layer;
// Weak pointer to a child ContentLayer, if any, which is presented alone
// for fullscreen low power mode. Set by CommitFullscreenLowPowerLayer().
ContentLayer* low_power_layer = nullptr;
private: private:
DISALLOW_COPY_AND_ASSIGN(RootLayer); DISALLOW_COPY_AND_ASSIGN(RootLayer);
}; };
......
...@@ -218,31 +218,24 @@ void CARendererLayerTree::CommitScheduledCALayers( ...@@ -218,31 +218,24 @@ void CARendererLayerTree::CommitScheduledCALayers(
scale_factor_ = scale_factor; scale_factor_ = scale_factor;
} }
bool CARendererLayerTree::RootLayer::CommitFullscreenLowPowerLayer( bool CARendererLayerTree::RootLayer::WantsFullcreenLowPowerBackdrop(
ContentLayer* old_low_power_layer, float scale_factor,
float scale_factor) { gfx::RectF* background_rect) {
ContentLayer* video_layer = nullptr; bool found_video_layer = false;
CGRect clip_rect;
CGRect frame_rect;
for (auto& clip_layer : clip_and_sorting_layers) { for (auto& clip_layer : clip_and_sorting_layers) {
for (auto& transform_layer : clip_layer.transform_layers) { for (auto& transform_layer : clip_layer.transform_layers) {
for (auto& content_layer : transform_layer.content_layers) { for (auto& content_layer : transform_layer.content_layers) {
// Detached mode requires that no layers be on top of the video layer. // Detached mode requires that no layers be on top of the video layer.
if (video_layer) if (found_video_layer)
return false; return false;
// See if this is the video layer. // See if this is the video layer.
if (content_layer.use_av_layer) { if (content_layer.use_av_layer) {
video_layer = &content_layer; found_video_layer = true;
if (!transform_layer.transform.IsPositiveScaleOrTranslation()) if (!transform_layer.transform.IsPositiveScaleOrTranslation())
return false; return false;
if (content_layer.opacity != 1) if (content_layer.opacity != 1)
return false; return false;
clip_rect = clip_layer.clip_rect.ToCGRect();
gfx::RectF frame_rect_f(video_layer->rect);
transform_layer.transform.TransformRect(&frame_rect_f);
frame_rect_f.Scale(1 / scale_factor);
frame_rect = frame_rect_f.ToCGRect();
continue; continue;
} }
...@@ -250,25 +243,16 @@ bool CARendererLayerTree::RootLayer::CommitFullscreenLowPowerLayer( ...@@ -250,25 +243,16 @@ bool CARendererLayerTree::RootLayer::CommitFullscreenLowPowerLayer(
// solid black or transparent // solid black or transparent
if (content_layer.io_surface) if (content_layer.io_surface)
return false; return false;
if (content_layer.background_color != SK_ColorBLACK && if (content_layer.background_color == SK_ColorBLACK) {
content_layer.background_color != SK_ColorTRANSPARENT) { background_rect->Union(gfx::RectF(content_layer.rect));
} else if (content_layer.background_color != SK_ColorTRANSPARENT) {
return false; return false;
} }
} }
} }
} }
if (!video_layer) background_rect->Scale(1 / scale_factor);
return false; return found_video_layer;
low_power_layer = video_layer;
low_power_layer->CommitToCA(ca_layer, old_low_power_layer, scale_factor);
if (![ca_layer backgroundColor])
[ca_layer setBackgroundColor:CGColorGetConstantColor(kCGColorBlack)];
if (!CGRectEqualToRect([ca_layer frame], clip_rect))
[ca_layer setFrame:clip_rect];
if (!CGRectEqualToRect([low_power_layer->ca_layer frame], frame_rect))
[low_power_layer->ca_layer setFrame:frame_rect];
return true;
} }
id CARendererLayerTree::ContentsForSolidColorForTesting(SkColor color) { id CARendererLayerTree::ContentsForSolidColorForTesting(SkColor color) {
...@@ -377,9 +361,13 @@ CARendererLayerTree::ContentLayer::ContentLayer( ...@@ -377,9 +361,13 @@ CARendererLayerTree::ContentLayer::ContentLayer(
// output monitor color space, but IOSurface-backed layers are color // output monitor color space, but IOSurface-backed layers are color
// corrected. Note that this is only the case when the CALayers are shared // corrected. Note that this is only the case when the CALayers are shared
// across processes. To make colors consistent across both solid color and // across processes. To make colors consistent across both solid color and
// IOSurface-backed layers, use a cache of solid-color IOSurfaces as contents. // IOSurface-backed layers, use a cache of solid-color IOSurfaces as
// contents. Black and transparent layers must use real colors to be eligible
// for low power detachment in fullscreen.
// https://crbug.com/633805 // https://crbug.com/633805
if (!io_surface && !tree->allow_solid_color_layers_) { if (!io_surface && !tree->allow_solid_color_layers_ &&
background_color != SK_ColorBLACK &&
background_color != SK_ColorTRANSPARENT) {
solid_color_contents = SolidColorContents::Get(background_color); solid_color_contents = SolidColorContents::Get(background_color);
ContentLayer::contents_rect = gfx::RectF(0, 0, 1, 1); ContentLayer::contents_rect = gfx::RectF(0, 0, 1, 1);
} }
...@@ -529,18 +517,17 @@ void CARendererLayerTree::RootLayer::CommitToCA(CALayer* superlayer, ...@@ -529,18 +517,17 @@ void CARendererLayerTree::RootLayer::CommitToCA(CALayer* superlayer,
DLOG(ERROR) << "CARendererLayerTree root layer not attached to tree."; DLOG(ERROR) << "CARendererLayerTree root layer not attached to tree.";
} }
ContentLayer* old_low_power_layer = gfx::RectF bg_rect;
old_layer ? old_layer->low_power_layer : nullptr; if (WantsFullcreenLowPowerBackdrop(scale_factor, &bg_rect)) {
if (gfx::RectF([ca_layer frame]) != bg_rect)
if (CommitFullscreenLowPowerLayer(old_low_power_layer, scale_factor)) { [ca_layer setFrame:bg_rect.ToCGRect()];
return; if (![ca_layer backgroundColor])
} else if (old_low_power_layer) { [ca_layer setBackgroundColor:CGColorGetConstantColor(kCGColorBlack)];
// Transitioning out of fullscreen low power mode, so: } else {
// 1. Reset the root CALayer's background color and frame. if (gfx::RectF([ca_layer frame]) != gfx::RectF())
[ca_layer setBackgroundColor:nil]; [ca_layer setFrame:CGRectZero];
[ca_layer setFrame:CGRectZero]; if ([ca_layer backgroundColor])
// 2. Reset old_layer so that the CALayer tree is rebuilt from scratch. [ca_layer setBackgroundColor:nil];
old_layer = nullptr;
} }
for (size_t i = 0; i < clip_and_sorting_layers.size(); ++i) { for (size_t i = 0; i < clip_and_sorting_layers.size(); ++i) {
......
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