1 /* 2 * Copyright (C) 1999 Lars Knoll (knoll (at) 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 "core/rendering/RenderView.h" 23 24 #include "RuntimeEnabledFeatures.h" 25 #include "core/dom/Document.h" 26 #include "core/dom/Element.h" 27 #include "core/html/HTMLDialogElement.h" 28 #include "core/html/HTMLFrameOwnerElement.h" 29 #include "core/html/HTMLIFrameElement.h" 30 #include "core/frame/Frame.h" 31 #include "core/page/Page.h" 32 #include "core/rendering/ColumnInfo.h" 33 #include "core/rendering/CompositedLayerMapping.h" 34 #include "core/rendering/FlowThreadController.h" 35 #include "core/rendering/GraphicsContextAnnotator.h" 36 #include "core/rendering/HitTestResult.h" 37 #include "core/rendering/LayoutRectRecorder.h" 38 #include "core/rendering/RenderFlowThread.h" 39 #include "core/rendering/RenderGeometryMap.h" 40 #include "core/rendering/RenderLayer.h" 41 #include "core/rendering/RenderLayerCompositor.h" 42 #include "core/rendering/RenderSelectionInfo.h" 43 #include "core/rendering/RenderWidget.h" 44 #include "core/svg/SVGDocumentExtensions.h" 45 #include "platform/geometry/FloatQuad.h" 46 #include "platform/geometry/TransformState.h" 47 #include "platform/graphics/GraphicsContext.h" 48 #include "platform/graphics/filters/custom/CustomFilterGlobalContext.h" 49 50 namespace WebCore { 51 52 RenderView::RenderView(Document* document) 53 : RenderBlockFlow(document) 54 , m_frameView(document->view()) 55 , m_selectionStart(0) 56 , m_selectionEnd(0) 57 , m_selectionStartPos(-1) 58 , m_selectionEndPos(-1) 59 , m_maximalOutlineSize(0) 60 , m_pageLogicalHeight(0) 61 , m_pageLogicalHeightChanged(false) 62 , m_layoutState(0) 63 , m_layoutStateDisableCount(0) 64 , m_renderQuoteHead(0) 65 , m_renderCounterCount(0) 66 { 67 // init RenderObject attributes 68 setInline(false); 69 70 m_minPreferredLogicalWidth = 0; 71 m_maxPreferredLogicalWidth = 0; 72 73 setPreferredLogicalWidthsDirty(MarkOnlyThis); 74 75 setPositionState(AbsolutePosition); // to 0,0 :) 76 } 77 78 RenderView::~RenderView() 79 { 80 } 81 82 bool RenderView::hitTest(const HitTestRequest& request, HitTestResult& result) 83 { 84 return hitTest(request, result.hitTestLocation(), result); 85 } 86 87 bool RenderView::hitTest(const HitTestRequest& request, const HitTestLocation& location, HitTestResult& result) 88 { 89 // We have to recursively update layout/style here because otherwise, when the hit test recurses 90 // into a child document, it could trigger a layout on the parent document, which can destroy RenderLayers 91 // that are higher up in the call stack, leading to crashes. 92 // Note that Document::updateLayout calls its parent's updateLayout. 93 // FIXME: It should be the caller's responsibility to ensure an up-to-date layout. 94 frameView()->updateLayoutAndStyleIfNeededRecursive(); 95 return layer()->hitTest(request, location, result); 96 } 97 98 void RenderView::computeLogicalHeight(LayoutUnit logicalHeight, LayoutUnit, LogicalExtentComputedValues& computedValues) const 99 { 100 computedValues.m_extent = (!shouldUsePrintingLayout() && m_frameView) ? LayoutUnit(viewLogicalHeight()) : logicalHeight; 101 } 102 103 void RenderView::updateLogicalWidth() 104 { 105 if (!shouldUsePrintingLayout() && m_frameView) 106 setLogicalWidth(viewLogicalWidth()); 107 } 108 109 LayoutUnit RenderView::availableLogicalHeight(AvailableLogicalHeightType heightType) const 110 { 111 // If we have columns, then the available logical height is reduced to the column height. 112 if (hasColumns()) 113 return columnInfo()->columnHeight(); 114 return RenderBlock::availableLogicalHeight(heightType); 115 } 116 117 bool RenderView::isChildAllowed(RenderObject* child, RenderStyle*) const 118 { 119 return child->isBox(); 120 } 121 122 static bool dialogNeedsCentering(const RenderStyle* style) 123 { 124 return style->position() == AbsolutePosition && style->hasAutoTopAndBottom(); 125 } 126 127 void RenderView::positionDialog(RenderBox* box) 128 { 129 HTMLDialogElement* dialog = toHTMLDialogElement(box->node()); 130 if (dialog->centeringMode() == HTMLDialogElement::NotCentered) 131 return; 132 if (dialog->centeringMode() == HTMLDialogElement::Centered) { 133 if (dialogNeedsCentering(box->style())) 134 box->setY(dialog->centeredPosition()); 135 return; 136 } 137 138 if (!dialogNeedsCentering(box->style())) { 139 dialog->setNotCentered(); 140 return; 141 } 142 FrameView* frameView = document().view(); 143 int scrollTop = frameView->scrollOffset().height(); 144 int visibleHeight = frameView->visibleContentRect(ScrollableArea::IncludeScrollbars).height(); 145 LayoutUnit top = scrollTop; 146 if (box->height() < visibleHeight) 147 top += (visibleHeight - box->height()) / 2; 148 box->setY(top); 149 dialog->setCentered(top); 150 } 151 152 void RenderView::positionDialogs() 153 { 154 TrackedRendererListHashSet* positionedDescendants = positionedObjects(); 155 if (!positionedDescendants) 156 return; 157 TrackedRendererListHashSet::iterator end = positionedDescendants->end(); 158 for (TrackedRendererListHashSet::iterator it = positionedDescendants->begin(); it != end; ++it) { 159 RenderBox* box = *it; 160 if (box->node() && box->node()->hasTagName(HTMLNames::dialogTag)) 161 positionDialog(box); 162 } 163 } 164 165 void RenderView::layoutContent(const LayoutState& state) 166 { 167 ASSERT(needsLayout()); 168 169 LayoutRectRecorder recorder(*this); 170 RenderBlock::layout(); 171 172 if (RuntimeEnabledFeatures::dialogElementEnabled()) 173 positionDialogs(); 174 175 if (m_frameView->partialLayout().isStopping()) 176 return; 177 178 if (hasRenderNamedFlowThreads()) 179 flowThreadController()->layoutRenderNamedFlowThreads(); 180 181 #ifndef NDEBUG 182 checkLayoutState(state); 183 #endif 184 } 185 186 #ifndef NDEBUG 187 void RenderView::checkLayoutState(const LayoutState& state) 188 { 189 ASSERT(layoutDeltaMatches(LayoutSize())); 190 ASSERT(!m_layoutStateDisableCount); 191 ASSERT(m_layoutState == &state); 192 } 193 #endif 194 195 static RenderBox* enclosingSeamlessRenderer(const Document& doc) 196 { 197 Element* ownerElement = doc.seamlessParentIFrame(); 198 if (!ownerElement) 199 return 0; 200 return ownerElement->renderBox(); 201 } 202 203 void RenderView::addChild(RenderObject* newChild, RenderObject* beforeChild) 204 { 205 // Seamless iframes are considered part of an enclosing render flow thread from the parent document. This is necessary for them to look 206 // up regions in the parent document during layout. 207 if (newChild && !newChild->isRenderFlowThread()) { 208 RenderBox* seamlessBox = enclosingSeamlessRenderer(document()); 209 if (seamlessBox && seamlessBox->flowThreadContainingBlock()) 210 newChild->setFlowThreadState(seamlessBox->flowThreadState()); 211 } 212 RenderBlock::addChild(newChild, beforeChild); 213 } 214 215 bool RenderView::initializeLayoutState(LayoutState& state) 216 { 217 bool isSeamlessAncestorInFlowThread = false; 218 219 // FIXME: May be better to push a clip and avoid issuing offscreen repaints. 220 state.m_clipped = false; 221 222 // Check the writing mode of the seamless ancestor. It has to match our document's writing mode, or we won't inherit any 223 // pagination information. 224 RenderBox* seamlessAncestor = enclosingSeamlessRenderer(document()); 225 LayoutState* seamlessLayoutState = seamlessAncestor ? seamlessAncestor->view()->layoutState() : 0; 226 bool shouldInheritPagination = seamlessLayoutState && !m_pageLogicalHeight && seamlessAncestor->style()->writingMode() == style()->writingMode(); 227 228 state.m_pageLogicalHeight = shouldInheritPagination ? seamlessLayoutState->m_pageLogicalHeight : m_pageLogicalHeight; 229 state.m_pageLogicalHeightChanged = shouldInheritPagination ? seamlessLayoutState->m_pageLogicalHeightChanged : m_pageLogicalHeightChanged; 230 state.m_isPaginated = state.m_pageLogicalHeight; 231 if (state.m_isPaginated && shouldInheritPagination) { 232 // Set up the correct pagination offset. We can use a negative offset in order to push the top of the RenderView into its correct place 233 // on a page. We can take the iframe's offset from the logical top of the first page and make the negative into the pagination offset within the child 234 // view. 235 bool isFlipped = seamlessAncestor->style()->isFlippedBlocksWritingMode(); 236 LayoutSize layoutOffset = seamlessLayoutState->layoutOffset(); 237 LayoutSize iFrameOffset(layoutOffset.width() + seamlessAncestor->x() + (!isFlipped ? seamlessAncestor->borderLeft() + seamlessAncestor->paddingLeft() : 238 seamlessAncestor->borderRight() + seamlessAncestor->paddingRight()), 239 layoutOffset.height() + seamlessAncestor->y() + (!isFlipped ? seamlessAncestor->borderTop() + seamlessAncestor->paddingTop() : 240 seamlessAncestor->borderBottom() + seamlessAncestor->paddingBottom())); 241 242 LayoutSize offsetDelta = seamlessLayoutState->m_pageOffset - iFrameOffset; 243 state.m_pageOffset = offsetDelta; 244 245 // Set the current render flow thread to point to our ancestor. This will allow the seamless document to locate the correct 246 // regions when doing a layout. 247 if (seamlessAncestor->flowThreadContainingBlock()) { 248 flowThreadController()->setCurrentRenderFlowThread(seamlessAncestor->view()->flowThreadController()->currentRenderFlowThread()); 249 isSeamlessAncestorInFlowThread = true; 250 } 251 } 252 253 // FIXME: We need to make line grids and exclusions work with seamless iframes as well here. Basically all layout state information needs 254 // to propagate here and not just pagination information. 255 return isSeamlessAncestorInFlowThread; 256 } 257 258 // The algorithm below assumes this is a full layout. In case there are previously computed values for regions, supplemental steps are taken 259 // 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 260 // layout). 261 // 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 262 // inner flows have the necessary information to correctly fragment the content. 263 // 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 264 // 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 265 // belonging to inner flows. This step will correctly set the computedAutoHeight for the auto-height regions. It's possible for non-auto-height 266 // regions to relayout if they depend on auto-height regions. This will invalidate the inner flow threads and mark them as needing layout. 267 // 3. The last step is to do one last layout if there are pathological dependencies between non-auto-height regions and auto-height regions 268 // as detected in the previous step. 269 void RenderView::layoutContentInAutoLogicalHeightRegions(const LayoutState& state) 270 { 271 if (!m_frameView->partialLayout().isStopping()) { 272 // Disable partial layout for any two-pass layout algorithm. 273 m_frameView->partialLayout().reset(); 274 } 275 276 // We need to invalidate all the flows with auto-height regions if one such flow needs layout. 277 // If none is found we do a layout a check back again afterwards. 278 if (!flowThreadController()->updateFlowThreadsNeedingLayout()) { 279 // 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). 280 layoutContent(state); 281 282 // If we find no named flow needing a two step layout after the first layout, exit early. 283 // Otherwise, initiate the two step layout algorithm and recompute all the flows. 284 if (!flowThreadController()->updateFlowThreadsNeedingTwoStepLayout()) 285 return; 286 } 287 288 // Layout to recompute all the named flows with auto-height regions. 289 layoutContent(state); 290 291 // Propagate the computed auto-height values upwards. 292 // Non-auto-height regions may invalidate the flow thread because they depended on auto-height regions, but that's ok. 293 flowThreadController()->updateFlowThreadsIntoConstrainedPhase(); 294 295 // Do one last layout that should update the auto-height regions found in the main flow 296 // and solve pathological dependencies between regions (e.g. a non-auto-height region depending 297 // on an auto-height one). 298 if (needsLayout()) 299 layoutContent(state); 300 } 301 302 void RenderView::layout() 303 { 304 if (!document().paginated()) 305 setPageLogicalHeight(0); 306 307 if (shouldUsePrintingLayout()) 308 m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = logicalWidth(); 309 310 SubtreeLayoutScope layoutScope(this); 311 312 // Use calcWidth/Height to get the new width/height, since this will take the full page zoom factor into account. 313 bool relayoutChildren = !shouldUsePrintingLayout() && (!m_frameView || width() != viewWidth() || height() != viewHeight()); 314 if (relayoutChildren) { 315 layoutScope.setChildNeedsLayout(this); 316 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { 317 if (child->isSVGRoot()) 318 continue; 319 320 if ((child->isBox() && toRenderBox(child)->hasRelativeLogicalHeight()) 321 || child->style()->logicalHeight().isPercent() 322 || child->style()->logicalMinHeight().isPercent() 323 || child->style()->logicalMaxHeight().isPercent() 324 || child->style()->logicalHeight().isViewportPercentage() 325 || child->style()->logicalMinHeight().isViewportPercentage() 326 || child->style()->logicalMaxHeight().isViewportPercentage()) 327 layoutScope.setChildNeedsLayout(child); 328 } 329 330 if (document().svgExtensions()) 331 document().accessSVGExtensions()->invalidateSVGRootsWithRelativeLengthDescendents(&layoutScope); 332 } 333 334 ASSERT(!m_layoutState); 335 if (!needsLayout()) 336 return; 337 338 LayoutState state; 339 bool isSeamlessAncestorInFlowThread = initializeLayoutState(state); 340 341 m_pageLogicalHeightChanged = false; 342 m_layoutState = &state; 343 344 if (checkTwoPassLayoutForAutoHeightRegions()) 345 layoutContentInAutoLogicalHeightRegions(state); 346 else 347 layoutContent(state); 348 349 if (m_frameView->partialLayout().isStopping()) { 350 m_layoutState = 0; 351 return; 352 } 353 354 #ifndef NDEBUG 355 checkLayoutState(state); 356 #endif 357 m_layoutState = 0; 358 clearNeedsLayout(); 359 360 if (isSeamlessAncestorInFlowThread) 361 flowThreadController()->setCurrentRenderFlowThread(0); 362 } 363 364 void RenderView::mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState& transformState, MapCoordinatesFlags mode, bool* wasFixed) const 365 { 366 ASSERT_UNUSED(wasFixed, !wasFixed || *wasFixed == static_cast<bool>(mode & IsFixed)); 367 368 if (!repaintContainer && mode & UseTransforms && shouldUseTransformFromContainer(0)) { 369 TransformationMatrix t; 370 getTransformFromContainer(0, LayoutSize(), t); 371 transformState.applyTransform(t); 372 } 373 374 if (mode & IsFixed && m_frameView) 375 transformState.move(m_frameView->scrollOffsetForFixedPosition()); 376 377 if (repaintContainer == this) 378 return; 379 380 if (mode & TraverseDocumentBoundaries) { 381 if (RenderObject* parentDocRenderer = frame()->ownerRenderer()) { 382 transformState.move(-frame()->view()->scrollOffset()); 383 if (parentDocRenderer->isBox()) 384 transformState.move(toLayoutSize(toRenderBox(parentDocRenderer)->contentBoxRect().location())); 385 parentDocRenderer->mapLocalToContainer(repaintContainer, transformState, mode, wasFixed); 386 return; 387 } 388 } 389 390 // If a container was specified, and was not 0 or the RenderView, 391 // then we should have found it by now. 392 ASSERT_ARG(repaintContainer, !repaintContainer); 393 } 394 395 const RenderObject* RenderView::pushMappingToContainer(const RenderLayerModelObject* ancestorToStopAt, RenderGeometryMap& geometryMap) const 396 { 397 LayoutSize offsetForFixedPosition; 398 LayoutSize offset; 399 RenderObject* container = 0; 400 401 if (m_frameView) 402 offsetForFixedPosition = m_frameView->scrollOffsetForFixedPosition(); 403 404 if (geometryMap.mapCoordinatesFlags() & TraverseDocumentBoundaries) { 405 if (RenderPart* parentDocRenderer = frame()->ownerRenderer()) { 406 offset = -m_frameView->scrollOffset(); 407 offset += toLayoutSize(parentDocRenderer->contentBoxRect().location()); 408 container = parentDocRenderer; 409 } 410 } 411 412 // If a container was specified, and was not 0 or the RenderView, then we 413 // should have found it by now unless we're traversing to a parent document. 414 ASSERT_ARG(ancestorToStopAt, !ancestorToStopAt || ancestorToStopAt == this || container); 415 416 if ((!ancestorToStopAt || container) && shouldUseTransformFromContainer(container)) { 417 TransformationMatrix t; 418 getTransformFromContainer(container, LayoutSize(), t); 419 geometryMap.push(this, t, false, false, false, true, offsetForFixedPosition); 420 } else { 421 geometryMap.push(this, offset, false, false, false, false, offsetForFixedPosition); 422 } 423 424 return container; 425 } 426 427 void RenderView::mapAbsoluteToLocalPoint(MapCoordinatesFlags mode, TransformState& transformState) const 428 { 429 if (mode & IsFixed && m_frameView) 430 transformState.move(m_frameView->scrollOffsetForFixedPosition()); 431 432 if (mode & UseTransforms && shouldUseTransformFromContainer(0)) { 433 TransformationMatrix t; 434 getTransformFromContainer(0, LayoutSize(), t); 435 transformState.applyTransform(t); 436 } 437 } 438 439 void RenderView::computeSelfHitTestRects(Vector<LayoutRect>& rects, const LayoutPoint&) const 440 { 441 // Record the entire size of the contents of the frame. Note that we don't just 442 // use the viewport size (containing block) here because we want to ensure this includes 443 // all children (so we can avoid walking them explicitly). 444 rects.append(LayoutRect(LayoutPoint::zero(), frameView()->contentsSize())); 445 } 446 447 bool RenderView::requiresColumns(int desiredColumnCount) const 448 { 449 if (m_frameView) 450 return m_frameView->pagination().mode != Pagination::Unpaginated; 451 452 return RenderBlock::requiresColumns(desiredColumnCount); 453 } 454 455 void RenderView::calcColumnWidth() 456 { 457 int columnWidth = contentLogicalWidth(); 458 if (m_frameView && style()->hasInlineColumnAxis()) { 459 if (int pageLength = m_frameView->pagination().pageLength) 460 columnWidth = pageLength; 461 } 462 setDesiredColumnCountAndWidth(1, columnWidth); 463 } 464 465 ColumnInfo::PaginationUnit RenderView::paginationUnit() const 466 { 467 if (m_frameView) 468 return m_frameView->pagination().behavesLikeColumns ? ColumnInfo::Column : ColumnInfo::Page; 469 470 return ColumnInfo::Page; 471 } 472 473 void RenderView::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset) 474 { 475 // If we ever require layout but receive a paint anyway, something has gone horribly wrong. 476 ASSERT(!needsLayout()); 477 // RenderViews should never be called to paint with an offset not on device pixels. 478 ASSERT(LayoutPoint(IntPoint(paintOffset.x(), paintOffset.y())) == paintOffset); 479 480 ANNOTATE_GRAPHICS_CONTEXT(paintInfo, this); 481 482 // This avoids painting garbage between columns if there is a column gap. 483 if (m_frameView && m_frameView->pagination().mode != Pagination::Unpaginated) 484 paintInfo.context->fillRect(paintInfo.rect, m_frameView->baseBackgroundColor()); 485 486 paintObject(paintInfo, paintOffset); 487 } 488 489 static inline bool rendererObscuresBackground(RenderObject* rootObject) 490 { 491 if (!rootObject) 492 return false; 493 494 RenderStyle* style = rootObject->style(); 495 if (style->visibility() != VISIBLE 496 || style->opacity() != 1 497 || style->hasTransform()) 498 return false; 499 500 if (rootObject->compositingState() == PaintsIntoOwnBacking) 501 return false; 502 503 const RenderObject* rootRenderer = rootObject->rendererForRootBackground(); 504 if (rootRenderer->style()->backgroundClip() == TextFillBox) 505 return false; 506 507 return true; 508 } 509 510 void RenderView::paintBoxDecorations(PaintInfo& paintInfo, const LayoutPoint&) 511 { 512 // Check to see if we are enclosed by a layer that requires complex painting rules. If so, we cannot blit 513 // when scrolling, and we need to use slow repaints. Examples of layers that require this are transparent layers, 514 // layers with reflections, or transformed layers. 515 // FIXME: This needs to be dynamic. We should be able to go back to blitting if we ever stop being inside 516 // a transform, transparency layer, etc. 517 Element* elt; 518 for (elt = document().ownerElement(); view() && elt && elt->renderer(); elt = elt->document().ownerElement()) { 519 RenderLayer* layer = elt->renderer()->enclosingLayer(); 520 if (layer->cannotBlitToWindow()) { 521 frameView()->setCannotBlitToWindow(); 522 break; 523 } 524 525 if (layer->enclosingCompositingLayerForRepaint()) { 526 frameView()->setCannotBlitToWindow(); 527 break; 528 } 529 } 530 531 if (document().ownerElement() || !view()) 532 return; 533 534 if (paintInfo.skipRootBackground()) 535 return; 536 537 bool rootFillsViewport = false; 538 bool rootObscuresBackground = false; 539 Node* documentElement = document().documentElement(); 540 if (RenderObject* rootRenderer = documentElement ? documentElement->renderer() : 0) { 541 // The document element's renderer is currently forced to be a block, but may not always be. 542 RenderBox* rootBox = rootRenderer->isBox() ? toRenderBox(rootRenderer) : 0; 543 rootFillsViewport = rootBox && !rootBox->x() && !rootBox->y() && rootBox->width() >= width() && rootBox->height() >= height(); 544 rootObscuresBackground = rendererObscuresBackground(rootRenderer); 545 } 546 547 Page* page = document().page(); 548 float pageScaleFactor = page ? page->pageScaleFactor() : 1; 549 550 // If painting will entirely fill the view, no need to fill the background. 551 if (rootFillsViewport && rootObscuresBackground && pageScaleFactor >= 1) 552 return; 553 554 // This code typically only executes if the root element's visibility has been set to hidden, 555 // if there is a transform on the <html>, or if there is a page scale factor less than 1. 556 // Only fill with the base background color (typically white) if we're the root document, 557 // since iframes/frames with no background in the child document should show the parent's background. 558 if (frameView()->isTransparent()) // FIXME: This needs to be dynamic. We should be able to go back to blitting if we ever stop being transparent. 559 frameView()->setCannotBlitToWindow(); // The parent must show behind the child. 560 else { 561 Color baseColor = frameView()->baseBackgroundColor(); 562 if (baseColor.alpha()) { 563 CompositeOperator previousOperator = paintInfo.context->compositeOperation(); 564 paintInfo.context->setCompositeOperation(CompositeCopy); 565 paintInfo.context->fillRect(paintInfo.rect, baseColor); 566 paintInfo.context->setCompositeOperation(previousOperator); 567 } else { 568 paintInfo.context->clearRect(paintInfo.rect); 569 } 570 } 571 } 572 573 bool RenderView::shouldRepaint(const LayoutRect& rect) const 574 { 575 if (document().printing()) 576 return false; 577 return m_frameView && !rect.isEmpty(); 578 } 579 580 void RenderView::repaintViewRectangle(const LayoutRect& ur) const 581 { 582 if (!shouldRepaint(ur)) 583 return; 584 585 // We always just invalidate the root view, since we could be an iframe that is clipped out 586 // or even invisible. 587 Element* elt = document().ownerElement(); 588 if (!elt) 589 m_frameView->repaintContentRectangle(pixelSnappedIntRect(ur)); 590 else if (RenderBox* obj = elt->renderBox()) { 591 LayoutRect vr = viewRect(); 592 LayoutRect r = intersection(ur, vr); 593 594 // Subtract out the contentsX and contentsY offsets to get our coords within the viewing 595 // rectangle. 596 r.moveBy(-vr.location()); 597 598 // FIXME: Hardcoded offsets here are not good. 599 r.moveBy(obj->contentBoxRect().location()); 600 obj->repaintRectangle(r); 601 } 602 } 603 604 void RenderView::repaintRectangleInViewAndCompositedLayers(const LayoutRect& ur) 605 { 606 if (!shouldRepaint(ur)) 607 return; 608 609 repaintViewRectangle(ur); 610 611 if (compositor()->inCompositingMode()) { 612 IntRect repaintRect = pixelSnappedIntRect(ur); 613 compositor()->repaintCompositedLayers(&repaintRect); 614 } 615 } 616 617 void RenderView::repaintViewAndCompositedLayers() 618 { 619 repaint(); 620 621 if (compositor()->inCompositingMode()) 622 compositor()->repaintCompositedLayers(); 623 } 624 625 void RenderView::computeRectForRepaint(const RenderLayerModelObject* repaintContainer, LayoutRect& rect, bool fixed) const 626 { 627 // If a container was specified, and was not 0 or the RenderView, 628 // then we should have found it by now. 629 ASSERT_ARG(repaintContainer, !repaintContainer || repaintContainer == this); 630 631 if (document().printing()) 632 return; 633 634 if (style()->isFlippedBlocksWritingMode()) { 635 // We have to flip by hand since the view's logical height has not been determined. We 636 // can use the viewport width and height. 637 if (style()->isHorizontalWritingMode()) 638 rect.setY(viewHeight() - rect.maxY()); 639 else 640 rect.setX(viewWidth() - rect.maxX()); 641 } 642 643 if (fixed && m_frameView) 644 rect.move(m_frameView->scrollOffsetForFixedPosition()); 645 646 // Apply our transform if we have one (because of full page zooming). 647 if (!repaintContainer && layer() && layer()->transform()) 648 rect = layer()->transform()->mapRect(rect); 649 } 650 651 void RenderView::absoluteRects(Vector<IntRect>& rects, const LayoutPoint& accumulatedOffset) const 652 { 653 rects.append(pixelSnappedIntRect(accumulatedOffset, layer()->size())); 654 } 655 656 void RenderView::absoluteQuads(Vector<FloatQuad>& quads, bool* wasFixed) const 657 { 658 if (wasFixed) 659 *wasFixed = false; 660 quads.append(FloatRect(FloatPoint(), layer()->size())); 661 } 662 663 static RenderObject* rendererAfterPosition(RenderObject* object, unsigned offset) 664 { 665 if (!object) 666 return 0; 667 668 RenderObject* child = object->childAt(offset); 669 return child ? child : object->nextInPreOrderAfterChildren(); 670 } 671 672 IntRect RenderView::selectionBounds(bool clipToVisibleContent) const 673 { 674 typedef HashMap<RenderObject*, OwnPtr<RenderSelectionInfo> > SelectionMap; 675 SelectionMap selectedObjects; 676 677 RenderObject* os = m_selectionStart; 678 RenderObject* stop = rendererAfterPosition(m_selectionEnd, m_selectionEndPos); 679 while (os && os != stop) { 680 if ((os->canBeSelectionLeaf() || os == m_selectionStart || os == m_selectionEnd) && os->selectionState() != SelectionNone) { 681 // Blocks are responsible for painting line gaps and margin gaps. They must be examined as well. 682 selectedObjects.set(os, adoptPtr(new RenderSelectionInfo(os, clipToVisibleContent))); 683 RenderBlock* cb = os->containingBlock(); 684 while (cb && !cb->isRenderView()) { 685 OwnPtr<RenderSelectionInfo>& blockInfo = selectedObjects.add(cb, nullptr).iterator->value; 686 if (blockInfo) 687 break; 688 blockInfo = adoptPtr(new RenderSelectionInfo(cb, clipToVisibleContent)); 689 cb = cb->containingBlock(); 690 } 691 } 692 693 os = os->nextInPreOrder(); 694 } 695 696 // Now create a single bounding box rect that encloses the whole selection. 697 LayoutRect selRect; 698 SelectionMap::iterator end = selectedObjects.end(); 699 for (SelectionMap::iterator i = selectedObjects.begin(); i != end; ++i) { 700 RenderSelectionInfo* info = i->value.get(); 701 // RenderSelectionInfo::rect() is in the coordinates of the repaintContainer, so map to page coordinates. 702 LayoutRect currRect = info->rect(); 703 if (RenderLayerModelObject* repaintContainer = info->repaintContainer()) { 704 FloatQuad absQuad = repaintContainer->localToAbsoluteQuad(FloatRect(currRect)); 705 currRect = absQuad.enclosingBoundingBox(); 706 } 707 selRect.unite(currRect); 708 } 709 return pixelSnappedIntRect(selRect); 710 } 711 712 void RenderView::repaintSelection() const 713 { 714 HashSet<RenderBlock*> processedBlocks; 715 716 RenderObject* end = rendererAfterPosition(m_selectionEnd, m_selectionEndPos); 717 for (RenderObject* o = m_selectionStart; o && o != end; o = o->nextInPreOrder()) { 718 if (!o->canBeSelectionLeaf() && o != m_selectionStart && o != m_selectionEnd) 719 continue; 720 if (o->selectionState() == SelectionNone) 721 continue; 722 723 RenderSelectionInfo(o, true).repaint(); 724 725 // Blocks are responsible for painting line gaps and margin gaps. They must be examined as well. 726 for (RenderBlock* block = o->containingBlock(); block && !block->isRenderView(); block = block->containingBlock()) { 727 if (!processedBlocks.add(block).isNewEntry) 728 break; 729 RenderSelectionInfo(block, true).repaint(); 730 } 731 } 732 } 733 734 // Compositing layer dimensions take outline size into account, so we have to recompute layer 735 // bounds when it changes. 736 // FIXME: This is ugly; it would be nice to have a better way to do this. 737 void RenderView::setMaximalOutlineSize(int o) 738 { 739 if (o != m_maximalOutlineSize) { 740 m_maximalOutlineSize = o; 741 742 // maximalOutlineSize affects compositing layer dimensions. 743 compositor()->setCompositingLayersNeedRebuild(); // FIXME: this really just needs to be a geometry update. 744 } 745 } 746 747 // When exploring the RenderTree looking for the nodes involved in the Selection, sometimes it's 748 // required to change the traversing direction because the "start" position is below the "end" one. 749 static inline RenderObject* getNextOrPrevRenderObjectBasedOnDirection(const RenderObject* o, const RenderObject* stop, bool& continueExploring, bool& exploringBackwards) 750 { 751 RenderObject* next; 752 if (exploringBackwards) { 753 next = o->previousInPreOrder(); 754 continueExploring = next && !(next)->isRenderView(); 755 } else { 756 next = o->nextInPreOrder(); 757 continueExploring = next && next != stop; 758 exploringBackwards = !next && (next != stop); 759 if (exploringBackwards) { 760 next = stop->previousInPreOrder(); 761 continueExploring = next && !next->isRenderView(); 762 } 763 } 764 765 return next; 766 } 767 768 void RenderView::setSelection(RenderObject* start, int startPos, RenderObject* end, int endPos, SelectionRepaintMode blockRepaintMode) 769 { 770 // This code makes no assumptions as to if the rendering tree is up to date or not 771 // and will not try to update it. Currently clearSelection calls this 772 // (intentionally) without updating the rendering tree as it doesn't care. 773 // Other callers may want to force recalc style before calling this. 774 775 // Make sure both our start and end objects are defined. 776 // Check www.msnbc.com and try clicking around to find the case where this happened. 777 if ((start && !end) || (end && !start)) 778 return; 779 780 // Just return if the selection hasn't changed. 781 if (m_selectionStart == start && m_selectionStartPos == startPos && 782 m_selectionEnd == end && m_selectionEndPos == endPos) 783 return; 784 785 // Record the old selected objects. These will be used later 786 // when we compare against the new selected objects. 787 int oldStartPos = m_selectionStartPos; 788 int oldEndPos = m_selectionEndPos; 789 790 // Objects each have a single selection rect to examine. 791 typedef HashMap<RenderObject*, OwnPtr<RenderSelectionInfo> > SelectedObjectMap; 792 SelectedObjectMap oldSelectedObjects; 793 SelectedObjectMap newSelectedObjects; 794 795 // Blocks contain selected objects and fill gaps between them, either on the left, right, or in between lines and blocks. 796 // In order to get the repaint rect right, we have to examine left, middle, and right rects individually, since otherwise 797 // the union of those rects might remain the same even when changes have occurred. 798 typedef HashMap<RenderBlock*, OwnPtr<RenderBlockSelectionInfo> > SelectedBlockMap; 799 SelectedBlockMap oldSelectedBlocks; 800 SelectedBlockMap newSelectedBlocks; 801 802 RenderObject* os = m_selectionStart; 803 RenderObject* stop = rendererAfterPosition(m_selectionEnd, m_selectionEndPos); 804 bool exploringBackwards = false; 805 bool continueExploring = os && (os != stop); 806 while (continueExploring) { 807 if ((os->canBeSelectionLeaf() || os == m_selectionStart || os == m_selectionEnd) && os->selectionState() != SelectionNone) { 808 // Blocks are responsible for painting line gaps and margin gaps. They must be examined as well. 809 oldSelectedObjects.set(os, adoptPtr(new RenderSelectionInfo(os, true))); 810 if (blockRepaintMode == RepaintNewXOROld) { 811 RenderBlock* cb = os->containingBlock(); 812 while (cb && !cb->isRenderView()) { 813 OwnPtr<RenderBlockSelectionInfo>& blockInfo = oldSelectedBlocks.add(cb, nullptr).iterator->value; 814 if (blockInfo) 815 break; 816 blockInfo = adoptPtr(new RenderBlockSelectionInfo(cb)); 817 cb = cb->containingBlock(); 818 } 819 } 820 } 821 822 os = getNextOrPrevRenderObjectBasedOnDirection(os, stop, continueExploring, exploringBackwards); 823 } 824 825 // Now clear the selection. 826 SelectedObjectMap::iterator oldObjectsEnd = oldSelectedObjects.end(); 827 for (SelectedObjectMap::iterator i = oldSelectedObjects.begin(); i != oldObjectsEnd; ++i) 828 i->key->setSelectionStateIfNeeded(SelectionNone); 829 830 // set selection start and end 831 m_selectionStart = start; 832 m_selectionStartPos = startPos; 833 m_selectionEnd = end; 834 m_selectionEndPos = endPos; 835 836 // Update the selection status of all objects between m_selectionStart and m_selectionEnd 837 if (start && start == end) 838 start->setSelectionStateIfNeeded(SelectionBoth); 839 else { 840 if (start) 841 start->setSelectionStateIfNeeded(SelectionStart); 842 if (end) 843 end->setSelectionStateIfNeeded(SelectionEnd); 844 } 845 846 RenderObject* o = start; 847 stop = rendererAfterPosition(end, endPos); 848 849 while (o && o != stop) { 850 if (o != start && o != end && o->canBeSelectionLeaf()) 851 o->setSelectionStateIfNeeded(SelectionInside); 852 o = o->nextInPreOrder(); 853 } 854 855 if (blockRepaintMode != RepaintNothing) 856 layer()->clearBlockSelectionGapsBounds(); 857 858 // Now that the selection state has been updated for the new objects, walk them again and 859 // put them in the new objects list. 860 o = start; 861 exploringBackwards = false; 862 continueExploring = o && (o != stop); 863 while (continueExploring) { 864 if ((o->canBeSelectionLeaf() || o == start || o == end) && o->selectionState() != SelectionNone) { 865 newSelectedObjects.set(o, adoptPtr(new RenderSelectionInfo(o, true))); 866 RenderBlock* cb = o->containingBlock(); 867 while (cb && !cb->isRenderView()) { 868 OwnPtr<RenderBlockSelectionInfo>& blockInfo = newSelectedBlocks.add(cb, nullptr).iterator->value; 869 if (blockInfo) 870 break; 871 blockInfo = adoptPtr(new RenderBlockSelectionInfo(cb)); 872 cb = cb->containingBlock(); 873 } 874 } 875 876 o = getNextOrPrevRenderObjectBasedOnDirection(o, stop, continueExploring, exploringBackwards); 877 } 878 879 if (!m_frameView || blockRepaintMode == RepaintNothing) 880 return; 881 882 FrameView::DeferredRepaintScope deferRepaints(*m_frameView); 883 884 // Have any of the old selected objects changed compared to the new selection? 885 for (SelectedObjectMap::iterator i = oldSelectedObjects.begin(); i != oldObjectsEnd; ++i) { 886 RenderObject* obj = i->key; 887 RenderSelectionInfo* newInfo = newSelectedObjects.get(obj); 888 RenderSelectionInfo* oldInfo = i->value.get(); 889 if (!newInfo || oldInfo->rect() != newInfo->rect() || oldInfo->state() != newInfo->state() || 890 (m_selectionStart == obj && oldStartPos != m_selectionStartPos) || 891 (m_selectionEnd == obj && oldEndPos != m_selectionEndPos)) { 892 oldInfo->repaint(); 893 if (newInfo) { 894 newInfo->repaint(); 895 newSelectedObjects.remove(obj); 896 } 897 } 898 } 899 900 // Any new objects that remain were not found in the old objects dict, and so they need to be updated. 901 SelectedObjectMap::iterator newObjectsEnd = newSelectedObjects.end(); 902 for (SelectedObjectMap::iterator i = newSelectedObjects.begin(); i != newObjectsEnd; ++i) 903 i->value->repaint(); 904 905 // Have any of the old blocks changed? 906 SelectedBlockMap::iterator oldBlocksEnd = oldSelectedBlocks.end(); 907 for (SelectedBlockMap::iterator i = oldSelectedBlocks.begin(); i != oldBlocksEnd; ++i) { 908 RenderBlock* block = i->key; 909 RenderBlockSelectionInfo* newInfo = newSelectedBlocks.get(block); 910 RenderBlockSelectionInfo* oldInfo = i->value.get(); 911 if (!newInfo || oldInfo->rects() != newInfo->rects() || oldInfo->state() != newInfo->state()) { 912 oldInfo->repaint(); 913 if (newInfo) { 914 newInfo->repaint(); 915 newSelectedBlocks.remove(block); 916 } 917 } 918 } 919 920 // Any new blocks that remain were not found in the old blocks dict, and so they need to be updated. 921 SelectedBlockMap::iterator newBlocksEnd = newSelectedBlocks.end(); 922 for (SelectedBlockMap::iterator i = newSelectedBlocks.begin(); i != newBlocksEnd; ++i) 923 i->value->repaint(); 924 } 925 926 void RenderView::getSelection(RenderObject*& startRenderer, int& startOffset, RenderObject*& endRenderer, int& endOffset) const 927 { 928 startRenderer = m_selectionStart; 929 startOffset = m_selectionStartPos; 930 endRenderer = m_selectionEnd; 931 endOffset = m_selectionEndPos; 932 } 933 934 void RenderView::clearSelection() 935 { 936 layer()->repaintBlockSelectionGaps(); 937 setSelection(0, -1, 0, -1, RepaintNewMinusOld); 938 } 939 940 void RenderView::selectionStartEnd(int& startPos, int& endPos) const 941 { 942 startPos = m_selectionStartPos; 943 endPos = m_selectionEndPos; 944 } 945 946 bool RenderView::shouldUsePrintingLayout() const 947 { 948 if (!document().printing() || !m_frameView) 949 return false; 950 return m_frameView->frame().shouldUsePrintingLayout(); 951 } 952 953 size_t RenderView::getRetainedWidgets(Vector<RenderWidget*>& renderWidgets) 954 { 955 size_t size = m_widgets.size(); 956 957 renderWidgets.reserveCapacity(size); 958 959 RenderWidgetSet::const_iterator end = m_widgets.end(); 960 for (RenderWidgetSet::const_iterator it = m_widgets.begin(); it != end; ++it) { 961 renderWidgets.uncheckedAppend(*it); 962 (*it)->ref(); 963 } 964 965 return size; 966 } 967 968 void RenderView::releaseWidgets(Vector<RenderWidget*>& renderWidgets) 969 { 970 size_t size = renderWidgets.size(); 971 972 for (size_t i = 0; i < size; ++i) 973 renderWidgets[i]->deref(); 974 } 975 976 void RenderView::updateWidgetPositions() 977 { 978 // updateWidgetPosition() can possibly cause layout to be re-entered (via plug-ins running 979 // scripts in response to NPP_SetWindow, for example), so we need to keep the Widgets 980 // alive during enumeration. 981 982 Vector<RenderWidget*> renderWidgets; 983 size_t size = getRetainedWidgets(renderWidgets); 984 985 for (size_t i = 0; i < size; ++i) 986 renderWidgets[i]->updateWidgetPosition(); 987 988 for (size_t i = 0; i < size; ++i) 989 renderWidgets[i]->widgetPositionsUpdated(); 990 991 releaseWidgets(renderWidgets); 992 } 993 994 void RenderView::addWidget(RenderWidget* o) 995 { 996 m_widgets.add(o); 997 } 998 999 void RenderView::removeWidget(RenderWidget* o) 1000 { 1001 m_widgets.remove(o); 1002 } 1003 1004 LayoutRect RenderView::viewRect() const 1005 { 1006 if (shouldUsePrintingLayout()) 1007 return LayoutRect(LayoutPoint(), size()); 1008 if (m_frameView) 1009 return m_frameView->visibleContentRect(); 1010 return LayoutRect(); 1011 } 1012 1013 IntRect RenderView::unscaledDocumentRect() const 1014 { 1015 LayoutRect overflowRect(layoutOverflowRect()); 1016 flipForWritingMode(overflowRect); 1017 return pixelSnappedIntRect(overflowRect); 1018 } 1019 1020 bool RenderView::rootBackgroundIsEntirelyFixed() const 1021 { 1022 RenderObject* rootObject = document().documentElement() ? document().documentElement()->renderer() : 0; 1023 if (!rootObject) 1024 return false; 1025 1026 RenderObject* rootRenderer = rootObject->rendererForRootBackground(); 1027 return rootRenderer->hasEntirelyFixedBackground(); 1028 } 1029 1030 LayoutRect RenderView::backgroundRect(RenderBox* backgroundRenderer) const 1031 { 1032 if (!hasColumns()) 1033 return unscaledDocumentRect(); 1034 1035 ColumnInfo* columnInfo = this->columnInfo(); 1036 LayoutRect backgroundRect(0, 0, columnInfo->desiredColumnWidth(), columnInfo->columnHeight() * columnInfo->columnCount()); 1037 if (!isHorizontalWritingMode()) 1038 backgroundRect = backgroundRect.transposedRect(); 1039 backgroundRenderer->flipForWritingMode(backgroundRect); 1040 1041 return backgroundRect; 1042 } 1043 1044 IntRect RenderView::documentRect() const 1045 { 1046 FloatRect overflowRect(unscaledDocumentRect()); 1047 if (hasTransform()) 1048 overflowRect = layer()->currentTransform().mapRect(overflowRect); 1049 return IntRect(overflowRect); 1050 } 1051 1052 int RenderView::viewHeight(ScrollableArea::IncludeScrollbarsInRect scrollbarInclusion) const 1053 { 1054 int height = 0; 1055 if (!shouldUsePrintingLayout() && m_frameView) 1056 height = m_frameView->layoutSize(scrollbarInclusion).height(); 1057 1058 return height; 1059 } 1060 1061 int RenderView::viewWidth(ScrollableArea::IncludeScrollbarsInRect scrollbarInclusion) const 1062 { 1063 int width = 0; 1064 if (!shouldUsePrintingLayout() && m_frameView) 1065 width = m_frameView->layoutSize(scrollbarInclusion).width(); 1066 1067 return width; 1068 } 1069 1070 int RenderView::viewLogicalHeight(ScrollableArea::IncludeScrollbarsInRect scrollbarInclusion) const 1071 { 1072 int height = style()->isHorizontalWritingMode() ? viewHeight(scrollbarInclusion) : viewWidth(scrollbarInclusion); 1073 1074 if (hasColumns() && !style()->hasInlineColumnAxis()) { 1075 if (int pageLength = m_frameView->pagination().pageLength) 1076 height = pageLength; 1077 } 1078 1079 return height; 1080 } 1081 1082 float RenderView::zoomFactor() const 1083 { 1084 return m_frameView->frame().pageZoomFactor(); 1085 } 1086 1087 void RenderView::pushLayoutState(RenderObject* root) 1088 { 1089 ASSERT(m_layoutStateDisableCount == 0); 1090 ASSERT(m_layoutState == 0); 1091 1092 pushLayoutStateForCurrentFlowThread(root); 1093 m_layoutState = new LayoutState(root); 1094 } 1095 1096 bool RenderView::shouldDisableLayoutStateForSubtree(RenderObject* renderer) const 1097 { 1098 RenderObject* o = renderer; 1099 while (o) { 1100 if (o->hasColumns() || o->hasTransform() || o->hasReflection()) 1101 return true; 1102 o = o->container(); 1103 } 1104 return false; 1105 } 1106 1107 void RenderView::updateHitTestResult(HitTestResult& result, const LayoutPoint& point) 1108 { 1109 if (result.innerNode()) 1110 return; 1111 1112 Node* node = document().documentElement(); 1113 if (node) { 1114 result.setInnerNode(node); 1115 if (!result.innerNonSharedNode()) 1116 result.setInnerNonSharedNode(node); 1117 1118 LayoutPoint adjustedPoint = point; 1119 offsetForContents(adjustedPoint); 1120 1121 result.setLocalPoint(adjustedPoint); 1122 } 1123 } 1124 1125 bool RenderView::usesCompositing() const 1126 { 1127 return m_compositor && m_compositor->inCompositingMode(); 1128 } 1129 1130 RenderLayerCompositor* RenderView::compositor() 1131 { 1132 if (!m_compositor) 1133 m_compositor = adoptPtr(new RenderLayerCompositor(this)); 1134 1135 return m_compositor.get(); 1136 } 1137 1138 void RenderView::setIsInWindow(bool isInWindow) 1139 { 1140 if (m_compositor) 1141 m_compositor->setIsInWindow(isInWindow); 1142 } 1143 1144 CustomFilterGlobalContext* RenderView::customFilterGlobalContext() 1145 { 1146 if (!m_customFilterGlobalContext) 1147 m_customFilterGlobalContext = adoptPtr(new CustomFilterGlobalContext()); 1148 return m_customFilterGlobalContext.get(); 1149 } 1150 1151 void RenderView::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) 1152 { 1153 RenderBlock::styleDidChange(diff, oldStyle); 1154 if (hasRenderNamedFlowThreads()) 1155 flowThreadController()->styleDidChange(); 1156 } 1157 1158 bool RenderView::hasRenderNamedFlowThreads() const 1159 { 1160 return m_flowThreadController && m_flowThreadController->hasRenderNamedFlowThreads(); 1161 } 1162 1163 bool RenderView::checkTwoPassLayoutForAutoHeightRegions() const 1164 { 1165 return hasRenderNamedFlowThreads() && m_flowThreadController->hasFlowThreadsWithAutoLogicalHeightRegions(); 1166 } 1167 1168 FlowThreadController* RenderView::flowThreadController() 1169 { 1170 if (!m_flowThreadController) 1171 m_flowThreadController = FlowThreadController::create(this); 1172 1173 return m_flowThreadController.get(); 1174 } 1175 1176 void RenderView::pushLayoutStateForCurrentFlowThread(const RenderObject* object) 1177 { 1178 if (!m_flowThreadController) 1179 return; 1180 1181 RenderFlowThread* currentFlowThread = m_flowThreadController->currentRenderFlowThread(); 1182 if (!currentFlowThread) 1183 return; 1184 1185 currentFlowThread->pushFlowThreadLayoutState(object); 1186 } 1187 1188 void RenderView::popLayoutStateForCurrentFlowThread() 1189 { 1190 if (!m_flowThreadController) 1191 return; 1192 1193 RenderFlowThread* currentFlowThread = m_flowThreadController->currentRenderFlowThread(); 1194 if (!currentFlowThread) 1195 return; 1196 1197 currentFlowThread->popFlowThreadLayoutState(); 1198 } 1199 1200 IntervalArena* RenderView::intervalArena() 1201 { 1202 if (!m_intervalArena) 1203 m_intervalArena = IntervalArena::create(); 1204 return m_intervalArena.get(); 1205 } 1206 1207 bool RenderView::backgroundIsKnownToBeOpaqueInRect(const LayoutRect&) const 1208 { 1209 // FIXME: Remove this main frame check. Same concept applies to subframes too. 1210 if (!m_frameView || !m_frameView->isMainFrame()) 1211 return false; 1212 1213 return m_frameView->hasOpaqueBackground(); 1214 } 1215 1216 LayoutUnit RenderView::viewportPercentageWidth(float percentage) const 1217 { 1218 return viewLogicalWidth(ScrollableArea::IncludeScrollbars) * percentage / 100.f; 1219 } 1220 1221 LayoutUnit RenderView::viewportPercentageHeight(float percentage) const 1222 { 1223 return viewLogicalHeight(ScrollableArea::IncludeScrollbars) * percentage / 100.f; 1224 } 1225 1226 LayoutUnit RenderView::viewportPercentageMin(float percentage) const 1227 { 1228 return std::min(viewLogicalWidth(ScrollableArea::IncludeScrollbars), viewLogicalHeight(ScrollableArea::IncludeScrollbars)) 1229 * percentage / 100.f; 1230 } 1231 1232 LayoutUnit RenderView::viewportPercentageMax(float percentage) const 1233 { 1234 return std::max(viewLogicalWidth(ScrollableArea::IncludeScrollbars), viewLogicalHeight(ScrollableArea::IncludeScrollbars)) 1235 * percentage / 100.f; 1236 } 1237 1238 FragmentationDisabler::FragmentationDisabler(RenderObject* root) 1239 { 1240 RenderView* renderView = root->view(); 1241 ASSERT(renderView); 1242 1243 LayoutState* layoutState = renderView->layoutState(); 1244 1245 m_root = root; 1246 m_fragmenting = layoutState && layoutState->isPaginated(); 1247 m_flowThreadState = m_root->flowThreadState(); 1248 #ifndef NDEBUG 1249 m_layoutState = layoutState; 1250 #endif 1251 1252 if (layoutState) 1253 layoutState->m_isPaginated = false; 1254 1255 if (m_flowThreadState != RenderObject::NotInsideFlowThread) 1256 m_root->setFlowThreadStateIncludingDescendants(RenderObject::NotInsideFlowThread); 1257 } 1258 1259 FragmentationDisabler::~FragmentationDisabler() 1260 { 1261 RenderView* renderView = m_root->view(); 1262 ASSERT(renderView); 1263 1264 LayoutState* layoutState = renderView->layoutState(); 1265 #ifndef NDEBUG 1266 ASSERT(m_layoutState == layoutState); 1267 #endif 1268 1269 if (layoutState) 1270 layoutState->m_isPaginated = m_fragmenting; 1271 1272 if (m_flowThreadState != RenderObject::NotInsideFlowThread) 1273 m_root->setFlowThreadStateIncludingDescendants(m_flowThreadState); 1274 } 1275 1276 } // namespace WebCore 1277