1/* 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) 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 "FloatingObjects.h" 28#include "FlowThreadController.h" 29#include "Frame.h" 30#include "FrameSelection.h" 31#include "FrameView.h" 32#include "GraphicsContext.h" 33#include "HTMLFrameOwnerElement.h" 34#include "HTMLIFrameElement.h" 35#include "HitTestResult.h" 36#include "ImageQualityController.h" 37#include "NodeTraversal.h" 38#include "Page.h" 39#include "RenderGeometryMap.h" 40#include "RenderIterator.h" 41#include "RenderLayer.h" 42#include "RenderLayerBacking.h" 43#include "RenderLayerCompositor.h" 44#include "RenderMultiColumnFlowThread.h" 45#include "RenderMultiColumnSet.h" 46#include "RenderMultiColumnSpannerPlaceholder.h" 47#include "RenderNamedFlowThread.h" 48#include "RenderSelectionInfo.h" 49#include "RenderWidget.h" 50#include "Settings.h" 51#include "StyleInheritedData.h" 52#include "TransformState.h" 53#include <wtf/StackStats.h> 54 55namespace WebCore { 56 57struct SelectionIterator { 58 RenderObject* m_current; 59 Vector<RenderMultiColumnSpannerPlaceholder*> m_spannerStack; 60 61 SelectionIterator(RenderObject* o) 62 { 63 m_current = o; 64 checkForSpanner(); 65 } 66 67 void checkForSpanner() 68 { 69 if (!m_current || !m_current->isRenderMultiColumnSpannerPlaceholder()) 70 return; 71 RenderMultiColumnSpannerPlaceholder* placeholder = toRenderMultiColumnSpannerPlaceholder(m_current); 72 m_spannerStack.append(placeholder); 73 m_current = placeholder->spanner(); 74 } 75 76 RenderObject* current() 77 { 78 return m_current; 79 } 80 81 RenderObject* next() 82 { 83 RenderObject* currentSpan = m_spannerStack.isEmpty() ? 0 : m_spannerStack.last()->spanner(); 84 m_current = m_current->nextInPreOrder(currentSpan); 85 checkForSpanner(); 86 if (!m_current && currentSpan) { 87 RenderObject* placeholder = m_spannerStack.last(); 88 m_spannerStack.removeLast(); 89 m_current = placeholder->nextInPreOrder(); 90 checkForSpanner(); 91 } 92 return m_current; 93 } 94}; 95 96RenderView::RenderView(Document& document, PassRef<RenderStyle> style) 97 : RenderBlockFlow(document, WTF::move(style)) 98 , m_frameView(*document.view()) 99 , m_selectionStart(0) 100 , m_selectionEnd(0) 101 , m_selectionStartPos(-1) 102 , m_selectionEndPos(-1) 103 , m_rendererCount(0) 104 , m_maximalOutlineSize(0) 105 , m_lazyRepaintTimer(this, &RenderView::lazyRepaintTimerFired) 106 , m_pageLogicalHeight(0) 107 , m_pageLogicalHeightChanged(false) 108 , m_layoutState(nullptr) 109 , m_layoutStateDisableCount(0) 110 , m_renderQuoteHead(0) 111 , m_renderCounterCount(0) 112 , m_selectionWasCaret(false) 113#if ENABLE(CSS_FILTERS) 114 , m_hasSoftwareFilters(false) 115#endif 116#if ENABLE(SERVICE_CONTROLS) 117 , m_selectionRectGatherer(*this) 118#endif 119{ 120 setIsRenderView(); 121 122 // FIXME: We should find a way to enforce this at compile time. 123 ASSERT(document.view()); 124 125 // init RenderObject attributes 126 setInline(false); 127 128 m_minPreferredLogicalWidth = 0; 129 m_maxPreferredLogicalWidth = 0; 130 131 setPreferredLogicalWidthsDirty(true, MarkOnlyThis); 132 133 setPositionState(AbsolutePosition); // to 0,0 :) 134} 135 136RenderView::~RenderView() 137{ 138} 139 140void RenderView::scheduleLazyRepaint(RenderBox& renderer) 141{ 142 if (renderer.renderBoxNeedsLazyRepaint()) 143 return; 144 renderer.setRenderBoxNeedsLazyRepaint(true); 145 m_renderersNeedingLazyRepaint.add(&renderer); 146 if (!m_lazyRepaintTimer.isActive()) 147 m_lazyRepaintTimer.startOneShot(0); 148} 149 150void RenderView::unscheduleLazyRepaint(RenderBox& renderer) 151{ 152 if (!renderer.renderBoxNeedsLazyRepaint()) 153 return; 154 renderer.setRenderBoxNeedsLazyRepaint(false); 155 m_renderersNeedingLazyRepaint.remove(&renderer); 156 if (m_renderersNeedingLazyRepaint.isEmpty()) 157 m_lazyRepaintTimer.stop(); 158} 159 160void RenderView::lazyRepaintTimerFired(Timer<RenderView>&) 161{ 162 bool shouldRepaint = !document().inPageCache(); 163 164 for (auto& renderer : m_renderersNeedingLazyRepaint) { 165 if (shouldRepaint) 166 renderer->repaint(); 167 renderer->setRenderBoxNeedsLazyRepaint(false); 168 } 169 m_renderersNeedingLazyRepaint.clear(); 170} 171 172bool RenderView::hitTest(const HitTestRequest& request, HitTestResult& result) 173{ 174 return hitTest(request, result.hitTestLocation(), result); 175} 176 177bool RenderView::hitTest(const HitTestRequest& request, const HitTestLocation& location, HitTestResult& result) 178{ 179 if (layer()->hitTest(request, location, result)) 180 return true; 181 182 // FIXME: Consider if this test should be done unconditionally. 183 if (request.allowsFrameScrollbars()) { 184 // ScrollView scrollbars are not the same as RenderLayer scrollbars tested by RenderLayer::hitTestOverflowControls, 185 // so we need to test ScrollView scrollbars separately here. 186 Scrollbar* frameScrollbar = frameView().scrollbarAtPoint(location.roundedPoint()); 187 if (frameScrollbar) { 188 result.setScrollbar(frameScrollbar); 189 return true; 190 } 191 } 192 193 return false; 194} 195 196void RenderView::computeLogicalHeight(LayoutUnit logicalHeight, LayoutUnit, LogicalExtentComputedValues& computedValues) const 197{ 198 computedValues.m_extent = !shouldUsePrintingLayout() ? LayoutUnit(viewLogicalHeight()) : logicalHeight; 199} 200 201void RenderView::updateLogicalWidth() 202{ 203 if (!shouldUsePrintingLayout()) 204 setLogicalWidth(viewLogicalWidth()); 205} 206 207LayoutUnit RenderView::availableLogicalHeight(AvailableLogicalHeightType) const 208{ 209 // Make sure block progression pagination for percentages uses the column extent and 210 // not the view's extent. See https://bugs.webkit.org/show_bug.cgi?id=135204. 211 if (multiColumnFlowThread() && multiColumnFlowThread()->firstMultiColumnSet()) 212 return multiColumnFlowThread()->firstMultiColumnSet()->computedColumnHeight(); 213 214#if PLATFORM(IOS) 215 // Workaround for <rdar://problem/7166808>. 216 if (document().isPluginDocument() && frameView().useFixedLayout()) 217 return frameView().fixedLayoutSize().height(); 218#endif 219 return isHorizontalWritingMode() ? frameView().visibleHeight() : frameView().visibleWidth(); 220} 221 222bool RenderView::isChildAllowed(const RenderObject& child, const RenderStyle&) const 223{ 224 return child.isBox(); 225} 226 227void RenderView::layoutContent(const LayoutState& state) 228{ 229 UNUSED_PARAM(state); 230 ASSERT(needsLayout()); 231 232 RenderBlockFlow::layout(); 233 if (hasRenderNamedFlowThreads()) 234 flowThreadController().layoutRenderNamedFlowThreads(); 235#ifndef NDEBUG 236 checkLayoutState(state); 237#endif 238} 239 240#ifndef NDEBUG 241void RenderView::checkLayoutState(const LayoutState& state) 242{ 243 ASSERT(layoutDeltaMatches(LayoutSize())); 244 ASSERT(!m_layoutStateDisableCount); 245 ASSERT(m_layoutState.get() == &state); 246} 247#endif 248 249void RenderView::initializeLayoutState(LayoutState& state) 250{ 251 // FIXME: May be better to push a clip and avoid issuing offscreen repaints. 252 state.m_clipped = false; 253 254 state.m_pageLogicalHeight = m_pageLogicalHeight; 255 state.m_pageLogicalHeightChanged = m_pageLogicalHeightChanged; 256 state.m_isPaginated = state.m_pageLogicalHeight; 257} 258 259// The algorithm below assumes this is a full layout. In case there are previously computed values for regions, supplemental steps are taken 260// to ensure the results are the same as those obtained from a full layout (i.e. the auto-height regions from all the flows are marked as needing 261// layout). 262// 1. The flows are laid out from the outer flow to the inner flow. This successfully computes the outer non-auto-height regions size so the 263// inner flows have the necessary information to correctly fragment the content. 264// 2. The flows are laid out from the inner flow to the outer flow. After an inner flow is laid out it goes into the constrained layout phase 265// and marks the auto-height regions they need layout. This means the outer flows will relayout if they depend on regions with auto-height regions 266// belonging to inner flows. This step will correctly set the computedAutoHeight for the auto-height regions. It's possible for non-auto-height 267// regions to relayout if they depend on auto-height regions. This will invalidate the inner flow threads and mark them as needing layout. 268// 3. The last step is to do one last layout if there are pathological dependencies between non-auto-height regions and auto-height regions 269// as detected in the previous step. 270void RenderView::layoutContentInAutoLogicalHeightRegions(const LayoutState& state) 271{ 272 // We need to invalidate all the flows with auto-height regions if one such flow needs layout. 273 // If none is found we do a layout a check back again afterwards. 274 if (!flowThreadController().updateFlowThreadsNeedingLayout()) { 275 // Do a first layout of the content. In some cases more layouts are not needed (e.g. only flows with non-auto-height regions have changed). 276 layoutContent(state); 277 278 // If we find no named flow needing a two step layout after the first layout, exit early. 279 // Otherwise, initiate the two step layout algorithm and recompute all the flows. 280 if (!flowThreadController().updateFlowThreadsNeedingTwoStepLayout()) 281 return; 282 } 283 284 // Layout to recompute all the named flows with auto-height regions. 285 layoutContent(state); 286 287 // Propagate the computed auto-height values upwards. 288 // Non-auto-height regions may invalidate the flow thread because they depended on auto-height regions, but that's ok. 289 flowThreadController().updateFlowThreadsIntoConstrainedPhase(); 290 291 // Do one last layout that should update the auto-height regions found in the main flow 292 // and solve pathological dependencies between regions (e.g. a non-auto-height region depending 293 // on an auto-height one). 294 if (needsLayout()) 295 layoutContent(state); 296} 297 298void RenderView::layoutContentToComputeOverflowInRegions(const LayoutState& state) 299{ 300 if (!hasRenderNamedFlowThreads()) 301 return; 302 303 // First pass through the flow threads and mark the regions as needing a simple layout. 304 // The regions extract the overflow from the flow thread and pass it to their containg 305 // block chain. 306 flowThreadController().updateFlowThreadsIntoOverflowPhase(); 307 if (needsLayout()) 308 layoutContent(state); 309 310 // In case scrollbars resized the regions a new pass is necessary to update the flow threads 311 // and recompute the overflow on regions. This is the final state of the flow threads. 312 flowThreadController().updateFlowThreadsIntoFinalPhase(); 313 if (needsLayout()) 314 layoutContent(state); 315 316 // Finally reset the layout state of the flow threads. 317 flowThreadController().updateFlowThreadsIntoMeasureContentPhase(); 318} 319 320void RenderView::layout() 321{ 322 StackStats::LayoutCheckPoint layoutCheckPoint; 323 if (!document().paginated()) 324 setPageLogicalHeight(0); 325 326 if (shouldUsePrintingLayout()) 327 m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = logicalWidth(); 328 329 // Use calcWidth/Height to get the new width/height, since this will take the full page zoom factor into account. 330 bool relayoutChildren = !shouldUsePrintingLayout() && (width() != viewWidth() || height() != viewHeight()); 331 if (relayoutChildren) { 332 setChildNeedsLayout(MarkOnlyThis); 333 334 for (auto& box : childrenOfType<RenderBox>(*this)) { 335 if (box.hasRelativeLogicalHeight() 336 || box.style().logicalHeight().isPercent() 337 || box.style().logicalMinHeight().isPercent() 338 || box.style().logicalMaxHeight().isPercent() 339 || box.isSVGRoot() 340 ) 341 box.setChildNeedsLayout(MarkOnlyThis); 342 } 343 } 344 345 ASSERT(!m_layoutState); 346 if (!needsLayout()) 347 return; 348 349 m_layoutState = std::make_unique<LayoutState>(); 350 initializeLayoutState(*m_layoutState); 351 352 m_pageLogicalHeightChanged = false; 353 354 if (checkTwoPassLayoutForAutoHeightRegions()) 355 layoutContentInAutoLogicalHeightRegions(*m_layoutState); 356 else 357 layoutContent(*m_layoutState); 358 359 layoutContentToComputeOverflowInRegions(*m_layoutState); 360 361#ifndef NDEBUG 362 checkLayoutState(*m_layoutState); 363#endif 364 m_layoutState = nullptr; 365 clearNeedsLayout(); 366} 367 368LayoutUnit RenderView::pageOrViewLogicalHeight() const 369{ 370 if (document().printing()) 371 return pageLogicalHeight(); 372 373 if (multiColumnFlowThread() && !style().hasInlineColumnAxis()) { 374 if (int pageLength = frameView().pagination().pageLength) 375 return pageLength; 376 } 377 378 return viewLogicalHeight(); 379} 380 381LayoutUnit RenderView::clientLogicalWidthForFixedPosition() const 382{ 383 // FIXME: If the FrameView's fixedVisibleContentRect() is not empty, perhaps it should be consulted here too? 384 if (frameView().fixedElementsLayoutRelativeToFrame()) 385 return (isHorizontalWritingMode() ? frameView().visibleWidth() : frameView().visibleHeight()) / frameView().frame().frameScaleFactor(); 386 387#if PLATFORM(IOS) 388 if (frameView().useCustomFixedPositionLayoutRect()) 389 return isHorizontalWritingMode() ? frameView().customFixedPositionLayoutRect().width() : frameView().customFixedPositionLayoutRect().height(); 390#endif 391 392 return clientLogicalWidth(); 393} 394 395LayoutUnit RenderView::clientLogicalHeightForFixedPosition() const 396{ 397 // FIXME: If the FrameView's fixedVisibleContentRect() is not empty, perhaps it should be consulted here too? 398 if (frameView().fixedElementsLayoutRelativeToFrame()) 399 return (isHorizontalWritingMode() ? frameView().visibleHeight() : frameView().visibleWidth()) / frameView().frame().frameScaleFactor(); 400 401#if PLATFORM(IOS) 402 if (frameView().useCustomFixedPositionLayoutRect()) 403 return isHorizontalWritingMode() ? frameView().customFixedPositionLayoutRect().height() : frameView().customFixedPositionLayoutRect().width(); 404#endif 405 406 return clientLogicalHeight(); 407} 408 409#if PLATFORM(IOS) 410static inline LayoutSize fixedPositionOffset(const FrameView& frameView) 411{ 412 return frameView.useCustomFixedPositionLayoutRect() ? (frameView.customFixedPositionLayoutRect().location() - LayoutPoint()) : frameView.scrollOffset(); 413} 414#endif 415 416void RenderView::mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState& transformState, MapCoordinatesFlags mode, bool* wasFixed) const 417{ 418 // If a container was specified, and was not 0 or the RenderView, 419 // then we should have found it by now. 420 ASSERT_ARG(repaintContainer, !repaintContainer || repaintContainer == this); 421 ASSERT_UNUSED(wasFixed, !wasFixed || *wasFixed == (mode & IsFixed)); 422 423 if (!repaintContainer && mode & UseTransforms && shouldUseTransformFromContainer(0)) { 424 TransformationMatrix t; 425 getTransformFromContainer(0, LayoutSize(), t); 426 transformState.applyTransform(t); 427 } 428 429 if (mode & IsFixed) 430#if PLATFORM(IOS) 431 transformState.move(fixedPositionOffset(m_frameView)); 432#else 433 transformState.move(frameView().scrollOffsetForFixedPosition()); 434#endif 435} 436 437const RenderObject* RenderView::pushMappingToContainer(const RenderLayerModelObject* ancestorToStopAt, RenderGeometryMap& geometryMap) const 438{ 439 // If a container was specified, and was not 0 or the RenderView, 440 // then we should have found it by now. 441 ASSERT_ARG(ancestorToStopAt, !ancestorToStopAt || ancestorToStopAt == this); 442 443#if PLATFORM(IOS) 444 LayoutSize scrollOffset = fixedPositionOffset(frameView()); 445#else 446 LayoutSize scrollOffset = frameView().scrollOffsetForFixedPosition(); 447#endif 448 449 if (!ancestorToStopAt && shouldUseTransformFromContainer(0)) { 450 TransformationMatrix t; 451 getTransformFromContainer(0, LayoutSize(), t); 452 geometryMap.pushView(this, scrollOffset, &t); 453 } else 454 geometryMap.pushView(this, scrollOffset); 455 456 return 0; 457} 458 459void RenderView::mapAbsoluteToLocalPoint(MapCoordinatesFlags mode, TransformState& transformState) const 460{ 461 if (mode & IsFixed) 462#if PLATFORM(IOS) 463 transformState.move(fixedPositionOffset(frameView())); 464#else 465 transformState.move(frameView().scrollOffsetForFixedPosition()); 466#endif 467 468 if (mode & UseTransforms && shouldUseTransformFromContainer(0)) { 469 TransformationMatrix t; 470 getTransformFromContainer(0, LayoutSize(), t); 471 transformState.applyTransform(t); 472 } 473} 474 475bool RenderView::requiresColumns(int) const 476{ 477 return frameView().pagination().mode != Pagination::Unpaginated; 478} 479 480void RenderView::computeColumnCountAndWidth() 481{ 482 int columnWidth = contentLogicalWidth(); 483 if (style().hasInlineColumnAxis()) { 484 if (int pageLength = frameView().pagination().pageLength) 485 columnWidth = pageLength; 486 } 487 setComputedColumnCountAndWidth(1, columnWidth); 488} 489 490void RenderView::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset) 491{ 492 // If we ever require layout but receive a paint anyway, something has gone horribly wrong. 493 ASSERT(!needsLayout()); 494 // RenderViews should never be called to paint with an offset not on device pixels. 495 ASSERT(LayoutPoint(IntPoint(paintOffset.x(), paintOffset.y())) == paintOffset); 496 497 // This avoids painting garbage between columns if there is a column gap. 498 if (frameView().pagination().mode != Pagination::Unpaginated && paintInfo.shouldPaintWithinRoot(*this)) 499 paintInfo.context->fillRect(paintInfo.rect, frameView().baseBackgroundColor(), ColorSpaceDeviceRGB); 500 501 paintObject(paintInfo, paintOffset); 502} 503 504static inline bool isComposited(RenderElement* object) 505{ 506 return object->hasLayer() && toRenderLayerModelObject(object)->layer()->isComposited(); 507} 508 509static inline bool rendererObscuresBackground(RenderElement* rootObject) 510{ 511 if (!rootObject) 512 return false; 513 514 const RenderStyle& style = rootObject->style(); 515 if (style.visibility() != VISIBLE 516 || style.opacity() != 1 517 || style.hasTransform()) 518 return false; 519 520 if (isComposited(rootObject)) 521 return false; 522 523 if (rootObject->rendererForRootBackground().style().backgroundClip() == TextFillBox) 524 return false; 525 526 return true; 527} 528 529void RenderView::paintBoxDecorations(PaintInfo& paintInfo, const LayoutPoint&) 530{ 531 if (!paintInfo.shouldPaintWithinRoot(*this)) 532 return; 533 534 // Check to see if we are enclosed by a layer that requires complex painting rules. If so, we cannot blit 535 // when scrolling, and we need to use slow repaints. Examples of layers that require this are transparent layers, 536 // layers with reflections, or transformed layers. 537 // FIXME: This needs to be dynamic. We should be able to go back to blitting if we ever stop being inside 538 // a transform, transparency layer, etc. 539 Element* elt; 540 for (elt = document().ownerElement(); elt && elt->renderer(); elt = elt->document().ownerElement()) { 541 RenderLayer* layer = elt->renderer()->enclosingLayer(); 542 if (layer->cannotBlitToWindow()) { 543 frameView().setCannotBlitToWindow(); 544 break; 545 } 546 547 if (RenderLayer* compositingLayer = layer->enclosingCompositingLayerForRepaint()) { 548 if (!compositingLayer->backing()->paintsIntoWindow()) { 549 frameView().setCannotBlitToWindow(); 550 break; 551 } 552 } 553 } 554 555 if (document().ownerElement()) 556 return; 557 558 if (paintInfo.skipRootBackground()) 559 return; 560 561 bool rootFillsViewport = false; 562 bool rootObscuresBackground = false; 563 Element* documentElement = document().documentElement(); 564 if (RenderElement* rootRenderer = documentElement ? documentElement->renderer() : 0) { 565 // The document element's renderer is currently forced to be a block, but may not always be. 566 RenderBox* rootBox = rootRenderer->isBox() ? toRenderBox(rootRenderer) : 0; 567 rootFillsViewport = rootBox && !rootBox->x() && !rootBox->y() && rootBox->width() >= width() && rootBox->height() >= height(); 568 rootObscuresBackground = rendererObscuresBackground(rootRenderer); 569 } 570 571 compositor().setRootExtendedBackgroundColor(frameView().frame().settings().backgroundShouldExtendBeyondPage() 572 ? frameView().documentBackgroundColor() : Color()); 573 574 Page* page = document().page(); 575 float pageScaleFactor = page ? page->pageScaleFactor() : 1; 576 577 // If painting will entirely fill the view, no need to fill the background. 578 if (rootFillsViewport && rootObscuresBackground && pageScaleFactor >= 1) 579 return; 580 581 // This code typically only executes if the root element's visibility has been set to hidden, 582 // if there is a transform on the <html>, or if there is a page scale factor less than 1. 583 // Only fill with the base background color (typically white) if we're the root document, 584 // since iframes/frames with no background in the child document should show the parent's background. 585 if (frameView().isTransparent()) // FIXME: This needs to be dynamic. We should be able to go back to blitting if we ever stop being transparent. 586 frameView().setCannotBlitToWindow(); // The parent must show behind the child. 587 else { 588 Color backgroundColor = frameView().baseBackgroundColor(); 589 if (backgroundColor.alpha()) { 590 CompositeOperator previousOperator = paintInfo.context->compositeOperation(); 591 paintInfo.context->setCompositeOperation(CompositeCopy); 592 paintInfo.context->fillRect(paintInfo.rect, backgroundColor, style().colorSpace()); 593 paintInfo.context->setCompositeOperation(previousOperator); 594 } else 595 paintInfo.context->clearRect(paintInfo.rect); 596 } 597} 598 599bool RenderView::shouldRepaint(const LayoutRect& rect) const 600{ 601 return !printing() && !rect.isEmpty(); 602} 603 604void RenderView::repaintRootContents() 605{ 606 if (layer()->isComposited()) { 607 layer()->setBackingNeedsRepaint(GraphicsLayer::DoNotClipToLayer); 608 return; 609 } 610 repaint(); 611} 612 613void RenderView::repaintViewRectangle(const LayoutRect& repaintRect) const 614{ 615 if (!shouldRepaint(repaintRect)) 616 return; 617 618 if (auto ownerElement = document().ownerElement()) { 619 RenderBox* ownerBox = ownerElement->renderBox(); 620 if (!ownerBox) 621 return; 622 LayoutRect viewRect = this->viewRect(); 623#if PLATFORM(IOS) 624 // Don't clip using the visible rect since clipping is handled at a higher level on iPhone. 625 LayoutRect adjustedRect = repaintRect; 626#else 627 LayoutRect adjustedRect = intersection(repaintRect, viewRect); 628#endif 629 adjustedRect.moveBy(-viewRect.location()); 630 adjustedRect.moveBy(ownerBox->contentBoxRect().location()); 631 ownerBox->repaintRectangle(adjustedRect); 632 return; 633 } 634 635 frameView().addTrackedRepaintRect(pixelSnappedForPainting(repaintRect, document().deviceScaleFactor())); 636 637 // FIXME: convert all repaint rect dependencies to FloatRect. 638 IntRect enclosingRect = enclosingIntRect(repaintRect); 639 if (!m_accumulatedRepaintRegion) { 640 frameView().repaintContentRectangle(enclosingRect); 641 return; 642 } 643 m_accumulatedRepaintRegion->unite(enclosingRect); 644 645 // Region will get slow if it gets too complex. Merge all rects so far to bounds if this happens. 646 // FIXME: Maybe there should be a region type that does this automatically. 647 static const unsigned maximumRepaintRegionGridSize = 16 * 16; 648 if (m_accumulatedRepaintRegion->gridSize() > maximumRepaintRegionGridSize) 649 m_accumulatedRepaintRegion = std::make_unique<Region>(m_accumulatedRepaintRegion->bounds()); 650} 651 652void RenderView::flushAccumulatedRepaintRegion() const 653{ 654 ASSERT(!document().ownerElement()); 655 ASSERT(m_accumulatedRepaintRegion); 656 auto repaintRects = m_accumulatedRepaintRegion->rects(); 657 for (auto& rect : repaintRects) 658 frameView().repaintContentRectangle(rect); 659 m_accumulatedRepaintRegion = nullptr; 660} 661 662void RenderView::repaintViewAndCompositedLayers() 663{ 664 repaintRootContents(); 665 666 RenderLayerCompositor& compositor = this->compositor(); 667 if (compositor.inCompositingMode()) 668 compositor.repaintCompositedLayers(); 669} 670 671LayoutRect RenderView::visualOverflowRect() const 672{ 673 if (frameView().paintsEntireContents()) 674 return layoutOverflowRect(); 675 676 return RenderBlockFlow::visualOverflowRect(); 677} 678 679void RenderView::computeRectForRepaint(const RenderLayerModelObject* repaintContainer, LayoutRect& rect, bool fixed) const 680{ 681 // If a container was specified, and was not 0 or the RenderView, 682 // then we should have found it by now. 683 ASSERT_ARG(repaintContainer, !repaintContainer || repaintContainer == this); 684 685 if (printing()) 686 return; 687 688 if (style().isFlippedBlocksWritingMode()) { 689 // We have to flip by hand since the view's logical height has not been determined. We 690 // can use the viewport width and height. 691 if (style().isHorizontalWritingMode()) 692 rect.setY(viewHeight() - rect.maxY()); 693 else 694 rect.setX(viewWidth() - rect.maxX()); 695 } 696 697 if (fixed) { 698#if PLATFORM(IOS) 699 rect.move(fixedPositionOffset(frameView())); 700#else 701 rect.move(frameView().scrollOffsetForFixedPosition()); 702#endif 703 } 704 705 // Apply our transform if we have one (because of full page zooming). 706 if (!repaintContainer && layer() && layer()->transform()) 707 rect = LayoutRect(layer()->transform()->mapRect(pixelSnappedForPainting(rect, document().deviceScaleFactor()))); 708} 709 710void RenderView::absoluteRects(Vector<IntRect>& rects, const LayoutPoint& accumulatedOffset) const 711{ 712 rects.append(pixelSnappedIntRect(accumulatedOffset, layer()->size())); 713} 714 715void RenderView::absoluteQuads(Vector<FloatQuad>& quads, bool* wasFixed) const 716{ 717 if (wasFixed) 718 *wasFixed = false; 719 quads.append(FloatRect(FloatPoint(), layer()->size())); 720} 721 722static RenderObject* rendererAfterPosition(RenderObject* object, unsigned offset) 723{ 724 if (!object) 725 return 0; 726 727 RenderObject* child = object->childAt(offset); 728 return child ? child : object->nextInPreOrderAfterChildren(); 729} 730 731IntRect RenderView::selectionBounds(bool clipToVisibleContent) const 732{ 733 LayoutRect selRect = subtreeSelectionBounds(*this, clipToVisibleContent); 734 735 if (hasRenderNamedFlowThreads()) { 736 for (auto* namedFlowThread : *m_flowThreadController->renderNamedFlowThreadList()) { 737 LayoutRect currRect = subtreeSelectionBounds(*namedFlowThread, clipToVisibleContent); 738 selRect.unite(currRect); 739 } 740 } 741 742 return pixelSnappedIntRect(selRect); 743} 744 745LayoutRect RenderView::subtreeSelectionBounds(const SelectionSubtreeRoot& root, bool clipToVisibleContent) const 746{ 747 typedef HashMap<RenderObject*, std::unique_ptr<RenderSelectionInfo>> SelectionMap; 748 SelectionMap selectedObjects; 749 750 RenderObject* os = root.selectionStart(); 751 RenderObject* stop = rendererAfterPosition(root.selectionEnd(), root.selectionEndPos()); 752 SelectionIterator selectionIterator(os); 753 while (os && os != stop) { 754 if ((os->canBeSelectionLeaf() || os == root.selectionStart() || os == root.selectionEnd()) && os->selectionState() != SelectionNone) { 755 // Blocks are responsible for painting line gaps and margin gaps. They must be examined as well. 756 selectedObjects.set(os, std::make_unique<RenderSelectionInfo>(os, clipToVisibleContent)); 757 RenderBlock* cb = os->containingBlock(); 758 while (cb && !cb->isRenderView()) { 759 std::unique_ptr<RenderSelectionInfo>& blockInfo = selectedObjects.add(cb, nullptr).iterator->value; 760 if (blockInfo) 761 break; 762 blockInfo = std::make_unique<RenderSelectionInfo>(cb, clipToVisibleContent); 763 cb = cb->containingBlock(); 764 } 765 } 766 767 os = selectionIterator.next(); 768 } 769 770 // Now create a single bounding box rect that encloses the whole selection. 771 LayoutRect selRect; 772 SelectionMap::iterator end = selectedObjects.end(); 773 for (SelectionMap::iterator i = selectedObjects.begin(); i != end; ++i) { 774 RenderSelectionInfo* info = i->value.get(); 775 // RenderSelectionInfo::rect() is in the coordinates of the repaintContainer, so map to page coordinates. 776 LayoutRect currRect = info->rect(); 777 if (RenderLayerModelObject* repaintContainer = info->repaintContainer()) { 778 FloatQuad absQuad = repaintContainer->localToAbsoluteQuad(FloatRect(currRect)); 779 currRect = absQuad.enclosingBoundingBox(); 780 } 781 selRect.unite(currRect); 782 } 783 return selRect; 784} 785 786void RenderView::repaintSelection() const 787{ 788 repaintSubtreeSelection(*this); 789 790 if (hasRenderNamedFlowThreads()) { 791 for (auto* namedFlowThread : *m_flowThreadController->renderNamedFlowThreadList()) 792 repaintSubtreeSelection(*namedFlowThread); 793 } 794} 795 796void RenderView::repaintSubtreeSelection(const SelectionSubtreeRoot& root) const 797{ 798 HashSet<RenderBlock*> processedBlocks; 799 800 RenderObject* end = rendererAfterPosition(root.selectionEnd(), root.selectionEndPos()); 801 SelectionIterator selectionIterator(root.selectionStart()); 802 for (RenderObject* o = selectionIterator.current(); o && o != end; o = selectionIterator.next()) { 803 if (!o->canBeSelectionLeaf() && o != root.selectionStart() && o != root.selectionEnd()) 804 continue; 805 if (o->selectionState() == SelectionNone) 806 continue; 807 808 RenderSelectionInfo(o, true).repaint(); 809 810 // Blocks are responsible for painting line gaps and margin gaps. They must be examined as well. 811 for (RenderBlock* block = o->containingBlock(); block && !block->isRenderView(); block = block->containingBlock()) { 812 if (!processedBlocks.add(block).isNewEntry) 813 break; 814 RenderSelectionInfo(block, true).repaint(); 815 } 816 } 817} 818 819// Compositing layer dimensions take outline size into account, so we have to recompute layer 820// bounds when it changes. 821// FIXME: This is ugly; it would be nice to have a better way to do this. 822void RenderView::setMaximalOutlineSize(int o) 823{ 824 if (o != m_maximalOutlineSize) { 825 m_maximalOutlineSize = o; 826 827 // maximalOutlineSize affects compositing layer dimensions. 828 compositor().setCompositingLayersNeedRebuild(); // FIXME: this really just needs to be a geometry update. 829 } 830} 831 832void RenderView::setSelection(RenderObject* start, int startPos, RenderObject* end, int endPos, SelectionRepaintMode blockRepaintMode) 833{ 834 // Make sure both our start and end objects are defined. 835 // Check www.msnbc.com and try clicking around to find the case where this happened. 836 if ((start && !end) || (end && !start)) 837 return; 838 839 bool caretChanged = m_selectionWasCaret != frame().selection().isCaret(); 840 m_selectionWasCaret = frame().selection().isCaret(); 841 // Just return if the selection hasn't changed. 842 if (m_selectionStart == start && m_selectionStartPos == startPos && 843 m_selectionEnd == end && m_selectionEndPos == endPos && !caretChanged) 844 return; 845 846#if ENABLE(SERVICE_CONTROLS) 847 // Clear the current rects and create a notifier for the new rects we are about to gather. 848 // The Notifier updates the Editor when it goes out of scope and is destroyed. 849 std::unique_ptr<SelectionRectGatherer::Notifier> rectNotifier = m_selectionRectGatherer.clearAndCreateNotifier(); 850#endif // ENABLE(SERVICE_CONTROLS) 851 // Set global positions for new selection. 852 m_selectionStart = start; 853 m_selectionStartPos = startPos; 854 m_selectionEnd = end; 855 m_selectionEndPos = endPos; 856 857 // If there is no RenderNamedFlowThreads we follow the regular selection. 858 if (!hasRenderNamedFlowThreads()) { 859 setSubtreeSelection(*this, start, startPos, end, endPos, blockRepaintMode); 860 return; 861 } 862 863 splitSelectionBetweenSubtrees(start, startPos, end, endPos, blockRepaintMode); 864} 865 866void RenderView::splitSelectionBetweenSubtrees(RenderObject* start, int startPos, RenderObject* end, int endPos, SelectionRepaintMode blockRepaintMode) 867{ 868 // Compute the visible selection end points for each of the subtrees. 869 typedef HashMap<SelectionSubtreeRoot*, SelectionSubtreeRoot> RenderSubtreesMap; 870 RenderSubtreesMap renderSubtreesMap; 871 872 SelectionSubtreeRoot initialSelection; 873 renderSubtreesMap.set(this, initialSelection); 874 for (auto* namedFlowThread : *flowThreadController().renderNamedFlowThreadList()) 875 renderSubtreesMap.set(namedFlowThread, initialSelection); 876 877 if (start && end) { 878 Node* startNode = start->node(); 879 Node* endNode = end->node(); 880 Node* stopNode = NodeTraversal::nextSkippingChildren(endNode); 881 882 for (Node* node = startNode; node != stopNode; node = NodeTraversal::next(node)) { 883 RenderObject* renderer = node->renderer(); 884 if (!renderer) 885 continue; 886 887 SelectionSubtreeRoot& root = renderer->selectionRoot(); 888 SelectionSubtreeRoot selectionData = renderSubtreesMap.get(&root); 889 if (selectionData.selectionClear()) { 890 selectionData.setSelectionStart(node->renderer()); 891 selectionData.setSelectionStartPos(node == startNode ? startPos : 0); 892 } 893 894 selectionData.setSelectionEnd(node->renderer()); 895 if (node == endNode) 896 selectionData.setSelectionEndPos(endPos); 897 else 898 selectionData.setSelectionEndPos(node->offsetInCharacters() ? node->maxCharacterOffset() : node->childNodeCount()); 899 900 renderSubtreesMap.set(&root, selectionData); 901 } 902 } 903 904 for (RenderSubtreesMap::iterator i = renderSubtreesMap.begin(); i != renderSubtreesMap.end(); ++i) { 905 SelectionSubtreeRoot subtreeSelectionData = i->value; 906 subtreeSelectionData.adjustForVisibleSelection(document()); 907 setSubtreeSelection(*i->key, subtreeSelectionData.selectionStart(), subtreeSelectionData.selectionStartPos(), 908 subtreeSelectionData.selectionEnd(), subtreeSelectionData.selectionEndPos(), blockRepaintMode); 909 } 910} 911 912void RenderView::setSubtreeSelection(SelectionSubtreeRoot& root, RenderObject* start, int startPos, RenderObject* end, int endPos, SelectionRepaintMode blockRepaintMode) 913{ 914 // Record the old selected objects. These will be used later 915 // when we compare against the new selected objects. 916 int oldStartPos = root.selectionStartPos(); 917 int oldEndPos = root.selectionEndPos(); 918 919 // Objects each have a single selection rect to examine. 920 typedef HashMap<RenderObject*, std::unique_ptr<RenderSelectionInfo>> SelectedObjectMap; 921 SelectedObjectMap oldSelectedObjects; 922 SelectedObjectMap newSelectedObjects; 923 924 // Blocks contain selected objects and fill gaps between them, either on the left, right, or in between lines and blocks. 925 // In order to get the repaint rect right, we have to examine left, middle, and right rects individually, since otherwise 926 // the union of those rects might remain the same even when changes have occurred. 927 typedef HashMap<RenderBlock*, std::unique_ptr<RenderBlockSelectionInfo>> SelectedBlockMap; 928 SelectedBlockMap oldSelectedBlocks; 929 SelectedBlockMap newSelectedBlocks; 930 931 RenderObject* os = root.selectionStart(); 932 RenderObject* stop = rendererAfterPosition(root.selectionEnd(), root.selectionEndPos()); 933 SelectionIterator selectionIterator(os); 934 while (os && os != stop) { 935 if ((os->canBeSelectionLeaf() || os == root.selectionStart() || os == root.selectionEnd()) 936 && os->selectionState() != SelectionNone) { 937 // Blocks are responsible for painting line gaps and margin gaps. They must be examined as well. 938 oldSelectedObjects.set(os, std::make_unique<RenderSelectionInfo>(os, true)); 939 if (blockRepaintMode == RepaintNewXOROld) { 940 RenderBlock* cb = os->containingBlock(); 941 while (cb && !cb->isRenderView()) { 942 std::unique_ptr<RenderBlockSelectionInfo>& blockInfo = oldSelectedBlocks.add(cb, nullptr).iterator->value; 943 if (blockInfo) 944 break; 945 blockInfo = std::make_unique<RenderBlockSelectionInfo>(cb); 946 cb = cb->containingBlock(); 947 } 948 } 949 } 950 951 os = selectionIterator.next(); 952 } 953 954 // Now clear the selection. 955 SelectedObjectMap::iterator oldObjectsEnd = oldSelectedObjects.end(); 956 for (SelectedObjectMap::iterator i = oldSelectedObjects.begin(); i != oldObjectsEnd; ++i) 957 i->key->setSelectionStateIfNeeded(SelectionNone); 958 959 // set selection start and end 960 root.setSelectionStart(start); 961 root.setSelectionStartPos(startPos); 962 root.setSelectionEnd(end); 963 root.setSelectionEndPos(endPos); 964 965 // Update the selection status of all objects between selectionStart and selectionEnd 966 if (start && start == end) 967 start->setSelectionStateIfNeeded(SelectionBoth); 968 else { 969 if (start) 970 start->setSelectionStateIfNeeded(SelectionStart); 971 if (end) 972 end->setSelectionStateIfNeeded(SelectionEnd); 973 } 974 975 RenderObject* o = start; 976 stop = rendererAfterPosition(end, endPos); 977 selectionIterator = SelectionIterator(o); 978 979 while (o && o != stop) { 980 if (o != start && o != end && o->canBeSelectionLeaf()) 981 o->setSelectionStateIfNeeded(SelectionInside); 982 o = selectionIterator.next(); 983 } 984 985 if (blockRepaintMode != RepaintNothing) 986 layer()->clearBlockSelectionGapsBounds(); 987 988 // Now that the selection state has been updated for the new objects, walk them again and 989 // put them in the new objects list. 990 o = start; 991 selectionIterator = SelectionIterator(o); 992 while (o && o != stop) { 993 if ((o->canBeSelectionLeaf() || o == start || o == end) && o->selectionState() != SelectionNone) { 994 std::unique_ptr<RenderSelectionInfo> selectionInfo = std::make_unique<RenderSelectionInfo>(o, true); 995 996#if ENABLE(SERVICE_CONTROLS) 997 for (auto& rect : selectionInfo->rects()) 998 m_selectionRectGatherer.addRect(selectionInfo->repaintContainer(), rect); 999 if (!o->isTextOrLineBreak()) 1000 m_selectionRectGatherer.setTextOnly(false); 1001#endif 1002 1003 newSelectedObjects.set(o, WTF::move(selectionInfo)); 1004 1005 RenderBlock* cb = o->containingBlock(); 1006 while (cb && !cb->isRenderView()) { 1007 std::unique_ptr<RenderBlockSelectionInfo>& blockInfo = newSelectedBlocks.add(cb, nullptr).iterator->value; 1008 if (blockInfo) 1009 break; 1010 blockInfo = std::make_unique<RenderBlockSelectionInfo>(cb); 1011 cb = cb->containingBlock(); 1012 1013#if ENABLE(SERVICE_CONTROLS) 1014 m_selectionRectGatherer.addGapRects(blockInfo->repaintContainer(), blockInfo->rects()); 1015#endif 1016 } 1017 } 1018 1019 o = selectionIterator.next(); 1020 } 1021 1022 if (blockRepaintMode == RepaintNothing) 1023 return; 1024 1025 // Have any of the old selected objects changed compared to the new selection? 1026 for (SelectedObjectMap::iterator i = oldSelectedObjects.begin(); i != oldObjectsEnd; ++i) { 1027 RenderObject* obj = i->key; 1028 RenderSelectionInfo* newInfo = newSelectedObjects.get(obj); 1029 RenderSelectionInfo* oldInfo = i->value.get(); 1030 if (!newInfo || oldInfo->rect() != newInfo->rect() || oldInfo->state() != newInfo->state() 1031 || (root.selectionStart() == obj && oldStartPos != root.selectionStartPos()) 1032 || (root.selectionEnd() == obj && oldEndPos != root.selectionEndPos())) { 1033 oldInfo->repaint(); 1034 if (newInfo) { 1035 newInfo->repaint(); 1036 newSelectedObjects.remove(obj); 1037 } 1038 } 1039 } 1040 1041 // Any new objects that remain were not found in the old objects dict, and so they need to be updated. 1042 SelectedObjectMap::iterator newObjectsEnd = newSelectedObjects.end(); 1043 for (SelectedObjectMap::iterator i = newSelectedObjects.begin(); i != newObjectsEnd; ++i) 1044 i->value->repaint(); 1045 1046 // Have any of the old blocks changed? 1047 SelectedBlockMap::iterator oldBlocksEnd = oldSelectedBlocks.end(); 1048 for (SelectedBlockMap::iterator i = oldSelectedBlocks.begin(); i != oldBlocksEnd; ++i) { 1049 RenderBlock* block = i->key; 1050 RenderBlockSelectionInfo* newInfo = newSelectedBlocks.get(block); 1051 RenderBlockSelectionInfo* oldInfo = i->value.get(); 1052 if (!newInfo || oldInfo->rects() != newInfo->rects() || oldInfo->state() != newInfo->state()) { 1053 oldInfo->repaint(); 1054 if (newInfo) { 1055 newInfo->repaint(); 1056 newSelectedBlocks.remove(block); 1057 } 1058 } 1059 } 1060 1061 // Any new blocks that remain were not found in the old blocks dict, and so they need to be updated. 1062 SelectedBlockMap::iterator newBlocksEnd = newSelectedBlocks.end(); 1063 for (SelectedBlockMap::iterator i = newSelectedBlocks.begin(); i != newBlocksEnd; ++i) 1064 i->value->repaint(); 1065} 1066 1067void RenderView::getSelection(RenderObject*& startRenderer, int& startOffset, RenderObject*& endRenderer, int& endOffset) const 1068{ 1069 startRenderer = m_selectionStart; 1070 startOffset = m_selectionStartPos; 1071 endRenderer = m_selectionEnd; 1072 endOffset = m_selectionEndPos; 1073} 1074 1075void RenderView::clearSelection() 1076{ 1077 layer()->repaintBlockSelectionGaps(); 1078 setSelection(0, -1, 0, -1, RepaintNewMinusOld); 1079} 1080 1081bool RenderView::printing() const 1082{ 1083 return document().printing(); 1084} 1085 1086bool RenderView::shouldUsePrintingLayout() const 1087{ 1088 if (!printing()) 1089 return false; 1090 return frameView().frame().shouldUsePrintingLayout(); 1091} 1092 1093LayoutRect RenderView::viewRect() const 1094{ 1095 if (shouldUsePrintingLayout()) 1096 return LayoutRect(LayoutPoint(), size()); 1097 return frameView().visibleContentRect(ScrollableArea::LegacyIOSDocumentVisibleRect); 1098} 1099 1100IntRect RenderView::unscaledDocumentRect() const 1101{ 1102 LayoutRect overflowRect(layoutOverflowRect()); 1103 flipForWritingMode(overflowRect); 1104 return pixelSnappedIntRect(overflowRect); 1105} 1106 1107bool RenderView::rootBackgroundIsEntirelyFixed() const 1108{ 1109 RenderElement* rootObject = document().documentElement() ? document().documentElement()->renderer() : 0; 1110 if (!rootObject) 1111 return false; 1112 1113 return rootObject->rendererForRootBackground().hasEntirelyFixedBackground(); 1114} 1115 1116LayoutRect RenderView::unextendedBackgroundRect(RenderBox*) const 1117{ 1118 // FIXME: What is this? Need to patch for new columns? 1119 return unscaledDocumentRect(); 1120} 1121 1122LayoutRect RenderView::backgroundRect(RenderBox* backgroundRenderer) const 1123{ 1124 // FIXME: New columns care about this? 1125 if (frameView().hasExtendedBackgroundRectForPainting()) 1126 return frameView().extendedBackgroundRectForPainting(); 1127 1128 return unextendedBackgroundRect(backgroundRenderer); 1129} 1130 1131IntRect RenderView::documentRect() const 1132{ 1133 FloatRect overflowRect(unscaledDocumentRect()); 1134 if (hasTransform()) 1135 overflowRect = layer()->currentTransform().mapRect(overflowRect); 1136 return IntRect(overflowRect); 1137} 1138 1139int RenderView::viewHeight() const 1140{ 1141 int height = 0; 1142 if (!shouldUsePrintingLayout()) { 1143 height = frameView().layoutHeight(); 1144 height = frameView().useFixedLayout() ? ceilf(style().effectiveZoom() * float(height)) : height; 1145 } 1146 return height; 1147} 1148 1149int RenderView::viewWidth() const 1150{ 1151 int width = 0; 1152 if (!shouldUsePrintingLayout()) { 1153 width = frameView().layoutWidth(); 1154 width = frameView().useFixedLayout() ? ceilf(style().effectiveZoom() * float(width)) : width; 1155 } 1156 return width; 1157} 1158 1159int RenderView::viewLogicalHeight() const 1160{ 1161 int height = style().isHorizontalWritingMode() ? viewHeight() : viewWidth(); 1162 return height; 1163} 1164 1165float RenderView::zoomFactor() const 1166{ 1167 return frameView().frame().pageZoomFactor(); 1168} 1169 1170void RenderView::pushLayoutState(RenderObject& root) 1171{ 1172 ASSERT(m_layoutStateDisableCount == 0); 1173 ASSERT(m_layoutState == 0); 1174 1175 m_layoutState = std::make_unique<LayoutState>(root); 1176 pushLayoutStateForCurrentFlowThread(root); 1177} 1178 1179bool RenderView::shouldDisableLayoutStateForSubtree(RenderObject* renderer) const 1180{ 1181 RenderObject* o = renderer; 1182 while (o) { 1183 if (o->hasTransform() || o->hasReflection()) 1184 return true; 1185 o = o->container(); 1186 } 1187 return false; 1188} 1189 1190IntSize RenderView::viewportSizeForCSSViewportUnits() const 1191{ 1192 return frameView().viewportSizeForCSSViewportUnits(); 1193} 1194 1195void RenderView::updateHitTestResult(HitTestResult& result, const LayoutPoint& point) 1196{ 1197 if (result.innerNode()) 1198 return; 1199 1200 Node* node = document().documentElement(); 1201 if (node) { 1202 result.setInnerNode(node); 1203 if (!result.innerNonSharedNode()) 1204 result.setInnerNonSharedNode(node); 1205 1206 LayoutPoint adjustedPoint = point; 1207 offsetForContents(adjustedPoint); 1208 1209 result.setLocalPoint(adjustedPoint); 1210 } 1211} 1212 1213// FIXME: This function is obsolete and only used by embedded WebViews inside AppKit NSViews. 1214// Do not add callers of this function! 1215// The idea here is to take into account what object is moving the pagination point, and 1216// thus choose the best place to chop it. 1217void RenderView::setBestTruncatedAt(int y, RenderBoxModelObject* forRenderer, bool forcedBreak) 1218{ 1219 // Nobody else can set a page break once we have a forced break. 1220 if (m_legacyPrinting.m_forcedPageBreak) 1221 return; 1222 1223 // Forced breaks always win over unforced breaks. 1224 if (forcedBreak) { 1225 m_legacyPrinting.m_forcedPageBreak = true; 1226 m_legacyPrinting.m_bestTruncatedAt = y; 1227 return; 1228 } 1229 1230 // Prefer the widest object that tries to move the pagination point 1231 IntRect boundingBox = forRenderer->borderBoundingBox(); 1232 if (boundingBox.width() > m_legacyPrinting.m_truncatorWidth) { 1233 m_legacyPrinting.m_truncatorWidth = boundingBox.width(); 1234 m_legacyPrinting.m_bestTruncatedAt = y; 1235 } 1236} 1237 1238bool RenderView::usesCompositing() const 1239{ 1240 return m_compositor && m_compositor->inCompositingMode(); 1241} 1242 1243RenderLayerCompositor& RenderView::compositor() 1244{ 1245 if (!m_compositor) 1246 m_compositor = std::make_unique<RenderLayerCompositor>(*this); 1247 1248 return *m_compositor; 1249} 1250 1251void RenderView::setIsInWindow(bool isInWindow) 1252{ 1253 if (m_compositor) 1254 m_compositor->setIsInWindow(isInWindow); 1255} 1256 1257void RenderView::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) 1258{ 1259 RenderBlockFlow::styleDidChange(diff, oldStyle); 1260 if (hasRenderNamedFlowThreads()) 1261 flowThreadController().styleDidChange(); 1262 1263 frameView().styleDidChange(); 1264} 1265 1266bool RenderView::hasRenderNamedFlowThreads() const 1267{ 1268 return m_flowThreadController && m_flowThreadController->hasRenderNamedFlowThreads(); 1269} 1270 1271bool RenderView::checkTwoPassLayoutForAutoHeightRegions() const 1272{ 1273 return hasRenderNamedFlowThreads() && m_flowThreadController->hasFlowThreadsWithAutoLogicalHeightRegions(); 1274} 1275 1276FlowThreadController& RenderView::flowThreadController() 1277{ 1278 if (!m_flowThreadController) 1279 m_flowThreadController = std::make_unique<FlowThreadController>(this); 1280 1281 return *m_flowThreadController; 1282} 1283 1284void RenderView::pushLayoutStateForCurrentFlowThread(const RenderObject& object) 1285{ 1286 if (!m_flowThreadController) 1287 return; 1288 1289 RenderFlowThread* currentFlowThread = m_flowThreadController->currentRenderFlowThread(); 1290 if (!currentFlowThread) 1291 return; 1292 1293 currentFlowThread->pushFlowThreadLayoutState(object); 1294} 1295 1296void RenderView::popLayoutStateForCurrentFlowThread() 1297{ 1298 if (!m_flowThreadController) 1299 return; 1300 1301 RenderFlowThread* currentFlowThread = m_flowThreadController->currentRenderFlowThread(); 1302 if (!currentFlowThread) 1303 return; 1304 1305 currentFlowThread->popFlowThreadLayoutState(); 1306} 1307 1308IntervalArena* RenderView::intervalArena() 1309{ 1310 if (!m_intervalArena) 1311 m_intervalArena = IntervalArena::create(); 1312 return m_intervalArena.get(); 1313} 1314 1315ImageQualityController& RenderView::imageQualityController() 1316{ 1317 if (!m_imageQualityController) 1318 m_imageQualityController = std::make_unique<ImageQualityController>(*this); 1319 return *m_imageQualityController; 1320} 1321 1322void RenderView::addRendererWithPausedImageAnimations(RenderElement& renderer) 1323{ 1324 if (renderer.hasPausedImageAnimations()) { 1325 ASSERT(m_renderersWithPausedImageAnimation.contains(&renderer)); 1326 return; 1327 } 1328 renderer.setHasPausedImageAnimations(true); 1329 m_renderersWithPausedImageAnimation.add(&renderer); 1330} 1331 1332void RenderView::removeRendererWithPausedImageAnimations(RenderElement& renderer) 1333{ 1334 ASSERT(renderer.hasPausedImageAnimations()); 1335 ASSERT(m_renderersWithPausedImageAnimation.contains(&renderer)); 1336 1337 renderer.setHasPausedImageAnimations(false); 1338 m_renderersWithPausedImageAnimation.remove(&renderer); 1339} 1340 1341void RenderView::resumePausedImageAnimationsIfNeeded() 1342{ 1343 auto visibleRect = frameView().windowToContents(frameView().windowClipRect()); 1344 Vector<RenderElement*, 10> toRemove; 1345 for (auto* renderer : m_renderersWithPausedImageAnimation) { 1346 if (renderer->repaintForPausedImageAnimationsIfNeeded(visibleRect)) 1347 toRemove.append(renderer); 1348 } 1349 for (auto& renderer : toRemove) 1350 removeRendererWithPausedImageAnimations(*renderer); 1351} 1352 1353RenderView::RepaintRegionAccumulator::RepaintRegionAccumulator(RenderView* view) 1354 : m_rootView(view ? view->document().topDocument().renderView() : nullptr) 1355{ 1356 if (!m_rootView) 1357 return; 1358 m_wasAccumulatingRepaintRegion = !!m_rootView->m_accumulatedRepaintRegion; 1359 if (!m_wasAccumulatingRepaintRegion) 1360 m_rootView->m_accumulatedRepaintRegion = std::make_unique<Region>(); 1361} 1362 1363RenderView::RepaintRegionAccumulator::~RepaintRegionAccumulator() 1364{ 1365 if (!m_rootView) 1366 return; 1367 if (m_wasAccumulatingRepaintRegion) 1368 return; 1369 m_rootView->flushAccumulatedRepaintRegion(); 1370} 1371 1372unsigned RenderView::pageNumberForBlockProgressionOffset(int offset) const 1373{ 1374 int columnNumber = 0; 1375 const Pagination& pagination = frameView().frame().page()->pagination(); 1376 if (pagination.mode == Pagination::Unpaginated) 1377 return columnNumber; 1378 1379 bool progressionIsInline = false; 1380 bool progressionIsReversed = false; 1381 1382 if (multiColumnFlowThread()) { 1383 progressionIsInline = multiColumnFlowThread()->progressionIsInline(); 1384 progressionIsReversed = multiColumnFlowThread()->progressionIsReversed(); 1385 } else 1386 return columnNumber; 1387 1388 if (!progressionIsInline) { 1389 if (!progressionIsReversed) 1390 columnNumber = (pagination.pageLength + pagination.gap - offset) / (pagination.pageLength + pagination.gap); 1391 else 1392 columnNumber = offset / (pagination.pageLength + pagination.gap); 1393 } 1394 1395 return columnNumber; 1396} 1397 1398unsigned RenderView::pageCount() const 1399{ 1400 const Pagination& pagination = frameView().frame().page()->pagination(); 1401 if (pagination.mode == Pagination::Unpaginated) 1402 return 0; 1403 1404 if (multiColumnFlowThread() && multiColumnFlowThread()->firstMultiColumnSet()) 1405 return multiColumnFlowThread()->firstMultiColumnSet()->columnCount(); 1406 1407 return 0; 1408} 1409 1410} // namespace WebCore 1411