1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "cc/output/overlay_strategy_sandwich.h"
7 #include "cc/base/math_util.h"
8 #include "cc/base/region.h"
9 #include "cc/output/overlay_candidate_validator.h"
10 #include "cc/quads/draw_quad.h"
11 #include "cc/quads/solid_color_draw_quad.h"
12 #include "ui/gfx/geometry/dip_util.h"
13 #include "ui/gfx/geometry/rect_conversions.h"
17 gfx::Rect
AlignPixelRectToDIP(float scale_factor
, const gfx::Rect
& pixel_rect
) {
19 gfx::ScaleToEnclosingRect(pixel_rect
, 1.0f
/ scale_factor
);
20 gfx::Rect new_pixel_rect
= gfx::ScaleToEnclosingRect(dip_rect
, scale_factor
);
21 return new_pixel_rect
;
24 bool IsPixelRectAlignedToDIP(float scale_factor
, const gfx::Rect
& pixel_rect
) {
25 return (pixel_rect
== AlignPixelRectToDIP(scale_factor
, pixel_rect
));
32 OverlayStrategySandwich::~OverlayStrategySandwich() {}
34 OverlayResult
OverlayStrategySandwich::TryOverlay(
35 OverlayCandidateValidator
* capability_checker
,
36 RenderPassList
* render_passes_in_draw_order
,
37 OverlayCandidateList
* candidate_list
,
38 const OverlayCandidate
& candidate
,
39 QuadList::Iterator
* candidate_iter_in_quad_list
,
40 float device_scale_factor
) {
41 RenderPass
* root_render_pass
= render_passes_in_draw_order
->back();
42 QuadList
& quad_list
= root_render_pass
->quad_list
;
43 gfx::Rect pixel_bounds
= root_render_pass
->output_rect
;
45 const DrawQuad
* candidate_quad
= **candidate_iter_in_quad_list
;
46 const gfx::Transform
& candidate_transform
=
47 candidate_quad
->shared_quad_state
->quad_to_target_transform
;
48 gfx::Transform candidate_inverse_transform
;
49 if (!candidate_transform
.GetInverse(&candidate_inverse_transform
))
50 return DID_NOT_CREATE_OVERLAY
;
52 // Compute the candidate's rect in display space (pixels on the screen). The
53 // rect needs to be DIP-aligned, or we cannot use it.
54 const gfx::Rect candidate_pixel_rect
=
55 gfx::ToNearestRect(candidate
.display_rect
);
56 if (!IsPixelRectAlignedToDIP(device_scale_factor
, candidate_pixel_rect
))
57 return DID_NOT_CREATE_OVERLAY
;
59 // Don't allow overlapping overlays for now.
60 for (const OverlayCandidate
& other_candidate
: *candidate_list
) {
61 if (other_candidate
.display_rect
.Intersects(candidate
.display_rect
) &&
62 other_candidate
.plane_z_order
== 1) {
63 return DID_NOT_CREATE_OVERLAY
;
67 // Iterate through the quads in front of |candidate|, and compute the region
68 // of |candidate| that is covered.
69 Region pixel_covered_region
;
70 for (auto overlap_iter
= quad_list
.cbegin();
71 overlap_iter
!= *candidate_iter_in_quad_list
; ++overlap_iter
) {
72 if (OverlayStrategyCommon::IsInvisibleQuad(*overlap_iter
))
74 // Compute the quad's bounds in display space, and ensure that it is rounded
75 // up to be DIP-aligned.
76 gfx::Rect unaligned_pixel_covered_rect
= MathUtil::MapEnclosingClippedRect(
77 overlap_iter
->shared_quad_state
->quad_to_target_transform
,
79 gfx::Rect pixel_covered_rect
=
80 AlignPixelRectToDIP(device_scale_factor
, unaligned_pixel_covered_rect
);
82 // Include the intersection of that quad with the candidate's quad in the
84 pixel_covered_rect
.Intersect(candidate_pixel_rect
);
85 pixel_covered_region
.Union(pixel_covered_rect
);
88 // Add the candidate's overlay.
89 DCHECK(candidate
.resource_id
);
90 OverlayCandidateList new_candidate_list
= *candidate_list
;
91 new_candidate_list
.push_back(candidate
);
92 new_candidate_list
.back().plane_z_order
= 1;
94 // Add an overlay of the primary surface for any part of the candidate's
95 // quad that was covered.
96 std::vector
<gfx::Rect
> pixel_covered_rects
;
97 for (Region::Iterator
it(pixel_covered_region
); it
.has_rect(); it
.next()) {
98 DCHECK(IsPixelRectAlignedToDIP(device_scale_factor
, it
.rect()));
99 pixel_covered_rects
.push_back(it
.rect());
101 for (const gfx::Rect
& pixel_covered_rect
: pixel_covered_rects
) {
102 OverlayCandidate main_image_on_top
;
103 main_image_on_top
.display_rect
= gfx::RectF(pixel_covered_rect
);
104 main_image_on_top
.uv_rect
= gfx::RectF(pixel_covered_rect
);
105 main_image_on_top
.uv_rect
.Scale(1.f
/ pixel_bounds
.width(),
106 1.f
/ pixel_bounds
.height());
107 main_image_on_top
.plane_z_order
= 2;
108 main_image_on_top
.transform
= gfx::OVERLAY_TRANSFORM_NONE
;
109 main_image_on_top
.use_output_surface_for_resource
= true;
110 new_candidate_list
.push_back(main_image_on_top
);
113 // Check for support.
114 capability_checker
->CheckOverlaySupport(&new_candidate_list
);
115 for (const OverlayCandidate
& candidate
: new_candidate_list
) {
116 if (candidate
.plane_z_order
> 0 && !candidate
.overlay_handled
)
117 return DID_NOT_CREATE_OVERLAY
;
120 // Remove the quad for the overlay quad. Replace it with a transparent quad
121 // if we're putting a new overlay on top.
122 if (pixel_covered_rects
.empty()) {
123 *candidate_iter_in_quad_list
=
124 quad_list
.EraseAndInvalidateAllPointers(*candidate_iter_in_quad_list
);
126 // Cache the information from the candidate quad that we'll need to
127 // construct the solid color quads.
128 const SharedQuadState
* candidate_shared_quad_state
=
129 candidate_quad
->shared_quad_state
;
130 const gfx::Rect candidate_rect
= candidate_quad
->rect
;
132 // Reserve space in the quad list for the transparent quads.
133 quad_list
.ReplaceExistingElement
<SolidColorDrawQuad
>(
134 *candidate_iter_in_quad_list
);
135 *candidate_iter_in_quad_list
=
136 quad_list
.InsertBeforeAndInvalidateAllPointers
<SolidColorDrawQuad
>(
137 *candidate_iter_in_quad_list
, pixel_covered_rects
.size() - 1);
139 // Cover the region with transparent quads.
140 for (const gfx::Rect
& pixel_covered_rect
: pixel_covered_rects
) {
141 gfx::Rect quad_space_covered_rect
= MathUtil::MapEnclosingClippedRect(
142 candidate_inverse_transform
, pixel_covered_rect
);
143 quad_space_covered_rect
.Intersect(candidate_rect
);
145 SolidColorDrawQuad
* transparent_quad
=
146 static_cast<SolidColorDrawQuad
*>(**candidate_iter_in_quad_list
);
147 transparent_quad
->SetAll(candidate_shared_quad_state
,
148 quad_space_covered_rect
, quad_space_covered_rect
,
149 quad_space_covered_rect
, false,
150 SK_ColorTRANSPARENT
, true);
151 ++(*candidate_iter_in_quad_list
);
155 candidate_list
->swap(new_candidate_list
);
156 return CREATED_OVERLAY_KEEP_LOOKING
;