source: webkit/trunk/Source/WebCore/rendering/RenderView.cpp

Last change on this file was 294902, checked in by Alan Bujtas, 3 years ago

Do not issue repaint when the ancestor layer has already been scheduled for one
https://bugs.webkit.org/show_bug.cgi?id=240728

Reviewed by Simon Fraser.

When a renderer needs repaint, we walk the layer tree to search for the repaint container (root for all the paints).
If we find a layer between the renderer and the repaint container that has already been scheduled for a full repaint
we know that this repaint is redundant and will be covered by the ancestor layer.
Since layers paint their overflow content, this works even when the renderer "sticks out" of the ancestor layer's renderer's border box (i.e. produces ink/scrollable overflow).

  • Source/WebCore/rendering/RenderLayer.cpp:

(WebCore::RenderLayer::enclosingCompositingLayerForRepaint const):
(WebCore::RenderLayer::clipCrossesPaintingBoundary const):
(WebCore::RenderLayer::calculateClipRects const):

  • Source/WebCore/rendering/RenderLayer.h:

(WebCore::RenderLayer::needsFullRepaint const):

  • Source/WebCore/rendering/RenderLayerCompositor.cpp:

(WebCore::RenderLayerCompositor::repaintInCompositedAncestor):

  • Source/WebCore/rendering/RenderObject.cpp:

(WebCore::RenderObject::containerForRepaint const):
(WebCore::fullRepaintIsScheduled): This covers the cases when the content is embedded inside an iframe and the iframe's view is not composited.
(WebCore::RenderObject::repaint const):
(WebCore::RenderObject::repaintRectangle const):

  • Source/WebCore/rendering/RenderView.cpp:

(WebCore::RenderView::paintBoxDecorations):

Canonical link: https://commits.webkit.org/251025@main

  • Property svn:eol-style set to native
