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/frame/LocalFrame.h" 27 #include "core/html/HTMLDialogElement.h" 28 #include "core/html/HTMLFrameOwnerElement.h" 29 #include "core/html/HTMLIFrameElement.h" 30 #include "core/page/Page.h" 31 #include "core/rendering/ColumnInfo.h" 32 #include "core/rendering/FlowThreadController.h" 33 #include "core/rendering/GraphicsContextAnnotator.h" 34 #include "core/rendering/HitTestResult.h" 35 #include "core/rendering/RenderFlowThread.h" 36 #include "core/rendering/RenderGeometryMap.h" 37 #include "core/rendering/RenderLayer.h" 38 #include "core/rendering/RenderSelectionInfo.h" 39 #include "core/rendering/compositing/CompositedLayerMapping.h" 40 #include "core/rendering/compositing/RenderLayerCompositor.h" 41 #include "core/svg/SVGDocumentExtensions.h" 42 #include "platform/RuntimeEnabledFeatures.h" 43 #include "platform/TraceEvent.h" 44 #include "platform/geometry/FloatQuad.h" 45 #include "platform/geometry/TransformState.h" 46 #include "platform/graphics/GraphicsContext.h" 47 48 namespace WebCore { 49 50 RenderView::RenderView(Document* document) 51 : RenderBlockFlow(document) 52 , m_frameView(document->view()) 53 , m_selectionStart(0) 54 , m_selectionEnd(0) 55 , m_selectionStartPos(-1) 56 , m_selectionEndPos(-1) 57 , m_pageLogicalHeight(0) 58 , m_pageLogicalHeightChanged(false) 59 , m_layoutState(0) 60 , m_renderQuoteHead(0) 61 , m_renderCounterCount(0) 62 { 63 // init RenderObject attributes 64 setInline(false); 65 66 m_minPreferredLogicalWidth = 0; 67 m_maxPreferredLogicalWidth = 0; 68 69 setPreferredLogicalWidthsDirty(MarkOnlyThis); 70 71 setPositionState(AbsolutePosition); // to 0,0 :) 72 } 73 74 RenderView::~RenderView() 75 { 76 } 77 78 bool RenderView::hitTest(const HitTestRequest& request, HitTestResult& result) 79 { 80 return hitTest(request, result.hitTestLocation(), result); 81 } 82 83 bool RenderView::hitTest(const HitTestRequest& request, const HitTestLocation& location, HitTestResult& result) 84 { 85 TRACE_EVENT0("blink", "RenderView::hitTest"); 86 87 // We have to recursively update layout/style here because otherwise, when the hit test recurses 88 // into a child document, it could trigger a layout on the parent document, which can destroy RenderLayers 89 // that are higher up in the call stack, leading to crashes. 90 // Note that Document::updateLayout calls its parent's updateLayout. 91 // FIXME: It should be the caller's responsibility to ensure an up-to-date layout. 92 frameView()->updateLayoutAndStyleIfNeededRecursive(); 93 return layer()->hitTest(request, location, result); 94 } 95 96 void RenderView::computeLogicalHeight(LayoutUnit logicalHeight, LayoutUnit, LogicalExtentComputedValues& computedValues) const 97 { 98 computedValues.m_extent = (!shouldUsePrintingLayout() && m_frameView) ? LayoutUnit(viewLogicalHeight()) : logicalHeight; 99 } 100 101 void RenderView::updateLogicalWidth() 102 { 103 if (!shouldUsePrintingLayout() && m_frameView) 104 setLogicalWidth(viewLogicalWidth()); 105 } 106 107 LayoutUnit RenderView::availableLogicalHeight(AvailableLogicalHeightType heightType) const 108 { 109 // If we have columns, then the available logical height is reduced to the column height. 110 if (hasColumns()) 111 return columnInfo()->columnHeight(); 112 return RenderBlockFlow::availableLogicalHeight(heightType); 113 } 114 115 bool RenderView::isChildAllowed(RenderObject* child, RenderStyle*) const 116 { 117 return child->isBox(); 118 } 119 120 static bool canCenterDialog(const RenderStyle* style) 121 { 122 // FIXME: We must center for FixedPosition as well. 123 return style->position() == AbsolutePosition && style->hasAutoTopAndBottom(); 124 } 125 126 void RenderView::positionDialog(RenderBox* box) 127 { 128 HTMLDialogElement* dialog = toHTMLDialogElement(box->node()); 129 if (dialog->centeringMode() == HTMLDialogElement::NotCentered) 130 return; 131 if (dialog->centeringMode() == HTMLDialogElement::Centered) { 132 if (canCenterDialog(box->style())) 133 box->setY(dialog->centeredPosition()); 134 return; 135 } 136 137 ASSERT(dialog->centeringMode() == HTMLDialogElement::NeedsCentering); 138 if (!canCenterDialog(box->style())) { 139 dialog->setNotCentered(); 140 return; 141 } 142 FrameView* frameView = document().view(); 143 int scrollTop = frameView->scrollOffset().height(); 144 int visibleHeight = frameView->visibleContentRect(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 (isHTMLDialogElement(box->node())) 161 positionDialog(box); 162 } 163 } 164 165 void RenderView::layoutContent() 166 { 167 ASSERT(needsLayout()); 168 169 RenderBlockFlow::layout(); 170 171 if (RuntimeEnabledFeatures::dialogElementEnabled()) 172 positionDialogs(); 173 174 #ifndef NDEBUG 175 checkLayoutState(); 176 #endif 177 } 178 179 #ifndef NDEBUG 180 void RenderView::checkLayoutState() 181 { 182 if (!RuntimeEnabledFeatures::repaintAfterLayoutEnabled()) { 183 ASSERT(layoutDeltaMatches(LayoutSize())); 184 } 185 ASSERT(!m_layoutState->next()); 186 } 187 #endif 188 189 bool RenderView::shouldDoFullRepaintForNextLayout() const 190 { 191 // It's hard to predict here which of full repaint or per-descendant repaint costs less. 192 // For vertical writing mode or width change it's more likely that per-descendant repaint 193 // eventually turns out to be full repaint but with the cost to handle more layout states 194 // and discrete repaint rects, so marking full repaint here is more likely to cost less. 195 // Otherwise, per-descendant repaint is more likely to avoid unnecessary full repaints. 196 197 if (shouldUsePrintingLayout()) 198 return true; 199 200 if (!style()->isHorizontalWritingMode() || width() != viewWidth()) 201 return true; 202 203 if (height() != viewHeight()) { 204 // FIXME: Disable optimization to fix crbug.com/390378 for the branch. 205 return true; 206 #if 0 207 if (RenderObject* backgroundRenderer = this->backgroundRenderer()) { 208 // When background-attachment is 'fixed', we treat the viewport (instead of the 'root' 209 // i.e. html or body) as the background positioning area, and we should full repaint 210 // viewport resize if the background image is not composited and needs full repaint on 211 // background positioning area resize. 212 if (!m_compositor || !m_compositor->needsFixedRootBackgroundLayer(layer())) { 213 if (backgroundRenderer->style()->hasFixedBackgroundImage() 214 && mustInvalidateFillLayersPaintOnHeightChange(*backgroundRenderer->style()->backgroundLayers())) 215 return true; 216 } 217 } 218 #endif 219 } 220 221 return false; 222 } 223 224 void RenderView::layout() 225 { 226 if (!document().paginated()) 227 setPageLogicalHeight(0); 228 229 if (shouldUsePrintingLayout()) 230 m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = logicalWidth(); 231 232 SubtreeLayoutScope layoutScope(*this); 233 234 // Use calcWidth/Height to get the new width/height, since this will take the full page zoom factor into account. 235 bool relayoutChildren = !shouldUsePrintingLayout() && (!m_frameView || width() != viewWidth() || height() != viewHeight()); 236 if (relayoutChildren) { 237 layoutScope.setChildNeedsLayout(this); 238 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { 239 if (child->isSVGRoot()) 240 continue; 241 242 if ((child->isBox() && toRenderBox(child)->hasRelativeLogicalHeight()) 243 || child->style()->logicalHeight().isPercent() 244 || child->style()->logicalMinHeight().isPercent() 245 || child->style()->logicalMaxHeight().isPercent()) 246 layoutScope.setChildNeedsLayout(child); 247 } 248 249 if (document().svgExtensions()) 250 document().accessSVGExtensions().invalidateSVGRootsWithRelativeLengthDescendents(&layoutScope); 251 } 252 253 ASSERT(!m_layoutState); 254 if (!needsLayout()) 255 return; 256 257 LayoutState rootLayoutState(pageLogicalHeight(), pageLogicalHeightChanged(), *this); 258 259 m_pageLogicalHeightChanged = false; 260 261 layoutContent(); 262 263 #ifndef NDEBUG 264 checkLayoutState(); 265 #endif 266 clearNeedsLayout(); 267 } 268 269 void RenderView::mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState& transformState, MapCoordinatesFlags mode, bool* wasFixed) const 270 { 271 ASSERT_UNUSED(wasFixed, !wasFixed || *wasFixed == static_cast<bool>(mode & IsFixed)); 272 273 if (!repaintContainer && mode & UseTransforms && shouldUseTransformFromContainer(0)) { 274 TransformationMatrix t; 275 getTransformFromContainer(0, LayoutSize(), t); 276 transformState.applyTransform(t); 277 } 278 279 if (mode & IsFixed && m_frameView) 280 transformState.move(m_frameView->scrollOffsetForFixedPosition()); 281 282 if (repaintContainer == this) 283 return; 284 285 if (mode & TraverseDocumentBoundaries) { 286 if (RenderObject* parentDocRenderer = frame()->ownerRenderer()) { 287 transformState.move(-frame()->view()->scrollOffset()); 288 if (parentDocRenderer->isBox()) 289 transformState.move(toLayoutSize(toRenderBox(parentDocRenderer)->contentBoxRect().location())); 290 parentDocRenderer->mapLocalToContainer(repaintContainer, transformState, mode, wasFixed); 291 return; 292 } 293 } 294 295 // If a container was specified, and was not 0 or the RenderView, 296 // then we should have found it by now. 297 ASSERT_ARG(repaintContainer, !repaintContainer); 298 } 299 300 const RenderObject* RenderView::pushMappingToContainer(const RenderLayerModelObject* ancestorToStopAt, RenderGeometryMap& geometryMap) const 301 { 302 LayoutSize offsetForFixedPosition; 303 LayoutSize offset; 304 RenderObject* container = 0; 305 306 if (m_frameView) 307 offsetForFixedPosition = m_frameView->scrollOffsetForFixedPosition(); 308 309 if (geometryMap.mapCoordinatesFlags() & TraverseDocumentBoundaries) { 310 if (RenderPart* parentDocRenderer = frame()->ownerRenderer()) { 311 offset = -m_frameView->scrollOffset(); 312 offset += toLayoutSize(parentDocRenderer->contentBoxRect().location()); 313 container = parentDocRenderer; 314 } 315 } 316 317 // If a container was specified, and was not 0 or the RenderView, then we 318 // should have found it by now unless we're traversing to a parent document. 319 ASSERT_ARG(ancestorToStopAt, !ancestorToStopAt || ancestorToStopAt == this || container); 320 321 if ((!ancestorToStopAt || container) && shouldUseTransformFromContainer(container)) { 322 TransformationMatrix t; 323 getTransformFromContainer(container, LayoutSize(), t); 324 geometryMap.push(this, t, false, false, false, true, offsetForFixedPosition); 325 } else { 326 geometryMap.push(this, offset, false, false, false, false, offsetForFixedPosition); 327 } 328 329 return container; 330 } 331 332 void RenderView::mapAbsoluteToLocalPoint(MapCoordinatesFlags mode, TransformState& transformState) const 333 { 334 if (mode & IsFixed && m_frameView) 335 transformState.move(m_frameView->scrollOffsetForFixedPosition()); 336 337 if (mode & UseTransforms && shouldUseTransformFromContainer(0)) { 338 TransformationMatrix t; 339 getTransformFromContainer(0, LayoutSize(), t); 340 transformState.applyTransform(t); 341 } 342 } 343 344 void RenderView::computeSelfHitTestRects(Vector<LayoutRect>& rects, const LayoutPoint&) const 345 { 346 // Record the entire size of the contents of the frame. Note that we don't just 347 // use the viewport size (containing block) here because we want to ensure this includes 348 // all children (so we can avoid walking them explicitly). 349 rects.append(LayoutRect(LayoutPoint::zero(), frameView()->contentsSize())); 350 } 351 352 void RenderView::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset) 353 { 354 // If we ever require layout but receive a paint anyway, something has gone horribly wrong. 355 ASSERT(!needsLayout()); 356 // RenderViews should never be called to paint with an offset not on device pixels. 357 ASSERT(LayoutPoint(IntPoint(paintOffset.x(), paintOffset.y())) == paintOffset); 358 359 ANNOTATE_GRAPHICS_CONTEXT(paintInfo, this); 360 361 // This avoids painting garbage between columns if there is a column gap. 362 if (m_frameView && style()->isOverflowPaged()) 363 paintInfo.context->fillRect(paintInfo.rect, m_frameView->baseBackgroundColor()); 364 365 paintObject(paintInfo, paintOffset); 366 } 367 368 static inline bool rendererObscuresBackground(RenderBox* rootBox) 369 { 370 ASSERT(rootBox); 371 RenderStyle* style = rootBox->style(); 372 if (style->visibility() != VISIBLE 373 || style->opacity() != 1 374 || style->hasFilter() 375 || style->hasTransform()) 376 return false; 377 378 if (rootBox->compositingState() == PaintsIntoOwnBacking) 379 return false; 380 381 const RenderObject* rootRenderer = rootBox->rendererForRootBackground(); 382 if (rootRenderer->style()->backgroundClip() == TextFillBox) 383 return false; 384 385 return true; 386 } 387 388 bool RenderView::rootFillsViewportBackground(RenderBox* rootBox) const 389 { 390 ASSERT(rootBox); 391 // CSS Boxes always fill the viewport background (see paintRootBoxFillLayers) 392 if (!rootBox->isSVG()) 393 return true; 394 395 return rootBox->frameRect().contains(frameRect()); 396 } 397 398 void RenderView::paintBoxDecorations(PaintInfo& paintInfo, const LayoutPoint&) 399 { 400 // Check to see if we are enclosed by a layer that requires complex painting rules. If so, we cannot blit 401 // when scrolling, and we need to use slow repaints. Examples of layers that require this are transparent layers, 402 // layers with reflections, or transformed layers. 403 // FIXME: This needs to be dynamic. We should be able to go back to blitting if we ever stop being inside 404 // a transform, transparency layer, etc. 405 Element* elt; 406 for (elt = document().ownerElement(); view() && elt && elt->renderer(); elt = elt->document().ownerElement()) { 407 RenderLayer* layer = elt->renderer()->enclosingLayer(); 408 if (layer->cannotBlitToWindow()) { 409 frameView()->setCannotBlitToWindow(); 410 break; 411 } 412 413 if (layer->enclosingCompositingLayerForRepaint()) { 414 frameView()->setCannotBlitToWindow(); 415 break; 416 } 417 } 418 419 if (document().ownerElement() || !view()) 420 return; 421 422 if (paintInfo.skipRootBackground()) 423 return; 424 425 bool shouldPaintBackground = true; 426 Node* documentElement = document().documentElement(); 427 if (RenderBox* rootBox = documentElement ? toRenderBox(documentElement->renderer()) : 0) 428 shouldPaintBackground = !rootFillsViewportBackground(rootBox) || !rendererObscuresBackground(rootBox); 429 430 // If painting will entirely fill the view, no need to fill the background. 431 if (!shouldPaintBackground) 432 return; 433 434 // This code typically only executes if the root element's visibility has been set to hidden, 435 // if there is a transform on the <html>, or if there is a page scale factor less than 1. 436 // Only fill with the base background color (typically white) if we're the root document, 437 // since iframes/frames with no background in the child document should show the parent's background. 438 if (frameView()->isTransparent()) // FIXME: This needs to be dynamic. We should be able to go back to blitting if we ever stop being transparent. 439 frameView()->setCannotBlitToWindow(); // The parent must show behind the child. 440 else { 441 Color baseColor = frameView()->baseBackgroundColor(); 442 if (baseColor.alpha()) { 443 CompositeOperator previousOperator = paintInfo.context->compositeOperation(); 444 paintInfo.context->setCompositeOperation(CompositeCopy); 445 paintInfo.context->fillRect(paintInfo.rect, baseColor); 446 paintInfo.context->setCompositeOperation(previousOperator); 447 } else { 448 paintInfo.context->clearRect(paintInfo.rect); 449 } 450 } 451 } 452 453 void RenderView::invalidateTreeAfterLayout(const RenderLayerModelObject& paintInvalidationContainer) 454 { 455 ASSERT(RuntimeEnabledFeatures::repaintAfterLayoutEnabled()); 456 ASSERT(!needsLayout()); 457 458 // We specifically need to repaint the viewRect since other renderers 459 // short-circuit on full-repaint. 460 if (doingFullRepaint() && !viewRect().isEmpty()) 461 repaintViewRectangle(viewRect()); 462 463 LayoutState rootLayoutState(0, false, *this); 464 RenderBlock::invalidateTreeAfterLayout(paintInvalidationContainer); 465 } 466 467 void RenderView::repaintViewRectangle(const LayoutRect& repaintRect) const 468 { 469 ASSERT(!repaintRect.isEmpty()); 470 471 if (document().printing() || !m_frameView) 472 return; 473 474 // We always just invalidate the root view, since we could be an iframe that is clipped out 475 // or even invisible. 476 Element* owner = document().ownerElement(); 477 if (layer()->compositingState() == PaintsIntoOwnBacking) { 478 layer()->repainter().setBackingNeedsRepaintInRect(repaintRect); 479 } else if (!owner) { 480 m_frameView->contentRectangleForPaintInvalidation(pixelSnappedIntRect(repaintRect)); 481 } else if (RenderBox* obj = owner->renderBox()) { 482 LayoutRect viewRectangle = viewRect(); 483 LayoutRect rectToRepaint = intersection(repaintRect, viewRectangle); 484 485 // Subtract out the contentsX and contentsY offsets to get our coords within the viewing 486 // rectangle. 487 rectToRepaint.moveBy(-viewRectangle.location()); 488 489 // FIXME: Hardcoded offsets here are not good. 490 rectToRepaint.moveBy(obj->contentBoxRect().location()); 491 obj->invalidatePaintRectangle(rectToRepaint); 492 } 493 } 494 495 void RenderView::repaintViewAndCompositedLayers() 496 { 497 paintInvalidationForWholeRenderer(); 498 499 // The only way we know how to hit these ASSERTS below this point is via the Chromium OS login screen. 500 DisableCompositingQueryAsserts disabler; 501 502 if (compositor()->inCompositingMode()) 503 compositor()->repaintCompositedLayers(); 504 } 505 506 void RenderView::mapRectToPaintInvalidationBacking(const RenderLayerModelObject* paintInvalidationContainer, LayoutRect& rect, bool fixed) const 507 { 508 // If a container was specified, and was not 0 or the RenderView, 509 // then we should have found it by now. 510 ASSERT_ARG(paintInvalidationContainer, !paintInvalidationContainer || paintInvalidationContainer == this); 511 512 if (document().printing()) 513 return; 514 515 if (style()->isFlippedBlocksWritingMode()) { 516 // We have to flip by hand since the view's logical height has not been determined. We 517 // can use the viewport width and height. 518 if (style()->isHorizontalWritingMode()) 519 rect.setY(viewHeight() - rect.maxY()); 520 else 521 rect.setX(viewWidth() - rect.maxX()); 522 } 523 524 if (fixed && m_frameView) { 525 rect.move(m_frameView->scrollOffsetForFixedPosition()); 526 // If we have a pending scroll, invalidate the previous scroll position. 527 if (!m_frameView->pendingScrollDelta().isZero()) { 528 rect.move(-m_frameView->pendingScrollDelta()); 529 } 530 } 531 532 // Apply our transform if we have one (because of full page zooming). 533 if (!paintInvalidationContainer && layer() && layer()->transform()) 534 rect = layer()->transform()->mapRect(rect); 535 } 536 537 void RenderView::absoluteRects(Vector<IntRect>& rects, const LayoutPoint& accumulatedOffset) const 538 { 539 rects.append(pixelSnappedIntRect(accumulatedOffset, layer()->size())); 540 } 541 542 void RenderView::absoluteQuads(Vector<FloatQuad>& quads, bool* wasFixed) const 543 { 544 if (wasFixed) 545 *wasFixed = false; 546 quads.append(FloatRect(FloatPoint(), layer()->size())); 547 } 548 549 static RenderObject* rendererAfterPosition(RenderObject* object, unsigned offset) 550 { 551 if (!object) 552 return 0; 553 554 RenderObject* child = object->childAt(offset); 555 return child ? child : object->nextInPreOrderAfterChildren(); 556 } 557 558 IntRect RenderView::selectionBounds(bool clipToVisibleContent) const 559 { 560 typedef HashMap<RenderObject*, OwnPtr<RenderSelectionInfo> > SelectionMap; 561 SelectionMap selectedObjects; 562 563 RenderObject* os = m_selectionStart; 564 RenderObject* stop = rendererAfterPosition(m_selectionEnd, m_selectionEndPos); 565 while (os && os != stop) { 566 if ((os->canBeSelectionLeaf() || os == m_selectionStart || os == m_selectionEnd) && os->selectionState() != SelectionNone) { 567 // Blocks are responsible for painting line gaps and margin gaps. They must be examined as well. 568 selectedObjects.set(os, adoptPtr(new RenderSelectionInfo(os, clipToVisibleContent))); 569 RenderBlock* cb = os->containingBlock(); 570 while (cb && !cb->isRenderView()) { 571 OwnPtr<RenderSelectionInfo>& blockInfo = selectedObjects.add(cb, nullptr).storedValue->value; 572 if (blockInfo) 573 break; 574 blockInfo = adoptPtr(new RenderSelectionInfo(cb, clipToVisibleContent)); 575 cb = cb->containingBlock(); 576 } 577 } 578 579 os = os->nextInPreOrder(); 580 } 581 582 // Now create a single bounding box rect that encloses the whole selection. 583 LayoutRect selRect; 584 SelectionMap::iterator end = selectedObjects.end(); 585 for (SelectionMap::iterator i = selectedObjects.begin(); i != end; ++i) { 586 RenderSelectionInfo* info = i->value.get(); 587 // RenderSelectionInfo::rect() is in the coordinates of the repaintContainer, so map to page coordinates. 588 LayoutRect currRect = info->rect(); 589 if (const RenderLayerModelObject* repaintContainer = info->repaintContainer()) { 590 FloatQuad absQuad = repaintContainer->localToAbsoluteQuad(FloatRect(currRect)); 591 currRect = absQuad.enclosingBoundingBox(); 592 } 593 selRect.unite(currRect); 594 } 595 return pixelSnappedIntRect(selRect); 596 } 597 598 void RenderView::repaintSelection() const 599 { 600 HashSet<RenderBlock*> processedBlocks; 601 602 RenderObject* end = rendererAfterPosition(m_selectionEnd, m_selectionEndPos); 603 for (RenderObject* o = m_selectionStart; o && o != end; o = o->nextInPreOrder()) { 604 if (!o->canBeSelectionLeaf() && o != m_selectionStart && o != m_selectionEnd) 605 continue; 606 if (o->selectionState() == SelectionNone) 607 continue; 608 609 RenderSelectionInfo(o, true).repaint(); 610 611 // Blocks are responsible for painting line gaps and margin gaps. They must be examined as well. 612 for (RenderBlock* block = o->containingBlock(); block && !block->isRenderView(); block = block->containingBlock()) { 613 if (!processedBlocks.add(block).isNewEntry) 614 break; 615 RenderSelectionInfo(block, true).repaint(); 616 } 617 } 618 } 619 620 // When exploring the RenderTree looking for the nodes involved in the Selection, sometimes it's 621 // required to change the traversing direction because the "start" position is below the "end" one. 622 static inline RenderObject* getNextOrPrevRenderObjectBasedOnDirection(const RenderObject* o, const RenderObject* stop, bool& continueExploring, bool& exploringBackwards) 623 { 624 RenderObject* next; 625 if (exploringBackwards) { 626 next = o->previousInPreOrder(); 627 continueExploring = next && !(next)->isRenderView(); 628 } else { 629 next = o->nextInPreOrder(); 630 continueExploring = next && next != stop; 631 exploringBackwards = !next && (next != stop); 632 if (exploringBackwards) { 633 next = stop->previousInPreOrder(); 634 continueExploring = next && !next->isRenderView(); 635 } 636 } 637 638 return next; 639 } 640 641 void RenderView::setSelection(RenderObject* start, int startPos, RenderObject* end, int endPos, SelectionRepaintMode blockRepaintMode) 642 { 643 // This code makes no assumptions as to if the rendering tree is up to date or not 644 // and will not try to update it. Currently clearSelection calls this 645 // (intentionally) without updating the rendering tree as it doesn't care. 646 // Other callers may want to force recalc style before calling this. 647 648 // Make sure both our start and end objects are defined. 649 // Check www.msnbc.com and try clicking around to find the case where this happened. 650 if ((start && !end) || (end && !start)) 651 return; 652 653 // Just return if the selection hasn't changed. 654 if (m_selectionStart == start && m_selectionStartPos == startPos && 655 m_selectionEnd == end && m_selectionEndPos == endPos) 656 return; 657 658 // Record the old selected objects. These will be used later 659 // when we compare against the new selected objects. 660 int oldStartPos = m_selectionStartPos; 661 int oldEndPos = m_selectionEndPos; 662 663 // Objects each have a single selection rect to examine. 664 typedef HashMap<RenderObject*, OwnPtr<RenderSelectionInfo> > SelectedObjectMap; 665 SelectedObjectMap oldSelectedObjects; 666 SelectedObjectMap newSelectedObjects; 667 668 // Blocks contain selected objects and fill gaps between them, either on the left, right, or in between lines and blocks. 669 // In order to get the repaint rect right, we have to examine left, middle, and right rects individually, since otherwise 670 // the union of those rects might remain the same even when changes have occurred. 671 typedef HashMap<RenderBlock*, OwnPtr<RenderBlockSelectionInfo> > SelectedBlockMap; 672 SelectedBlockMap oldSelectedBlocks; 673 SelectedBlockMap newSelectedBlocks; 674 675 RenderObject* os = m_selectionStart; 676 RenderObject* stop = rendererAfterPosition(m_selectionEnd, m_selectionEndPos); 677 bool exploringBackwards = false; 678 bool continueExploring = os && (os != stop); 679 while (continueExploring) { 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 oldSelectedObjects.set(os, adoptPtr(new RenderSelectionInfo(os, true))); 683 if (blockRepaintMode == RepaintNewXOROld) { 684 RenderBlock* cb = os->containingBlock(); 685 while (cb && !cb->isRenderView()) { 686 OwnPtr<RenderBlockSelectionInfo>& blockInfo = oldSelectedBlocks.add(cb, nullptr).storedValue->value; 687 if (blockInfo) 688 break; 689 blockInfo = adoptPtr(new RenderBlockSelectionInfo(cb)); 690 cb = cb->containingBlock(); 691 } 692 } 693 } 694 695 os = getNextOrPrevRenderObjectBasedOnDirection(os, stop, continueExploring, exploringBackwards); 696 } 697 698 // Now clear the selection. 699 SelectedObjectMap::iterator oldObjectsEnd = oldSelectedObjects.end(); 700 for (SelectedObjectMap::iterator i = oldSelectedObjects.begin(); i != oldObjectsEnd; ++i) 701 i->key->setSelectionStateIfNeeded(SelectionNone); 702 703 // set selection start and end 704 m_selectionStart = start; 705 m_selectionStartPos = startPos; 706 m_selectionEnd = end; 707 m_selectionEndPos = endPos; 708 709 // Update the selection status of all objects between m_selectionStart and m_selectionEnd 710 if (start && start == end) 711 start->setSelectionStateIfNeeded(SelectionBoth); 712 else { 713 if (start) 714 start->setSelectionStateIfNeeded(SelectionStart); 715 if (end) 716 end->setSelectionStateIfNeeded(SelectionEnd); 717 } 718 719 RenderObject* o = start; 720 stop = rendererAfterPosition(end, endPos); 721 722 while (o && o != stop) { 723 if (o != start && o != end && o->canBeSelectionLeaf()) 724 o->setSelectionStateIfNeeded(SelectionInside); 725 o = o->nextInPreOrder(); 726 } 727 728 if (blockRepaintMode != RepaintNothing) 729 layer()->clearBlockSelectionGapsBounds(); 730 731 // Now that the selection state has been updated for the new objects, walk them again and 732 // put them in the new objects list. 733 o = start; 734 exploringBackwards = false; 735 continueExploring = o && (o != stop); 736 while (continueExploring) { 737 if ((o->canBeSelectionLeaf() || o == start || o == end) && o->selectionState() != SelectionNone) { 738 newSelectedObjects.set(o, adoptPtr(new RenderSelectionInfo(o, true))); 739 RenderBlock* cb = o->containingBlock(); 740 while (cb && !cb->isRenderView()) { 741 OwnPtr<RenderBlockSelectionInfo>& blockInfo = newSelectedBlocks.add(cb, nullptr).storedValue->value; 742 if (blockInfo) 743 break; 744 blockInfo = adoptPtr(new RenderBlockSelectionInfo(cb)); 745 cb = cb->containingBlock(); 746 } 747 } 748 749 o = getNextOrPrevRenderObjectBasedOnDirection(o, stop, continueExploring, exploringBackwards); 750 } 751 752 if (!m_frameView || blockRepaintMode == RepaintNothing) 753 return; 754 755 // Have any of the old selected objects changed compared to the new selection? 756 for (SelectedObjectMap::iterator i = oldSelectedObjects.begin(); i != oldObjectsEnd; ++i) { 757 RenderObject* obj = i->key; 758 RenderSelectionInfo* newInfo = newSelectedObjects.get(obj); 759 RenderSelectionInfo* oldInfo = i->value.get(); 760 if (!newInfo || oldInfo->rect() != newInfo->rect() || oldInfo->state() != newInfo->state() || 761 (m_selectionStart == obj && oldStartPos != m_selectionStartPos) || 762 (m_selectionEnd == obj && oldEndPos != m_selectionEndPos)) { 763 oldInfo->repaint(); 764 if (newInfo) { 765 newInfo->repaint(); 766 newSelectedObjects.remove(obj); 767 } 768 } 769 } 770 771 // Any new objects that remain were not found in the old objects dict, and so they need to be updated. 772 SelectedObjectMap::iterator newObjectsEnd = newSelectedObjects.end(); 773 for (SelectedObjectMap::iterator i = newSelectedObjects.begin(); i != newObjectsEnd; ++i) 774 i->value->repaint(); 775 776 // Have any of the old blocks changed? 777 SelectedBlockMap::iterator oldBlocksEnd = oldSelectedBlocks.end(); 778 for (SelectedBlockMap::iterator i = oldSelectedBlocks.begin(); i != oldBlocksEnd; ++i) { 779 RenderBlock* block = i->key; 780 RenderBlockSelectionInfo* newInfo = newSelectedBlocks.get(block); 781 RenderBlockSelectionInfo* oldInfo = i->value.get(); 782 if (!newInfo || oldInfo->rects() != newInfo->rects() || oldInfo->state() != newInfo->state()) { 783 oldInfo->repaint(); 784 if (newInfo) { 785 newInfo->repaint(); 786 newSelectedBlocks.remove(block); 787 } 788 } 789 } 790 791 // Any new blocks that remain were not found in the old blocks dict, and so they need to be updated. 792 SelectedBlockMap::iterator newBlocksEnd = newSelectedBlocks.end(); 793 for (SelectedBlockMap::iterator i = newSelectedBlocks.begin(); i != newBlocksEnd; ++i) 794 i->value->repaint(); 795 } 796 797 void RenderView::getSelection(RenderObject*& startRenderer, int& startOffset, RenderObject*& endRenderer, int& endOffset) const 798 { 799 startRenderer = m_selectionStart; 800 startOffset = m_selectionStartPos; 801 endRenderer = m_selectionEnd; 802 endOffset = m_selectionEndPos; 803 } 804 805 void RenderView::clearSelection() 806 { 807 layer()->repaintBlockSelectionGaps(); 808 setSelection(0, -1, 0, -1, RepaintNewMinusOld); 809 } 810 811 void RenderView::selectionStartEnd(int& startPos, int& endPos) const 812 { 813 startPos = m_selectionStartPos; 814 endPos = m_selectionEndPos; 815 } 816 817 bool RenderView::shouldUsePrintingLayout() const 818 { 819 if (!document().printing() || !m_frameView) 820 return false; 821 return m_frameView->frame().shouldUsePrintingLayout(); 822 } 823 824 LayoutRect RenderView::viewRect() const 825 { 826 if (shouldUsePrintingLayout()) 827 return LayoutRect(LayoutPoint(), size()); 828 if (m_frameView) 829 return m_frameView->visibleContentRect(); 830 return LayoutRect(); 831 } 832 833 IntRect RenderView::unscaledDocumentRect() const 834 { 835 LayoutRect overflowRect(layoutOverflowRect()); 836 flipForWritingMode(overflowRect); 837 return pixelSnappedIntRect(overflowRect); 838 } 839 840 bool RenderView::rootBackgroundIsEntirelyFixed() const 841 { 842 if (RenderObject* backgroundRenderer = this->backgroundRenderer()) 843 return backgroundRenderer->hasEntirelyFixedBackground(); 844 return false; 845 } 846 847 RenderObject* RenderView::backgroundRenderer() const 848 { 849 if (Element* documentElement = document().documentElement()) { 850 if (RenderObject* rootObject = documentElement->renderer()) 851 return rootObject->rendererForRootBackground(); 852 } 853 return 0; 854 } 855 856 LayoutRect RenderView::backgroundRect(RenderBox* backgroundRenderer) const 857 { 858 if (!hasColumns()) 859 return unscaledDocumentRect(); 860 861 ColumnInfo* columnInfo = this->columnInfo(); 862 LayoutRect backgroundRect(0, 0, columnInfo->desiredColumnWidth(), columnInfo->columnHeight() * columnInfo->columnCount()); 863 if (!isHorizontalWritingMode()) 864 backgroundRect = backgroundRect.transposedRect(); 865 backgroundRenderer->flipForWritingMode(backgroundRect); 866 867 return backgroundRect; 868 } 869 870 IntRect RenderView::documentRect() const 871 { 872 FloatRect overflowRect(unscaledDocumentRect()); 873 if (hasTransform()) 874 overflowRect = layer()->currentTransform().mapRect(overflowRect); 875 return IntRect(overflowRect); 876 } 877 878 int RenderView::viewHeight(IncludeScrollbarsInRect scrollbarInclusion) const 879 { 880 int height = 0; 881 if (!shouldUsePrintingLayout() && m_frameView) 882 height = m_frameView->layoutSize(scrollbarInclusion).height(); 883 884 return height; 885 } 886 887 int RenderView::viewWidth(IncludeScrollbarsInRect scrollbarInclusion) const 888 { 889 int width = 0; 890 if (!shouldUsePrintingLayout() && m_frameView) 891 width = m_frameView->layoutSize(scrollbarInclusion).width(); 892 893 return width; 894 } 895 896 int RenderView::viewLogicalHeight() const 897 { 898 return style()->isHorizontalWritingMode() ? viewHeight(ExcludeScrollbars) : viewWidth(ExcludeScrollbars); 899 } 900 901 LayoutUnit RenderView::viewLogicalHeightForPercentages() const 902 { 903 if (shouldUsePrintingLayout()) 904 return pageLogicalHeight(); 905 return viewLogicalHeight(); 906 } 907 908 float RenderView::zoomFactor() const 909 { 910 return m_frameView->frame().pageZoomFactor(); 911 } 912 913 void RenderView::updateHitTestResult(HitTestResult& result, const LayoutPoint& point) 914 { 915 if (result.innerNode()) 916 return; 917 918 Node* node = document().documentElement(); 919 if (node) { 920 result.setInnerNode(node); 921 if (!result.innerNonSharedNode()) 922 result.setInnerNonSharedNode(node); 923 924 LayoutPoint adjustedPoint = point; 925 offsetForContents(adjustedPoint); 926 927 result.setLocalPoint(adjustedPoint); 928 } 929 } 930 931 bool RenderView::usesCompositing() const 932 { 933 return m_compositor && m_compositor->staleInCompositingMode(); 934 } 935 936 RenderLayerCompositor* RenderView::compositor() 937 { 938 if (!m_compositor) 939 m_compositor = adoptPtr(new RenderLayerCompositor(*this)); 940 941 return m_compositor.get(); 942 } 943 944 void RenderView::setIsInWindow(bool isInWindow) 945 { 946 if (m_compositor) 947 m_compositor->setIsInWindow(isInWindow); 948 } 949 950 FlowThreadController* RenderView::flowThreadController() 951 { 952 if (!m_flowThreadController) 953 m_flowThreadController = FlowThreadController::create(); 954 955 return m_flowThreadController.get(); 956 } 957 958 void RenderView::pushLayoutState(LayoutState& layoutState) 959 { 960 if (m_flowThreadController) { 961 RenderFlowThread* currentFlowThread = m_flowThreadController->currentRenderFlowThread(); 962 if (currentFlowThread) 963 currentFlowThread->pushFlowThreadLayoutState(layoutState.renderer()); 964 } 965 m_layoutState = &layoutState; 966 } 967 968 void RenderView::popLayoutState() 969 { 970 ASSERT(m_layoutState); 971 m_layoutState = m_layoutState->next(); 972 if (!m_flowThreadController) 973 return; 974 975 RenderFlowThread* currentFlowThread = m_flowThreadController->currentRenderFlowThread(); 976 if (!currentFlowThread) 977 return; 978 979 currentFlowThread->popFlowThreadLayoutState(); 980 } 981 982 IntervalArena* RenderView::intervalArena() 983 { 984 if (!m_intervalArena) 985 m_intervalArena = IntervalArena::create(); 986 return m_intervalArena.get(); 987 } 988 989 bool RenderView::backgroundIsKnownToBeOpaqueInRect(const LayoutRect&) const 990 { 991 // FIXME: Remove this main frame check. Same concept applies to subframes too. 992 if (!frame()->isMainFrame()) 993 return false; 994 995 return m_frameView->hasOpaqueBackground(); 996 } 997 998 double RenderView::layoutViewportWidth() const 999 { 1000 float scale = m_frameView ? m_frameView->frame().pageZoomFactor() : 1; 1001 return viewWidth(IncludeScrollbars) / scale; 1002 } 1003 1004 double RenderView::layoutViewportHeight() const 1005 { 1006 float scale = m_frameView ? m_frameView->frame().pageZoomFactor() : 1; 1007 return viewHeight(IncludeScrollbars) / scale; 1008 } 1009 1010 } // namespace WebCore 1011