• 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/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