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