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