1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
cc / paint / clear_for_opaque_raster.cc [blame]
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "cc/paint/clear_for_opaque_raster.h"
#include <cmath>
#include "base/check_op.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size_f.h"
#include "ui/gfx/geometry/vector2d_f.h"
namespace cc {
bool CalculateClearForOpaqueRasterRects(const gfx::Vector2dF& translation,
const gfx::Vector2dF& scale,
const gfx::Size& content_size,
const gfx::Rect& canvas_bitmap_rect,
const gfx::Rect& canvas_playback_rect,
gfx::Rect& outer_rect,
gfx::Rect& inner_rect) {
// If there is translation, the top and/or left texels are not guaranteed to
// be fully opaque.
DCHECK_GE(translation.x(), 0.0f);
DCHECK_GE(translation.y(), 0.0f);
DCHECK_LT(translation.x(), 1.0f);
DCHECK_LT(translation.y(), 1.0f);
bool left_opaque = translation.x() == 0.0f;
bool top_opaque = translation.y() == 0.0f;
// If there is scale, the right and/or bottom texels are not guaranteed to be
// fully opaque.
bool right_opaque = scale.x() == 1.0f;
bool bottom_opaque = scale.y() == 1.0f;
if (left_opaque && top_opaque && right_opaque && bottom_opaque)
return false;
// |outer_rect| is the bounds of all texels affected by content.
outer_rect = gfx::Rect(content_size);
// |inner_rect| is the opaque coverage of the content.
inner_rect = outer_rect;
// If not fully covered, one texel inside the content rect may not be opaque
// (because of blending during raster) and, for scale, one texel outside
// (because of bilinear filtering during draw) may not be opaque.
outer_rect.Inset(
gfx::Insets::TLBR(0, 0, bottom_opaque ? 0 : -1, right_opaque ? 0 : -1));
inner_rect.Inset(gfx::Insets::TLBR(top_opaque ? 0 : 1, left_opaque ? 0 : 1,
bottom_opaque ? 0 : 1,
right_opaque ? 0 : 1));
// If the playback rect is touching either edge of the content rect, extend it
// by one to include the extra texel outside that was added to outer_rect
// above.
bool touches_left_edge = !left_opaque && !canvas_playback_rect.x();
bool touches_top_edge = !top_opaque && !canvas_playback_rect.y();
bool touches_right_edge =
!right_opaque && content_size.width() == canvas_playback_rect.right();
bool touches_bottom_edge =
!bottom_opaque && content_size.height() == canvas_playback_rect.bottom();
gfx::Rect adjusted_playback_rect = canvas_playback_rect;
adjusted_playback_rect.Inset(gfx::Insets::TLBR(
touches_top_edge ? -1 : 0, touches_left_edge ? -1 : 0,
touches_bottom_edge ? -1 : 0, touches_right_edge ? -1 : 0));
// No need to clear if the playback area is fully covered by the opaque
// content.
if (inner_rect.Contains(adjusted_playback_rect))
return false;
if (!outer_rect.Intersects(adjusted_playback_rect))
return false;
outer_rect.Intersect(adjusted_playback_rect);
inner_rect.Intersect(adjusted_playback_rect);
// inner_rect can be empty if the content is very small.
// Move the rects into the device space.
outer_rect.Offset(-canvas_bitmap_rect.OffsetFromOrigin());
inner_rect.Offset(-canvas_bitmap_rect.OffsetFromOrigin());
return inner_rect != outer_rect;
}
} // namespace cc