forked from chromium/chromium
-
Notifications
You must be signed in to change notification settings - Fork 0
/
clear_for_opaque_raster.cc
79 lines (68 loc) · 3.33 KB
/
clear_for_opaque_raster.cc
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
// Copyright 2020 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.
#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::SizeF& 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.width() == 1.0f;
bool bottom_opaque = scale.height() == 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(0, 0, right_opaque ? 0 : -1, bottom_opaque ? 0 : -1);
inner_rect.Inset(left_opaque ? 0 : 1, top_opaque ? 0 : 1,
right_opaque ? 0 : 1, bottom_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(
touches_left_edge ? -1 : 0, touches_top_edge ? -1 : 0,
touches_right_edge ? -1 : 0, touches_bottom_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;
outer_rect.Intersect(adjusted_playback_rect);
DCHECK(!outer_rect.IsEmpty());
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