• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/HTMLFrameOwnerElement.h"
28 #include "core/html/HTMLIFrameElement.h"
29 #include "core/page/Page.h"
30 #include "core/paint/ViewPainter.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/RenderPart.h"
39 #include "core/rendering/RenderQuote.h"
40 #include "core/rendering/RenderSelectionInfo.h"
41 #include "core/rendering/compositing/CompositedLayerMapping.h"
42 #include "core/rendering/compositing/RenderLayerCompositor.h"
43 #include "core/svg/SVGDocumentExtensions.h"
44 #include "platform/TraceEvent.h"
45 #include "platform/geometry/FloatQuad.h"
46 #include "platform/geometry/TransformState.h"
47 #include "platform/graphics/GraphicsContext.h"
48 
49 namespace blink {
50 
RenderView(Document * document)51 RenderView::RenderView(Document* document)
52     : RenderBlockFlow(document)
53     , m_frameView(document->view())
54     , m_selectionStart(nullptr)
55     , m_selectionEnd(nullptr)
56     , m_selectionStartPos(-1)
57     , m_selectionEndPos(-1)
58     , m_pageLogicalHeight(0)
59     , m_pageLogicalHeightChanged(false)
60     , m_layoutState(0)
61     , m_renderQuoteHead(nullptr)
62     , m_renderCounterCount(0)
63     , m_hitTestCount(0)
64 {
65     // init RenderObject attributes
66     setInline(false);
67 
68     m_minPreferredLogicalWidth = 0;
69     m_maxPreferredLogicalWidth = 0;
70 
71     setPreferredLogicalWidthsDirty(MarkOnlyThis);
72 
73     setPositionState(AbsolutePosition); // to 0,0 :)
74 }
75 
~RenderView()76 RenderView::~RenderView()
77 {
78 }
79 
trace(Visitor * visitor)80 void RenderView::trace(Visitor* visitor)
81 {
82     visitor->trace(m_selectionStart);
83     visitor->trace(m_selectionEnd);
84     visitor->trace(m_renderQuoteHead);
85     RenderBlockFlow::trace(visitor);
86 }
87 
hitTest(const HitTestRequest & request,HitTestResult & result)88 bool RenderView::hitTest(const HitTestRequest& request, HitTestResult& result)
89 {
90     return hitTest(request, result.hitTestLocation(), result);
91 }
92 
hitTest(const HitTestRequest & request,const HitTestLocation & location,HitTestResult & result)93 bool RenderView::hitTest(const HitTestRequest& request, const HitTestLocation& location, HitTestResult& result)
94 {
95     TRACE_EVENT0("blink", "RenderView::hitTest");
96     m_hitTestCount++;
97 
98     // We have to recursively update layout/style here because otherwise, when the hit test recurses
99     // into a child document, it could trigger a layout on the parent document, which can destroy RenderLayers
100     // that are higher up in the call stack, leading to crashes.
101     // Note that Document::updateLayout calls its parent's updateLayout.
102     // FIXME: It should be the caller's responsibility to ensure an up-to-date layout.
103     frameView()->updateLayoutAndStyleIfNeededRecursive();
104 
105     bool hitLayer = layer()->hitTest(request, location, result);
106 
107     // ScrollView scrollbars are not the same as RenderLayer scrollbars tested by RenderLayer::hitTestOverflowControls,
108     // so we need to test ScrollView scrollbars separately here. Note that it's important we do this after
109     // the hit test above, because that may overwrite the entire HitTestResult when it finds a hit.
110     IntPoint viewPoint = location.roundedPoint() - frameView()->scrollOffset();
111     if (Scrollbar* frameScrollbar = frameView()->scrollbarAtViewPoint(viewPoint))
112         result.setScrollbar(frameScrollbar);
113 
114     return hitLayer;
115 }
116 
computeLogicalHeight(LayoutUnit logicalHeight,LayoutUnit,LogicalExtentComputedValues & computedValues) const117 void RenderView::computeLogicalHeight(LayoutUnit logicalHeight, LayoutUnit, LogicalExtentComputedValues& computedValues) const
118 {
119     computedValues.m_extent = (!shouldUsePrintingLayout() && m_frameView) ? LayoutUnit(viewLogicalHeight()) : logicalHeight;
120 }
121 
updateLogicalWidth()122 void RenderView::updateLogicalWidth()
123 {
124     if (!shouldUsePrintingLayout() && m_frameView)
125         setLogicalWidth(viewLogicalWidth());
126 }
127 
availableLogicalHeight(AvailableLogicalHeightType heightType) const128 LayoutUnit RenderView::availableLogicalHeight(AvailableLogicalHeightType heightType) const
129 {
130     // If we have columns, then the available logical height is reduced to the column height.
131     if (hasColumns())
132         return columnInfo()->columnHeight();
133     return RenderBlockFlow::availableLogicalHeight(heightType);
134 }
135 
isChildAllowed(RenderObject * child,RenderStyle *) const136 bool RenderView::isChildAllowed(RenderObject* child, RenderStyle*) const
137 {
138     return child->isBox();
139 }
140 
layoutContent()141 void RenderView::layoutContent()
142 {
143     ASSERT(needsLayout());
144 
145     RenderBlockFlow::layout();
146 
147 #if ENABLE(ASSERT)
148     checkLayoutState();
149 #endif
150 }
151 
152 #if ENABLE(ASSERT)
checkLayoutState()153 void RenderView::checkLayoutState()
154 {
155     ASSERT(!m_layoutState->next());
156 }
157 #endif
158 
shouldDoFullPaintInvalidationForNextLayout() const159 bool RenderView::shouldDoFullPaintInvalidationForNextLayout() const
160 {
161     // It's hard to predict here which of full paint invalidation or per-descendant paint invalidation costs less.
162     // For vertical writing mode or width change it's more likely that per-descendant paint invalidation
163     // eventually turns out to be full paint invalidation but with the cost to handle more layout states
164     // and discrete paint invalidation rects, so marking full paint invalidation here is more likely to cost less.
165     // Otherwise, per-descendant paint invalidation is more likely to avoid unnecessary full paint invalidation.
166 
167     if (shouldUsePrintingLayout())
168         return true;
169 
170     if (!style()->isHorizontalWritingMode() || width() != viewWidth())
171         return true;
172 
173     if (height() != viewHeight()) {
174         if (RenderObject* backgroundRenderer = this->backgroundRenderer()) {
175             // When background-attachment is 'fixed', we treat the viewport (instead of the 'root'
176             // i.e. html or body) as the background positioning area, and we should full paint invalidation
177             // viewport resize if the background image is not composited and needs full paint invalidation on
178             // background positioning area resize.
179             if (!m_compositor || !m_compositor->needsFixedRootBackgroundLayer(layer())) {
180                 if (backgroundRenderer->style()->hasFixedBackgroundImage()
181                     && mustInvalidateFillLayersPaintOnHeightChange(backgroundRenderer->style()->backgroundLayers()))
182                     return true;
183             }
184         }
185     }
186 
187     return false;
188 }
189 
layout()190 void RenderView::layout()
191 {
192     if (!document().paginated())
193         setPageLogicalHeight(0);
194 
195     if (shouldUsePrintingLayout())
196         m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = logicalWidth();
197 
198     SubtreeLayoutScope layoutScope(*this);
199 
200     // Use calcWidth/Height to get the new width/height, since this will take the full page zoom factor into account.
201     bool relayoutChildren = !shouldUsePrintingLayout() && (!m_frameView || width() != viewWidth() || height() != viewHeight());
202     if (relayoutChildren) {
203         layoutScope.setChildNeedsLayout(this);
204         for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
205             if (child->isSVGRoot())
206                 continue;
207 
208             if ((child->isBox() && toRenderBox(child)->hasRelativeLogicalHeight())
209                     || child->style()->logicalHeight().isPercent()
210                     || child->style()->logicalMinHeight().isPercent()
211                     || child->style()->logicalMaxHeight().isPercent())
212                 layoutScope.setChildNeedsLayout(child);
213         }
214 
215         if (document().svgExtensions())
216             document().accessSVGExtensions().invalidateSVGRootsWithRelativeLengthDescendents(&layoutScope);
217     }
218 
219     ASSERT(!m_layoutState);
220     if (!needsLayout())
221         return;
222 
223     LayoutState rootLayoutState(pageLogicalHeight(), pageLogicalHeightChanged(), *this);
224 
225     m_pageLogicalHeightChanged = false;
226 
227     layoutContent();
228 
229 #if ENABLE(ASSERT)
230     checkLayoutState();
231 #endif
232     clearNeedsLayout();
233 }
234 
mapLocalToContainer(const RenderLayerModelObject * paintInvalidationContainer,TransformState & transformState,MapCoordinatesFlags mode,bool * wasFixed,const PaintInvalidationState * paintInvalidationState) const235 void RenderView::mapLocalToContainer(const RenderLayerModelObject* paintInvalidationContainer, TransformState& transformState, MapCoordinatesFlags mode, bool* wasFixed, const PaintInvalidationState* paintInvalidationState) const
236 {
237     ASSERT_UNUSED(wasFixed, !wasFixed || *wasFixed == static_cast<bool>(mode & IsFixed));
238 
239     if (!paintInvalidationContainer && mode & UseTransforms && shouldUseTransformFromContainer(0)) {
240         TransformationMatrix t;
241         getTransformFromContainer(0, LayoutSize(), t);
242         transformState.applyTransform(t);
243     }
244 
245     if (mode & IsFixed && m_frameView)
246         transformState.move(m_frameView->scrollOffsetForFixedPosition());
247 
248     if (paintInvalidationContainer == this)
249         return;
250 
251     if (mode & TraverseDocumentBoundaries) {
252         if (RenderObject* parentDocRenderer = frame()->ownerRenderer()) {
253             transformState.move(-frame()->view()->scrollOffset());
254             if (parentDocRenderer->isBox())
255                 transformState.move(toLayoutSize(toRenderBox(parentDocRenderer)->contentBoxRect().location()));
256             parentDocRenderer->mapLocalToContainer(paintInvalidationContainer, transformState, mode, wasFixed, paintInvalidationState);
257             return;
258         }
259     }
260 }
261 
pushMappingToContainer(const RenderLayerModelObject * ancestorToStopAt,RenderGeometryMap & geometryMap) const262 const RenderObject* RenderView::pushMappingToContainer(const RenderLayerModelObject* ancestorToStopAt, RenderGeometryMap& geometryMap) const
263 {
264     LayoutSize offsetForFixedPosition;
265     LayoutSize offset;
266     RenderObject* container = 0;
267 
268     if (m_frameView)
269         offsetForFixedPosition = m_frameView->scrollOffsetForFixedPosition();
270 
271     if (geometryMap.mapCoordinatesFlags() & TraverseDocumentBoundaries) {
272         if (RenderPart* parentDocRenderer = frame()->ownerRenderer()) {
273             offset = -m_frameView->scrollOffset();
274             offset += toLayoutSize(parentDocRenderer->contentBoxRect().location());
275             container = parentDocRenderer;
276         }
277     }
278 
279     // If a container was specified, and was not 0 or the RenderView, then we
280     // should have found it by now unless we're traversing to a parent document.
281     ASSERT_ARG(ancestorToStopAt, !ancestorToStopAt || ancestorToStopAt == this || container);
282 
283     if ((!ancestorToStopAt || container) && shouldUseTransformFromContainer(container)) {
284         TransformationMatrix t;
285         getTransformFromContainer(container, LayoutSize(), t);
286         geometryMap.push(this, t, false, false, false, true, offsetForFixedPosition);
287     } else {
288         geometryMap.push(this, offset, false, false, false, false, offsetForFixedPosition);
289     }
290 
291     return container;
292 }
293 
mapAbsoluteToLocalPoint(MapCoordinatesFlags mode,TransformState & transformState) const294 void RenderView::mapAbsoluteToLocalPoint(MapCoordinatesFlags mode, TransformState& transformState) const
295 {
296     if (mode & IsFixed && m_frameView)
297         transformState.move(m_frameView->scrollOffsetForFixedPosition());
298 
299     if (mode & UseTransforms && shouldUseTransformFromContainer(0)) {
300         TransformationMatrix t;
301         getTransformFromContainer(0, LayoutSize(), t);
302         transformState.applyTransform(t);
303     }
304 }
305 
computeSelfHitTestRects(Vector<LayoutRect> & rects,const LayoutPoint &) const306 void RenderView::computeSelfHitTestRects(Vector<LayoutRect>& rects, const LayoutPoint&) const
307 {
308     // Record the entire size of the contents of the frame. Note that we don't just
309     // use the viewport size (containing block) here because we want to ensure this includes
310     // all children (so we can avoid walking them explicitly).
311     rects.append(LayoutRect(LayoutPoint::zero(), frameView()->contentsSize()));
312 }
313 
paint(PaintInfo & paintInfo,const LayoutPoint & paintOffset)314 void RenderView::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
315 {
316     ViewPainter(*this).paint(paintInfo, paintOffset);
317 }
318 
paintBoxDecorationBackground(PaintInfo & paintInfo,const LayoutPoint &)319 void RenderView::paintBoxDecorationBackground(PaintInfo& paintInfo, const LayoutPoint&)
320 {
321     ViewPainter(*this).paintBoxDecorationBackground(paintInfo);
322 }
323 
invalidateTreeIfNeeded(const PaintInvalidationState & paintInvalidationState)324 void RenderView::invalidateTreeIfNeeded(const PaintInvalidationState& paintInvalidationState)
325 {
326     ASSERT(!needsLayout());
327 
328     // We specifically need to issue paint invalidations for the viewRect since other renderers
329     // short-circuit on full-paint invalidation.
330     LayoutRect dirtyRect = viewRect();
331     if (doingFullPaintInvalidation() && !dirtyRect.isEmpty()) {
332         const RenderLayerModelObject* paintInvalidationContainer = &paintInvalidationState.paintInvalidationContainer();
333         mapRectToPaintInvalidationBacking(paintInvalidationContainer, dirtyRect, &paintInvalidationState);
334         invalidatePaintUsingContainer(paintInvalidationContainer, dirtyRect, InvalidationFull);
335     }
336     RenderBlock::invalidateTreeIfNeeded(paintInvalidationState);
337 }
338 
invalidatePaintForRectangle(const LayoutRect & paintInvalidationRect) const339 void RenderView::invalidatePaintForRectangle(const LayoutRect& paintInvalidationRect) const
340 {
341     ASSERT(!paintInvalidationRect.isEmpty());
342 
343     if (document().printing() || !m_frameView)
344         return;
345 
346     ASSERT(layer()->compositingState() == PaintsIntoOwnBacking || !frame()->ownerRenderer());
347 
348     if (layer()->compositingState() == PaintsIntoOwnBacking) {
349         setBackingNeedsPaintInvalidationInRect(paintInvalidationRect);
350     } else {
351         m_frameView->contentRectangleForPaintInvalidation(pixelSnappedIntRect(paintInvalidationRect));
352     }
353 }
354 
invalidatePaintForViewAndCompositedLayers()355 void RenderView::invalidatePaintForViewAndCompositedLayers()
356 {
357     setShouldDoFullPaintInvalidation(true);
358 
359     // The only way we know how to hit these ASSERTS below this point is via the Chromium OS login screen.
360     DisableCompositingQueryAsserts disabler;
361 
362     if (compositor()->inCompositingMode())
363         compositor()->fullyInvalidatePaint();
364 }
365 
mapRectToPaintInvalidationBacking(const RenderLayerModelObject * paintInvalidationContainer,LayoutRect & rect,const PaintInvalidationState * invalidationState) const366 void RenderView::mapRectToPaintInvalidationBacking(const RenderLayerModelObject* paintInvalidationContainer, LayoutRect& rect, const PaintInvalidationState* invalidationState) const
367 {
368     mapRectToPaintInvalidationBacking(paintInvalidationContainer, rect, IsNotFixedPosition, invalidationState);
369 }
370 
mapRectToPaintInvalidationBacking(const RenderLayerModelObject * paintInvalidationContainer,LayoutRect & rect,ViewportConstrainedPosition viewportConstraint,const PaintInvalidationState * state) const371 void RenderView::mapRectToPaintInvalidationBacking(const RenderLayerModelObject* paintInvalidationContainer, LayoutRect& rect, ViewportConstrainedPosition viewportConstraint, const PaintInvalidationState* state) const
372 {
373     if (document().printing())
374         return;
375 
376     if (style()->isFlippedBlocksWritingMode()) {
377         // We have to flip by hand since the view's logical height has not been determined.  We
378         // can use the viewport width and height.
379         if (style()->isHorizontalWritingMode())
380             rect.setY(viewHeight() - rect.maxY());
381         else
382             rect.setX(viewWidth() - rect.maxX());
383     }
384 
385     if (viewportConstraint == IsFixedPosition && m_frameView) {
386         rect.move(m_frameView->scrollOffsetForFixedPosition());
387         // If we have a pending scroll, invalidate the previous scroll position.
388         if (!m_frameView->pendingScrollDelta().isZero()) {
389             rect.move(-m_frameView->pendingScrollDelta());
390         }
391     }
392 
393     // Apply our transform if we have one (because of full page zooming).
394     if (!paintInvalidationContainer && layer() && layer()->transform())
395         rect = layer()->transform()->mapRect(rect);
396 
397     ASSERT(paintInvalidationContainer);
398     if (paintInvalidationContainer == this)
399         return;
400 
401     Element* owner = document().ownerElement();
402     if (!owner)
403         return;
404 
405     if (RenderBox* obj = owner->renderBox()) {
406         // Intersect the viewport with the paint invalidation rect.
407         LayoutRect viewRectangle = viewRect();
408         rect.intersect(viewRectangle);
409 
410         // Adjust for scroll offset of the view.
411         rect.moveBy(-viewRectangle.location());
412 
413         // Adjust for frame border.
414         rect.moveBy(obj->contentBoxRect().location());
415         obj->mapRectToPaintInvalidationBacking(paintInvalidationContainer, rect, 0);
416     }
417 }
418 
419 
absoluteRects(Vector<IntRect> & rects,const LayoutPoint & accumulatedOffset) const420 void RenderView::absoluteRects(Vector<IntRect>& rects, const LayoutPoint& accumulatedOffset) const
421 {
422     rects.append(pixelSnappedIntRect(accumulatedOffset, layer()->size()));
423 }
424 
absoluteQuads(Vector<FloatQuad> & quads,bool * wasFixed) const425 void RenderView::absoluteQuads(Vector<FloatQuad>& quads, bool* wasFixed) const
426 {
427     if (wasFixed)
428         *wasFixed = false;
429     quads.append(FloatRect(FloatPoint(), layer()->size()));
430 }
431 
rendererAfterPosition(RenderObject * object,unsigned offset)432 static RenderObject* rendererAfterPosition(RenderObject* object, unsigned offset)
433 {
434     if (!object)
435         return 0;
436 
437     RenderObject* child = object->childAt(offset);
438     return child ? child : object->nextInPreOrderAfterChildren();
439 }
440 
selectionBounds() const441 IntRect RenderView::selectionBounds() const
442 {
443     typedef WillBeHeapHashMap<RawPtrWillBeMember<RenderObject>, OwnPtrWillBeMember<RenderSelectionInfo> > SelectionMap;
444     SelectionMap selectedObjects;
445 
446     RenderObject* os = m_selectionStart;
447     RenderObject* stop = rendererAfterPosition(m_selectionEnd, m_selectionEndPos);
448     while (os && os != stop) {
449         if ((os->canBeSelectionLeaf() || os == m_selectionStart || os == m_selectionEnd) && os->selectionState() != SelectionNone) {
450             // Blocks are responsible for painting line gaps and margin gaps. They must be examined as well.
451             selectedObjects.set(os, adoptPtrWillBeNoop(new RenderSelectionInfo(os)));
452             RenderBlock* cb = os->containingBlock();
453             while (cb && !cb->isRenderView()) {
454                 OwnPtrWillBeMember<RenderSelectionInfo>& blockInfo = selectedObjects.add(cb, nullptr).storedValue->value;
455                 if (blockInfo)
456                     break;
457                 blockInfo = adoptPtrWillBeNoop(new RenderSelectionInfo(cb));
458                 cb = cb->containingBlock();
459             }
460         }
461 
462         os = os->nextInPreOrder();
463     }
464 
465     // Now create a single bounding box rect that encloses the whole selection.
466     LayoutRect selRect;
467     SelectionMap::iterator end = selectedObjects.end();
468     for (SelectionMap::iterator i = selectedObjects.begin(); i != end; ++i) {
469         RenderSelectionInfo* info = i->value.get();
470         // RenderSelectionInfo::rect() is in the coordinates of the paintInvalidationContainer, so map to page coordinates.
471         LayoutRect currRect = info->rect();
472         if (const RenderLayerModelObject* paintInvalidationContainer = info->paintInvalidationContainer()) {
473             FloatQuad absQuad = paintInvalidationContainer->localToAbsoluteQuad(FloatRect(currRect));
474             currRect = absQuad.enclosingBoundingBox();
475         }
476         selRect.unite(currRect);
477     }
478     return pixelSnappedIntRect(selRect);
479 }
480 
invalidatePaintForSelection() const481 void RenderView::invalidatePaintForSelection() const
482 {
483     HashSet<RenderBlock*> processedBlocks;
484 
485     // For querying RenderLayer::compositingState()
486     // FIXME: this may be wrong. crbug.com/407416
487     DisableCompositingQueryAsserts disabler;
488 
489     RenderObject* end = rendererAfterPosition(m_selectionEnd, m_selectionEndPos);
490     for (RenderObject* o = m_selectionStart; o && o != end; o = o->nextInPreOrder()) {
491         if (!o->canBeSelectionLeaf() && o != m_selectionStart && o != m_selectionEnd)
492             continue;
493         if (o->selectionState() == SelectionNone)
494             continue;
495 
496         RenderSelectionInfo(o).invalidatePaint();
497 
498         // Blocks are responsible for painting line gaps and margin gaps. They must be examined as well.
499         for (RenderBlock* block = o->containingBlock(); block && !block->isRenderView(); block = block->containingBlock()) {
500             if (!processedBlocks.add(block).isNewEntry)
501                 break;
502             RenderSelectionInfo(block).invalidatePaint();
503         }
504     }
505 }
506 
507 // When exploring the RenderTree looking for the nodes involved in the Selection, sometimes it's
508 // 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)509 static inline RenderObject* getNextOrPrevRenderObjectBasedOnDirection(const RenderObject* o, const RenderObject* stop, bool& continueExploring, bool& exploringBackwards)
510 {
511     RenderObject* next;
512     if (exploringBackwards) {
513         next = o->previousInPreOrder();
514         continueExploring = next && !(next)->isRenderView();
515     } else {
516         next = o->nextInPreOrder();
517         continueExploring = next && next != stop;
518         exploringBackwards = !next && (next != stop);
519         if (exploringBackwards) {
520             next = stop->previousInPreOrder();
521             continueExploring = next && !next->isRenderView();
522         }
523     }
524 
525     return next;
526 }
527 
setSelection(RenderObject * start,int startPos,RenderObject * end,int endPos,SelectionPaintInvalidationMode blockPaintInvalidationMode)528 void RenderView::setSelection(RenderObject* start, int startPos, RenderObject* end, int endPos, SelectionPaintInvalidationMode blockPaintInvalidationMode)
529 {
530     // This code makes no assumptions as to if the rendering tree is up to date or not
531     // and will not try to update it. Currently clearSelection calls this
532     // (intentionally) without updating the rendering tree as it doesn't care.
533     // Other callers may want to force recalc style before calling this.
534 
535     // Make sure both our start and end objects are defined.
536     // Check www.msnbc.com and try clicking around to find the case where this happened.
537     if ((start && !end) || (end && !start))
538         return;
539 
540     // Just return if the selection hasn't changed.
541     if (m_selectionStart == start && m_selectionStartPos == startPos &&
542         m_selectionEnd == end && m_selectionEndPos == endPos)
543         return;
544 
545     // Record the old selected objects.  These will be used later
546     // when we compare against the new selected objects.
547     int oldStartPos = m_selectionStartPos;
548     int oldEndPos = m_selectionEndPos;
549 
550     // Objects each have a single selection rect to examine.
551     typedef WillBeHeapHashMap<RawPtrWillBeMember<RenderObject>, OwnPtrWillBeMember<RenderSelectionInfo> > SelectedObjectMap;
552     SelectedObjectMap oldSelectedObjects;
553     SelectedObjectMap newSelectedObjects;
554 
555     // Blocks contain selected objects and fill gaps between them, either on the left, right, or in between lines and blocks.
556     // In order to get the paint invalidation rect right, we have to examine left, middle, and right rects individually, since otherwise
557     // the union of those rects might remain the same even when changes have occurred.
558     typedef WillBeHeapHashMap<RawPtrWillBeMember<RenderBlock>, OwnPtrWillBeMember<RenderBlockSelectionInfo> > SelectedBlockMap;
559     SelectedBlockMap oldSelectedBlocks;
560     SelectedBlockMap newSelectedBlocks;
561 
562     RenderObject* os = m_selectionStart;
563     RenderObject* stop = rendererAfterPosition(m_selectionEnd, m_selectionEndPos);
564     bool exploringBackwards = false;
565     bool continueExploring = os && (os != stop);
566     while (continueExploring) {
567         if ((os->canBeSelectionLeaf() || os == m_selectionStart || os == m_selectionEnd) && os->selectionState() != SelectionNone) {
568             // Blocks are responsible for painting line gaps and margin gaps.  They must be examined as well.
569             oldSelectedObjects.set(os, adoptPtrWillBeNoop(new RenderSelectionInfo(os)));
570             if (blockPaintInvalidationMode == PaintInvalidationNewXOROld) {
571                 RenderBlock* cb = os->containingBlock();
572                 while (cb && !cb->isRenderView()) {
573                     OwnPtrWillBeMember<RenderBlockSelectionInfo>& blockInfo = oldSelectedBlocks.add(cb, nullptr).storedValue->value;
574                     if (blockInfo)
575                         break;
576                     blockInfo = adoptPtrWillBeNoop(new RenderBlockSelectionInfo(cb));
577                     cb = cb->containingBlock();
578                 }
579             }
580         }
581 
582         os = getNextOrPrevRenderObjectBasedOnDirection(os, stop, continueExploring, exploringBackwards);
583     }
584 
585     // Now clear the selection.
586     SelectedObjectMap::iterator oldObjectsEnd = oldSelectedObjects.end();
587     for (SelectedObjectMap::iterator i = oldSelectedObjects.begin(); i != oldObjectsEnd; ++i)
588         i->key->setSelectionStateIfNeeded(SelectionNone);
589 
590     // set selection start and end
591     m_selectionStart = start;
592     m_selectionStartPos = startPos;
593     m_selectionEnd = end;
594     m_selectionEndPos = endPos;
595 
596     // Update the selection status of all objects between m_selectionStart and m_selectionEnd
597     if (start && start == end)
598         start->setSelectionStateIfNeeded(SelectionBoth);
599     else {
600         if (start)
601             start->setSelectionStateIfNeeded(SelectionStart);
602         if (end)
603             end->setSelectionStateIfNeeded(SelectionEnd);
604     }
605 
606     RenderObject* o = start;
607     stop = rendererAfterPosition(end, endPos);
608 
609     while (o && o != stop) {
610         if (o != start && o != end && o->canBeSelectionLeaf())
611             o->setSelectionStateIfNeeded(SelectionInside);
612         o = o->nextInPreOrder();
613     }
614 
615     if (blockPaintInvalidationMode != PaintInvalidationNothing)
616         layer()->clearBlockSelectionGapsBounds();
617 
618     // Now that the selection state has been updated for the new objects, walk them again and
619     // put them in the new objects list.
620     o = start;
621     exploringBackwards = false;
622     continueExploring = o && (o != stop);
623     while (continueExploring) {
624         if ((o->canBeSelectionLeaf() || o == start || o == end) && o->selectionState() != SelectionNone) {
625             newSelectedObjects.set(o, adoptPtrWillBeNoop(new RenderSelectionInfo(o)));
626             RenderBlock* cb = o->containingBlock();
627             while (cb && !cb->isRenderView()) {
628                 OwnPtrWillBeMember<RenderBlockSelectionInfo>& blockInfo = newSelectedBlocks.add(cb, nullptr).storedValue->value;
629                 if (blockInfo)
630                     break;
631                 blockInfo = adoptPtrWillBeNoop(new RenderBlockSelectionInfo(cb));
632                 cb = cb->containingBlock();
633             }
634         }
635 
636         o = getNextOrPrevRenderObjectBasedOnDirection(o, stop, continueExploring, exploringBackwards);
637     }
638 
639     if (!m_frameView || blockPaintInvalidationMode == PaintInvalidationNothing)
640         return;
641 
642     // For querying RenderLayer::compositingState()
643     // FIXME: this is wrong, selection should not cause eager invalidation. crbug.com/407416
644     DisableCompositingQueryAsserts disabler;
645 
646     // Have any of the old selected objects changed compared to the new selection?
647     for (SelectedObjectMap::iterator i = oldSelectedObjects.begin(); i != oldObjectsEnd; ++i) {
648         RenderObject* obj = i->key;
649         RenderSelectionInfo* newInfo = newSelectedObjects.get(obj);
650         RenderSelectionInfo* oldInfo = i->value.get();
651         if (!newInfo || oldInfo->rect() != newInfo->rect() || oldInfo->state() != newInfo->state() ||
652             (m_selectionStart == obj && oldStartPos != m_selectionStartPos) ||
653             (m_selectionEnd == obj && oldEndPos != m_selectionEndPos)) {
654             oldInfo->invalidatePaint();
655             if (newInfo) {
656                 newInfo->invalidatePaint();
657                 newSelectedObjects.remove(obj);
658             }
659         }
660     }
661 
662     // Any new objects that remain were not found in the old objects dict, and so they need to be updated.
663     SelectedObjectMap::iterator newObjectsEnd = newSelectedObjects.end();
664     for (SelectedObjectMap::iterator i = newSelectedObjects.begin(); i != newObjectsEnd; ++i)
665         i->value->invalidatePaint();
666 
667     // Have any of the old blocks changed?
668     SelectedBlockMap::iterator oldBlocksEnd = oldSelectedBlocks.end();
669     for (SelectedBlockMap::iterator i = oldSelectedBlocks.begin(); i != oldBlocksEnd; ++i) {
670         RenderBlock* block = i->key;
671         RenderBlockSelectionInfo* newInfo = newSelectedBlocks.get(block);
672         RenderBlockSelectionInfo* oldInfo = i->value.get();
673         if (!newInfo || oldInfo->rects() != newInfo->rects() || oldInfo->state() != newInfo->state()) {
674             oldInfo->invalidatePaint();
675             if (newInfo) {
676                 newInfo->invalidatePaint();
677                 newSelectedBlocks.remove(block);
678             }
679         }
680     }
681 
682     // Any new blocks that remain were not found in the old blocks dict, and so they need to be updated.
683     SelectedBlockMap::iterator newBlocksEnd = newSelectedBlocks.end();
684     for (SelectedBlockMap::iterator i = newSelectedBlocks.begin(); i != newBlocksEnd; ++i)
685         i->value->invalidatePaint();
686 }
687 
getSelection(RenderObject * & startRenderer,int & startOffset,RenderObject * & endRenderer,int & endOffset) const688 void RenderView::getSelection(RenderObject*& startRenderer, int& startOffset, RenderObject*& endRenderer, int& endOffset) const
689 {
690     startRenderer = m_selectionStart;
691     startOffset = m_selectionStartPos;
692     endRenderer = m_selectionEnd;
693     endOffset = m_selectionEndPos;
694 }
695 
clearSelection()696 void RenderView::clearSelection()
697 {
698     // For querying RenderLayer::compositingState()
699     // This is correct, since destroying render objects needs to cause eager paint invalidations.
700     DisableCompositingQueryAsserts disabler;
701 
702     layer()->invalidatePaintForBlockSelectionGaps();
703     setSelection(0, -1, 0, -1, PaintInvalidationNewMinusOld);
704 }
705 
selectionStartEnd(int & startPos,int & endPos) const706 void RenderView::selectionStartEnd(int& startPos, int& endPos) const
707 {
708     startPos = m_selectionStartPos;
709     endPos = m_selectionEndPos;
710 }
711 
shouldUsePrintingLayout() const712 bool RenderView::shouldUsePrintingLayout() const
713 {
714     if (!document().printing() || !m_frameView)
715         return false;
716     return m_frameView->frame().shouldUsePrintingLayout();
717 }
718 
viewRect() const719 LayoutRect RenderView::viewRect() const
720 {
721     if (shouldUsePrintingLayout())
722         return LayoutRect(LayoutPoint(), size());
723     if (m_frameView)
724         return m_frameView->visibleContentRect();
725     return LayoutRect();
726 }
727 
unscaledDocumentRect() const728 IntRect RenderView::unscaledDocumentRect() const
729 {
730     LayoutRect overflowRect(layoutOverflowRect());
731     flipForWritingMode(overflowRect);
732     return pixelSnappedIntRect(overflowRect);
733 }
734 
rootBackgroundIsEntirelyFixed() const735 bool RenderView::rootBackgroundIsEntirelyFixed() const
736 {
737     if (RenderObject* backgroundRenderer = this->backgroundRenderer())
738         return backgroundRenderer->hasEntirelyFixedBackground();
739     return false;
740 }
741 
backgroundRenderer() const742 RenderObject* RenderView::backgroundRenderer() const
743 {
744     if (Element* documentElement = document().documentElement()) {
745         if (RenderObject* rootObject = documentElement->renderer())
746             return rootObject->rendererForRootBackground();
747     }
748     return 0;
749 }
750 
backgroundRect(RenderBox * backgroundRenderer) const751 LayoutRect RenderView::backgroundRect(RenderBox* backgroundRenderer) const
752 {
753     if (!hasColumns())
754         return unscaledDocumentRect();
755 
756     ColumnInfo* columnInfo = this->columnInfo();
757     LayoutRect backgroundRect(0, 0, columnInfo->desiredColumnWidth(), columnInfo->columnHeight() * columnInfo->columnCount());
758     if (!isHorizontalWritingMode())
759         backgroundRect = backgroundRect.transposedRect();
760     backgroundRenderer->flipForWritingMode(backgroundRect);
761 
762     return backgroundRect;
763 }
764 
documentRect() const765 IntRect RenderView::documentRect() const
766 {
767     FloatRect overflowRect(unscaledDocumentRect());
768     if (hasTransform())
769         overflowRect = layer()->currentTransform().mapRect(overflowRect);
770     return IntRect(overflowRect);
771 }
772 
viewHeight(IncludeScrollbarsInRect scrollbarInclusion) const773 int RenderView::viewHeight(IncludeScrollbarsInRect scrollbarInclusion) const
774 {
775     int height = 0;
776     if (!shouldUsePrintingLayout() && m_frameView)
777         height = m_frameView->layoutSize(scrollbarInclusion).height();
778 
779     return height;
780 }
781 
viewWidth(IncludeScrollbarsInRect scrollbarInclusion) const782 int RenderView::viewWidth(IncludeScrollbarsInRect scrollbarInclusion) const
783 {
784     int width = 0;
785     if (!shouldUsePrintingLayout() && m_frameView)
786         width = m_frameView->layoutSize(scrollbarInclusion).width();
787 
788     return width;
789 }
790 
viewLogicalHeight() const791 int RenderView::viewLogicalHeight() const
792 {
793     return style()->isHorizontalWritingMode() ? viewHeight(ExcludeScrollbars) : viewWidth(ExcludeScrollbars);
794 }
795 
viewLogicalHeightForPercentages() const796 LayoutUnit RenderView::viewLogicalHeightForPercentages() const
797 {
798     if (shouldUsePrintingLayout())
799         return pageLogicalHeight();
800     return viewLogicalHeight();
801 }
802 
zoomFactor() const803 float RenderView::zoomFactor() const
804 {
805     return m_frameView->frame().pageZoomFactor();
806 }
807 
updateHitTestResult(HitTestResult & result,const LayoutPoint & point)808 void RenderView::updateHitTestResult(HitTestResult& result, const LayoutPoint& point)
809 {
810     if (result.innerNode())
811         return;
812 
813     Node* node = document().documentElement();
814     if (node) {
815         result.setInnerNode(node);
816         if (!result.innerNonSharedNode())
817             result.setInnerNonSharedNode(node);
818 
819         LayoutPoint adjustedPoint = point;
820         offsetForContents(adjustedPoint);
821 
822         result.setLocalPoint(adjustedPoint);
823     }
824 }
825 
usesCompositing() const826 bool RenderView::usesCompositing() const
827 {
828     return m_compositor && m_compositor->staleInCompositingMode();
829 }
830 
compositor()831 RenderLayerCompositor* RenderView::compositor()
832 {
833     if (!m_compositor)
834         m_compositor = adoptPtr(new RenderLayerCompositor(*this));
835 
836     return m_compositor.get();
837 }
838 
setIsInWindow(bool isInWindow)839 void RenderView::setIsInWindow(bool isInWindow)
840 {
841     if (m_compositor)
842         m_compositor->setIsInWindow(isInWindow);
843 }
844 
flowThreadController()845 FlowThreadController* RenderView::flowThreadController()
846 {
847     if (!m_flowThreadController)
848         m_flowThreadController = FlowThreadController::create();
849 
850     return m_flowThreadController.get();
851 }
852 
pushLayoutState(LayoutState & layoutState)853 void RenderView::pushLayoutState(LayoutState& layoutState)
854 {
855     if (m_flowThreadController) {
856         RenderFlowThread* currentFlowThread = m_flowThreadController->currentRenderFlowThread();
857         if (currentFlowThread)
858             currentFlowThread->pushFlowThreadLayoutState(layoutState.renderer());
859     }
860     m_layoutState = &layoutState;
861 }
862 
popLayoutState()863 void RenderView::popLayoutState()
864 {
865     ASSERT(m_layoutState);
866     m_layoutState = m_layoutState->next();
867     if (!m_flowThreadController)
868         return;
869 
870     RenderFlowThread* currentFlowThread = m_flowThreadController->currentRenderFlowThread();
871     if (!currentFlowThread)
872         return;
873 
874     currentFlowThread->popFlowThreadLayoutState();
875 }
876 
intervalArena()877 IntervalArena* RenderView::intervalArena()
878 {
879     if (!m_intervalArena)
880         m_intervalArena = IntervalArena::create();
881     return m_intervalArena.get();
882 }
883 
backgroundIsKnownToBeOpaqueInRect(const LayoutRect &) const884 bool RenderView::backgroundIsKnownToBeOpaqueInRect(const LayoutRect&) const
885 {
886     // FIXME: Remove this main frame check. Same concept applies to subframes too.
887     if (!frame()->isMainFrame())
888         return false;
889 
890     return m_frameView->hasOpaqueBackground();
891 }
892 
layoutViewportWidth() const893 double RenderView::layoutViewportWidth() const
894 {
895     float scale = m_frameView ? m_frameView->frame().pageZoomFactor() : 1;
896     return viewWidth(IncludeScrollbars) / scale;
897 }
898 
layoutViewportHeight() const899 double RenderView::layoutViewportHeight() const
900 {
901     float scale = m_frameView ? m_frameView->frame().pageZoomFactor() : 1;
902     return viewHeight(IncludeScrollbars) / scale;
903 }
904 
905 } // namespace blink
906