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 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
|
// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "third_party/blink/renderer/platform/graphics/paint/scrollbar_display_item.h"
#include "base/trace_event/traced_value.h"
#include "cc/input/scrollbar.h"
#include "cc/layers/scrollbar_layer_base.h"
#include "third_party/blink/renderer/platform/graphics/graphics_context.h"
#include "third_party/blink/renderer/platform/graphics/paint/drawing_recorder.h"
#include "third_party/blink/renderer/platform/graphics/paint/paint_controller.h"
#include "third_party/blink/renderer/platform/graphics/paint/paint_record_builder.h"
#include "third_party/blink/renderer/platform/graphics/paint/paint_recorder.h"
#include "third_party/blink/renderer/platform/graphics/paint/scroll_paint_property_node.h"
#include "ui/gfx/geometry/skia_conversions.h"
namespace blink {
ScrollbarDisplayItem::ScrollbarDisplayItem(
DisplayItemClientId client_id,
Type type,
scoped_refptr<cc::Scrollbar> scrollbar,
const gfx::Rect& visual_rect,
const TransformPaintPropertyNode* scroll_translation,
CompositorElementId element_id,
cc::HitTestOpaqueness hit_test_opaqueness,
RasterEffectOutset outset,
PaintInvalidationReason paint_invalidation_reason)
: DisplayItem(client_id,
type,
visual_rect,
outset,
paint_invalidation_reason,
/*draws_content*/ true),
data_(new Data{std::move(scrollbar), scroll_translation, element_id,
hit_test_opaqueness}) {
DCHECK(IsScrollbar());
CHECK(!data_->scroll_translation_ ||
data_->scroll_translation_->ScrollNode());
}
PaintRecord ScrollbarDisplayItem::Paint() const {
DCHECK(!IsTombstone());
if (!data_->record_.empty() && !NeedsUpdateDisplay()) {
return data_->record_;
}
PaintRecorder recorder;
const gfx::Rect& rect = VisualRect();
recorder.beginRecording();
auto* canvas = recorder.getRecordingCanvas();
auto* scrollbar = data_->scrollbar_.get();
// Skip track and button painting for Minimal mode Fluent scrollbars.
if (!scrollbar->IsFluentOverlayScrollbarMinimalMode()) {
scrollbar->PaintTrackAndButtons(*canvas, rect);
}
gfx::Rect thumb_rect = scrollbar->ThumbRect();
thumb_rect.Offset(rect.OffsetFromOrigin());
if (scrollbar->IsFluentOverlayScrollbarMinimalMode()) {
thumb_rect = scrollbar->ShrinkMainThreadedMinimalModeThumbRect(thumb_rect);
}
scrollbar->PaintThumb(*canvas, thumb_rect);
scrollbar->ClearNeedsUpdateDisplay();
data_->record_ = recorder.finishRecordingAsPicture();
return data_->record_;
}
bool ScrollbarDisplayItem::NeedsUpdateDisplay() const {
return data_->scrollbar_->NeedsUpdateDisplay();
}
scoped_refptr<cc::ScrollbarLayerBase> ScrollbarDisplayItem::CreateOrReuseLayer(
cc::ScrollbarLayerBase* existing_layer,
gfx::Vector2dF offset_of_decomposited_transforms) const {
DCHECK(!IsTombstone());
// This function is called when the scrollbar is composited. We don't need
// record_ which is for non-composited scrollbars.
data_->record_ = PaintRecord();
auto* scrollbar = data_->scrollbar_.get();
auto layer = cc::ScrollbarLayerBase::CreateOrReuse(scrollbar, existing_layer);
layer->SetIsDrawable(true);
layer->SetContentsOpaque(IsOpaque());
layer->SetHitTestOpaqueness(data_->hit_test_opaqueness_);
layer->SetElementId(data_->element_id_);
layer->SetScrollElementId(
data_->scroll_translation_
? data_->scroll_translation_->ScrollNode()->GetCompositorElementId()
: CompositorElementId());
layer->SetOffsetToTransformParent(
gfx::Vector2dF(VisualRect().OffsetFromOrigin()) +
offset_of_decomposited_transforms);
layer->SetBounds(VisualRect().size());
// TODO(crbug.com/1414885): This may be duplicate with
// ScrollableArea::ScrollableArea::SetScrollbarNeedsPaintInvalidation()
// which calls PaintArtifactCompositor::SetScrollbarNeedsDisplay().
if (NeedsUpdateDisplay()) {
layer->SetNeedsDisplay();
scrollbar->ClearNeedsUpdateDisplay();
}
return layer;
}
bool ScrollbarDisplayItem::IsOpaque() const {
DCHECK(!IsTombstone());
return data_->scrollbar_->IsOpaque();
}
bool ScrollbarDisplayItem::EqualsForUnderInvalidationImpl(
const ScrollbarDisplayItem& other) const {
DCHECK(RuntimeEnabledFeatures::PaintUnderInvalidationCheckingEnabled());
// Don't check scrollbar_ because it's always newly created when we repaint
// a scrollbar (including forced repaint for PaintUnderInvalidationChecking).
// Don't check record_ because it's lazily created, and the DCHECKs in Paint()
// can catch most under-invalidation cases.
return data_->scroll_translation_ == other.data_->scroll_translation_ &&
data_->element_id_ == other.data_->element_id_;
}
#if DCHECK_IS_ON()
void ScrollbarDisplayItem::PropertiesAsJSONImpl(JSONObject& json) const {
json.SetString("scrollTranslation",
String::Format("%p", data_->scroll_translation_.Get()));
}
#endif
void ScrollbarDisplayItem::Record(
GraphicsContext& context,
const DisplayItemClient& client,
DisplayItem::Type type,
scoped_refptr<cc::Scrollbar> scrollbar,
const gfx::Rect& visual_rect,
const TransformPaintPropertyNode* scroll_translation,
CompositorElementId element_id,
cc::HitTestOpaqueness hit_test_opaqueness) {
PaintController& paint_controller = context.GetPaintController();
// Must check PaintController::UseCachedItemIfPossible before this function.
DCHECK(RuntimeEnabledFeatures::PaintUnderInvalidationCheckingEnabled() ||
!paint_controller.UseCachedItemIfPossible(client, type));
CHECK(IsScrollbarElementId(element_id));
paint_controller.CreateAndAppend<ScrollbarDisplayItem>(
client, type, std::move(scrollbar), visual_rect, scroll_translation,
element_id, hit_test_opaqueness,
client.VisualRectOutsetForRasterEffects(),
client.GetPaintInvalidationReason());
}
} // namespace blink
|