| // 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::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(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 |