1 /* 2 * Copyright (C) 1999 Lars Knoll (knoll (at) kde.org) 3 * Copyright (C) 2006 Apple Computer, Inc. 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 22 #ifndef RenderView_h 23 #define RenderView_h 24 25 #include "core/page/FrameView.h" 26 #include "core/platform/PODFreeListArena.h" 27 #include "core/rendering/LayoutState.h" 28 #include "core/rendering/RenderBlock.h" 29 #include "wtf/OwnPtr.h" 30 31 namespace WebCore { 32 33 class CustomFilterGlobalContext; 34 class FlowThreadController; 35 class RenderLayerCompositor; 36 class RenderLazyBlock; 37 class RenderQuote; 38 class RenderWidget; 39 40 // The root of the render tree, corresponding to the CSS initial containing block. 41 // It's dimensions match that of the viewport, and it is always at position (0,0) 42 // relative to the document (and so isn't necessarily in view). 43 class RenderView FINAL : public RenderBlock { 44 public: 45 explicit RenderView(Document*); 46 virtual ~RenderView(); 47 48 bool hitTest(const HitTestRequest&, HitTestResult&); 49 bool hitTest(const HitTestRequest&, const HitTestLocation&, HitTestResult&); 50 51 virtual const char* renderName() const OVERRIDE { return "RenderView"; } 52 53 virtual bool isRenderView() const OVERRIDE { return true; } 54 55 virtual bool requiresLayer() const OVERRIDE { return true; } 56 57 virtual bool isChildAllowed(RenderObject*, RenderStyle*) const OVERRIDE; 58 59 virtual void layout() OVERRIDE; 60 virtual void updateLogicalWidth() OVERRIDE; 61 virtual void computeLogicalHeight(LayoutUnit logicalHeight, LayoutUnit logicalTop, LogicalExtentComputedValues&) const OVERRIDE; 62 63 virtual LayoutUnit availableLogicalHeight(AvailableLogicalHeightType) const OVERRIDE; 64 65 // The same as the FrameView's layoutHeight/layoutWidth but with null check guards. 66 int viewHeight() const; 67 int viewWidth() const; 68 int viewLogicalWidth() const { return style()->isHorizontalWritingMode() ? viewWidth() : viewHeight(); } 69 int viewLogicalHeight() const; 70 71 float zoomFactor() const; 72 73 FrameView* frameView() const { return m_frameView; } 74 75 virtual void computeRectForRepaint(const RenderLayerModelObject* repaintContainer, LayoutRect&, bool fixed = false) const OVERRIDE; 76 void repaintViewRectangle(const LayoutRect&) const; 77 // Repaint the view, and all composited layers that intersect the given absolute rectangle. 78 // FIXME: ideally we'd never have to do this, if all repaints are container-relative. 79 void repaintRectangleInViewAndCompositedLayers(const LayoutRect&); 80 void repaintViewAndCompositedLayers(); 81 82 virtual void paint(PaintInfo&, const LayoutPoint&); 83 virtual void paintBoxDecorations(PaintInfo&, const LayoutPoint&) OVERRIDE; 84 85 enum SelectionRepaintMode { RepaintNewXOROld, RepaintNewMinusOld, RepaintNothing }; 86 void setSelection(RenderObject* start, int startPos, RenderObject* end, int endPos, SelectionRepaintMode = RepaintNewXOROld); 87 void getSelection(RenderObject*& startRenderer, int& startOffset, RenderObject*& endRenderer, int& endOffset) const; 88 void clearSelection(); 89 RenderObject* selectionStart() const { return m_selectionStart; } 90 RenderObject* selectionEnd() const { return m_selectionEnd; } 91 IntRect selectionBounds(bool clipToVisibleContent = true) const; 92 void selectionStartEnd(int& startPos, int& endPos) const; 93 void repaintSelection() const; 94 95 bool printing() const; 96 97 virtual void absoluteRects(Vector<IntRect>&, const LayoutPoint& accumulatedOffset) const; 98 virtual void absoluteQuads(Vector<FloatQuad>&, bool* wasFixed) const; 99 100 void setMaximalOutlineSize(int o); 101 int maximalOutlineSize() const { return m_maximalOutlineSize; } 102 103 virtual LayoutRect viewRect() const OVERRIDE; 104 105 void updateWidgetPositions(); 106 void addWidget(RenderWidget*); 107 void removeWidget(RenderWidget*); 108 109 // layoutDelta is used transiently during layout to store how far an object has moved from its 110 // last layout location, in order to repaint correctly. 111 // If we're doing a full repaint m_layoutState will be 0, but in that case layoutDelta doesn't matter. 112 LayoutSize layoutDelta() const 113 { 114 return m_layoutState ? m_layoutState->m_layoutDelta : LayoutSize(); 115 } 116 void addLayoutDelta(const LayoutSize& delta) 117 { 118 if (m_layoutState) { 119 m_layoutState->m_layoutDelta += delta; 120 #if !ASSERT_DISABLED 121 m_layoutState->m_layoutDeltaXSaturated |= m_layoutState->m_layoutDelta.width() == LayoutUnit::max() || m_layoutState->m_layoutDelta.width() == LayoutUnit::min(); 122 m_layoutState->m_layoutDeltaYSaturated |= m_layoutState->m_layoutDelta.height() == LayoutUnit::max() || m_layoutState->m_layoutDelta.height() == LayoutUnit::min(); 123 #endif 124 } 125 } 126 127 #if !ASSERT_DISABLED 128 bool layoutDeltaMatches(const LayoutSize& delta) 129 { 130 if (!m_layoutState) 131 return false; 132 return (delta.width() == m_layoutState->m_layoutDelta.width() || m_layoutState->m_layoutDeltaXSaturated) && (delta.height() == m_layoutState->m_layoutDelta.height() || m_layoutState->m_layoutDeltaYSaturated); 133 } 134 #endif 135 136 bool doingFullRepaint() const { return m_frameView->needsFullRepaint(); } 137 138 // Subtree push/pop 139 void pushLayoutState(RenderObject*); 140 void popLayoutState(RenderObject*) { return popLayoutState(); } // Just doing this to keep popLayoutState() private and to make the subtree calls symmetrical. 141 142 bool shouldDisableLayoutStateForSubtree(RenderObject*) const; 143 144 // Returns true if layoutState should be used for its cached offset and clip. 145 bool layoutStateEnabled() const { return m_layoutStateDisableCount == 0 && m_layoutState; } 146 LayoutState* layoutState() const { return m_layoutState; } 147 148 virtual void updateHitTestResult(HitTestResult&, const LayoutPoint&); 149 150 LayoutUnit pageLogicalHeight() const { return m_pageLogicalHeight; } 151 void setPageLogicalHeight(LayoutUnit height) 152 { 153 if (m_pageLogicalHeight != height) { 154 m_pageLogicalHeight = height; 155 m_pageLogicalHeightChanged = true; 156 } 157 } 158 159 // Notification that this view moved into or out of a native window. 160 void setIsInWindow(bool); 161 162 RenderLayerCompositor* compositor(); 163 bool usesCompositing() const; 164 165 CustomFilterGlobalContext* customFilterGlobalContext(); 166 167 IntRect unscaledDocumentRect() const; 168 LayoutRect backgroundRect(RenderBox* backgroundRenderer) const; 169 170 IntRect documentRect() const; 171 172 // Renderer that paints the root background has background-images which all have background-attachment: fixed. 173 bool rootBackgroundIsEntirelyFixed() const; 174 175 bool hasRenderNamedFlowThreads() const; 176 bool checkTwoPassLayoutForAutoHeightRegions() const; 177 FlowThreadController* flowThreadController(); 178 179 void styleDidChange(StyleDifference, const RenderStyle* oldStyle); 180 181 IntervalArena* intervalArena(); 182 183 IntSize viewportSize() const { return document()->viewportSize(); } 184 185 void setRenderQuoteHead(RenderQuote* head) { m_renderQuoteHead = head; } 186 RenderQuote* renderQuoteHead() const { return m_renderQuoteHead; } 187 188 void setFirstLazyBlock(RenderLazyBlock* block) { m_firstLazyBlock = block; } 189 RenderLazyBlock* firstLazyBlock() const { return m_firstLazyBlock; } 190 void markLazyBlocksForLayout(); 191 192 // FIXME: This is a work around because the current implementation of counters 193 // requires walking the entire tree repeatedly and most pages don't actually use either 194 // feature so we shouldn't take the performance hit when not needed. Long term we should 195 // rewrite the counter and quotes code. 196 void addRenderCounter() { m_renderCounterCount++; } 197 void removeRenderCounter() { ASSERT(m_renderCounterCount > 0); m_renderCounterCount--; } 198 bool hasRenderCounters() { return m_renderCounterCount; } 199 200 virtual void addChild(RenderObject* newChild, RenderObject* beforeChild = 0) OVERRIDE; 201 202 virtual bool backgroundIsKnownToBeOpaqueInRect(const LayoutRect& localRect) const OVERRIDE FINAL; 203 204 protected: 205 virtual void mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState&, MapCoordinatesFlags = ApplyContainerFlip, bool* wasFixed = 0) const OVERRIDE; 206 virtual const RenderObject* pushMappingToContainer(const RenderLayerModelObject* ancestorToStopAt, RenderGeometryMap&) const OVERRIDE; 207 virtual void mapAbsoluteToLocalPoint(MapCoordinatesFlags, TransformState&) const; 208 virtual bool requiresColumns(int desiredColumnCount) const OVERRIDE; 209 virtual void computeSelfHitTestRects(Vector<LayoutRect>&, const LayoutPoint& layerOffset) const OVERRIDE; 210 211 private: 212 bool initializeLayoutState(LayoutState&); 213 214 virtual void calcColumnWidth() OVERRIDE; 215 virtual ColumnInfo::PaginationUnit paginationUnit() const OVERRIDE; 216 217 bool shouldRepaint(const LayoutRect&) const; 218 219 // These functions may only be accessed by LayoutStateMaintainer. 220 bool pushLayoutState(RenderBox* renderer, const LayoutSize& offset, LayoutUnit pageHeight = 0, bool pageHeightChanged = false, ColumnInfo* colInfo = 0) 221 { 222 // We push LayoutState even if layoutState is disabled because it stores layoutDelta too. 223 if (!doingFullRepaint() || m_layoutState->isPaginated() || renderer->hasColumns() || renderer->flowThreadContainingBlock() 224 || m_layoutState->lineGrid() || (renderer->style()->lineGrid() != RenderStyle::initialLineGrid() && renderer->isBlockFlow()) 225 || (renderer->isRenderBlock() && toRenderBlock(renderer)->shapeInsideInfo()) 226 || (m_layoutState->shapeInsideInfo() && renderer->isRenderBlock() && !toRenderBlock(renderer)->allowsShapeInsideInfoSharing()) 227 ) { 228 m_layoutState = new LayoutState(m_layoutState, renderer, offset, pageHeight, pageHeightChanged, colInfo); 229 return true; 230 } 231 return false; 232 } 233 234 void popLayoutState() 235 { 236 LayoutState* state = m_layoutState; 237 m_layoutState = state->m_next; 238 delete state; 239 } 240 241 // Suspends the LayoutState optimization. Used under transforms that cannot be represented by 242 // LayoutState (common in SVG) and when manipulating the render tree during layout in ways 243 // that can trigger repaint of a non-child (e.g. when a list item moves its list marker around). 244 // Note that even when disabled, LayoutState is still used to store layoutDelta. 245 // These functions may only be accessed by LayoutStateMaintainer or LayoutStateDisabler. 246 void disableLayoutState() { m_layoutStateDisableCount++; } 247 void enableLayoutState() { ASSERT(m_layoutStateDisableCount > 0); m_layoutStateDisableCount--; } 248 249 void layoutContent(const LayoutState&); 250 void layoutContentInAutoLogicalHeightRegions(const LayoutState&); 251 #ifndef NDEBUG 252 void checkLayoutState(const LayoutState&); 253 #endif 254 255 size_t getRetainedWidgets(Vector<RenderWidget*>&); 256 void releaseWidgets(Vector<RenderWidget*>&); 257 258 friend class LayoutStateMaintainer; 259 friend class LayoutStateDisabler; 260 261 protected: 262 FrameView* m_frameView; 263 264 RenderObject* m_selectionStart; 265 RenderObject* m_selectionEnd; 266 int m_selectionStartPos; 267 int m_selectionEndPos; 268 269 int m_maximalOutlineSize; // Used to apply a fudge factor to dirty-rect checks on blocks/tables. 270 271 typedef HashSet<RenderWidget*> RenderWidgetSet; 272 RenderWidgetSet m_widgets; 273 274 private: 275 bool shouldUsePrintingLayout() const; 276 277 LayoutUnit m_pageLogicalHeight; 278 bool m_pageLogicalHeightChanged; 279 LayoutState* m_layoutState; 280 unsigned m_layoutStateDisableCount; 281 OwnPtr<RenderLayerCompositor> m_compositor; 282 OwnPtr<CustomFilterGlobalContext> m_customFilterGlobalContext; 283 OwnPtr<FlowThreadController> m_flowThreadController; 284 RefPtr<IntervalArena> m_intervalArena; 285 286 RenderLazyBlock* m_firstLazyBlock; 287 RenderQuote* m_renderQuoteHead; 288 unsigned m_renderCounterCount; 289 }; 290 291 inline RenderView* toRenderView(RenderObject* object) 292 { 293 ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isRenderView()); 294 return static_cast<RenderView*>(object); 295 } 296 297 inline const RenderView* toRenderView(const RenderObject* object) 298 { 299 ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isRenderView()); 300 return static_cast<const RenderView*>(object); 301 } 302 303 // This will catch anyone doing an unnecessary cast. 304 void toRenderView(const RenderView*); 305 306 ALWAYS_INLINE RenderView* Document::renderView() const 307 { 308 return toRenderView(renderer()); 309 } 310 311 // Stack-based class to assist with LayoutState push/pop 312 class LayoutStateMaintainer { 313 WTF_MAKE_NONCOPYABLE(LayoutStateMaintainer); 314 public: 315 // ctor to push now 316 LayoutStateMaintainer(RenderView* view, RenderBox* root, LayoutSize offset, bool disableState = false, LayoutUnit pageHeight = 0, bool pageHeightChanged = false, ColumnInfo* colInfo = 0) 317 : m_view(view) 318 , m_disabled(disableState) 319 , m_didStart(false) 320 , m_didEnd(false) 321 , m_didCreateLayoutState(false) 322 { 323 push(root, offset, pageHeight, pageHeightChanged, colInfo); 324 } 325 326 // ctor to maybe push later 327 LayoutStateMaintainer(RenderView* view) 328 : m_view(view) 329 , m_disabled(false) 330 , m_didStart(false) 331 , m_didEnd(false) 332 , m_didCreateLayoutState(false) 333 { 334 } 335 336 ~LayoutStateMaintainer() 337 { 338 ASSERT(m_didStart == m_didEnd); // if this fires, it means that someone did a push(), but forgot to pop(). 339 } 340 341 void push(RenderBox* root, LayoutSize offset, LayoutUnit pageHeight = 0, bool pageHeightChanged = false, ColumnInfo* colInfo = 0) 342 { 343 ASSERT(!m_didStart); 344 // We push state even if disabled, because we still need to store layoutDelta 345 m_didCreateLayoutState = m_view->pushLayoutState(root, offset, pageHeight, pageHeightChanged, colInfo); 346 if (m_disabled && m_didCreateLayoutState) 347 m_view->disableLayoutState(); 348 m_didStart = true; 349 } 350 351 void pop() 352 { 353 if (m_didStart) { 354 ASSERT(!m_didEnd); 355 if (m_didCreateLayoutState) { 356 m_view->popLayoutState(); 357 if (m_disabled) 358 m_view->enableLayoutState(); 359 } 360 361 m_didEnd = true; 362 } 363 } 364 365 bool didPush() const { return m_didStart; } 366 367 private: 368 RenderView* m_view; 369 bool m_disabled : 1; // true if the offset and clip part of layoutState is disabled 370 bool m_didStart : 1; // true if we did a push or disable 371 bool m_didEnd : 1; // true if we popped or re-enabled 372 bool m_didCreateLayoutState : 1; // true if we actually made a layout state. 373 }; 374 375 class LayoutStateDisabler { 376 WTF_MAKE_NONCOPYABLE(LayoutStateDisabler); 377 public: 378 LayoutStateDisabler(RenderView* view) 379 : m_view(view) 380 { 381 if (m_view) 382 m_view->disableLayoutState(); 383 } 384 385 ~LayoutStateDisabler() 386 { 387 if (m_view) 388 m_view->enableLayoutState(); 389 } 390 private: 391 RenderView* m_view; 392 }; 393 394 class FragmentationDisabler { 395 WTF_MAKE_NONCOPYABLE(FragmentationDisabler); 396 public: 397 FragmentationDisabler(RenderObject* root); 398 ~FragmentationDisabler(); 399 private: 400 RenderObject* m_root; 401 RenderObject::FlowThreadState m_flowThreadState; 402 bool m_fragmenting; 403 #ifndef NDEBUG 404 LayoutState* m_layoutState; 405 #endif 406 }; 407 408 } // namespace WebCore 409 410 #endif // RenderView_h 411