File size: 33.9 KB
Line 
1/*
2 * Copyright (C) 1999 Lars Knoll ([email protected])
3 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public License
16 * along with this library; see the file COPYING.LIB. If not, write to
17 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 */
20
21#include "config.h"
22#include "RenderView.h"
23
24#include "Document.h"
25#include "Element.h"
26#include "FloatQuad.h"
27#include "Frame.h"
28#include "FrameView.h"
29#include "GraphicsContext.h"
30#include "HTMLBodyElement.h"
31#include "HTMLFrameOwnerElement.h"
32#include "HTMLFrameSetElement.h"
33#include "HTMLHtmlElement.h"
34#include "HTMLIFrameElement.h"
35#include "HitTestResult.h"
36#include "ImageQualityController.h"
37#include "NodeTraversal.h"
38#include "Page.h"
39#include "RenderDescendantIterator.h"
40#include "RenderGeometryMap.h"
41#include "RenderIterator.h"
42#include "RenderLayer.h"
43#include "RenderLayerBacking.h"
44#include "RenderLayerCompositor.h"
45#include "RenderLayoutState.h"
46#include "RenderMultiColumnFlow.h"
47#include "RenderMultiColumnSet.h"
48#include "RenderMultiColumnSpannerPlaceholder.h"
49#include "RenderQuote.h"
50#include "RenderTreeBuilder.h"
51#include "RenderWidget.h"
52#include "Settings.h"
53#include "StyleInheritedData.h"
54#include "TransformState.h"
55#include <wtf/IsoMallocInlines.h>
56#include <wtf/SetForScope.h>
57#include <wtf/StackStats.h>
58
59namespace WebCore {
60
61WTF_MAKE_ISO_ALLOCATED_IMPL(RenderView);
62
63RenderView::RenderView(Document& document, RenderStyle&& style)
64 : RenderBlockFlow(document, WTFMove(style))
65 , m_frameView(*document.view())
66 , m_selection(*this)
67 , m_lazyRepaintTimer(*this, &RenderView::lazyRepaintTimerFired)
68{
69 setIsRenderView();
70
71 // FIXME: We should find a way to enforce this at compile time.
72 ASSERT(document.view());
73
74 // init RenderObject attributes
75 setInline(false);
76
77 m_minPreferredLogicalWidth = 0;
78 m_maxPreferredLogicalWidth = 0;
79
80 setPreferredLogicalWidthsDirty(true, MarkOnlyThis);
81
82 setPositionState(PositionType::Absolute); // to 0,0 :)
83}
84
85RenderView::~RenderView()
86{
87 ASSERT_WITH_MESSAGE(m_rendererCount == 1, "All other renderers in this render tree should have been destroyed");
88}
89
90void RenderView::scheduleLazyRepaint(RenderBox& renderer)
91{
92 if (renderer.renderBoxNeedsLazyRepaint())
93 return;
94 renderer.setRenderBoxNeedsLazyRepaint(true);
95 m_renderersNeedingLazyRepaint.add(&renderer);
96 if (!m_lazyRepaintTimer.isActive())
97 m_lazyRepaintTimer.startOneShot(0_s);
98}
99
100void RenderView::unscheduleLazyRepaint(RenderBox& renderer)
101{
102 if (!renderer.renderBoxNeedsLazyRepaint())
103 return;
104 renderer.setRenderBoxNeedsLazyRepaint(false);
105 m_renderersNeedingLazyRepaint.remove(&renderer);
106 if (m_renderersNeedingLazyRepaint.isEmpty())
107 m_lazyRepaintTimer.stop();
108}
109
110void RenderView::lazyRepaintTimerFired()
111{
112 for (auto& renderer : m_renderersNeedingLazyRepaint) {
113 renderer->repaint();
114 renderer->setRenderBoxNeedsLazyRepaint(false);
115 }
116 m_renderersNeedingLazyRepaint.clear();
117}
118
119RenderBox::LogicalExtentComputedValues RenderView::computeLogicalHeight(LayoutUnit logicalHeight, LayoutUnit) const
120{
121 return { !shouldUsePrintingLayout() ? LayoutUnit(viewLogicalHeight()) : logicalHeight, 0_lu, ComputedMarginValues() };
122}
123
124void RenderView::updateLogicalWidth()
125{
126 setLogicalWidth(shouldUsePrintingLayout() ? m_pageLogicalSize->width() : LayoutUnit(viewLogicalWidth()));
127}
128
129LayoutUnit RenderView::availableLogicalHeight(AvailableLogicalHeightType) const
130{
131 // Make sure block progression pagination for percentages uses the column extent and
132 // not the view's extent. See https://bugs.webkit.org/show_bug.cgi?id=135204.
133 if (multiColumnFlow() && multiColumnFlow()->firstMultiColumnSet())
134 return multiColumnFlow()->firstMultiColumnSet()->computedColumnHeight();
135
136#if PLATFORM(IOS_FAMILY)
137 // Workaround for <rdar://problem/7166808>.
138 if (document().isPluginDocument() && frameView().useFixedLayout())
139 return frameView().fixedLayoutSize().height();
140#endif
141 return isHorizontalWritingMode() ? frameView().layoutSize().height() : frameView().layoutSize().width();
142}
143
144bool RenderView::isChildAllowed(const RenderObject& child, const RenderStyle&) const
145{
146 return child.isBox();
147}
148
149void RenderView::layout()
150{
151 StackStats::LayoutCheckPoint layoutCheckPoint;
152 if (!document().paginated())
153 m_pageLogicalSize = { };
154
155 if (shouldUsePrintingLayout()) {
156 if (!m_pageLogicalSize)
157 m_pageLogicalSize = LayoutSize(logicalWidth(), 0_lu);
158 m_minPreferredLogicalWidth = m_pageLogicalSize->width();
159 m_maxPreferredLogicalWidth = m_minPreferredLogicalWidth;
160 }
161
162 // Use calcWidth/Height to get the new width/height, since this will take the full page zoom factor into account.
163 bool relayoutChildren = !shouldUsePrintingLayout() && (width() != viewWidth() || height() != viewHeight());
164 if (relayoutChildren) {
165 setChildNeedsLayout(MarkOnlyThis);
166
167 for (auto& box : childrenOfType<RenderBox>(*this)) {
168 if (box.hasRelativeLogicalHeight()
169 || box.style().logicalHeight().isPercentOrCalculated()
170 || box.style().logicalMinHeight().isPercentOrCalculated()
171 || box.style().logicalMaxHeight().isPercentOrCalculated()
172 || box.isSVGRootOrLegacySVGRoot()
173 )
174 box.setChildNeedsLayout(MarkOnlyThis);
175 }
176 }
177
178 ASSERT(!frameView().layoutContext().layoutState());
179 if (!needsLayout())
180 return;
181
182 LayoutStateMaintainer statePusher(*this, { }, false, valueOrDefault(m_pageLogicalSize).height(), m_pageLogicalHeightChanged);
183
184 m_pageLogicalHeightChanged = false;
185
186 RenderBlockFlow::layout();
187
188#ifndef NDEBUG
189 frameView().layoutContext().checkLayoutState();
190#endif
191 clearNeedsLayout();
192}
193
194LayoutUnit RenderView::pageOrViewLogicalHeight() const
195{
196 if (shouldUsePrintingLayout())
197 return m_pageLogicalSize->height();
198
199 if (multiColumnFlow() && !style().hasInlineColumnAxis()) {
200 if (int pageLength = frameView().pagination().pageLength)
201 return pageLength;
202 }
203
204 return viewLogicalHeight();
205}
206
207LayoutUnit RenderView::clientLogicalWidthForFixedPosition() const
208{
209 // FIXME: If the FrameView's fixedVisibleContentRect() is not empty, perhaps it should be consulted here too?
210 if (frameView().fixedElementsLayoutRelativeToFrame())
211 return LayoutUnit((isHorizontalWritingMode() ? frameView().visibleWidth() : frameView().visibleHeight()) / frameView().frame().frameScaleFactor());
212
213#if PLATFORM(IOS_FAMILY)
214 if (frameView().useCustomFixedPositionLayoutRect())
215 return isHorizontalWritingMode() ? frameView().customFixedPositionLayoutRect().width() : frameView().customFixedPositionLayoutRect().height();
216#endif
217
218 if (settings().visualViewportEnabled())
219 return isHorizontalWritingMode() ? frameView().layoutViewportRect().width() : frameView().layoutViewportRect().height();
220
221 return clientLogicalWidth();
222}
223
224LayoutUnit RenderView::clientLogicalHeightForFixedPosition() const
225{
226 // FIXME: If the FrameView's fixedVisibleContentRect() is not empty, perhaps it should be consulted here too?
227 if (frameView().fixedElementsLayoutRelativeToFrame())
228 return LayoutUnit((isHorizontalWritingMode() ? frameView().visibleHeight() : frameView().visibleWidth()) / frameView().frame().frameScaleFactor());
229
230#if PLATFORM(IOS_FAMILY)
231 if (frameView().useCustomFixedPositionLayoutRect())
232 return isHorizontalWritingMode() ? frameView().customFixedPositionLayoutRect().height() : frameView().customFixedPositionLayoutRect().width();
233#endif
234
235 if (settings().visualViewportEnabled())
236 return isHorizontalWritingMode() ? frameView().layoutViewportRect().height() : frameView().layoutViewportRect().width();
237
238 return clientLogicalHeight();
239}
240
241void RenderView::mapLocalToContainer(const RenderLayerModelObject* ancestorContainer, TransformState& transformState, OptionSet<MapCoordinatesMode> mode, bool* wasFixed) const
242{
243 // If a container was specified, and was not nullptr or the RenderView,
244 // then we should have found it by now.
245 ASSERT_ARG(ancestorContainer, !ancestorContainer || ancestorContainer == this);
246 ASSERT_UNUSED(wasFixed, !wasFixed || *wasFixed == (mode.contains(IsFixed)));
247
248 if (mode.contains(IsFixed))
249 transformState.move(toLayoutSize(frameView().scrollPositionRespectingCustomFixedPosition()));
250
251 if (!ancestorContainer && mode.contains(UseTransforms) && shouldUseTransformFromContainer(nullptr)) {
252 TransformationMatrix t;
253 getTransformFromContainer(nullptr, LayoutSize(), t);
254 transformState.applyTransform(t);
255 }
256}
257
258const RenderObject* RenderView::pushMappingToContainer(const RenderLayerModelObject* ancestorToStopAt, RenderGeometryMap& geometryMap) const
259{
260 // If a container was specified, and was not nullptr or the RenderView,
261 // then we should have found it by now.
262 ASSERT_ARG(ancestorToStopAt, !ancestorToStopAt || ancestorToStopAt == this);
263
264 LayoutPoint scrollPosition = frameView().scrollPositionRespectingCustomFixedPosition();
265
266 if (!ancestorToStopAt && shouldUseTransformFromContainer(nullptr)) {
267 TransformationMatrix t;
268 getTransformFromContainer(nullptr, LayoutSize(), t);
269 geometryMap.pushView(this, toLayoutSize(scrollPosition), &t);
270 } else
271 geometryMap.pushView(this, toLayoutSize(scrollPosition));
272
273 return nullptr;
274}
275
276void RenderView::mapAbsoluteToLocalPoint(OptionSet<MapCoordinatesMode> mode, TransformState& transformState) const
277{
278 if (mode & UseTransforms && shouldUseTransformFromContainer(nullptr)) {
279 TransformationMatrix t;
280 getTransformFromContainer(nullptr, LayoutSize(), t);
281 transformState.applyTransform(t);
282 }
283
284 if (mode & IsFixed)
285 transformState.move(toLayoutSize(frameView().scrollPositionRespectingCustomFixedPosition()));
286}
287
288bool RenderView::requiresColumns(int) const
289{
290 return frameView().pagination().mode != Pagination::Unpaginated;
291}
292
293void RenderView::computeColumnCountAndWidth()
294{
295 int columnWidth = contentLogicalWidth();
296 if (style().hasInlineColumnAxis()) {
297 if (int pageLength = frameView().pagination().pageLength)
298 columnWidth = pageLength;
299 }
300 setComputedColumnCountAndWidth(1, columnWidth);
301}
302
303void RenderView::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
304{
305 // If we ever require layout but receive a paint anyway, something has gone horribly wrong.
306 ASSERT(!needsLayout());
307 // RenderViews should never be called to paint with an offset not on device pixels.
308 ASSERT(LayoutPoint(IntPoint(paintOffset.x(), paintOffset.y())) == paintOffset);
309
310 // This avoids painting garbage between columns if there is a column gap.
311 if (frameView().pagination().mode != Pagination::Unpaginated && paintInfo.shouldPaintWithinRoot(*this))
312 paintInfo.context().fillRect(paintInfo.rect, frameView().baseBackgroundColor());
313
314 paintObject(paintInfo, paintOffset);
315}
316
317RenderElement* RenderView::rendererForRootBackground() const
318{
319 auto* firstChild = this->firstChild();
320 if (!firstChild)
321 return nullptr;
322 ASSERT(is<RenderElement>(*firstChild));
323 auto& documentRenderer = downcast<RenderElement>(*firstChild);
324
325 if (documentRenderer.hasBackground())
326 return &documentRenderer;
327
328 // We propagate the background only for HTML content.
329 if (!is<HTMLHtmlElement>(documentRenderer.element()))
330 return &documentRenderer;
331
332 if (documentRenderer.shouldApplyAnyContainment())
333 return nullptr;
334
335 if (auto* body = document().body()) {
336 if (auto* renderer = body->renderer()) {
337 if (!renderer->shouldApplyAnyContainment())
338 return renderer;
339 }
340 }
341 return &documentRenderer;
342}
343
344static inline bool rendererObscuresBackground(const RenderElement& rootElement)
345{
346 auto& style = rootElement.style();
347 if (style.visibility() != Visibility::Visible || style.opacity() != 1 || style.hasTransform())
348 return false;
349
350 if (style.hasBorderRadius())
351 return false;
352
353 if (rootElement.isComposited())
354 return false;
355
356 auto* rendererForBackground = rootElement.view().rendererForRootBackground();
357 if (!rendererForBackground)
358 return false;
359
360 if (rendererForBackground->style().backgroundClip() == FillBox::Text)
361 return false;
362
363 return true;
364}
365
366void RenderView::paintBoxDecorations(PaintInfo& paintInfo, const LayoutPoint&)
367{
368 if (!paintInfo.shouldPaintWithinRoot(*this))
369 return;
370
371 // Check to see if we are enclosed by a layer that requires complex painting rules. If so, we cannot blit
372 // when scrolling, and we need to use slow repaints. Examples of layers that require this are transparent layers,
373 // layers with reflections, or transformed layers.
374 // FIXME: This needs to be dynamic. We should be able to go back to blitting if we ever stop being inside
375 // a transform, transparency layer, etc.
376 for (HTMLFrameOwnerElement* element = document().ownerElement(); element && element->renderer(); element = element->document().ownerElement()) {
377 RenderLayer* layer = element->renderer()->enclosingLayer();
378 if (layer->cannotBlitToWindow()) {
379 frameView().setCannotBlitToWindow();
380 break;
381 }
382
383 if (auto* compositingLayer = layer->enclosingCompositingLayerForRepaint().layer) {
384 if (!compositingLayer->backing()->paintsIntoWindow()) {
385 frameView().setCannotBlitToWindow();
386 break;
387 }
388 }
389 }
390
391 if (document().ownerElement())
392 return;
393
394 if (paintInfo.skipRootBackground())
395 return;
396
397 bool rootFillsViewport = false;
398 bool rootObscuresBackground = false;
399 Element* documentElement = document().documentElement();
400 if (RenderElement* rootRenderer = documentElement ? documentElement->renderer() : nullptr) {
401 // The document element's renderer is currently forced to be a block, but may not always be.
402 auto* rootBox = dynamicDowncast<RenderBox>(*rootRenderer);
403 rootFillsViewport = rootBox && !rootBox->x() && !rootBox->y() && rootBox->width() >= width() && rootBox->height() >= height();
404 rootObscuresBackground = rendererObscuresBackground(*rootRenderer);
405 }
406
407 compositor().rootBackgroundColorOrTransparencyChanged();
408
409 Page* page = document().page();
410 float pageScaleFactor = page ? page->pageScaleFactor() : 1;
411
412 // If painting will entirely fill the view, no need to fill the background.
413 if (rootFillsViewport && rootObscuresBackground && pageScaleFactor >= 1)
414 return;
415
416 // This code typically only executes if the root element's visibility has been set to hidden,
417 // if there is a transform on the <html>, or if there is a page scale factor less than 1.
418 // Only fill with a background color (typically white) if we're the root document,
419 // since iframes/frames with no background in the child document should show the parent's background.
420 // We use the base background color unless the backgroundShouldExtendBeyondPage setting is set,
421 // in which case we use the document's background color.
422 if (frameView().isTransparent()) // FIXME: This needs to be dynamic. We should be able to go back to blitting if we ever stop being transparent.
423 frameView().setCannotBlitToWindow(); // The parent must show behind the child.
424 else {
425 const Color& documentBackgroundColor = frameView().documentBackgroundColor();
426 const Color& backgroundColor = (settings().backgroundShouldExtendBeyondPage() && documentBackgroundColor.isValid()) ? documentBackgroundColor : frameView().baseBackgroundColor();
427 if (backgroundColor.isVisible()) {
428 CompositeOperator previousOperator = paintInfo.context().compositeOperation();
429 paintInfo.context().setCompositeOperation(CompositeOperator::Copy);
430 paintInfo.context().fillRect(paintInfo.rect, backgroundColor);
431 paintInfo.context().setCompositeOperation(previousOperator);
432 } else
433 paintInfo.context().clearRect(paintInfo.rect);
434 }
435}
436
437bool RenderView::shouldRepaint(const LayoutRect& rect) const
438{
439 return !printing() && !rect.isEmpty();
440}
441
442void RenderView::repaintRootContents()
443{
444 if (layer()->isComposited()) {
445 layer()->setBackingNeedsRepaint(GraphicsLayer::DoNotClipToLayer);
446 return;
447 }
448
449 // Always use layoutOverflowRect() to fix rdar://problem/27182267.
450 // This should be cleaned up via webkit.org/b/159913 and webkit.org/b/159914.
451 auto* repaintContainer = containerForRepaint().renderer;
452 repaintUsingContainer(repaintContainer, computeRectForRepaint(layoutOverflowRect(), repaintContainer));
453}
454
455void RenderView::repaintViewRectangle(const LayoutRect& repaintRect) const
456{
457 if (!shouldRepaint(repaintRect))
458 return;
459
460 // FIXME: enclosingRect is needed as long as we integral snap ScrollView/FrameView/RenderWidget size/position.
461 IntRect enclosingRect = enclosingIntRect(repaintRect);
462 if (auto ownerElement = document().ownerElement()) {
463 RenderBox* ownerBox = ownerElement->renderBox();
464 if (!ownerBox)
465 return;
466 LayoutRect viewRect = this->viewRect();
467#if PLATFORM(IOS_FAMILY)
468 // Don't clip using the visible rect since clipping is handled at a higher level on iPhone.
469 LayoutRect adjustedRect = enclosingRect;
470#else
471 LayoutRect adjustedRect = intersection(enclosingRect, viewRect);
472#endif
473 adjustedRect.moveBy(-viewRect.location());
474 adjustedRect.moveBy(ownerBox->contentBoxRect().location());
475
476 // A dirty rect in an iframe is relative to the contents of that iframe.
477 // When we traverse between parent frames and child frames, we need to make sure
478 // that the coordinate system is mapped appropriately between the iframe's contents
479 // and the Renderer that contains the iframe. This transformation must account for a
480 // left scrollbar (if one exists).
481 FrameView& frameView = this->frameView();
482 if (frameView.shouldPlaceVerticalScrollbarOnLeft() && frameView.verticalScrollbar())
483 adjustedRect.move(LayoutSize(frameView.verticalScrollbar()->occupiedWidth(), 0));
484
485 ownerBox->repaintRectangle(adjustedRect);
486 return;
487 }
488
489 frameView().addTrackedRepaintRect(snapRectToDevicePixels(repaintRect, document().deviceScaleFactor()));
490 if (!m_accumulatedRepaintRegion) {
491 frameView().repaintContentRectangle(enclosingRect);
492 return;
493 }
494 m_accumulatedRepaintRegion->unite(enclosingRect);
495
496 // Region will get slow if it gets too complex. Merge all rects so far to bounds if this happens.
497 // FIXME: Maybe there should be a region type that does this automatically.
498 static const unsigned maximumRepaintRegionGridSize = 16 * 16;
499 if (m_accumulatedRepaintRegion->gridSize() > maximumRepaintRegionGridSize)
500 m_accumulatedRepaintRegion = makeUnique<Region>(m_accumulatedRepaintRegion->bounds());
501}
502
503void RenderView::flushAccumulatedRepaintRegion() const
504{
505 ASSERT(!document().ownerElement());
506 ASSERT(m_accumulatedRepaintRegion);
507 auto repaintRects = m_accumulatedRepaintRegion->rects();
508 for (auto& rect : repaintRects)
509 frameView().repaintContentRectangle(rect);
510 m_accumulatedRepaintRegion = nullptr;
511}
512
513void RenderView::repaintViewAndCompositedLayers()
514{
515 repaintRootContents();
516
517 RenderLayerCompositor& compositor = this->compositor();
518 if (compositor.usesCompositing())
519 compositor.repaintCompositedLayers();
520}
521
522std::optional<LayoutRect> RenderView::computeVisibleRectInContainer(const LayoutRect& rect, const RenderLayerModelObject* container, VisibleRectContext context) const
523{
524 // If a container was specified, and was not nullptr or the RenderView,
525 // then we should have found it by now.
526 ASSERT_ARG(container, !container || container == this);
527
528 if (printing())
529 return rect;
530
531 LayoutRect adjustedRect = rect;
532 if (style().isFlippedBlocksWritingMode()) {
533 // We have to flip by hand since the view's logical height has not been determined. We
534 // can use the viewport width and height.
535 if (style().isHorizontalWritingMode())
536 adjustedRect.setY(viewHeight() - adjustedRect.maxY());
537 else
538 adjustedRect.setX(viewWidth() - adjustedRect.maxX());
539 }
540
541 if (context.hasPositionFixedDescendant)
542 adjustedRect.moveBy(frameView().scrollPositionRespectingCustomFixedPosition());
543
544 // Apply our transform if we have one (because of full page zooming).
545 if (!container && layer() && layer()->transform())
546 adjustedRect = LayoutRect(layer()->transform()->mapRect(snapRectToDevicePixels(adjustedRect, document().deviceScaleFactor())));
547 return adjustedRect;
548}
549
550bool RenderView::isScrollableOrRubberbandableBox() const
551{
552 // The main frame might be allowed to rubber-band even if there is no content to scroll to. This is unique to
553 // the main frame; subframes and overflow areas have to have content that can be scrolled to in order to rubber-band.
554 FrameView::Scrollability defineScrollable = frame().ownerElement() ? FrameView::Scrollability::Scrollable : FrameView::Scrollability::ScrollableOrRubberbandable;
555 return frameView().isScrollable(defineScrollable);
556}
557
558void RenderView::absoluteRects(Vector<IntRect>& rects, const LayoutPoint& accumulatedOffset) const
559{
560 rects.append(snappedIntRect(accumulatedOffset, layer()->size()));
561}
562
563void RenderView::absoluteQuads(Vector<FloatQuad>& quads, bool* wasFixed) const
564{
565 if (wasFixed)
566 *wasFixed = false;
567 quads.append(FloatRect(FloatPoint(), layer()->size()));
568}
569
570bool RenderView::printing() const
571{
572 return document().printing();
573}
574
575bool RenderView::shouldUsePrintingLayout() const
576{
577 if (!printing())
578 return false;
579 return frameView().frame().shouldUsePrintingLayout();
580}
581
582LayoutRect RenderView::viewRect() const
583{
584 if (shouldUsePrintingLayout())
585 return LayoutRect(LayoutPoint(), size());
586 return frameView().visibleContentRect(ScrollableArea::LegacyIOSDocumentVisibleRect);
587}
588
589IntRect RenderView::unscaledDocumentRect() const
590{
591 LayoutRect overflowRect(layoutOverflowRect());
592 flipForWritingMode(overflowRect);
593 return snappedIntRect(overflowRect);
594}
595
596bool RenderView::rootBackgroundIsEntirelyFixed() const
597{
598 if (auto* rootBackgroundRenderer = rendererForRootBackground())
599 return rootBackgroundRenderer->style().hasEntirelyFixedBackground();
600 return false;
601}
602
603bool RenderView::shouldPaintBaseBackground() const
604{
605 auto& document = this->document();
606 auto& frameView = this->frameView();
607 auto* ownerElement = document.ownerElement();
608
609 // Fill with a base color if we're the root document.
610 if (!ownerElement)
611 return !frameView.isTransparent();
612
613 if (ownerElement->hasTagName(HTMLNames::frameTag))
614 return true;
615
616 // Locate the <body> element using the DOM. This is easier than trying
617 // to crawl around a render tree with potential :before/:after content and
618 // anonymous blocks created by inline <body> tags etc. We can locate the <body>
619 // render object very easily via the DOM.
620 auto* body = document.bodyOrFrameset();
621
622 // SVG documents and XML documents with SVG root nodes are transparent.
623 if (!body)
624 return !document.hasSVGRootNode();
625
626 // Can't scroll a frameset document anyway.
627 if (is<HTMLFrameSetElement>(*body))
628 return true;
629
630 auto* frameRenderer = ownerElement->renderer();
631 if (!frameRenderer)
632 return false;
633
634 // iframes should fill with a base color if the used color scheme of the
635 // element and the used color scheme of the embedded document’s root
636 // element do not match.
637 if (frameView.useDarkAppearance() != frameRenderer->useDarkAppearance())
638 return !frameView.isTransparent();
639
640 return false;
641}
642
643LayoutRect RenderView::unextendedBackgroundRect() const
644{
645 // FIXME: What is this? Need to patch for new columns?
646 return unscaledDocumentRect();
647}
648
649LayoutRect RenderView::backgroundRect() const
650{
651 // FIXME: New columns care about this?
652 if (frameView().hasExtendedBackgroundRectForPainting())
653 return frameView().extendedBackgroundRectForPainting();
654
655 return unextendedBackgroundRect();
656}
657
658IntRect RenderView::documentRect() const
659{
660 FloatRect overflowRect(unscaledDocumentRect());
661 if (hasTransform())
662 overflowRect = layer()->currentTransform().mapRect(overflowRect);
663 return IntRect(overflowRect);
664}
665
666int RenderView::viewHeight() const
667{
668 int height = 0;
669 if (!shouldUsePrintingLayout()) {
670 height = frameView().layoutHeight();
671 height = frameView().useFixedLayout() ? ceilf(style().effectiveZoom() * float(height)) : height;
672 }
673 return height;
674}
675
676int RenderView::viewWidth() const
677{
678 int width = 0;
679 if (!shouldUsePrintingLayout()) {
680 width = frameView().layoutWidth();
681 width = frameView().useFixedLayout() ? ceilf(style().effectiveZoom() * float(width)) : width;
682 }
683 return width;
684}
685
686int RenderView::viewLogicalHeight() const
687{
688 int height = style().isHorizontalWritingMode() ? viewHeight() : viewWidth();
689 return height;
690}
691
692void RenderView::setPageLogicalSize(LayoutSize size)
693{
694 if (!m_pageLogicalSize || m_pageLogicalSize->height() != size.height())
695 m_pageLogicalHeightChanged = true;
696
697 m_pageLogicalSize = size;
698}
699
700float RenderView::zoomFactor() const
701{
702 return frameView().frame().pageZoomFactor();
703}
704
705FloatSize RenderView::sizeForCSSSmallViewportUnits() const
706{
707 return frameView().sizeForCSSSmallViewportUnits();
708}
709
710FloatSize RenderView::sizeForCSSLargeViewportUnits() const
711{
712 return frameView().sizeForCSSLargeViewportUnits();
713}
714
715FloatSize RenderView::sizeForCSSDynamicViewportUnits() const
716{
717 return frameView().sizeForCSSDynamicViewportUnits();
718}
719
720FloatSize RenderView::sizeForCSSDefaultViewportUnits() const
721{
722 return frameView().sizeForCSSDefaultViewportUnits();
723}
724
725Node* RenderView::nodeForHitTest() const
726{
727 return document().documentElement();
728}
729
730void RenderView::updateHitTestResult(HitTestResult& result, const LayoutPoint& point)
731{
732 if (result.innerNode())
733 return;
734
735 if (multiColumnFlow() && multiColumnFlow()->firstMultiColumnSet())
736 return multiColumnFlow()->firstMultiColumnSet()->updateHitTestResult(result, point);
737
738 if (auto* node = nodeForHitTest()) {
739 result.setInnerNode(node);
740 if (!result.innerNonSharedNode())
741 result.setInnerNonSharedNode(node);
742
743 LayoutPoint adjustedPoint = point;
744 offsetForContents(adjustedPoint);
745
746 result.setLocalPoint(adjustedPoint);
747 }
748}
749
750// FIXME: This function is obsolete and only used by embedded WebViews inside AppKit NSViews.
751// Do not add callers of this function!
752// The idea here is to take into account what object is moving the pagination point, and
753// thus choose the best place to chop it.
754void RenderView::setBestTruncatedAt(int y, RenderBoxModelObject* forRenderer, bool forcedBreak)
755{
756 // Nobody else can set a page break once we have a forced break.
757 if (m_legacyPrinting.m_forcedPageBreak)
758 return;
759
760 // Forced breaks always win over unforced breaks.
761 if (forcedBreak) {
762 m_legacyPrinting.m_forcedPageBreak = true;
763 m_legacyPrinting.m_bestTruncatedAt = y;
764 return;
765 }
766
767 // Prefer the widest object that tries to move the pagination point
768 LayoutRect boundingBox = forRenderer->borderBoundingBox();
769 if (boundingBox.width() > m_legacyPrinting.m_truncatorWidth) {
770 m_legacyPrinting.m_truncatorWidth = boundingBox.width();
771 m_legacyPrinting.m_bestTruncatedAt = y;
772 }
773}
774
775bool RenderView::usesCompositing() const
776{
777 return m_compositor && m_compositor->usesCompositing();
778}
779
780RenderLayerCompositor& RenderView::compositor()
781{
782 if (!m_compositor)
783 m_compositor = makeUnique<RenderLayerCompositor>(*this);
784
785 return *m_compositor;
786}
787
788void RenderView::setIsInWindow(bool isInWindow)
789{
790 if (m_compositor)
791 m_compositor->setIsInWindow(isInWindow);
792}
793
794ImageQualityController& RenderView::imageQualityController()
795{
796 if (!m_imageQualityController)
797 m_imageQualityController = makeUnique<ImageQualityController>(*this);
798 return *m_imageQualityController;
799}
800
801void RenderView::registerForVisibleInViewportCallback(RenderElement& renderer)
802{
803 ASSERT(!m_visibleInViewportRenderers.contains(&renderer));
804 m_visibleInViewportRenderers.add(&renderer);
805}
806
807void RenderView::unregisterForVisibleInViewportCallback(RenderElement& renderer)
808{
809 ASSERT(m_visibleInViewportRenderers.contains(&renderer));
810 m_visibleInViewportRenderers.remove(&renderer);
811}
812
813void RenderView::updateVisibleViewportRect(const IntRect& visibleRect)
814{
815 resumePausedImageAnimationsIfNeeded(visibleRect);
816
817 for (auto* renderer : m_visibleInViewportRenderers) {
818 auto state = visibleRect.intersects(enclosingIntRect(renderer->absoluteClippedOverflowRectForRepaint())) ? VisibleInViewportState::Yes : VisibleInViewportState::No;
819 renderer->setVisibleInViewportState(state);
820 }
821}
822
823void RenderView::addRendererWithPausedImageAnimations(RenderElement& renderer, CachedImage& image)
824{
825 ASSERT(!renderer.hasPausedImageAnimations() || m_renderersWithPausedImageAnimation.contains(&renderer));
826
827 renderer.setHasPausedImageAnimations(true);
828 auto& images = m_renderersWithPausedImageAnimation.ensure(&renderer, [] {
829 return Vector<CachedImage*>();
830 }).iterator->value;
831 if (!images.contains(&image))
832 images.append(&image);
833}
834
835void RenderView::removeRendererWithPausedImageAnimations(RenderElement& renderer)
836{
837 ASSERT(renderer.hasPausedImageAnimations());
838 ASSERT(m_renderersWithPausedImageAnimation.contains(&renderer));
839
840 renderer.setHasPausedImageAnimations(false);
841 m_renderersWithPausedImageAnimation.remove(&renderer);
842}
843
844void RenderView::removeRendererWithPausedImageAnimations(RenderElement& renderer, CachedImage& image)
845{
846 ASSERT(renderer.hasPausedImageAnimations());
847
848 auto it = m_renderersWithPausedImageAnimation.find(&renderer);
849 ASSERT(it != m_renderersWithPausedImageAnimation.end());
850
851 auto& images = it->value;
852 if (!images.contains(&image))
853 return;
854
855 if (images.size() == 1)
856 removeRendererWithPausedImageAnimations(renderer);
857 else
858 images.removeFirst(&image);
859}
860
861void RenderView::resumePausedImageAnimationsIfNeeded(const IntRect& visibleRect)
862{
863 Vector<std::pair<RenderElement*, CachedImage*>, 10> toRemove;
864 for (auto& it : m_renderersWithPausedImageAnimation) {
865 auto* renderer = it.key;
866 for (auto* image : it.value) {
867 if (renderer->repaintForPausedImageAnimationsIfNeeded(visibleRect, *image))
868 toRemove.append(std::make_pair(renderer, image));
869 }
870 }
871 for (auto& pair : toRemove)
872 removeRendererWithPausedImageAnimations(*pair.first, *pair.second);
873}
874
875RenderView::RepaintRegionAccumulator::RepaintRegionAccumulator(RenderView* view)
876{
877 if (!view)
878 return;
879
880 auto* rootRenderView = view->document().topDocument().renderView();
881 if (!rootRenderView)
882 return;
883
884 m_wasAccumulatingRepaintRegion = !!rootRenderView->m_accumulatedRepaintRegion;
885 if (!m_wasAccumulatingRepaintRegion)
886 rootRenderView->m_accumulatedRepaintRegion = makeUnique<Region>();
887 m_rootView = *rootRenderView;
888}
889
890RenderView::RepaintRegionAccumulator::~RepaintRegionAccumulator()
891{
892 if (m_wasAccumulatingRepaintRegion)
893 return;
894 if (!m_rootView)
895 return;
896 m_rootView.get()->flushAccumulatedRepaintRegion();
897}
898
899unsigned RenderView::pageNumberForBlockProgressionOffset(int offset) const
900{
901 int columnNumber = 0;
902 const Pagination& pagination = page().pagination();
903 if (pagination.mode == Pagination::Unpaginated)
904 return columnNumber;
905
906 bool progressionIsInline = false;
907 bool progressionIsReversed = false;
908
909 if (multiColumnFlow()) {
910 progressionIsInline = multiColumnFlow()->progressionIsInline();
911 progressionIsReversed = multiColumnFlow()->progressionIsReversed();
912 } else
913 return columnNumber;
914
915 if (!progressionIsInline) {
916 if (!progressionIsReversed)
917 columnNumber = (pagination.pageLength + pagination.gap - offset) / (pagination.pageLength + pagination.gap);
918 else
919 columnNumber = offset / (pagination.pageLength + pagination.gap);
920 }
921
922 return columnNumber;
923}
924
925unsigned RenderView::pageCount() const
926{
927 const Pagination& pagination = page().pagination();
928 if (pagination.mode == Pagination::Unpaginated)
929 return 0;
930
931 if (multiColumnFlow() && multiColumnFlow()->firstMultiColumnSet())
932 return multiColumnFlow()->firstMultiColumnSet()->columnCount();
933
934 return 0;
935}
936
937void RenderView::layerChildrenChangedDuringStyleChange(RenderLayer& layer)
938{
939 if (!m_styleChangeLayerMutationRoot) {
940 m_styleChangeLayerMutationRoot = layer;
941 return;
942 }
943
944 RenderLayer* commonAncestor = m_styleChangeLayerMutationRoot->commonAncestorWithLayer(layer);
945 m_styleChangeLayerMutationRoot = commonAncestor;
946}
947
948RenderLayer* RenderView::takeStyleChangeLayerTreeMutationRoot()
949{
950 auto* result = m_styleChangeLayerMutationRoot.get();
951 m_styleChangeLayerMutationRoot.clear();
952 return result;
953}
954
955void RenderView::registerBoxWithScrollSnapPositions(const RenderBox& box)
956{
957 m_boxesWithScrollSnapPositions.add(&box);
958}
959
960void RenderView::unregisterBoxWithScrollSnapPositions(const RenderBox& box)
961{
962 m_boxesWithScrollSnapPositions.remove(&box);
963}
964
965void RenderView::registerContainerQueryBox(const RenderBox& box)
966{
967 m_containerQueryBoxes.add(box);
968}
969
970void RenderView::unregisterContainerQueryBox(const RenderBox& box)
971{
972 m_containerQueryBoxes.remove(box);
973}
974
975} // namespace WebCore
Note: See TracBrowser for help on using the repository browser.