blob: dcf5389d761288545e15b4b4ae4fd872cca7c141 [file] [log] [blame]
// Copyright 2014 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 "third_party/blink/renderer/core/paint/frame_painter.h"
#include "third_party/blink/renderer/core/editing/markers/document_marker_controller.h"
#include "third_party/blink/renderer/core/frame/local_frame_view.h"
#include "third_party/blink/renderer/core/inspector/inspector_trace_events.h"
#include "third_party/blink/renderer/core/layout/layout_scrollbar_part.h"
#include "third_party/blink/renderer/core/layout/layout_view.h"
#include "third_party/blink/renderer/core/page/page.h"
#include "third_party/blink/renderer/core/paint/frame_paint_timing.h"
#include "third_party/blink/renderer/core/paint/paint_info.h"
#include "third_party/blink/renderer/core/paint/paint_layer.h"
#include "third_party/blink/renderer/core/paint/paint_layer_painter.h"
#include "third_party/blink/renderer/core/paint/scrollbar_painter.h"
#include "third_party/blink/renderer/core/paint/transform_recorder.h"
#include "third_party/blink/renderer/core/probe/core_probes.h"
#include "third_party/blink/renderer/platform/fonts/font_cache.h"
#include "third_party/blink/renderer/platform/graphics/graphics_context.h"
#include "third_party/blink/renderer/platform/graphics/graphics_layer.h"
#include "third_party/blink/renderer/platform/graphics/paint/clip_recorder.h"
#include "third_party/blink/renderer/platform/graphics/paint/drawing_recorder.h"
#include "third_party/blink/renderer/platform/loader/fetch/memory_cache.h"
#include "third_party/blink/renderer/platform/scroll/scrollbar_theme.h"
namespace blink {
bool FramePainter::in_paint_contents_ = false;
void FramePainter::Paint(GraphicsContext& context,
const GlobalPaintFlags global_paint_flags,
const CullRect& rect) {
if (GetFrameView().ShouldThrottleRendering())
return;
GetFrameView().NotifyPageThatContentAreaWillPaint();
IntRect document_dirty_rect;
IntPoint frame_view_location(GetFrameView().Location());
IntRect visible_area_without_scrollbars(frame_view_location,
GetFrameView().VisibleContentSize());
IntPoint content_offset =
-frame_view_location + GetFrameView().ScrollOffsetInt();
document_dirty_rect = rect.rect_;
document_dirty_rect.Intersect(visible_area_without_scrollbars);
document_dirty_rect.MoveBy(content_offset);
bool should_paint_contents = !document_dirty_rect.IsEmpty();
bool should_paint_scrollbars = !GetFrameView().ScrollbarsSuppressed() &&
(GetFrameView().HorizontalScrollbar() ||
GetFrameView().VerticalScrollbar());
if (!should_paint_contents && !should_paint_scrollbars)
return;
if (should_paint_contents) {
TransformRecorder transform_recorder(
context, *GetFrameView().GetLayoutView(),
AffineTransform::Translation(
frame_view_location.X() - GetFrameView().ScrollX(),
frame_view_location.Y() - GetFrameView().ScrollY()));
ClipRecorder clip_recorder(context, *GetFrameView().GetLayoutView(),
DisplayItem::kClipFrameToVisibleContentRect,
GetFrameView().VisibleContentRect());
PaintContents(context, global_paint_flags, document_dirty_rect);
}
}
void FramePainter::PaintContents(GraphicsContext& context,
const GlobalPaintFlags global_paint_flags,
const IntRect& rect) {
Document* document = GetFrameView().GetFrame().GetDocument();
if (GetFrameView().ShouldThrottleRendering() || !document->IsActive())
return;
LayoutView* layout_view = GetFrameView().GetLayoutView();
if (!layout_view) {
DLOG(ERROR) << "called FramePainter::paint with nil layoutObject";
return;
}
// TODO(crbug.com/590856): It's still broken when we choose not to crash when
// the check fails.
if (!GetFrameView().CheckDoesNotNeedLayout())
return;
// TODO(wangxianzhu): The following check should be stricter, but currently
// this is blocked by the svg root issue (crbug.com/442939).
DCHECK(document->Lifecycle().GetState() >=
DocumentLifecycle::kCompositingClean);
FramePaintTiming frame_paint_timing(context, &GetFrameView().GetFrame());
TRACE_EVENT1(
"devtools.timeline,rail", "Paint", "data",
InspectorPaintEvent::Data(layout_view, LayoutRect(rect), nullptr));
bool is_top_level_painter = !in_paint_contents_;
in_paint_contents_ = true;
FontCachePurgePreventer font_cache_purge_preventer;
// TODO(jchaffraix): GlobalPaintFlags should be const during a paint
// phase. Thus we should set this flag upfront (crbug.com/510280).
GlobalPaintFlags updated_global_paint_flags = global_paint_flags;
PaintLayerFlags root_layer_paint_flags = 0;
if (document->Printing()) {
updated_global_paint_flags |=
kGlobalPaintFlattenCompositingLayers | kGlobalPaintPrinting;
// This will prevent clipping the root PaintLayer to its visible content
// rect when root layer scrolling is enabled.
root_layer_paint_flags = kPaintLayerPaintingOverflowContents;
}
PaintLayer* root_layer = layout_view->Layer();
#if DCHECK_IS_ON()
layout_view->AssertSubtreeIsLaidOut();
LayoutObject::SetLayoutNeededForbiddenScope forbid_set_needs_layout(
root_layer->GetLayoutObject());
#endif
PaintLayerPainter layer_painter(*root_layer);
float device_scale_factor = blink::DeviceScaleFactorDeprecated(
root_layer->GetLayoutObject().GetFrame());
context.SetDeviceScaleFactor(device_scale_factor);
layer_painter.Paint(context, LayoutRect(rect), updated_global_paint_flags,
root_layer_paint_flags);
if (root_layer->ContainsDirtyOverlayScrollbars()) {
layer_painter.PaintOverlayScrollbars(context, LayoutRect(rect),
updated_global_paint_flags);
}
// Regions may have changed as a result of the visibility/z-index of element
// changing.
if (document->AnnotatedRegionsDirty())
GetFrameView().UpdateDocumentAnnotatedRegions();
if (is_top_level_painter) {
// Everything that happens after paintContents completions is considered
// to be part of the next frame.
GetMemoryCache()->UpdateFramePaintTimestamp();
in_paint_contents_ = false;
}
probe::didPaint(layout_view->GetFrame(), nullptr, context, LayoutRect(rect));
}
void FramePainter::PaintScrollbars(GraphicsContext& context,
const IntRect& rect) {
if (GetFrameView().HorizontalScrollbar() &&
!GetFrameView().LayerForHorizontalScrollbar())
PaintScrollbar(context, *GetFrameView().HorizontalScrollbar(), rect);
if (GetFrameView().VerticalScrollbar() &&
!GetFrameView().LayerForVerticalScrollbar())
PaintScrollbar(context, *GetFrameView().VerticalScrollbar(), rect);
if (!GetFrameView().LayerForScrollCorner() &&
GetFrameView().IsScrollCornerVisible())
PaintScrollCorner(context, GetFrameView().ScrollCornerRect());
}
void FramePainter::PaintScrollCorner(GraphicsContext& context,
const IntRect& corner_rect) {
if (const auto* scroll_corner = GetFrameView().ScrollCorner()) {
bool needs_background = GetFrameView().GetFrame().IsMainFrame();
if (needs_background &&
!DrawingRecorder::UseCachedDrawingIfPossible(
context, *scroll_corner, DisplayItem::kScrollbarBackground)) {
DrawingRecorder recorder(context, *scroll_corner,
DisplayItem::kScrollbarBackground);
context.FillRect(corner_rect, GetFrameView().BaseBackgroundColor());
}
ScrollbarPainter::PaintIntoRect(*scroll_corner, context,
corner_rect.Location(),
LayoutRect(corner_rect));
return;
}
ScrollbarTheme* theme = nullptr;
if (GetFrameView().HorizontalScrollbar()) {
theme = &GetFrameView().HorizontalScrollbar()->GetTheme();
} else if (GetFrameView().VerticalScrollbar()) {
theme = &GetFrameView().VerticalScrollbar()->GetTheme();
} else {
NOTREACHED();
}
const DisplayItemClient* client;
if (auto* graphics_layer = GetFrameView().LayerForScrollCorner())
client = graphics_layer;
else
client = GetFrameView().GetLayoutView();
theme->PaintScrollCorner(context, *client, corner_rect);
}
void FramePainter::PaintScrollbar(GraphicsContext& context,
Scrollbar& bar,
const IntRect& rect) {
bool needs_background =
bar.IsCustomScrollbar() && GetFrameView().GetFrame().IsMainFrame();
if (needs_background) {
IntRect to_fill = bar.FrameRect();
to_fill.Intersect(rect);
if (!to_fill.IsEmpty() &&
!DrawingRecorder::UseCachedDrawingIfPossible(
context, bar, DisplayItem::kScrollbarBackground)) {
DrawingRecorder recorder(context, bar, DisplayItem::kScrollbarBackground);
context.FillRect(to_fill, GetFrameView().BaseBackgroundColor());
}
}
bar.Paint(context, CullRect(rect));
}
const LocalFrameView& FramePainter::GetFrameView() {
DCHECK(frame_view_);
return *frame_view_;
}
} // namespace blink