summaryrefslogtreecommitdiff
path: root/chromium/ui/accelerated_widget_mac
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2017-01-04 14:17:57 +0100
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2017-01-05 10:05:06 +0000
commit39d357e3248f80abea0159765ff39554affb40db (patch)
treeaba0e6bfb76de0244bba0f5fdbd64b830dd6e621 /chromium/ui/accelerated_widget_mac
parent87778abf5a1f89266f37d1321b92a21851d8244d (diff)
downloadqtwebengine-chromium-39d357e3248f80abea0159765ff39554affb40db.tar.gz
BASELINE: Update Chromium to 55.0.2883.105
And updates ninja to 1.7.2 Change-Id: I20d43c737f82764d857ada9a55586901b18b9243 Reviewed-by: Michael BrĂ¼ning <michael.bruning@qt.io>
Diffstat (limited to 'chromium/ui/accelerated_widget_mac')
-rw-r--r--chromium/ui/accelerated_widget_mac/BUILD.gn5
-rw-r--r--chromium/ui/accelerated_widget_mac/accelerated_widget_mac.gyp77
-rw-r--r--chromium/ui/accelerated_widget_mac/ca_layer_tree_coordinator.h11
-rw-r--r--chromium/ui/accelerated_widget_mac/ca_layer_tree_coordinator.mm37
-rw-r--r--chromium/ui/accelerated_widget_mac/ca_layer_tree_unittest_mac.mm923
-rw-r--r--chromium/ui/accelerated_widget_mac/ca_renderer_layer_tree.h68
-rw-r--r--chromium/ui/accelerated_widget_mac/ca_renderer_layer_tree.mm233
7 files changed, 735 insertions, 619 deletions
diff --git a/chromium/ui/accelerated_widget_mac/BUILD.gn b/chromium/ui/accelerated_widget_mac/BUILD.gn
index 4e5a22ec31f..64834180917 100644
--- a/chromium/ui/accelerated_widget_mac/BUILD.gn
+++ b/chromium/ui/accelerated_widget_mac/BUILD.gn
@@ -4,7 +4,6 @@
import("//testing/test.gni")
-# GYP version: ui/accelerated_widget_mac/accelerated_widget_mac.gyp:accelerated_widget_mac
component("accelerated_widget_mac") {
sources = [
"accelerated_widget_mac.h",
@@ -39,7 +38,6 @@ component("accelerated_widget_mac") {
]
libs = [
- "ApplicationServices.framework", # Temporary hack around https://crbug.com/620127. Remove after https://crbug.com/622481 is fixed.
"AVFoundation.framework",
"CoreGraphics.framework",
"Foundation.framework",
@@ -51,7 +49,6 @@ component("accelerated_widget_mac") {
]
}
-# GYP version: ui/accelerated_widget_mac/accelerated_widget_mac.gyp:accelerated_widget_mac_unittests
test("accelerated_widget_mac_unittests") {
configs += [ "//build/config:precompiled_headers" ]
sources = [
@@ -66,7 +63,7 @@ test("accelerated_widget_mac_unittests") {
"//testing/gmock",
"//testing/gtest",
"//ui/gfx:test_support",
- "//ui/gl:test_support",
+ "//ui/gl",
]
libs = [
"AVFoundation.framework",
diff --git a/chromium/ui/accelerated_widget_mac/accelerated_widget_mac.gyp b/chromium/ui/accelerated_widget_mac/accelerated_widget_mac.gyp
deleted file mode 100644
index 40bbec7882a..00000000000
--- a/chromium/ui/accelerated_widget_mac/accelerated_widget_mac.gyp
+++ /dev/null
@@ -1,77 +0,0 @@
-# Copyright 2014 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-{
- 'variables': {
- 'chromium_code': 1,
- },
- 'targets': [
- {
- # GN version: //ui/accelerated_widget_mac
- 'target_name': 'accelerated_widget_mac',
- 'type': '<(component)',
- 'sources': [
- 'accelerated_widget_mac.h',
- 'accelerated_widget_mac.mm',
- 'accelerated_widget_mac_export.h',
- 'ca_layer_tree_coordinator.h',
- 'ca_layer_tree_coordinator.mm',
- 'ca_renderer_layer_tree.h',
- 'ca_renderer_layer_tree.mm',
- 'display_link_mac.cc',
- 'display_link_mac.h',
- 'fullscreen_low_power_coordinator.h',
- 'gl_renderer_layer_tree.h',
- 'gl_renderer_layer_tree.mm',
- 'io_surface_context.h',
- 'io_surface_context.mm',
- 'window_resize_helper_mac.cc',
- 'window_resize_helper_mac.h',
- ],
- 'defines': [
- 'ACCELERATED_WIDGET_MAC_IMPLEMENTATION',
- ],
- 'dependencies': [
- '<(DEPTH)/base/base.gyp:base',
- '<(DEPTH)/skia/skia.gyp:skia',
- '<(DEPTH)/third_party/khronos/khronos.gyp:khronos_headers',
- '<(DEPTH)/ui/base/ui_base.gyp:ui_base',
- '<(DEPTH)/ui/events/events.gyp:events_base',
- '<(DEPTH)/ui/gfx/gfx.gyp:gfx',
- '<(DEPTH)/ui/gfx/gfx.gyp:gfx_geometry',
- '<(DEPTH)/ui/gl/gl.gyp:gl',
- ],
- 'link_settings': {
- 'libraries': [
- '$(SDKROOT)/System/Library/Frameworks/AVFoundation.framework',
- '$(SDKROOT)/System/Library/Frameworks/CoreMedia.framework',
- '$(SDKROOT)/System/Library/Frameworks/QuartzCore.framework',
- ],
- },
- },
- {
- # GN version: //ui/accelerated_widget_mac:accelerated_widget_mac_unittests
- 'target_name': 'accelerated_widget_mac_unittests',
- 'type': '<(gtest_target_type)',
- 'dependencies': [
- '<(DEPTH)/base/base.gyp:base',
- '<(DEPTH)/base/base.gyp:run_all_unittests',
- '<(DEPTH)/base/base.gyp:test_support_base',
- '<(DEPTH)/skia/skia.gyp:skia',
- '<(DEPTH)/testing/gmock.gyp:gmock',
- '<(DEPTH)/testing/gtest.gyp:gtest',
- '<(DEPTH)/ui/gfx/gfx.gyp:gfx_test_support',
- 'accelerated_widget_mac',
- ],
- 'sources': [
- 'ca_layer_tree_unittest_mac.mm',
- ],
- 'link_settings': {
- 'libraries': [
- '$(SDKROOT)/System/Library/Frameworks/QuartzCore.framework',
- ],
- },
- },
- ],
-}
diff --git a/chromium/ui/accelerated_widget_mac/ca_layer_tree_coordinator.h b/chromium/ui/accelerated_widget_mac/ca_layer_tree_coordinator.h
index 6cd1c493d17..2602c252273 100644
--- a/chromium/ui/accelerated_widget_mac/ca_layer_tree_coordinator.h
+++ b/chromium/ui/accelerated_widget_mac/ca_layer_tree_coordinator.h
@@ -21,7 +21,8 @@ namespace ui {
// to the browser process in https://crbug.com/604052.
class ACCELERATED_WIDGET_MAC_EXPORT CALayerTreeCoordinator {
public:
- explicit CALayerTreeCoordinator(bool allow_remote_layers);
+ explicit CALayerTreeCoordinator(bool allow_remote_layers,
+ bool allow_av_sample_buffer_display_layer);
~CALayerTreeCoordinator();
// Set the composited frame's size.
@@ -56,7 +57,8 @@ class ACCELERATED_WIDGET_MAC_EXPORT CALayerTreeCoordinator {
IOSurfaceRef GetIOSurfaceForDisplay();
private:
- bool allow_remote_layers_ = true;
+ const bool allow_remote_layers_ = true;
+ const bool allow_av_sample_buffer_display_layer_ = true;
gfx::Size pixel_size_;
float scale_factor_ = 1;
@@ -71,7 +73,10 @@ class ACCELERATED_WIDGET_MAC_EXPORT CALayerTreeCoordinator {
// Frame that is currently being displayed on the screen.
std::unique_ptr<GLRendererLayerTree> current_gl_renderer_layer_tree_;
std::unique_ptr<CARendererLayerTree> current_ca_renderer_layer_tree_;
- bool current_fullscreen_low_power_layer_valid_ = false;
+
+ // The number of frames since we used the low power layer. Used to avoid
+ // flashes during transitions between windows.
+ uint64_t frames_since_low_power_layer_was_valid_ = 0;
DISALLOW_COPY_AND_ASSIGN(CALayerTreeCoordinator);
};
diff --git a/chromium/ui/accelerated_widget_mac/ca_layer_tree_coordinator.mm b/chromium/ui/accelerated_widget_mac/ca_layer_tree_coordinator.mm
index 5aaeb023ea0..e8a8dc40839 100644
--- a/chromium/ui/accelerated_widget_mac/ca_layer_tree_coordinator.mm
+++ b/chromium/ui/accelerated_widget_mac/ca_layer_tree_coordinator.mm
@@ -6,20 +6,31 @@
#include <AVFoundation/AVFoundation.h>
+#include "base/mac/mac_util.h"
#include "base/trace_event/trace_event.h"
#include "ui/base/cocoa/animation_utils.h"
namespace ui {
-CALayerTreeCoordinator::CALayerTreeCoordinator(bool allow_remote_layers)
- : allow_remote_layers_(allow_remote_layers) {
+namespace {
+const uint64_t kFramesBeforeFlushingLowPowerLayer = 15;
+}
+
+CALayerTreeCoordinator::CALayerTreeCoordinator(
+ bool allow_remote_layers,
+ bool allow_av_sample_buffer_display_layer)
+ : allow_remote_layers_(allow_remote_layers),
+ allow_av_sample_buffer_display_layer_(
+ allow_av_sample_buffer_display_layer) {
if (allow_remote_layers_) {
root_ca_layer_.reset([[CALayer alloc] init]);
[root_ca_layer_ setGeometryFlipped:YES];
[root_ca_layer_ setOpaque:YES];
- fullscreen_low_power_layer_.reset(
- [[AVSampleBufferDisplayLayer alloc] init]);
+ if (allow_av_sample_buffer_display_layer_) {
+ fullscreen_low_power_layer_.reset(
+ [[AVSampleBufferDisplayLayer alloc] init]);
+ }
}
}
@@ -55,7 +66,8 @@ CARendererLayerTree* CALayerTreeCoordinator::GetPendingCARendererLayerTree() {
"specified, but not both.";
}
if (!pending_ca_renderer_layer_tree_)
- pending_ca_renderer_layer_tree_.reset(new CARendererLayerTree);
+ pending_ca_renderer_layer_tree_.reset(new CARendererLayerTree(
+ allow_av_sample_buffer_display_layer_, false));
return pending_ca_renderer_layer_tree_.get();
}
@@ -88,14 +100,15 @@ void CALayerTreeCoordinator::CommitPendingTreesToCA(
current_ca_renderer_layer_tree_.reset();
}
- // TODO(ccameron): It may be necessary to leave the last image up for a few
- // extra frames to allow a smooth switch between the normal and low-power
- // NSWindows.
- if (current_fullscreen_low_power_layer_valid_ &&
- !*fullscreen_low_power_layer_valid) {
+ // It is necessary to leave the last image up for a few extra frames to allow
+ // a smooth switch between the normal and low-power NSWindows.
+ if (*fullscreen_low_power_layer_valid)
+ frames_since_low_power_layer_was_valid_ = 0;
+ else
+ frames_since_low_power_layer_was_valid_ += 1;
+ if (frames_since_low_power_layer_was_valid_ ==
+ kFramesBeforeFlushingLowPowerLayer)
[fullscreen_low_power_layer_ flushAndRemoveImage];
- }
- current_fullscreen_low_power_layer_valid_ = *fullscreen_low_power_layer_valid;
// Reset all state for the next frame.
pending_ca_renderer_layer_tree_.reset();
diff --git a/chromium/ui/accelerated_widget_mac/ca_layer_tree_unittest_mac.mm b/chromium/ui/accelerated_widget_mac/ca_layer_tree_unittest_mac.mm
index 882fc8c887d..e8cabcd6d94 100644
--- a/chromium/ui/accelerated_widget_mac/ca_layer_tree_unittest_mac.mm
+++ b/chromium/ui/accelerated_widget_mac/ca_layer_tree_unittest_mac.mm
@@ -13,12 +13,20 @@
#include "ui/accelerated_widget_mac/ca_renderer_layer_tree.h"
#include "ui/gfx/geometry/dip_util.h"
#include "ui/gfx/mac/io_surface.h"
+#include "ui/gl/ca_renderer_layer_params.h"
+#include "ui/gl/gl_image_io_surface.h"
namespace gpu {
namespace {
struct CALayerProperties {
+ CALayerProperties() {}
+ ~CALayerProperties() {
+ if (gl_image)
+ gl_image->Destroy(true);
+ }
+
bool is_clipped = true;
gfx::Rect clip_rect;
int sorting_context_id = 0;
@@ -30,25 +38,47 @@ struct CALayerProperties {
float opacity = 1.0f;
float scale_factor = 1.0f;
unsigned filter = GL_LINEAR;
- base::ScopedCFTypeRef<CVPixelBufferRef> cv_pixel_buffer;
- base::ScopedCFTypeRef<IOSurfaceRef> io_surface;
+ scoped_refptr<gl::GLImageIOSurface> gl_image;
+
+ bool allow_av_layers = true;
+ bool allow_solid_color_layers = true;
};
+scoped_refptr<gl::GLImageIOSurface> CreateGLImage(const gfx::Size& size,
+ gfx::BufferFormat format,
+ bool video) {
+ scoped_refptr<gl::GLImageIOSurface> gl_image(
+ new gl::GLImageIOSurface(size, GL_RGBA));
+ base::ScopedCFTypeRef<IOSurfaceRef> io_surface(
+ gfx::CreateIOSurface(size, format));
+ if (video) {
+ base::ScopedCFTypeRef<CVPixelBufferRef> cv_pixel_buffer;
+ CVPixelBufferCreateWithIOSurface(nullptr, io_surface, nullptr,
+ cv_pixel_buffer.InitializeInto());
+ gl_image->InitializeWithCVPixelBuffer(cv_pixel_buffer,
+ gfx::GenericSharedMemoryId(), format);
+ } else {
+ gl_image->Initialize(io_surface, gfx::GenericSharedMemoryId(), format);
+ }
+ return gl_image;
+}
+
bool ScheduleCALayer(ui::CARendererLayerTree* tree,
CALayerProperties* properties) {
- return tree->ScheduleCALayer(
+ return tree->ScheduleCALayer(ui::CARendererLayerParams(
properties->is_clipped, properties->clip_rect,
properties->sorting_context_id, properties->transform,
- properties->io_surface, properties->cv_pixel_buffer,
- properties->contents_rect, properties->rect, properties->background_color,
- properties->edge_aa_mask, properties->opacity, properties->filter);
+ properties->gl_image.get(), properties->contents_rect, properties->rect,
+ properties->background_color, properties->edge_aa_mask,
+ properties->opacity, properties->filter));
}
void UpdateCALayerTree(std::unique_ptr<ui::CARendererLayerTree>& ca_layer_tree,
CALayerProperties* properties,
CALayer* superlayer) {
std::unique_ptr<ui::CARendererLayerTree> new_ca_layer_tree(
- new ui::CARendererLayerTree);
+ new ui::CARendererLayerTree(properties->allow_av_layers,
+ properties->allow_solid_color_layers));
bool result = ScheduleCALayer(new_ca_layer_tree.get(), properties);
EXPECT_TRUE(result);
new_ca_layer_tree->CommitScheduledCALayers(
@@ -71,350 +101,385 @@ class CALayerTreeTest : public testing::Test {
};
// Test updating each layer's properties.
-TEST_F(CALayerTreeTest, PropertyUpdates) {
- CALayerProperties properties;
- properties.clip_rect = gfx::Rect(2, 4, 8, 16);
- properties.transform.Translate(10, 20);
- properties.contents_rect = gfx::RectF(0.0f, 0.25f, 0.5f, 0.75f);
- properties.rect = gfx::Rect(16, 32, 64, 128);
- properties.background_color = SkColorSetARGB(0xFF, 0xFF, 0, 0);
- properties.edge_aa_mask = GL_CA_LAYER_EDGE_LEFT_CHROMIUM;
- properties.opacity = 0.5f;
- properties.io_surface.reset(
- gfx::CreateIOSurface(gfx::Size(256, 256), gfx::BufferFormat::BGRA_8888));
-
- std::unique_ptr<ui::CARendererLayerTree> ca_layer_tree;
- CALayer* root_layer = nil;
- CALayer* clip_and_sorting_layer = nil;
- CALayer* transform_layer = nil;
- CALayer* content_layer = nil;
-
- // Validate the initial values.
- {
- std::unique_ptr<ui::CARendererLayerTree> new_ca_layer_tree(
- new ui::CARendererLayerTree);
-
- UpdateCALayerTree(ca_layer_tree, &properties, superlayer_);
-
- // Validate the tree structure.
- EXPECT_EQ(1u, [[superlayer_ sublayers] count]);
- root_layer = [[superlayer_ sublayers] objectAtIndex:0];
- EXPECT_EQ(1u, [[root_layer sublayers] count]);
- clip_and_sorting_layer = [[root_layer sublayers] objectAtIndex:0];
- EXPECT_EQ(1u, [[clip_and_sorting_layer sublayers] count]);
- transform_layer = [[clip_and_sorting_layer sublayers] objectAtIndex:0];
- EXPECT_EQ(1u, [[transform_layer sublayers] count]);
- content_layer = [[transform_layer sublayers] objectAtIndex:0];
-
- // Validate the clip and sorting context layer.
- EXPECT_TRUE([clip_and_sorting_layer masksToBounds]);
- EXPECT_EQ(gfx::Rect(properties.clip_rect.size()),
- gfx::Rect([clip_and_sorting_layer bounds]));
- EXPECT_EQ(properties.clip_rect.origin(),
- gfx::Point([clip_and_sorting_layer position]));
- EXPECT_EQ(-properties.clip_rect.origin().x(),
- [clip_and_sorting_layer sublayerTransform].m41);
- EXPECT_EQ(-properties.clip_rect.origin().y(),
- [clip_and_sorting_layer sublayerTransform].m42);
-
- // Validate the transform layer.
- EXPECT_EQ(properties.transform.matrix().get(3, 0),
- [transform_layer sublayerTransform].m41);
- EXPECT_EQ(properties.transform.matrix().get(3, 1),
- [transform_layer sublayerTransform].m42);
-
- // Validate the content layer.
- EXPECT_EQ(static_cast<id>(properties.io_surface.get()),
- [content_layer contents]);
- EXPECT_EQ(properties.contents_rect,
- gfx::RectF([content_layer contentsRect]));
- EXPECT_EQ(properties.rect.origin(), gfx::Point([content_layer position]));
- EXPECT_EQ(gfx::Rect(properties.rect.size()),
- gfx::Rect([content_layer bounds]));
- EXPECT_EQ(kCALayerLeftEdge, [content_layer edgeAntialiasingMask]);
- EXPECT_EQ(properties.opacity, [content_layer opacity]);
- EXPECT_NSEQ(kCAFilterLinear, [content_layer minificationFilter]);
- EXPECT_NSEQ(kCAFilterLinear, [content_layer magnificationFilter]);
- if ([content_layer respondsToSelector:(@selector(contentsScale))])
- EXPECT_EQ(properties.scale_factor, [content_layer contentsScale]);
- }
-
- // Update just the clip rect and re-commit.
- {
- properties.clip_rect = gfx::Rect(4, 8, 16, 32);
- UpdateCALayerTree(ca_layer_tree, &properties, superlayer_);
-
- // Validate the tree structure
- EXPECT_EQ(1u, [[superlayer_ sublayers] count]);
- EXPECT_EQ(root_layer, [[superlayer_ sublayers] objectAtIndex:0]);
- EXPECT_EQ(1u, [[root_layer sublayers] count]);
- EXPECT_EQ(clip_and_sorting_layer, [[root_layer sublayers] objectAtIndex:0]);
- EXPECT_EQ(1u, [[clip_and_sorting_layer sublayers] count]);
- EXPECT_EQ(transform_layer,
- [[clip_and_sorting_layer sublayers] objectAtIndex:0]);
-
- // Validate the clip and sorting context layer.
- EXPECT_TRUE([clip_and_sorting_layer masksToBounds]);
- EXPECT_EQ(gfx::Rect(properties.clip_rect.size()),
- gfx::Rect([clip_and_sorting_layer bounds]));
- EXPECT_EQ(properties.clip_rect.origin(),
- gfx::Point([clip_and_sorting_layer position]));
- EXPECT_EQ(-properties.clip_rect.origin().x(),
- [clip_and_sorting_layer sublayerTransform].m41);
- EXPECT_EQ(-properties.clip_rect.origin().y(),
- [clip_and_sorting_layer sublayerTransform].m42);
- }
-
- // Disable clipping and re-commit.
- {
- properties.is_clipped = false;
- UpdateCALayerTree(ca_layer_tree, &properties, superlayer_);
-
- // Validate the tree structure
- EXPECT_EQ(1u, [[superlayer_ sublayers] count]);
- EXPECT_EQ(root_layer, [[superlayer_ sublayers] objectAtIndex:0]);
- EXPECT_EQ(1u, [[root_layer sublayers] count]);
- EXPECT_EQ(clip_and_sorting_layer, [[root_layer sublayers] objectAtIndex:0]);
- EXPECT_EQ(1u, [[clip_and_sorting_layer sublayers] count]);
- EXPECT_EQ(transform_layer,
- [[clip_and_sorting_layer sublayers] objectAtIndex:0]);
-
- // Validate the clip and sorting context layer.
- EXPECT_FALSE([clip_and_sorting_layer masksToBounds]);
- EXPECT_EQ(gfx::Rect(), gfx::Rect([clip_and_sorting_layer bounds]));
- EXPECT_EQ(gfx::Point(), gfx::Point([clip_and_sorting_layer position]));
- EXPECT_EQ(0.0, [clip_and_sorting_layer sublayerTransform].m41);
- EXPECT_EQ(0.0, [clip_and_sorting_layer sublayerTransform].m42);
- EXPECT_EQ(1u, [[clip_and_sorting_layer sublayers] count]);
+class CALayerTreePropertyUpdatesTest : public CALayerTreeTest {
+ public:
+ void RunTest(bool allow_solid_color_layers) {
+ CALayerProperties properties;
+ properties.allow_solid_color_layers = allow_solid_color_layers;
+ properties.clip_rect = gfx::Rect(2, 4, 8, 16);
+ properties.transform.Translate(10, 20);
+ properties.contents_rect = gfx::RectF(0.0f, 0.25f, 0.5f, 0.75f);
+ properties.rect = gfx::Rect(16, 32, 64, 128);
+ properties.background_color = SkColorSetARGB(0xFF, 0xFF, 0, 0);
+ properties.edge_aa_mask = GL_CA_LAYER_EDGE_LEFT_CHROMIUM;
+ properties.opacity = 0.5f;
+ properties.gl_image =
+ CreateGLImage(gfx::Size(256, 256), gfx::BufferFormat::BGRA_8888, false);
+
+ std::unique_ptr<ui::CARendererLayerTree> ca_layer_tree;
+ CALayer* root_layer = nil;
+ CALayer* clip_and_sorting_layer = nil;
+ CALayer* transform_layer = nil;
+ CALayer* content_layer = nil;
+
+ // Validate the initial values.
+ {
+ std::unique_ptr<ui::CARendererLayerTree> new_ca_layer_tree(
+ new ui::CARendererLayerTree(true, allow_solid_color_layers));
+
+ UpdateCALayerTree(ca_layer_tree, &properties, superlayer_);
+
+ // Validate the tree structure.
+ EXPECT_EQ(1u, [[superlayer_ sublayers] count]);
+ root_layer = [[superlayer_ sublayers] objectAtIndex:0];
+ EXPECT_EQ(1u, [[root_layer sublayers] count]);
+ clip_and_sorting_layer = [[root_layer sublayers] objectAtIndex:0];
+ EXPECT_EQ(1u, [[clip_and_sorting_layer sublayers] count]);
+ transform_layer = [[clip_and_sorting_layer sublayers] objectAtIndex:0];
+ EXPECT_EQ(1u, [[transform_layer sublayers] count]);
+ content_layer = [[transform_layer sublayers] objectAtIndex:0];
+
+ // Validate the clip and sorting context layer.
+ EXPECT_TRUE([clip_and_sorting_layer masksToBounds]);
+ EXPECT_EQ(gfx::Rect(properties.clip_rect.size()),
+ gfx::Rect([clip_and_sorting_layer bounds]));
+ EXPECT_EQ(properties.clip_rect.origin(),
+ gfx::Point([clip_and_sorting_layer position]));
+ EXPECT_EQ(-properties.clip_rect.origin().x(),
+ [clip_and_sorting_layer sublayerTransform].m41);
+ EXPECT_EQ(-properties.clip_rect.origin().y(),
+ [clip_and_sorting_layer sublayerTransform].m42);
+
+ // Validate the transform layer.
+ EXPECT_EQ(properties.transform.matrix().get(3, 0),
+ [transform_layer sublayerTransform].m41);
+ EXPECT_EQ(properties.transform.matrix().get(3, 1),
+ [transform_layer sublayerTransform].m42);
+
+ // Validate the content layer.
+ EXPECT_EQ(static_cast<id>(properties.gl_image->io_surface().get()),
+ [content_layer contents]);
+ EXPECT_EQ(properties.contents_rect,
+ gfx::RectF([content_layer contentsRect]));
+ EXPECT_EQ(properties.rect.origin(), gfx::Point([content_layer position]));
+ EXPECT_EQ(gfx::Rect(properties.rect.size()),
+ gfx::Rect([content_layer bounds]));
+ EXPECT_EQ(kCALayerLeftEdge, [content_layer edgeAntialiasingMask]);
+ EXPECT_EQ(properties.opacity, [content_layer opacity]);
+ EXPECT_NSEQ(kCAFilterLinear, [content_layer minificationFilter]);
+ EXPECT_NSEQ(kCAFilterLinear, [content_layer magnificationFilter]);
+ if ([content_layer respondsToSelector:(@selector(contentsScale))])
+ EXPECT_EQ(properties.scale_factor, [content_layer contentsScale]);
+ }
+
+ // Update just the clip rect and re-commit.
+ {
+ properties.clip_rect = gfx::Rect(4, 8, 16, 32);
+ UpdateCALayerTree(ca_layer_tree, &properties, superlayer_);
+
+ // Validate the tree structure
+ EXPECT_EQ(1u, [[superlayer_ sublayers] count]);
+ EXPECT_EQ(root_layer, [[superlayer_ sublayers] objectAtIndex:0]);
+ EXPECT_EQ(1u, [[root_layer sublayers] count]);
+ EXPECT_EQ(clip_and_sorting_layer,
+ [[root_layer sublayers] objectAtIndex:0]);
+ EXPECT_EQ(1u, [[clip_and_sorting_layer sublayers] count]);
+ EXPECT_EQ(transform_layer,
+ [[clip_and_sorting_layer sublayers] objectAtIndex:0]);
+
+ // Validate the clip and sorting context layer.
+ EXPECT_TRUE([clip_and_sorting_layer masksToBounds]);
+ EXPECT_EQ(gfx::Rect(properties.clip_rect.size()),
+ gfx::Rect([clip_and_sorting_layer bounds]));
+ EXPECT_EQ(properties.clip_rect.origin(),
+ gfx::Point([clip_and_sorting_layer position]));
+ EXPECT_EQ(-properties.clip_rect.origin().x(),
+ [clip_and_sorting_layer sublayerTransform].m41);
+ EXPECT_EQ(-properties.clip_rect.origin().y(),
+ [clip_and_sorting_layer sublayerTransform].m42);
+ }
+
+ // Disable clipping and re-commit.
+ {
+ properties.is_clipped = false;
+ UpdateCALayerTree(ca_layer_tree, &properties, superlayer_);
+
+ // Validate the tree structure
+ EXPECT_EQ(1u, [[superlayer_ sublayers] count]);
+ EXPECT_EQ(root_layer, [[superlayer_ sublayers] objectAtIndex:0]);
+ EXPECT_EQ(1u, [[root_layer sublayers] count]);
+ EXPECT_EQ(clip_and_sorting_layer,
+ [[root_layer sublayers] objectAtIndex:0]);
+ EXPECT_EQ(1u, [[clip_and_sorting_layer sublayers] count]);
+ EXPECT_EQ(transform_layer,
+ [[clip_and_sorting_layer sublayers] objectAtIndex:0]);
+
+ // Validate the clip and sorting context layer.
+ EXPECT_FALSE([clip_and_sorting_layer masksToBounds]);
+ EXPECT_EQ(gfx::Rect(), gfx::Rect([clip_and_sorting_layer bounds]));
+ EXPECT_EQ(gfx::Point(), gfx::Point([clip_and_sorting_layer position]));
+ EXPECT_EQ(0.0, [clip_and_sorting_layer sublayerTransform].m41);
+ EXPECT_EQ(0.0, [clip_and_sorting_layer sublayerTransform].m42);
+ EXPECT_EQ(1u, [[clip_and_sorting_layer sublayers] count]);
+ }
+
+ // Change the transform and re-commit.
+ {
+ properties.transform.Translate(5, 5);
+ UpdateCALayerTree(ca_layer_tree, &properties, superlayer_);
+
+ // Validate the tree structure.
+ EXPECT_EQ(1u, [[superlayer_ sublayers] count]);
+ EXPECT_EQ(root_layer, [[superlayer_ sublayers] objectAtIndex:0]);
+ EXPECT_EQ(1u, [[root_layer sublayers] count]);
+ EXPECT_EQ(clip_and_sorting_layer,
+ [[root_layer sublayers] objectAtIndex:0]);
+ EXPECT_EQ(1u, [[clip_and_sorting_layer sublayers] count]);
+ EXPECT_EQ(transform_layer,
+ [[clip_and_sorting_layer sublayers] objectAtIndex:0]);
+
+ // Validate the transform layer.
+ EXPECT_EQ(properties.transform.matrix().get(3, 0),
+ [transform_layer sublayerTransform].m41);
+ EXPECT_EQ(properties.transform.matrix().get(3, 1),
+ [transform_layer sublayerTransform].m42);
+ }
+
+ // Change the edge antialiasing mask and commit.
+ {
+ properties.edge_aa_mask = GL_CA_LAYER_EDGE_TOP_CHROMIUM;
+ UpdateCALayerTree(ca_layer_tree, &properties, superlayer_);
+
+ // Validate the tree structure.
+ EXPECT_EQ(1u, [[superlayer_ sublayers] count]);
+ EXPECT_EQ(root_layer, [[superlayer_ sublayers] objectAtIndex:0]);
+ EXPECT_EQ(1u, [[root_layer sublayers] count]);
+ EXPECT_EQ(clip_and_sorting_layer,
+ [[root_layer sublayers] objectAtIndex:0]);
+ EXPECT_EQ(1u, [[clip_and_sorting_layer sublayers] count]);
+ EXPECT_EQ(transform_layer,
+ [[clip_and_sorting_layer sublayers] objectAtIndex:0]);
+ EXPECT_EQ(1u, [[transform_layer sublayers] count]);
+ EXPECT_EQ(content_layer, [[transform_layer sublayers] objectAtIndex:0]);
+
+ // Validate the content layer. Note that top and bottom edges flip.
+ EXPECT_EQ(kCALayerBottomEdge, [content_layer edgeAntialiasingMask]);
+ }
+
+ // Change the contents and commit.
+ {
+ properties.gl_image->Destroy(true);
+ properties.gl_image = nullptr;
+ UpdateCALayerTree(ca_layer_tree, &properties, superlayer_);
+
+ // Validate the tree structure.
+ EXPECT_EQ(1u, [[superlayer_ sublayers] count]);
+ EXPECT_EQ(root_layer, [[superlayer_ sublayers] objectAtIndex:0]);
+ EXPECT_EQ(1u, [[root_layer sublayers] count]);
+ EXPECT_EQ(clip_and_sorting_layer,
+ [[root_layer sublayers] objectAtIndex:0]);
+ EXPECT_EQ(1u, [[clip_and_sorting_layer sublayers] count]);
+ EXPECT_EQ(transform_layer,
+ [[clip_and_sorting_layer sublayers] objectAtIndex:0]);
+ EXPECT_EQ(1u, [[transform_layer sublayers] count]);
+ EXPECT_EQ(content_layer, [[transform_layer sublayers] objectAtIndex:0]);
+
+ // Validate the content layer. Note that edge anti-aliasing does not flip
+ // for solid colors.
+ if (allow_solid_color_layers) {
+ EXPECT_EQ(nil, [content_layer contents]);
+ EXPECT_EQ(kCALayerTopEdge, [content_layer edgeAntialiasingMask]);
+ } else {
+ EXPECT_EQ(ca_layer_tree->ContentsForSolidColorForTesting(
+ properties.background_color),
+ [content_layer contents]);
+ EXPECT_EQ(kCALayerBottomEdge, [content_layer edgeAntialiasingMask]);
+ }
+ }
+
+ // Change the rect size.
+ {
+ properties.rect = gfx::Rect(properties.rect.origin(), gfx::Size(32, 16));
+ UpdateCALayerTree(ca_layer_tree, &properties, superlayer_);
+
+ // Validate the tree structure.
+ EXPECT_EQ(1u, [[superlayer_ sublayers] count]);
+ EXPECT_EQ(root_layer, [[superlayer_ sublayers] objectAtIndex:0]);
+ EXPECT_EQ(1u, [[root_layer sublayers] count]);
+ EXPECT_EQ(clip_and_sorting_layer,
+ [[root_layer sublayers] objectAtIndex:0]);
+ EXPECT_EQ(1u, [[clip_and_sorting_layer sublayers] count]);
+ EXPECT_EQ(transform_layer,
+ [[clip_and_sorting_layer sublayers] objectAtIndex:0]);
+ EXPECT_EQ(1u, [[transform_layer sublayers] count]);
+ EXPECT_EQ(content_layer, [[transform_layer sublayers] objectAtIndex:0]);
+
+ // Validate the content layer.
+ EXPECT_EQ(properties.rect.origin(), gfx::Point([content_layer position]));
+ EXPECT_EQ(gfx::Rect(properties.rect.size()),
+ gfx::Rect([content_layer bounds]));
+ }
+
+ // Change the rect position.
+ {
+ properties.rect = gfx::Rect(gfx::Point(16, 4), properties.rect.size());
+ UpdateCALayerTree(ca_layer_tree, &properties, superlayer_);
+
+ // Validate the tree structure.
+ EXPECT_EQ(1u, [[superlayer_ sublayers] count]);
+ EXPECT_EQ(root_layer, [[superlayer_ sublayers] objectAtIndex:0]);
+ EXPECT_EQ(1u, [[root_layer sublayers] count]);
+ EXPECT_EQ(clip_and_sorting_layer,
+ [[root_layer sublayers] objectAtIndex:0]);
+ EXPECT_EQ(1u, [[clip_and_sorting_layer sublayers] count]);
+ EXPECT_EQ(transform_layer,
+ [[clip_and_sorting_layer sublayers] objectAtIndex:0]);
+ EXPECT_EQ(1u, [[transform_layer sublayers] count]);
+ EXPECT_EQ(content_layer, [[transform_layer sublayers] objectAtIndex:0]);
+
+ // Validate the content layer.
+ EXPECT_EQ(properties.rect.origin(), gfx::Point([content_layer position]));
+ EXPECT_EQ(gfx::Rect(properties.rect.size()),
+ gfx::Rect([content_layer bounds]));
+ }
+
+ // Change the opacity.
+ {
+ properties.opacity = 1.0f;
+ UpdateCALayerTree(ca_layer_tree, &properties, superlayer_);
+
+ // Validate the tree structure.
+ EXPECT_EQ(1u, [[superlayer_ sublayers] count]);
+ EXPECT_EQ(root_layer, [[superlayer_ sublayers] objectAtIndex:0]);
+ EXPECT_EQ(1u, [[root_layer sublayers] count]);
+ EXPECT_EQ(clip_and_sorting_layer,
+ [[root_layer sublayers] objectAtIndex:0]);
+ EXPECT_EQ(1u, [[clip_and_sorting_layer sublayers] count]);
+ EXPECT_EQ(transform_layer,
+ [[clip_and_sorting_layer sublayers] objectAtIndex:0]);
+ EXPECT_EQ(1u, [[transform_layer sublayers] count]);
+ EXPECT_EQ(content_layer, [[transform_layer sublayers] objectAtIndex:0]);
+
+ // Validate the content layer.
+ EXPECT_EQ(properties.opacity, [content_layer opacity]);
+ }
+
+ // Change the filter.
+ {
+ properties.filter = GL_NEAREST;
+ UpdateCALayerTree(ca_layer_tree, &properties, superlayer_);
+
+ // Validate the tree structure.
+ EXPECT_EQ(1u, [[superlayer_ sublayers] count]);
+ EXPECT_EQ(root_layer, [[superlayer_ sublayers] objectAtIndex:0]);
+ EXPECT_EQ(1u, [[root_layer sublayers] count]);
+ EXPECT_EQ(clip_and_sorting_layer,
+ [[root_layer sublayers] objectAtIndex:0]);
+ EXPECT_EQ(1u, [[clip_and_sorting_layer sublayers] count]);
+ EXPECT_EQ(transform_layer,
+ [[clip_and_sorting_layer sublayers] objectAtIndex:0]);
+ EXPECT_EQ(1u, [[transform_layer sublayers] count]);
+ EXPECT_EQ(content_layer, [[transform_layer sublayers] objectAtIndex:0]);
+
+ // Validate the content layer.
+ EXPECT_NSEQ(kCAFilterNearest, [content_layer minificationFilter]);
+ EXPECT_NSEQ(kCAFilterNearest, [content_layer magnificationFilter]);
+ }
+
+ // Add the clipping and IOSurface contents back.
+ {
+ properties.is_clipped = true;
+ properties.gl_image = CreateGLImage(gfx::Size(256, 256),
+ gfx::BufferFormat::BGRA_8888, false);
+ UpdateCALayerTree(ca_layer_tree, &properties, superlayer_);
+
+ // Validate the tree structure.
+ EXPECT_EQ(1u, [[superlayer_ sublayers] count]);
+ EXPECT_EQ(root_layer, [[superlayer_ sublayers] objectAtIndex:0]);
+ EXPECT_EQ(1u, [[root_layer sublayers] count]);
+ EXPECT_EQ(clip_and_sorting_layer,
+ [[root_layer sublayers] objectAtIndex:0]);
+ EXPECT_EQ(1u, [[clip_and_sorting_layer sublayers] count]);
+ EXPECT_EQ(transform_layer,
+ [[clip_and_sorting_layer sublayers] objectAtIndex:0]);
+ EXPECT_EQ(1u, [[transform_layer sublayers] count]);
+ EXPECT_EQ(content_layer, [[transform_layer sublayers] objectAtIndex:0]);
+
+ // Validate the content layer.
+ EXPECT_EQ(static_cast<id>(properties.gl_image->io_surface().get()),
+ [content_layer contents]);
+ EXPECT_EQ(kCALayerBottomEdge, [content_layer edgeAntialiasingMask]);
+ }
+
+ // Change the scale factor. This should result in a new tree being created.
+ {
+ properties.scale_factor = 2.0f;
+ UpdateCALayerTree(ca_layer_tree, &properties, superlayer_);
+
+ // Validate the tree structure.
+ EXPECT_EQ(1u, [[superlayer_ sublayers] count]);
+ EXPECT_NE(root_layer, [[superlayer_ sublayers] objectAtIndex:0]);
+ root_layer = [[superlayer_ sublayers] objectAtIndex:0];
+ EXPECT_EQ(1u, [[root_layer sublayers] count]);
+ EXPECT_NE(clip_and_sorting_layer,
+ [[root_layer sublayers] objectAtIndex:0]);
+ clip_and_sorting_layer = [[root_layer sublayers] objectAtIndex:0];
+ EXPECT_EQ(1u, [[clip_and_sorting_layer sublayers] count]);
+ EXPECT_NE(transform_layer,
+ [[clip_and_sorting_layer sublayers] objectAtIndex:0]);
+ transform_layer = [[clip_and_sorting_layer sublayers] objectAtIndex:0];
+ EXPECT_EQ(1u, [[transform_layer sublayers] count]);
+ EXPECT_NE(content_layer, [[transform_layer sublayers] objectAtIndex:0]);
+ content_layer = [[transform_layer sublayers] objectAtIndex:0];
+
+ // Validate the clip and sorting context layer.
+ EXPECT_TRUE([clip_and_sorting_layer masksToBounds]);
+ EXPECT_EQ(gfx::ConvertRectToDIP(properties.scale_factor,
+ gfx::Rect(properties.clip_rect.size())),
+ gfx::Rect([clip_and_sorting_layer bounds]));
+ EXPECT_EQ(gfx::ConvertPointToDIP(properties.scale_factor,
+ properties.clip_rect.origin()),
+ gfx::Point([clip_and_sorting_layer position]));
+ EXPECT_EQ(-properties.clip_rect.origin().x() / properties.scale_factor,
+ [clip_and_sorting_layer sublayerTransform].m41);
+ EXPECT_EQ(-properties.clip_rect.origin().y() / properties.scale_factor,
+ [clip_and_sorting_layer sublayerTransform].m42);
+
+ // Validate the transform layer.
+ EXPECT_EQ(
+ properties.transform.matrix().get(3, 0) / properties.scale_factor,
+ [transform_layer sublayerTransform].m41);
+ EXPECT_EQ(
+ properties.transform.matrix().get(3, 1) / properties.scale_factor,
+ [transform_layer sublayerTransform].m42);
+
+ // Validate the content layer.
+ EXPECT_EQ(static_cast<id>(properties.gl_image->io_surface().get()),
+ [content_layer contents]);
+ EXPECT_EQ(properties.contents_rect,
+ gfx::RectF([content_layer contentsRect]));
+ EXPECT_EQ(gfx::ConvertPointToDIP(properties.scale_factor,
+ properties.rect.origin()),
+ gfx::Point([content_layer position]));
+ EXPECT_EQ(gfx::ConvertRectToDIP(properties.scale_factor,
+ gfx::Rect(properties.rect.size())),
+ gfx::Rect([content_layer bounds]));
+ EXPECT_EQ(kCALayerBottomEdge, [content_layer edgeAntialiasingMask]);
+ EXPECT_EQ(properties.opacity, [content_layer opacity]);
+ if ([content_layer respondsToSelector:(@selector(contentsScale))])
+ EXPECT_EQ(properties.scale_factor, [content_layer contentsScale]);
+ }
+
+ properties.gl_image->Destroy(true);
}
+};
- // Change the transform and re-commit.
- {
- properties.transform.Translate(5, 5);
- UpdateCALayerTree(ca_layer_tree, &properties, superlayer_);
-
- // Validate the tree structure.
- EXPECT_EQ(1u, [[superlayer_ sublayers] count]);
- EXPECT_EQ(root_layer, [[superlayer_ sublayers] objectAtIndex:0]);
- EXPECT_EQ(1u, [[root_layer sublayers] count]);
- EXPECT_EQ(clip_and_sorting_layer, [[root_layer sublayers] objectAtIndex:0]);
- EXPECT_EQ(1u, [[clip_and_sorting_layer sublayers] count]);
- EXPECT_EQ(transform_layer,
- [[clip_and_sorting_layer sublayers] objectAtIndex:0]);
-
- // Validate the transform layer.
- EXPECT_EQ(properties.transform.matrix().get(3, 0),
- [transform_layer sublayerTransform].m41);
- EXPECT_EQ(properties.transform.matrix().get(3, 1),
- [transform_layer sublayerTransform].m42);
- }
-
- // Change the edge antialiasing mask and commit.
- {
- properties.edge_aa_mask = GL_CA_LAYER_EDGE_TOP_CHROMIUM;
- UpdateCALayerTree(ca_layer_tree, &properties, superlayer_);
-
- // Validate the tree structure.
- EXPECT_EQ(1u, [[superlayer_ sublayers] count]);
- EXPECT_EQ(root_layer, [[superlayer_ sublayers] objectAtIndex:0]);
- EXPECT_EQ(1u, [[root_layer sublayers] count]);
- EXPECT_EQ(clip_and_sorting_layer, [[root_layer sublayers] objectAtIndex:0]);
- EXPECT_EQ(1u, [[clip_and_sorting_layer sublayers] count]);
- EXPECT_EQ(transform_layer,
- [[clip_and_sorting_layer sublayers] objectAtIndex:0]);
- EXPECT_EQ(1u, [[transform_layer sublayers] count]);
- EXPECT_EQ(content_layer, [[transform_layer sublayers] objectAtIndex:0]);
-
- // Validate the content layer. Note that top and bottom edges flip.
- EXPECT_EQ(kCALayerBottomEdge, [content_layer edgeAntialiasingMask]);
- }
-
- // Change the contents and commit.
- {
- properties.io_surface.reset();
- UpdateCALayerTree(ca_layer_tree, &properties, superlayer_);
-
- // Validate the tree structure.
- EXPECT_EQ(1u, [[superlayer_ sublayers] count]);
- EXPECT_EQ(root_layer, [[superlayer_ sublayers] objectAtIndex:0]);
- EXPECT_EQ(1u, [[root_layer sublayers] count]);
- EXPECT_EQ(clip_and_sorting_layer, [[root_layer sublayers] objectAtIndex:0]);
- EXPECT_EQ(1u, [[clip_and_sorting_layer sublayers] count]);
- EXPECT_EQ(transform_layer,
- [[clip_and_sorting_layer sublayers] objectAtIndex:0]);
- EXPECT_EQ(1u, [[transform_layer sublayers] count]);
- EXPECT_EQ(content_layer, [[transform_layer sublayers] objectAtIndex:0]);
-
- // Validate the content layer. Note that edge anti-aliasing no longer flips.
- EXPECT_EQ(nil, [content_layer contents]);
- EXPECT_EQ(kCALayerTopEdge, [content_layer edgeAntialiasingMask]);
- }
-
- // Change the rect size.
- {
- properties.rect = gfx::Rect(properties.rect.origin(), gfx::Size(32, 16));
- UpdateCALayerTree(ca_layer_tree, &properties, superlayer_);
-
- // Validate the tree structure.
- EXPECT_EQ(1u, [[superlayer_ sublayers] count]);
- EXPECT_EQ(root_layer, [[superlayer_ sublayers] objectAtIndex:0]);
- EXPECT_EQ(1u, [[root_layer sublayers] count]);
- EXPECT_EQ(clip_and_sorting_layer, [[root_layer sublayers] objectAtIndex:0]);
- EXPECT_EQ(1u, [[clip_and_sorting_layer sublayers] count]);
- EXPECT_EQ(transform_layer,
- [[clip_and_sorting_layer sublayers] objectAtIndex:0]);
- EXPECT_EQ(1u, [[transform_layer sublayers] count]);
- EXPECT_EQ(content_layer, [[transform_layer sublayers] objectAtIndex:0]);
-
- // Validate the content layer.
- EXPECT_EQ(properties.rect.origin(), gfx::Point([content_layer position]));
- EXPECT_EQ(gfx::Rect(properties.rect.size()),
- gfx::Rect([content_layer bounds]));
- }
-
- // Change the rect position.
- {
- properties.rect = gfx::Rect(gfx::Point(16, 4), properties.rect.size());
- UpdateCALayerTree(ca_layer_tree, &properties, superlayer_);
-
- // Validate the tree structure.
- EXPECT_EQ(1u, [[superlayer_ sublayers] count]);
- EXPECT_EQ(root_layer, [[superlayer_ sublayers] objectAtIndex:0]);
- EXPECT_EQ(1u, [[root_layer sublayers] count]);
- EXPECT_EQ(clip_and_sorting_layer, [[root_layer sublayers] objectAtIndex:0]);
- EXPECT_EQ(1u, [[clip_and_sorting_layer sublayers] count]);
- EXPECT_EQ(transform_layer,
- [[clip_and_sorting_layer sublayers] objectAtIndex:0]);
- EXPECT_EQ(1u, [[transform_layer sublayers] count]);
- EXPECT_EQ(content_layer, [[transform_layer sublayers] objectAtIndex:0]);
-
- // Validate the content layer.
- EXPECT_EQ(properties.rect.origin(), gfx::Point([content_layer position]));
- EXPECT_EQ(gfx::Rect(properties.rect.size()),
- gfx::Rect([content_layer bounds]));
- }
-
- // Change the opacity.
- {
- properties.opacity = 1.0f;
- UpdateCALayerTree(ca_layer_tree, &properties, superlayer_);
-
- // Validate the tree structure.
- EXPECT_EQ(1u, [[superlayer_ sublayers] count]);
- EXPECT_EQ(root_layer, [[superlayer_ sublayers] objectAtIndex:0]);
- EXPECT_EQ(1u, [[root_layer sublayers] count]);
- EXPECT_EQ(clip_and_sorting_layer, [[root_layer sublayers] objectAtIndex:0]);
- EXPECT_EQ(1u, [[clip_and_sorting_layer sublayers] count]);
- EXPECT_EQ(transform_layer,
- [[clip_and_sorting_layer sublayers] objectAtIndex:0]);
- EXPECT_EQ(1u, [[transform_layer sublayers] count]);
- EXPECT_EQ(content_layer, [[transform_layer sublayers] objectAtIndex:0]);
-
- // Validate the content layer.
- EXPECT_EQ(properties.opacity, [content_layer opacity]);
- }
-
- // Change the filter.
- {
- properties.filter = GL_NEAREST;
- UpdateCALayerTree(ca_layer_tree, &properties, superlayer_);
-
- // Validate the tree structure.
- EXPECT_EQ(1u, [[superlayer_ sublayers] count]);
- EXPECT_EQ(root_layer, [[superlayer_ sublayers] objectAtIndex:0]);
- EXPECT_EQ(1u, [[root_layer sublayers] count]);
- EXPECT_EQ(clip_and_sorting_layer, [[root_layer sublayers] objectAtIndex:0]);
- EXPECT_EQ(1u, [[clip_and_sorting_layer sublayers] count]);
- EXPECT_EQ(transform_layer,
- [[clip_and_sorting_layer sublayers] objectAtIndex:0]);
- EXPECT_EQ(1u, [[transform_layer sublayers] count]);
- EXPECT_EQ(content_layer, [[transform_layer sublayers] objectAtIndex:0]);
-
- // Validate the content layer.
- EXPECT_NSEQ(kCAFilterNearest, [content_layer minificationFilter]);
- EXPECT_NSEQ(kCAFilterNearest, [content_layer magnificationFilter]);
- }
-
- // Add the clipping and IOSurface contents back.
- {
- properties.is_clipped = true;
- properties.io_surface.reset(
- gfx::CreateIOSurface(gfx::Size(256, 256),
- gfx::BufferFormat::BGRA_8888));
- UpdateCALayerTree(ca_layer_tree, &properties, superlayer_);
-
- // Validate the tree structure.
- EXPECT_EQ(1u, [[superlayer_ sublayers] count]);
- EXPECT_EQ(root_layer, [[superlayer_ sublayers] objectAtIndex:0]);
- EXPECT_EQ(1u, [[root_layer sublayers] count]);
- EXPECT_EQ(clip_and_sorting_layer, [[root_layer sublayers] objectAtIndex:0]);
- EXPECT_EQ(1u, [[clip_and_sorting_layer sublayers] count]);
- EXPECT_EQ(transform_layer,
- [[clip_and_sorting_layer sublayers] objectAtIndex:0]);
- EXPECT_EQ(1u, [[transform_layer sublayers] count]);
- EXPECT_EQ(content_layer, [[transform_layer sublayers] objectAtIndex:0]);
-
- // Validate the content layer.
- EXPECT_EQ(static_cast<id>(properties.io_surface.get()),
- [content_layer contents]);
- EXPECT_EQ(kCALayerBottomEdge, [content_layer edgeAntialiasingMask]);
- }
-
- // Change the scale factor. This should result in a new tree being created.
- {
- properties.scale_factor = 2.0f;
- UpdateCALayerTree(ca_layer_tree, &properties, superlayer_);
-
- // Validate the tree structure.
- EXPECT_EQ(1u, [[superlayer_ sublayers] count]);
- EXPECT_NE(root_layer, [[superlayer_ sublayers] objectAtIndex:0]);
- root_layer = [[superlayer_ sublayers] objectAtIndex:0];
- EXPECT_EQ(1u, [[root_layer sublayers] count]);
- EXPECT_NE(clip_and_sorting_layer, [[root_layer sublayers] objectAtIndex:0]);
- clip_and_sorting_layer = [[root_layer sublayers] objectAtIndex:0];
- EXPECT_EQ(1u, [[clip_and_sorting_layer sublayers] count]);
- EXPECT_NE(transform_layer,
- [[clip_and_sorting_layer sublayers] objectAtIndex:0]);
- transform_layer = [[clip_and_sorting_layer sublayers] objectAtIndex:0];
- EXPECT_EQ(1u, [[transform_layer sublayers] count]);
- EXPECT_NE(content_layer, [[transform_layer sublayers] objectAtIndex:0]);
- content_layer = [[transform_layer sublayers] objectAtIndex:0];
-
- // Validate the clip and sorting context layer.
- EXPECT_TRUE([clip_and_sorting_layer masksToBounds]);
- EXPECT_EQ(gfx::ConvertRectToDIP(properties.scale_factor,
- gfx::Rect(properties.clip_rect.size())),
- gfx::Rect([clip_and_sorting_layer bounds]));
- EXPECT_EQ(gfx::ConvertPointToDIP(properties.scale_factor,
- properties.clip_rect.origin()),
- gfx::Point([clip_and_sorting_layer position]));
- EXPECT_EQ(-properties.clip_rect.origin().x() / properties.scale_factor,
- [clip_and_sorting_layer sublayerTransform].m41);
- EXPECT_EQ(-properties.clip_rect.origin().y() / properties.scale_factor,
- [clip_and_sorting_layer sublayerTransform].m42);
-
- // Validate the transform layer.
- EXPECT_EQ(properties.transform.matrix().get(3, 0) / properties.scale_factor,
- [transform_layer sublayerTransform].m41);
- EXPECT_EQ(properties.transform.matrix().get(3, 1) / properties.scale_factor,
- [transform_layer sublayerTransform].m42);
+TEST_F(CALayerTreePropertyUpdatesTest, AllowSolidColors) {
+ RunTest(true);
+}
- // Validate the content layer.
- EXPECT_EQ(static_cast<id>(properties.io_surface.get()),
- [content_layer contents]);
- EXPECT_EQ(properties.contents_rect,
- gfx::RectF([content_layer contentsRect]));
- EXPECT_EQ(gfx::ConvertPointToDIP(properties.scale_factor,
- properties.rect.origin()),
- gfx::Point([content_layer position]));
- EXPECT_EQ(gfx::ConvertRectToDIP(properties.scale_factor,
- gfx::Rect(properties.rect.size())),
- gfx::Rect([content_layer bounds]));
- EXPECT_EQ(kCALayerBottomEdge, [content_layer edgeAntialiasingMask]);
- EXPECT_EQ(properties.opacity, [content_layer opacity]);
- if ([content_layer respondsToSelector:(@selector(contentsScale))])
- EXPECT_EQ(properties.scale_factor, [content_layer contentsScale]);
- }
+TEST_F(CALayerTreePropertyUpdatesTest, DisallowSolidColors) {
+ RunTest(false);
}
// Verify that sorting context zero is split at non-flat transforms.
@@ -425,10 +490,10 @@ TEST_F(CALayerTreeTest, SplitSortingContextZero) {
properties.rect = gfx::Rect(0, 0, 256, 256);
// We'll use the IOSurface contents to identify the content layers.
- base::ScopedCFTypeRef<IOSurfaceRef> io_surfaces[5];
+ scoped_refptr<gl::GLImageIOSurface> gl_images[5];
for (size_t i = 0; i < 5; ++i) {
- io_surfaces[i].reset(gfx::CreateIOSurface(
- gfx::Size(256, 256), gfx::BufferFormat::BGRA_8888));
+ gl_images[i] =
+ CreateGLImage(gfx::Size(256, 256), gfx::BufferFormat::BGRA_8888, false);
}
// Have 5 transforms:
@@ -444,9 +509,9 @@ TEST_F(CALayerTreeTest, SplitSortingContextZero) {
// Schedule and commit the layers.
std::unique_ptr<ui::CARendererLayerTree> ca_layer_tree(
- new ui::CARendererLayerTree);
+ new ui::CARendererLayerTree(true, true));
for (size_t i = 0; i < 5; ++i) {
- properties.io_surface = io_surfaces[i];
+ properties.gl_image = gl_images[i];
properties.transform = transforms[i];
bool result = ScheduleCALayer(ca_layer_tree.get(), &properties);
EXPECT_TRUE(result);
@@ -494,11 +559,19 @@ TEST_F(CALayerTreeTest, SplitSortingContextZero) {
CALayer* content_layer_4 = [[transform_layer_2_0 sublayers] objectAtIndex:1];
// Validate that the layers come out in order.
- EXPECT_EQ(static_cast<id>(io_surfaces[0].get()), [content_layer_0 contents]);
- EXPECT_EQ(static_cast<id>(io_surfaces[1].get()), [content_layer_1 contents]);
- EXPECT_EQ(static_cast<id>(io_surfaces[2].get()), [content_layer_2 contents]);
- EXPECT_EQ(static_cast<id>(io_surfaces[3].get()), [content_layer_3 contents]);
- EXPECT_EQ(static_cast<id>(io_surfaces[4].get()), [content_layer_4 contents]);
+ EXPECT_EQ(static_cast<id>(gl_images[0]->io_surface().get()),
+ [content_layer_0 contents]);
+ EXPECT_EQ(static_cast<id>(gl_images[1]->io_surface().get()),
+ [content_layer_1 contents]);
+ EXPECT_EQ(static_cast<id>(gl_images[2]->io_surface().get()),
+ [content_layer_2 contents]);
+ EXPECT_EQ(static_cast<id>(gl_images[3]->io_surface().get()),
+ [content_layer_3 contents]);
+ EXPECT_EQ(static_cast<id>(gl_images[4]->io_surface().get()),
+ [content_layer_4 contents]);
+
+ for (size_t i = 0; i < 5; ++i)
+ gl_images[i]->Destroy(true);
}
// Verify that sorting contexts are allocated appropriately.
@@ -509,20 +582,20 @@ TEST_F(CALayerTreeTest, SortingContexts) {
properties.rect = gfx::Rect(0, 0, 256, 256);
// We'll use the IOSurface contents to identify the content layers.
- base::ScopedCFTypeRef<IOSurfaceRef> io_surfaces[3];
+ scoped_refptr<gl::GLImageIOSurface> gl_images[3];
for (size_t i = 0; i < 3; ++i) {
- io_surfaces[i].reset(gfx::CreateIOSurface(
- gfx::Size(256, 256), gfx::BufferFormat::BGRA_8888));
+ gl_images[i] =
+ CreateGLImage(gfx::Size(256, 256), gfx::BufferFormat::BGRA_8888, false);
}
int sorting_context_ids[3] = {3, -1, 0};
// Schedule and commit the layers.
std::unique_ptr<ui::CARendererLayerTree> ca_layer_tree(
- new ui::CARendererLayerTree);
+ new ui::CARendererLayerTree(true, true));
for (size_t i = 0; i < 3; ++i) {
properties.sorting_context_id = sorting_context_ids[i];
- properties.io_surface = io_surfaces[i];
+ properties.gl_image = gl_images[i];
bool result = ScheduleCALayer(ca_layer_tree.get(), &properties);
EXPECT_TRUE(result);
}
@@ -559,9 +632,15 @@ TEST_F(CALayerTreeTest, SortingContexts) {
CALayer* content_layer_2 = [[transform_layer_2 sublayers] objectAtIndex:0];
// Validate that the layers come out in order.
- EXPECT_EQ(static_cast<id>(io_surfaces[0].get()), [content_layer_0 contents]);
- EXPECT_EQ(static_cast<id>(io_surfaces[1].get()), [content_layer_1 contents]);
- EXPECT_EQ(static_cast<id>(io_surfaces[2].get()), [content_layer_2 contents]);
+ EXPECT_EQ(static_cast<id>(gl_images[0]->io_surface().get()),
+ [content_layer_0 contents]);
+ EXPECT_EQ(static_cast<id>(gl_images[1]->io_surface().get()),
+ [content_layer_1 contents]);
+ EXPECT_EQ(static_cast<id>(gl_images[2]->io_surface().get()),
+ [content_layer_2 contents]);
+
+ for (size_t i = 0; i < 3; ++i)
+ gl_images[i]->Destroy(true);
}
// Verify that sorting contexts must all have the same clipping properties.
@@ -577,7 +656,7 @@ TEST_F(CALayerTreeTest, SortingContextMustHaveConsistentClip) {
};
std::unique_ptr<ui::CARendererLayerTree> ca_layer_tree(
- new ui::CARendererLayerTree);
+ new ui::CARendererLayerTree(true, true));
// First send the various clip parameters to sorting context zero. This is
// legitimate.
for (size_t i = 0; i < 3; ++i) {
@@ -614,8 +693,8 @@ TEST_F(CALayerTreeTest, SortingContextMustHaveConsistentClip) {
// Test updating each layer's properties.
TEST_F(CALayerTreeTest, AVLayer) {
CALayerProperties properties;
- properties.io_surface.reset(gfx::CreateIOSurface(
- gfx::Size(256, 256), gfx::BufferFormat::YUV_420_BIPLANAR));
+ properties.gl_image =
+ CreateGLImage(gfx::Size(256, 256), gfx::BufferFormat::BGRA_8888, false);
std::unique_ptr<ui::CARendererLayerTree> ca_layer_tree;
CALayer* root_layer = nil;
@@ -624,6 +703,7 @@ TEST_F(CALayerTreeTest, AVLayer) {
CALayer* content_layer1 = nil;
CALayer* content_layer2 = nil;
CALayer* content_layer3 = nil;
+ CALayer* content_layer4 = nil;
// Validate the initial values.
{
@@ -644,10 +724,12 @@ TEST_F(CALayerTreeTest, AVLayer) {
isKindOfClass:NSClassFromString(@"AVSampleBufferDisplayLayer")]);
}
- properties.io_surface.reset(gfx::CreateIOSurface(
- gfx::Size(256, 256), gfx::BufferFormat::YUV_420_BIPLANAR));
+ properties.gl_image->Destroy(true);
+ properties.gl_image = CreateGLImage(
+ gfx::Size(256, 256), gfx::BufferFormat::YUV_420_BIPLANAR, false);
- // Pass another frame.
+ // Pass another frame. This will automatically create a CVPixelBuffer
+ // behind the scenes, because the underlying buffer is YUV 420.
{
UpdateCALayerTree(ca_layer_tree, &properties, superlayer_);
@@ -662,17 +744,16 @@ TEST_F(CALayerTreeTest, AVLayer) {
content_layer2 = [[transform_layer sublayers] objectAtIndex:0];
// Validate the content layer.
- EXPECT_FALSE([content_layer2
+ EXPECT_TRUE([content_layer2
isKindOfClass:NSClassFromString(@"AVSampleBufferDisplayLayer")]);
- EXPECT_EQ(content_layer2, content_layer1);
+ EXPECT_NE(content_layer2, content_layer1);
}
- properties.io_surface.reset(gfx::CreateIOSurface(
- gfx::Size(256, 256), gfx::BufferFormat::YUV_420_BIPLANAR));
- CVPixelBufferCreateWithIOSurface(nullptr, properties.io_surface, nullptr,
- properties.cv_pixel_buffer.InitializeInto());
+ properties.gl_image->Destroy(true);
+ properties.gl_image = CreateGLImage(
+ gfx::Size(256, 256), gfx::BufferFormat::YUV_420_BIPLANAR, true);
- // Pass a frame with a CVPixelBuffer
+ // Pass a frame with a CVPixelBuffer.
{
UpdateCALayerTree(ca_layer_tree, &properties, superlayer_);
@@ -684,17 +765,17 @@ TEST_F(CALayerTreeTest, AVLayer) {
EXPECT_EQ(1u, [[clip_and_sorting_layer sublayers] count]);
transform_layer = [[clip_and_sorting_layer sublayers] objectAtIndex:0];
EXPECT_EQ(1u, [[transform_layer sublayers] count]);
- content_layer2 = [[transform_layer sublayers] objectAtIndex:0];
+ content_layer3 = [[transform_layer sublayers] objectAtIndex:0];
// Validate the content layer.
- EXPECT_TRUE([content_layer2
+ EXPECT_TRUE([content_layer3
isKindOfClass:NSClassFromString(@"AVSampleBufferDisplayLayer")]);
- EXPECT_NE(content_layer2, content_layer1);
+ EXPECT_EQ(content_layer3, content_layer2);
}
- properties.io_surface.reset(gfx::CreateIOSurface(
- gfx::Size(256, 256), gfx::BufferFormat::YUV_420_BIPLANAR));
- properties.cv_pixel_buffer.reset();
+ properties.gl_image->Destroy(true);
+ properties.gl_image = CreateGLImage(
+ gfx::Size(256, 256), gfx::BufferFormat::YUV_420_BIPLANAR, false);
// Pass a frame that is clipped.
properties.contents_rect = gfx::RectF(0, 0, 1, 0.9);
@@ -709,23 +790,73 @@ TEST_F(CALayerTreeTest, AVLayer) {
EXPECT_EQ(1u, [[clip_and_sorting_layer sublayers] count]);
transform_layer = [[clip_and_sorting_layer sublayers] objectAtIndex:0];
EXPECT_EQ(1u, [[transform_layer sublayers] count]);
- content_layer3 = [[transform_layer sublayers] objectAtIndex:0];
+ content_layer4 = [[transform_layer sublayers] objectAtIndex:0];
// Validate the content layer.
- EXPECT_FALSE([content_layer3
+ EXPECT_FALSE([content_layer4
+ isKindOfClass:NSClassFromString(@"AVSampleBufferDisplayLayer")]);
+ EXPECT_NE(content_layer4, content_layer3);
+ }
+}
+
+// Ensure that blacklisting AVSampleBufferDisplayLayer works.
+TEST_F(CALayerTreeTest, AVLayerBlacklist) {
+ CALayerProperties properties;
+ properties.gl_image = CreateGLImage(
+ gfx::Size(256, 256), gfx::BufferFormat::YUV_420_BIPLANAR, false);
+
+ std::unique_ptr<ui::CARendererLayerTree> ca_layer_tree;
+ CALayer* root_layer = nil;
+ CALayer* clip_and_sorting_layer = nil;
+ CALayer* transform_layer = nil;
+ CALayer* content_layer1 = nil;
+ CALayer* content_layer2 = nil;
+
+ {
+ UpdateCALayerTree(ca_layer_tree, &properties, superlayer_);
+
+ // Validate the tree structure.
+ EXPECT_EQ(1u, [[superlayer_ sublayers] count]);
+ root_layer = [[superlayer_ sublayers] objectAtIndex:0];
+ EXPECT_EQ(1u, [[root_layer sublayers] count]);
+ clip_and_sorting_layer = [[root_layer sublayers] objectAtIndex:0];
+ EXPECT_EQ(1u, [[clip_and_sorting_layer sublayers] count]);
+ transform_layer = [[clip_and_sorting_layer sublayers] objectAtIndex:0];
+ EXPECT_EQ(1u, [[transform_layer sublayers] count]);
+ content_layer1 = [[transform_layer sublayers] objectAtIndex:0];
+
+ // Validate the content layer.
+ EXPECT_TRUE([content_layer1
+ isKindOfClass:NSClassFromString(@"AVSampleBufferDisplayLayer")]);
+ }
+
+ {
+ properties.allow_av_layers = false;
+ UpdateCALayerTree(ca_layer_tree, &properties, superlayer_);
+
+ // Validate the tree structure.
+ EXPECT_EQ(1u, [[superlayer_ sublayers] count]);
+ root_layer = [[superlayer_ sublayers] objectAtIndex:0];
+ EXPECT_EQ(1u, [[root_layer sublayers] count]);
+ clip_and_sorting_layer = [[root_layer sublayers] objectAtIndex:0];
+ EXPECT_EQ(1u, [[clip_and_sorting_layer sublayers] count]);
+ transform_layer = [[clip_and_sorting_layer sublayers] objectAtIndex:0];
+ EXPECT_EQ(1u, [[transform_layer sublayers] count]);
+ content_layer2 = [[transform_layer sublayers] objectAtIndex:0];
+
+ // Validate the content layer.
+ EXPECT_FALSE([content_layer2
isKindOfClass:NSClassFromString(@"AVSampleBufferDisplayLayer")]);
- EXPECT_NE(content_layer3, content_layer2);
+ EXPECT_NE(content_layer1, content_layer2);
}
}
// Test fullscreen low power detection.
TEST_F(CALayerTreeTest, FullscreenLowPower) {
CALayerProperties properties;
- properties.io_surface.reset(gfx::CreateIOSurface(
- gfx::Size(256, 256), gfx::BufferFormat::YUV_420_BIPLANAR));
+ properties.gl_image = CreateGLImage(
+ gfx::Size(256, 256), gfx::BufferFormat::YUV_420_BIPLANAR, true);
properties.is_clipped = false;
- CVPixelBufferCreateWithIOSurface(nullptr, properties.io_surface, nullptr,
- properties.cv_pixel_buffer.InitializeInto());
CALayerProperties properties_black;
properties_black.is_clipped = false;
@@ -739,7 +870,7 @@ TEST_F(CALayerTreeTest, FullscreenLowPower) {
// Test a configuration with no background.
{
std::unique_ptr<ui::CARendererLayerTree> new_ca_layer_tree(
- new ui::CARendererLayerTree);
+ new ui::CARendererLayerTree(true, true));
bool result = ScheduleCALayer(new_ca_layer_tree.get(), &properties);
EXPECT_TRUE(result);
new_ca_layer_tree->CommitScheduledCALayers(
@@ -769,7 +900,7 @@ TEST_F(CALayerTreeTest, FullscreenLowPower) {
// Test a configuration with a black background.
{
std::unique_ptr<ui::CARendererLayerTree> new_ca_layer_tree(
- new ui::CARendererLayerTree);
+ new ui::CARendererLayerTree(true, true));
bool result = ScheduleCALayer(new_ca_layer_tree.get(), &properties_black);
EXPECT_TRUE(result);
result = ScheduleCALayer(new_ca_layer_tree.get(), &properties);
@@ -801,7 +932,7 @@ TEST_F(CALayerTreeTest, FullscreenLowPower) {
// Test a configuration with a white background. It will fail.
{
std::unique_ptr<ui::CARendererLayerTree> new_ca_layer_tree(
- new ui::CARendererLayerTree);
+ new ui::CARendererLayerTree(true, true));
bool result = ScheduleCALayer(new_ca_layer_tree.get(), &properties_white);
EXPECT_TRUE(result);
result = ScheduleCALayer(new_ca_layer_tree.get(), &properties);
@@ -833,7 +964,7 @@ TEST_F(CALayerTreeTest, FullscreenLowPower) {
// Test a configuration with a black foreground. It too will fail.
{
std::unique_ptr<ui::CARendererLayerTree> new_ca_layer_tree(
- new ui::CARendererLayerTree);
+ new ui::CARendererLayerTree(true, true));
bool result = ScheduleCALayer(new_ca_layer_tree.get(), &properties);
EXPECT_TRUE(result);
result = ScheduleCALayer(new_ca_layer_tree.get(), &properties_black);
diff --git a/chromium/ui/accelerated_widget_mac/ca_renderer_layer_tree.h b/chromium/ui/accelerated_widget_mac/ca_renderer_layer_tree.h
index 7e7e31f9fb7..e4724a8f07e 100644
--- a/chromium/ui/accelerated_widget_mac/ca_renderer_layer_tree.h
+++ b/chromium/ui/accelerated_widget_mac/ca_renderer_layer_tree.h
@@ -14,6 +14,7 @@
#include "base/mac/scoped_cftyperef.h"
#include "base/mac/scoped_nsobject.h"
+#include "base/memory/ref_counted.h"
#include "ui/accelerated_widget_mac/accelerated_widget_mac_export.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/rect_f.h"
@@ -24,13 +25,16 @@
namespace ui {
+struct CARendererLayerParams;
+
// The CARendererLayerTree will construct a hierarchy of CALayers from a linear
// list provided by the CoreAnimation renderer using the algorithm and structure
// referenced described in
// https://docs.google.com/document/d/1DtSN9zzvCF44_FQPM7ie01UxGHagQ66zfF5L9HnigQY/edit?usp=sharing
class ACCELERATED_WIDGET_MAC_EXPORT CARendererLayerTree {
public:
- CARendererLayerTree();
+ CARendererLayerTree(bool allow_av_sample_buffer_display_layer,
+ bool allow_solid_color_layers);
// This will remove all CALayers from this tree from their superlayer.
~CARendererLayerTree();
@@ -38,18 +42,7 @@ class ACCELERATED_WIDGET_MAC_EXPORT CARendererLayerTree {
// Append the description of a new CALayer to the tree. This will not
// create any new CALayers until CommitScheduledCALayers is called. This
// cannot be called anymore after CommitScheduledCALayers has been called.
- bool ScheduleCALayer(bool is_clipped,
- const gfx::Rect& clip_rect,
- unsigned sorting_context_id,
- const gfx::Transform& transform,
- base::ScopedCFTypeRef<IOSurfaceRef> io_surface,
- base::ScopedCFTypeRef<CVPixelBufferRef> cv_pixel_buffer,
- const gfx::RectF& contents_rect,
- const gfx::Rect& rect,
- unsigned background_color,
- unsigned edge_aa_mask,
- float opacity,
- unsigned filter);
+ bool ScheduleCALayer(const CARendererLayerParams& params);
// Create a CALayer tree for the scheduled layers, and set |superlayer| to
// have only this tree as its sublayers. If |old_tree| is non-null, then try
@@ -67,11 +60,16 @@ class ACCELERATED_WIDGET_MAC_EXPORT CARendererLayerTree {
bool CommitFullscreenLowPowerLayer(
AVSampleBufferDisplayLayer* fullscreen_low_power_layer);
+ // Returns the contents used for a given solid color.
+ id ContentsForSolidColorForTesting(unsigned int color);
+
private:
+ class SolidColorContents;
struct RootLayer;
struct ClipAndSortingLayer;
struct TransformLayer;
struct ContentLayer;
+ friend struct ContentLayer;
struct RootLayer {
RootLayer();
@@ -82,19 +80,8 @@ class ACCELERATED_WIDGET_MAC_EXPORT CARendererLayerTree {
// Append a new content layer, without modifying the actual CALayer
// structure.
- bool AddContentLayer(
- bool is_clipped,
- const gfx::Rect& clip_rect,
- unsigned sorting_context_id,
- const gfx::Transform& transform,
- base::ScopedCFTypeRef<IOSurfaceRef> io_surface,
- base::ScopedCFTypeRef<CVPixelBufferRef> cv_pixel_buffer,
- const gfx::RectF& contents_rect,
- const gfx::Rect& rect,
- unsigned background_color,
- unsigned edge_aa_mask,
- float opacity,
- unsigned filter);
+ bool AddContentLayer(CARendererLayerTree* tree,
+ const CARendererLayerParams& params);
// Allocate CALayers for this layer and its children, and set their
// properties appropriately. Re-use the CALayers from |old_layer| if
@@ -120,16 +107,8 @@ class ACCELERATED_WIDGET_MAC_EXPORT CARendererLayerTree {
// See the behavior of RootLayer for the effects of these functions on the
// |ca_layer| member and |old_layer| argument.
~ClipAndSortingLayer();
- void AddContentLayer(
- const gfx::Transform& transform,
- base::ScopedCFTypeRef<IOSurfaceRef> io_surface,
- base::ScopedCFTypeRef<CVPixelBufferRef> cv_pixel_buffer,
- const gfx::RectF& contents_rect,
- const gfx::Rect& rect,
- unsigned background_color,
- unsigned edge_aa_mask,
- float opacity,
- unsigned filter);
+ void AddContentLayer(CARendererLayerTree* tree,
+ const CARendererLayerParams& params);
void CommitToCA(CALayer* superlayer,
ClipAndSortingLayer* old_layer,
float scale_factor);
@@ -151,15 +130,8 @@ class ACCELERATED_WIDGET_MAC_EXPORT CARendererLayerTree {
// See the behavior of RootLayer for the effects of these functions on the
// |ca_layer| member and |old_layer| argument.
~TransformLayer();
- void AddContentLayer(
- base::ScopedCFTypeRef<IOSurfaceRef> io_surface,
- base::ScopedCFTypeRef<CVPixelBufferRef> cv_pixel_buffer,
- const gfx::RectF& contents_rect,
- const gfx::Rect& rect,
- unsigned background_color,
- unsigned edge_aa_mask,
- float opacity,
- unsigned filter);
+ void AddContentLayer(CARendererLayerTree* tree,
+ const CARendererLayerParams& params);
void CommitToCA(CALayer* superlayer,
TransformLayer* old_layer,
float scale_factor);
@@ -172,7 +144,8 @@ class ACCELERATED_WIDGET_MAC_EXPORT CARendererLayerTree {
DISALLOW_COPY_AND_ASSIGN(TransformLayer);
};
struct ContentLayer {
- ContentLayer(base::ScopedCFTypeRef<IOSurfaceRef> io_surface,
+ ContentLayer(CARendererLayerTree* tree,
+ base::ScopedCFTypeRef<IOSurfaceRef> io_surface,
base::ScopedCFTypeRef<CVPixelBufferRef> cv_pixel_buffer,
const gfx::RectF& contents_rect,
const gfx::Rect& rect,
@@ -194,6 +167,7 @@ class ACCELERATED_WIDGET_MAC_EXPORT CARendererLayerTree {
// their use count.
const gfx::ScopedInUseIOSurface io_surface;
const base::ScopedCFTypeRef<CVPixelBufferRef> cv_pixel_buffer;
+ scoped_refptr<SolidColorContents> solid_color_contents;
gfx::RectF contents_rect;
gfx::Rect rect;
unsigned background_color = 0;
@@ -216,6 +190,8 @@ class ACCELERATED_WIDGET_MAC_EXPORT CARendererLayerTree {
RootLayer root_layer_;
float scale_factor_ = 1;
bool has_committed_ = false;
+ const bool allow_av_sample_buffer_display_layer_ = true;
+ const bool allow_solid_color_layers_ = true;
private:
DISALLOW_COPY_AND_ASSIGN(CARendererLayerTree);
diff --git a/chromium/ui/accelerated_widget_mac/ca_renderer_layer_tree.mm b/chromium/ui/accelerated_widget_mac/ca_renderer_layer_tree.mm
index 496cfb81e2f..a139dc7d073 100644
--- a/chromium/ui/accelerated_widget_mac/ca_renderer_layer_tree.mm
+++ b/chromium/ui/accelerated_widget_mac/ca_renderer_layer_tree.mm
@@ -10,13 +10,15 @@
#include <GLES2/gl2extchromium.h>
#include "base/command_line.h"
-#include "base/mac/mac_util.h"
+#include "base/lazy_instance.h"
#include "base/mac/sdk_forward_declarations.h"
#include "base/trace_event/trace_event.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/base/cocoa/animation_utils.h"
#include "ui/base/ui_base_switches.h"
#include "ui/gfx/geometry/dip_util.h"
+#include "ui/gl/ca_renderer_layer_params.h"
+#include "ui/gl/gl_image_io_surface.h"
#if !defined(MAC_OS_X_VERSION_10_8) || \
MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_8
@@ -128,32 +130,91 @@ bool AVSampleBufferDisplayLayerEnqueueIOSurface(
} // namespace
-CARendererLayerTree::CARendererLayerTree() {}
+class CARendererLayerTree::SolidColorContents
+ : public base::RefCounted<CARendererLayerTree::SolidColorContents> {
+ public:
+ static scoped_refptr<SolidColorContents> Get(SkColor color);
+ id GetContents() const;
+
+ private:
+ friend class base::RefCounted<SolidColorContents>;
+
+ SolidColorContents(SkColor color, IOSurfaceRef io_surface);
+ ~SolidColorContents();
+
+ SkColor color_ = 0;
+ base::ScopedCFTypeRef<IOSurfaceRef> io_surface_;
+ static base::LazyInstance<std::map<SkColor, SolidColorContents*>> map_;
+};
+
+base::LazyInstance<std::map<SkColor, CARendererLayerTree::SolidColorContents*>>
+ CARendererLayerTree::SolidColorContents::map_;
+
+// static
+scoped_refptr<CARendererLayerTree::SolidColorContents>
+CARendererLayerTree::SolidColorContents::Get(SkColor color) {
+ const int kSolidColorContentsSize = 16;
+
+ auto found = map_.Get().find(color);
+ if (found != map_.Get().end())
+ return found->second;
+
+ IOSurfaceRef io_surface = CreateIOSurface(
+ gfx::Size(kSolidColorContentsSize, kSolidColorContentsSize),
+ gfx::BufferFormat::BGRA_8888);
+ if (!io_surface)
+ return nullptr;
+
+ size_t bytes_per_row = IOSurfaceGetBytesPerRowOfPlane(io_surface, 0);
+ IOSurfaceLock(io_surface, 0, NULL);
+ char* row_base_address =
+ reinterpret_cast<char*>(IOSurfaceGetBaseAddress(io_surface));
+ for (int i = 0; i < kSolidColorContentsSize; ++i) {
+ unsigned int* pixel = reinterpret_cast<unsigned int*>(row_base_address);
+ for (int j = 0; j < kSolidColorContentsSize; ++j)
+ *(pixel++) = color;
+ row_base_address += bytes_per_row;
+ }
+ IOSurfaceUnlock(io_surface, 0, NULL);
+
+ return new SolidColorContents(color, io_surface);
+}
+
+id CARendererLayerTree::SolidColorContents::GetContents() const {
+ return static_cast<id>(io_surface_.get());
+}
+
+CARendererLayerTree::SolidColorContents::SolidColorContents(
+ SkColor color,
+ IOSurfaceRef io_surface)
+ : color_(color), io_surface_(io_surface) {
+ DCHECK(map_.Get().find(color_) == map_.Get().end());
+ map_.Get()[color_] = this;
+}
+
+CARendererLayerTree::SolidColorContents::~SolidColorContents() {
+ auto found = map_.Get().find(color_);
+ DCHECK(found != map_.Get().end());
+ DCHECK(found->second == this);
+ map_.Get().erase(color_);
+}
+
+CARendererLayerTree::CARendererLayerTree(
+ bool allow_av_sample_buffer_display_layer,
+ bool allow_solid_color_layers)
+ : allow_av_sample_buffer_display_layer_(
+ allow_av_sample_buffer_display_layer),
+ allow_solid_color_layers_(allow_solid_color_layers) {}
CARendererLayerTree::~CARendererLayerTree() {}
-bool CARendererLayerTree::ScheduleCALayer(
- bool is_clipped,
- const gfx::Rect& clip_rect,
- unsigned sorting_context_id,
- const gfx::Transform& transform,
- base::ScopedCFTypeRef<IOSurfaceRef> io_surface,
- base::ScopedCFTypeRef<CVPixelBufferRef> cv_pixel_buffer,
- const gfx::RectF& contents_rect,
- const gfx::Rect& rect,
- unsigned background_color,
- unsigned edge_aa_mask,
- float opacity,
- unsigned filter) {
+bool CARendererLayerTree::ScheduleCALayer(const CARendererLayerParams& params) {
// Excessive logging to debug white screens (crbug.com/583805).
// TODO(ccameron): change this back to a DLOG.
if (has_committed_) {
LOG(ERROR) << "ScheduleCALayer called after CommitScheduledCALayers.";
return false;
}
- return root_layer_.AddContentLayer(is_clipped, clip_rect, sorting_context_id,
- transform, io_surface, cv_pixel_buffer,
- contents_rect, rect, background_color,
- edge_aa_mask, opacity, filter);
+ return root_layer_.AddContentLayer(this, params);
}
void CARendererLayerTree::CommitScheduledCALayers(
@@ -227,6 +288,9 @@ bool CARendererLayerTree::CommitFullscreenLowPowerLayer(
return true;
}
+id CARendererLayerTree::ContentsForSolidColorForTesting(SkColor color) {
+ return SolidColorContents::Get(color)->GetContents();
+}
CARendererLayerTree::RootLayer::RootLayer() {}
@@ -281,6 +345,7 @@ CARendererLayerTree::TransformLayer::~TransformLayer() {
}
CARendererLayerTree::ContentLayer::ContentLayer(
+ CARendererLayerTree* tree,
base::ScopedCFTypeRef<IOSurfaceRef> io_surface,
base::ScopedCFTypeRef<CVPixelBufferRef> cv_pixel_buffer,
const gfx::RectF& contents_rect,
@@ -299,6 +364,17 @@ CARendererLayerTree::ContentLayer::ContentLayer(
ca_filter(filter == GL_LINEAR ? kCAFilterLinear : kCAFilterNearest) {
DCHECK(filter == GL_LINEAR || filter == GL_NEAREST);
+ // On Mac OS Sierra, solid color layers are not color color corrected to the
+ // output monitor color space, but IOSurface-backed layers are color
+ // corrected. Note that this is only the case when the CALayers are shared
+ // across processes. To make colors consistent across both solid color and
+ // IOSurface-backed layers, use a cache of solid-color IOSurfaces as contents.
+ // https://crbug.com/633805
+ if (!io_surface && !tree->allow_solid_color_layers_) {
+ solid_color_contents = SolidColorContents::Get(background_color);
+ ContentLayer::contents_rect = gfx::RectF(0, 0, 1, 1);
+ }
+
// Because the root layer has setGeometryFlipped:YES, there is some ambiguity
// about what exactly top and bottom mean. This ambiguity is resolved in
// different ways for solid color CALayers and for CALayers that have content
@@ -311,7 +387,7 @@ CARendererLayerTree::ContentLayer::ContentLayer(
ca_edge_aa_mask |= kCALayerLeftEdge;
if (edge_aa_mask & GL_CA_LAYER_EDGE_RIGHT_CHROMIUM)
ca_edge_aa_mask |= kCALayerRightEdge;
- if (io_surface) {
+ if (io_surface || solid_color_contents) {
if (edge_aa_mask & GL_CA_LAYER_EDGE_TOP_CHROMIUM)
ca_edge_aa_mask |= kCALayerBottomEdge;
if (edge_aa_mask & GL_CA_LAYER_EDGE_BOTTOM_CHROMIUM)
@@ -325,20 +401,18 @@ CARendererLayerTree::ContentLayer::ContentLayer(
// Only allow 4:2:0 frames which fill the layer's contents to be promoted to
// AV layers.
- if (IOSurfaceGetPixelFormat(io_surface) ==
+ if (tree->allow_av_sample_buffer_display_layer_ &&
+ IOSurfaceGetPixelFormat(io_surface) ==
kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange &&
contents_rect == gfx::RectF(0, 0, 1, 1)) {
- // Disable AVSampleBufferDisplayLayer on <10.11 due to reports of memory
- // leaks on 10.9.
- // https://crbug.com/631485
- if (base::mac::IsOSElCapitanOrLater())
- use_av_layer = true;
+ use_av_layer = true;
}
}
CARendererLayerTree::ContentLayer::ContentLayer(ContentLayer&& layer)
: io_surface(layer.io_surface),
cv_pixel_buffer(layer.cv_pixel_buffer),
+ solid_color_contents(layer.solid_color_contents),
contents_rect(layer.contents_rect),
rect(layer.rect),
background_color(layer.background_color),
@@ -357,18 +431,8 @@ CARendererLayerTree::ContentLayer::~ContentLayer() {
}
bool CARendererLayerTree::RootLayer::AddContentLayer(
- bool is_clipped,
- const gfx::Rect& clip_rect,
- unsigned sorting_context_id,
- const gfx::Transform& transform,
- base::ScopedCFTypeRef<IOSurfaceRef> io_surface,
- base::ScopedCFTypeRef<CVPixelBufferRef> cv_pixel_buffer,
- const gfx::RectF& contents_rect,
- const gfx::Rect& rect,
- unsigned background_color,
- unsigned edge_aa_mask,
- float opacity,
- unsigned filter) {
+ CARendererLayerTree* tree,
+ const CARendererLayerParams& params) {
bool needs_new_clip_and_sorting_layer = true;
// In sorting_context_id 0, all quads are listed in back-to-front order.
@@ -376,16 +440,16 @@ bool CARendererLayerTree::RootLayer::AddContentLayer(
// If a quad has a 3D transform, it is necessary to put it in its own sorting
// context, so that it will not intersect with quads before and after it.
bool is_singleton_sorting_context =
- !sorting_context_id && !transform.IsFlat();
+ !params.sorting_context_id && !params.transform.IsFlat();
if (!clip_and_sorting_layers.empty()) {
ClipAndSortingLayer& current_layer = clip_and_sorting_layers.back();
// It is in error to change the clipping settings within a non-zero sorting
// context. The result will be incorrect layering and intersection.
- if (sorting_context_id &&
- current_layer.sorting_context_id == sorting_context_id &&
- (current_layer.is_clipped != is_clipped ||
- current_layer.clip_rect != clip_rect)) {
+ if (params.sorting_context_id &&
+ current_layer.sorting_context_id == params.sorting_context_id &&
+ (current_layer.is_clipped != params.is_clipped ||
+ current_layer.clip_rect != params.clip_rect)) {
// Excessive logging to debug white screens (crbug.com/583805).
// TODO(ccameron): change this back to a DLOG.
LOG(ERROR) << "CALayer changed clip inside non-zero sorting context.";
@@ -393,58 +457,52 @@ bool CARendererLayerTree::RootLayer::AddContentLayer(
}
if (!is_singleton_sorting_context &&
!current_layer.is_singleton_sorting_context &&
- current_layer.is_clipped == is_clipped &&
- current_layer.clip_rect == clip_rect &&
- current_layer.sorting_context_id == sorting_context_id) {
+ current_layer.is_clipped == params.is_clipped &&
+ current_layer.clip_rect == params.clip_rect &&
+ current_layer.sorting_context_id == params.sorting_context_id) {
needs_new_clip_and_sorting_layer = false;
}
}
if (needs_new_clip_and_sorting_layer) {
- clip_and_sorting_layers.push_back(
- ClipAndSortingLayer(is_clipped, clip_rect, sorting_context_id,
- is_singleton_sorting_context));
+ clip_and_sorting_layers.push_back(ClipAndSortingLayer(
+ params.is_clipped, params.clip_rect, params.sorting_context_id,
+ is_singleton_sorting_context));
}
- clip_and_sorting_layers.back().AddContentLayer(
- transform, io_surface, cv_pixel_buffer, contents_rect, rect,
- background_color, edge_aa_mask, opacity, filter);
+ clip_and_sorting_layers.back().AddContentLayer(tree, params);
return true;
}
void CARendererLayerTree::ClipAndSortingLayer::AddContentLayer(
- const gfx::Transform& transform,
- base::ScopedCFTypeRef<IOSurfaceRef> io_surface,
- base::ScopedCFTypeRef<CVPixelBufferRef> cv_pixel_buffer,
- const gfx::RectF& contents_rect,
- const gfx::Rect& rect,
- unsigned background_color,
- unsigned edge_aa_mask,
- float opacity,
- unsigned filter) {
+ CARendererLayerTree* tree,
+ const CARendererLayerParams& params) {
bool needs_new_transform_layer = true;
if (!transform_layers.empty()) {
const TransformLayer& current_layer = transform_layers.back();
- if (current_layer.transform == transform)
+ if (current_layer.transform == params.transform)
needs_new_transform_layer = false;
}
if (needs_new_transform_layer)
- transform_layers.push_back(TransformLayer(transform));
- transform_layers.back().AddContentLayer(io_surface, cv_pixel_buffer,
- contents_rect, rect, background_color,
- edge_aa_mask, opacity, filter);
+ transform_layers.push_back(TransformLayer(params.transform));
+ transform_layers.back().AddContentLayer(tree, params);
}
void CARendererLayerTree::TransformLayer::AddContentLayer(
- base::ScopedCFTypeRef<IOSurfaceRef> io_surface,
- base::ScopedCFTypeRef<CVPixelBufferRef> cv_pixel_buffer,
- const gfx::RectF& contents_rect,
- const gfx::Rect& rect,
- unsigned background_color,
- unsigned edge_aa_mask,
- float opacity,
- unsigned filter) {
- content_layers.push_back(ContentLayer(io_surface, cv_pixel_buffer,
- contents_rect, rect, background_color,
- edge_aa_mask, opacity, filter));
+ CARendererLayerTree* tree,
+ const CARendererLayerParams& params) {
+ base::ScopedCFTypeRef<IOSurfaceRef> io_surface;
+ base::ScopedCFTypeRef<CVPixelBufferRef> cv_pixel_buffer;
+ if (params.image) {
+ gl::GLImageIOSurface* io_surface_image =
+ gl::GLImageIOSurface::FromGLImage(params.image);
+ DCHECK(io_surface_image);
+ io_surface = io_surface_image->io_surface();
+ cv_pixel_buffer = io_surface_image->cv_pixel_buffer();
+ }
+
+ content_layers.push_back(
+ ContentLayer(tree, io_surface, cv_pixel_buffer, params.contents_rect,
+ params.rect, params.background_color, params.edge_aa_mask,
+ params.opacity, params.filter));
}
void CARendererLayerTree::RootLayer::CommitToCA(CALayer* superlayer,
@@ -577,7 +635,8 @@ void CARendererLayerTree::ContentLayer::CommitToCA(CALayer* superlayer,
std::swap(ca_layer, old_layer->ca_layer);
std::swap(av_layer, old_layer->av_layer);
update_contents = old_layer->io_surface != io_surface ||
- old_layer->cv_pixel_buffer != cv_pixel_buffer;
+ old_layer->cv_pixel_buffer != cv_pixel_buffer ||
+ old_layer->solid_color_contents != solid_color_contents;
update_contents_rect = old_layer->contents_rect != contents_rect;
update_rect = old_layer->rect != rect;
update_background_color = old_layer->background_color != background_color;
@@ -614,7 +673,13 @@ void CARendererLayerTree::ContentLayer::CommitToCA(CALayer* superlayer,
}
} else {
if (update_contents) {
- [ca_layer setContents:static_cast<id>(io_surface.get())];
+ if (io_surface) {
+ [ca_layer setContents:static_cast<id>(io_surface.get())];
+ } else if (solid_color_contents) {
+ [ca_layer setContents:solid_color_contents->GetContents()];
+ } else {
+ [ca_layer setContents:nil];
+ }
if ([ca_layer respondsToSelector:(@selector(setContentsScale:))])
[ca_layer setContentsScale:scale_factor];
}
@@ -655,9 +720,15 @@ void CARendererLayerTree::ContentLayer::CommitToCA(CALayer* superlayer,
if (use_av_layer) {
// Yellow represents an AV layer that changed this frame.
color.reset(CGColorCreateGenericRGB(1, 1, 0, 1));
- } else {
- // Pink represents a CALayer that changed this frame.
+ } else if (io_surface) {
+ // Magenta represents a CALayer that changed this frame.
color.reset(CGColorCreateGenericRGB(1, 0, 1, 1));
+ } else if (solid_color_contents) {
+ // Cyan represents a solid color IOSurface-backed layer.
+ color.reset(CGColorCreateGenericRGB(0, 1, 1, 1));
+ } else {
+ // Red represents a solid color layer.
+ color.reset(CGColorCreateGenericRGB(1, 0, 0, 1));
}
} else {
// Grey represents a CALayer that has not changed.