1 /*
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public License
16 * along with this library; see the file COPYING.LIB. If not, write to
17 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 */
20
21 #include "config.h"
22 #include "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
RenderView(Document * document)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
~RenderView()74 RenderView::~RenderView()
75 {
76 }
77
hitTest(const HitTestRequest & request,HitTestResult & result)78 bool RenderView::hitTest(const HitTestRequest& request, HitTestResult& result)
79 {
80 return hitTest(request, result.hitTestLocation(), result);
81 }
82
hitTest(const HitTestRequest & request,const HitTestLocation & location,HitTestResult & result)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
computeLogicalHeight(LayoutUnit logicalHeight,LayoutUnit,LogicalExtentComputedValues & computedValues) const96 void RenderView::computeLogicalHeight(LayoutUnit logicalHeight, LayoutUnit, LogicalExtentComputedValues& computedValues) const
97 {
98 computedValues.m_extent = (!shouldUsePrintingLayout() && m_frameView) ? LayoutUnit(viewLogicalHeight()) : logicalHeight;
99 }
100
updateLogicalWidth()101 void RenderView::updateLogicalWidth()
102 {
103 if (!shouldUsePrintingLayout() && m_frameView)
104 setLogicalWidth(viewLogicalWidth());
105 }
106
availableLogicalHeight(AvailableLogicalHeightType heightType) const107 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
isChildAllowed(RenderObject * child,RenderStyle *) const115 bool RenderView::isChildAllowed(RenderObject* child, RenderStyle*) const
116 {
117 return child->isBox();
118 }
119
canCenterDialog(const RenderStyle * style)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
positionDialog(RenderBox * box)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
positionDialogs()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
layoutContent()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
checkLayoutState()180 void RenderView::checkLayoutState()
181 {
182 if (!RuntimeEnabledFeatures::repaintAfterLayoutEnabled()) {
183 ASSERT(layoutDeltaMatches(LayoutSize()));
184 }
185 ASSERT(!m_layoutState->next());
186 }
187 #endif
188
shouldDoFullRepaintForNextLayout() const189 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
layout()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
mapLocalToContainer(const RenderLayerModelObject * repaintContainer,TransformState & transformState,MapCoordinatesFlags mode,bool * wasFixed) const269 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
pushMappingToContainer(const RenderLayerModelObject * ancestorToStopAt,RenderGeometryMap & geometryMap) const300 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
mapAbsoluteToLocalPoint(MapCoordinatesFlags mode,TransformState & transformState) const332 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
computeSelfHitTestRects(Vector<LayoutRect> & rects,const LayoutPoint &) const344 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
paint(PaintInfo & paintInfo,const LayoutPoint & paintOffset)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
rendererObscuresBackground(RenderBox * rootBox)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
rootFillsViewportBackground(RenderBox * rootBox) const388 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
paintBoxDecorations(PaintInfo & paintInfo,const LayoutPoint &)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
invalidateTreeAfterLayout(const RenderLayerModelObject & paintInvalidationContainer)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
repaintViewRectangle(const LayoutRect & repaintRect) const467 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
repaintViewAndCompositedLayers()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
mapRectToPaintInvalidationBacking(const RenderLayerModelObject * paintInvalidationContainer,LayoutRect & rect,bool fixed) const506 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
absoluteRects(Vector<IntRect> & rects,const LayoutPoint & accumulatedOffset) const537 void RenderView::absoluteRects(Vector<IntRect>& rects, const LayoutPoint& accumulatedOffset) const
538 {
539 rects.append(pixelSnappedIntRect(accumulatedOffset, layer()->size()));
540 }
541
absoluteQuads(Vector<FloatQuad> & quads,bool * wasFixed) const542 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
rendererAfterPosition(RenderObject * object,unsigned offset)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
selectionBounds(bool clipToVisibleContent) const558 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
repaintSelection() const598 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.
getNextOrPrevRenderObjectBasedOnDirection(const RenderObject * o,const RenderObject * stop,bool & continueExploring,bool & exploringBackwards)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
setSelection(RenderObject * start,int startPos,RenderObject * end,int endPos,SelectionRepaintMode blockRepaintMode)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
getSelection(RenderObject * & startRenderer,int & startOffset,RenderObject * & endRenderer,int & endOffset) const797 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
clearSelection()805 void RenderView::clearSelection()
806 {
807 layer()->repaintBlockSelectionGaps();
808 setSelection(0, -1, 0, -1, RepaintNewMinusOld);
809 }
810
selectionStartEnd(int & startPos,int & endPos) const811 void RenderView::selectionStartEnd(int& startPos, int& endPos) const
812 {
813 startPos = m_selectionStartPos;
814 endPos = m_selectionEndPos;
815 }
816
shouldUsePrintingLayout() const817 bool RenderView::shouldUsePrintingLayout() const
818 {
819 if (!document().printing() || !m_frameView)
820 return false;
821 return m_frameView->frame().shouldUsePrintingLayout();
822 }
823
viewRect() const824 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
unscaledDocumentRect() const833 IntRect RenderView::unscaledDocumentRect() const
834 {
835 LayoutRect overflowRect(layoutOverflowRect());
836 flipForWritingMode(overflowRect);
837 return pixelSnappedIntRect(overflowRect);
838 }
839
rootBackgroundIsEntirelyFixed() const840 bool RenderView::rootBackgroundIsEntirelyFixed() const
841 {
842 if (RenderObject* backgroundRenderer = this->backgroundRenderer())
843 return backgroundRenderer->hasEntirelyFixedBackground();
844 return false;
845 }
846
backgroundRenderer() const847 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
backgroundRect(RenderBox * backgroundRenderer) const856 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
documentRect() const870 IntRect RenderView::documentRect() const
871 {
872 FloatRect overflowRect(unscaledDocumentRect());
873 if (hasTransform())
874 overflowRect = layer()->currentTransform().mapRect(overflowRect);
875 return IntRect(overflowRect);
876 }
877
viewHeight(IncludeScrollbarsInRect scrollbarInclusion) const878 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
viewWidth(IncludeScrollbarsInRect scrollbarInclusion) const887 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
viewLogicalHeight() const896 int RenderView::viewLogicalHeight() const
897 {
898 return style()->isHorizontalWritingMode() ? viewHeight(ExcludeScrollbars) : viewWidth(ExcludeScrollbars);
899 }
900
viewLogicalHeightForPercentages() const901 LayoutUnit RenderView::viewLogicalHeightForPercentages() const
902 {
903 if (shouldUsePrintingLayout())
904 return pageLogicalHeight();
905 return viewLogicalHeight();
906 }
907
zoomFactor() const908 float RenderView::zoomFactor() const
909 {
910 return m_frameView->frame().pageZoomFactor();
911 }
912
updateHitTestResult(HitTestResult & result,const LayoutPoint & point)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
usesCompositing() const931 bool RenderView::usesCompositing() const
932 {
933 return m_compositor && m_compositor->staleInCompositingMode();
934 }
935
compositor()936 RenderLayerCompositor* RenderView::compositor()
937 {
938 if (!m_compositor)
939 m_compositor = adoptPtr(new RenderLayerCompositor(*this));
940
941 return m_compositor.get();
942 }
943
setIsInWindow(bool isInWindow)944 void RenderView::setIsInWindow(bool isInWindow)
945 {
946 if (m_compositor)
947 m_compositor->setIsInWindow(isInWindow);
948 }
949
flowThreadController()950 FlowThreadController* RenderView::flowThreadController()
951 {
952 if (!m_flowThreadController)
953 m_flowThreadController = FlowThreadController::create();
954
955 return m_flowThreadController.get();
956 }
957
pushLayoutState(LayoutState & layoutState)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
popLayoutState()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
intervalArena()982 IntervalArena* RenderView::intervalArena()
983 {
984 if (!m_intervalArena)
985 m_intervalArena = IntervalArena::create();
986 return m_intervalArena.get();
987 }
988
backgroundIsKnownToBeOpaqueInRect(const LayoutRect &) const989 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
layoutViewportWidth() const998 double RenderView::layoutViewportWidth() const
999 {
1000 float scale = m_frameView ? m_frameView->frame().pageZoomFactor() : 1;
1001 return viewWidth(IncludeScrollbars) / scale;
1002 }
1003
layoutViewportHeight() const1004 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