1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
6 #include "core/paint/FramePainter.h"
8 #include "core/editing/markers/DocumentMarkerController.h"
9 #include "core/fetch/MemoryCache.h"
10 #include "core/frame/FrameView.h"
11 #include "core/inspector/InspectorInstrumentation.h"
12 #include "core/inspector/InspectorTraceEvents.h"
13 #include "core/layout/LayoutView.h"
14 #include "core/page/Page.h"
15 #include "core/paint/DeprecatedPaintLayer.h"
16 #include "core/paint/DeprecatedPaintLayerPainter.h"
17 #include "core/paint/LayoutObjectDrawingRecorder.h"
18 #include "core/paint/PaintInfo.h"
19 #include "core/paint/ScrollbarPainter.h"
20 #include "core/paint/TransformRecorder.h"
21 #include "platform/fonts/FontCache.h"
22 #include "platform/graphics/GraphicsContext.h"
23 #include "platform/graphics/paint/ClipRecorder.h"
24 #include "platform/scroll/ScrollbarTheme.h"
28 bool FramePainter::s_inPaintContents
= false;
30 void FramePainter::paint(GraphicsContext
* context
, const GlobalPaintFlags globalPaintFlags
, const IntRect
& rect
)
32 frameView().notifyPageThatContentAreaWillPaint();
34 IntRect documentDirtyRect
= rect
;
35 IntRect
visibleAreaWithoutScrollbars(frameView().location(), frameView().visibleContentRect().size());
36 documentDirtyRect
.intersect(visibleAreaWithoutScrollbars
);
38 if (!documentDirtyRect
.isEmpty()) {
39 TransformRecorder
transformRecorder(*context
, *frameView().layoutView(),
40 AffineTransform::translation(frameView().x() - frameView().scrollX(), frameView().y() - frameView().scrollY()));
42 ClipRecorder
recorder(*context
, *frameView().layoutView(), DisplayItem::ClipFrameToVisibleContentRect
, LayoutRect(frameView().visibleContentRect()));
44 documentDirtyRect
.moveBy(-frameView().location() + frameView().scrollPosition());
45 paintContents(context
, globalPaintFlags
, documentDirtyRect
);
48 // Now paint the scrollbars.
49 if (!frameView().scrollbarsSuppressed() && (frameView().horizontalScrollbar() || frameView().verticalScrollbar())) {
50 IntRect scrollViewDirtyRect
= rect
;
51 IntRect
visibleAreaWithScrollbars(frameView().location(), frameView().visibleContentRect(IncludeScrollbars
).size());
52 scrollViewDirtyRect
.intersect(visibleAreaWithScrollbars
);
53 scrollViewDirtyRect
.moveBy(-frameView().location());
55 TransformRecorder
transformRecorder(*context
, *frameView().layoutView(),
56 AffineTransform::translation(frameView().x(), frameView().y()));
58 ClipRecorder
recorder(*context
, *frameView().layoutView(), DisplayItem::ClipFrameScrollbars
, LayoutRect(IntPoint(), visibleAreaWithScrollbars
.size()));
60 paintScrollbars(context
, scrollViewDirtyRect
);
64 void FramePainter::paintContents(GraphicsContext
* context
, const GlobalPaintFlags globalPaintFlags
, const IntRect
& rect
)
66 Document
* document
= frameView().frame().document();
70 if (document
->printing())
71 fillWithRed
= false; // Printing, don't fill with red (can't remember why).
72 else if (frameView().frame().owner())
73 fillWithRed
= false; // Subframe, don't fill with red.
74 else if (frameView().isTransparent())
75 fillWithRed
= false; // Transparent, don't fill with red.
76 else if (globalPaintFlags
& GlobalPaintSelectionOnly
)
77 fillWithRed
= false; // Selections are transparent, don't fill with red.
78 else if (frameView().nodeToDraw())
79 fillWithRed
= false; // Element images are transparent, don't fill with red.
83 if (fillWithRed
&& !LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(*context
, *frameView().layoutView(), DisplayItem::DebugRedFill
, LayoutPoint())) {
84 IntRect
contentRect(IntPoint(), frameView().contentsSize());
85 LayoutObjectDrawingRecorder
drawingRecorder(*context
, *frameView().layoutView(), DisplayItem::DebugRedFill
, contentRect
, LayoutPoint());
89 LayoutView
* layoutView
= frameView().layoutView();
91 WTF_LOG_ERROR("called FramePainter::paint with nil layoutObject");
95 RELEASE_ASSERT(!frameView().needsLayout());
96 ASSERT(document
->lifecycle().state() >= DocumentLifecycle::CompositingClean
);
98 TRACE_EVENT1("devtools.timeline", "Paint", "data", InspectorPaintEvent::data(layoutView
, LayoutRect(rect
), 0));
100 bool isTopLevelPainter
= !s_inPaintContents
;
101 s_inPaintContents
= true;
103 FontCachePurgePreventer fontCachePurgePreventer
;
105 // TODO(jchaffraix): GlobalPaintFlags should be const during a paint
106 // phase. Thus we should set this flag upfront (crbug.com/510280).
107 GlobalPaintFlags localPaintFlags
= globalPaintFlags
;
108 if (document
->printing())
109 localPaintFlags
|= GlobalPaintFlattenCompositingLayers
| GlobalPaintPrinting
;
111 ASSERT(!frameView().isPainting());
112 frameView().setIsPainting(true);
114 // frameView().nodeToDraw() is used to draw only one element (and its descendants)
115 LayoutObject
* layoutObject
= frameView().nodeToDraw() ? frameView().nodeToDraw()->layoutObject() : 0;
116 DeprecatedPaintLayer
* rootLayer
= layoutView
->layer();
119 layoutView
->assertSubtreeIsLaidOut();
120 LayoutObject::SetLayoutNeededForbiddenScope
forbidSetNeedsLayout(*rootLayer
->layoutObject());
123 DeprecatedPaintLayerPainter
layerPainter(*rootLayer
);
125 float deviceScaleFactor
= blink::deviceScaleFactor(rootLayer
->layoutObject()->frame());
126 context
->setDeviceScaleFactor(deviceScaleFactor
);
128 layerPainter
.paint(context
, LayoutRect(rect
), localPaintFlags
, layoutObject
);
130 if (rootLayer
->containsDirtyOverlayScrollbars())
131 layerPainter
.paintOverlayScrollbars(context
, LayoutRect(rect
), localPaintFlags
, layoutObject
);
133 frameView().setIsPainting(false);
135 frameView().setLastPaintTime(currentTime());
137 // Regions may have changed as a result of the visibility/z-index of element changing.
138 if (document
->annotatedRegionsDirty())
139 frameView().updateAnnotatedRegions();
141 if (isTopLevelPainter
) {
142 // Everything that happens after paintContents completions is considered
143 // to be part of the next frame.
144 memoryCache()->updateFramePaintTimestamp();
145 s_inPaintContents
= false;
148 InspectorInstrumentation::didPaint(layoutView
, 0, context
, LayoutRect(rect
));
151 void FramePainter::paintScrollbars(GraphicsContext
* context
, const IntRect
& rect
)
153 if (frameView().horizontalScrollbar() && !frameView().layerForHorizontalScrollbar())
154 paintScrollbar(context
, frameView().horizontalScrollbar(), rect
);
155 if (frameView().verticalScrollbar() && !frameView().layerForVerticalScrollbar())
156 paintScrollbar(context
, frameView().verticalScrollbar(), rect
);
158 if (frameView().layerForScrollCorner())
161 paintScrollCorner(context
, frameView().scrollCornerRect());
164 void FramePainter::paintScrollCorner(GraphicsContext
* context
, const IntRect
& cornerRect
)
166 if (frameView().scrollCorner()) {
167 bool needsBackground
= frameView().frame().isMainFrame();
168 if (needsBackground
&& !LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(*context
, *frameView().layoutView(), DisplayItem::ScrollbarCorner
, LayoutPoint())) {
169 LayoutObjectDrawingRecorder
drawingRecorder(*context
, *frameView().layoutView(), DisplayItem::ScrollbarCorner
, FloatRect(cornerRect
), LayoutPoint());
170 context
->fillRect(cornerRect
, frameView().baseBackgroundColor());
173 ScrollbarPainter::paintIntoRect(frameView().scrollCorner(), context
, cornerRect
.location(), LayoutRect(cornerRect
));
177 ScrollbarTheme::theme()->paintScrollCorner(context
, *frameView().layoutView(), cornerRect
);
180 void FramePainter::paintScrollbar(GraphicsContext
* context
, Scrollbar
* bar
, const IntRect
& rect
)
182 bool needsBackground
= bar
->isCustomScrollbar() && frameView().frame().isMainFrame();
183 if (needsBackground
) {
184 IntRect toFill
= bar
->frameRect();
185 toFill
.intersect(rect
);
186 context
->fillRect(toFill
, frameView().baseBackgroundColor());
189 bar
->paint(context
, rect
);
192 FrameView
& FramePainter::frameView()