1/* 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) 3 * Copyright (C) 2006 Apple 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 "FrameView.h" 26#include "LayoutState.h" 27#include "PODFreeListArena.h" 28#include "Region.h" 29#include "RenderBlockFlow.h" 30#include "SelectionSubtreeRoot.h" 31#include <memory> 32#include <wtf/HashSet.h> 33#include <wtf/OwnPtr.h> 34 35#if ENABLE(SERVICE_CONTROLS) 36#include "SelectionRectGatherer.h" 37#endif 38 39namespace WebCore { 40 41class FlowThreadController; 42class ImageQualityController; 43class RenderLayerCompositor; 44class RenderQuote; 45 46class RenderView final : public RenderBlockFlow, public SelectionSubtreeRoot { 47public: 48 RenderView(Document&, PassRef<RenderStyle>); 49 virtual ~RenderView(); 50 51 bool hitTest(const HitTestRequest&, HitTestResult&); 52 bool hitTest(const HitTestRequest&, const HitTestLocation&, HitTestResult&); 53 54 virtual const char* renderName() const override { return "RenderView"; } 55 56 virtual bool requiresLayer() const override { return true; } 57 58 virtual bool isChildAllowed(const RenderObject&, const RenderStyle&) const override; 59 60 virtual void layout() override; 61 virtual void updateLogicalWidth() override; 62 virtual void computeLogicalHeight(LayoutUnit logicalHeight, LayoutUnit logicalTop, LogicalExtentComputedValues&) const override; 63 64 virtual LayoutUnit availableLogicalHeight(AvailableLogicalHeightType) const override; 65 66 // The same as the FrameView's layoutHeight/layoutWidth but with null check guards. 67 int viewHeight() const; 68 int viewWidth() const; 69 int viewLogicalWidth() const { return style().isHorizontalWritingMode() ? viewWidth() : viewHeight(); } 70 int viewLogicalHeight() const; 71 72 LayoutUnit clientLogicalWidthForFixedPosition() const; 73 LayoutUnit clientLogicalHeightForFixedPosition() const; 74 75 float zoomFactor() const; 76 77 FrameView& frameView() const { return m_frameView; } 78 79 virtual LayoutRect visualOverflowRect() const override; 80 virtual void computeRectForRepaint(const RenderLayerModelObject* repaintContainer, LayoutRect&, bool fixed = false) const override; 81 void repaintRootContents(); 82 void repaintViewRectangle(const LayoutRect&) const; 83 void repaintViewAndCompositedLayers(); 84 85 virtual void paint(PaintInfo&, const LayoutPoint&) override; 86 virtual void paintBoxDecorations(PaintInfo&, const LayoutPoint&) override; 87 88 enum SelectionRepaintMode { RepaintNewXOROld, RepaintNewMinusOld, RepaintNothing }; 89 void setSelection(RenderObject* start, int startPos, RenderObject* end, int endPos, SelectionRepaintMode = RepaintNewXOROld); 90 void getSelection(RenderObject*& startRenderer, int& startOffset, RenderObject*& endRenderer, int& endOffset) const; 91 void clearSelection(); 92 RenderObject* selectionStart() const { return m_selectionStart; } 93 RenderObject* selectionEnd() const { return m_selectionEnd; } 94 IntRect selectionBounds(bool clipToVisibleContent = true) const; 95 void repaintSelection() const; 96 97 bool printing() const; 98 99 virtual void absoluteRects(Vector<IntRect>&, const LayoutPoint& accumulatedOffset) const override; 100 virtual void absoluteQuads(Vector<FloatQuad>&, bool* wasFixed) const override; 101 102 void setMaximalOutlineSize(int o); 103 int maximalOutlineSize() const { return m_maximalOutlineSize; } 104 105 LayoutRect viewRect() const; 106 107 // layoutDelta is used transiently during layout to store how far an object has moved from its 108 // last layout location, in order to repaint correctly. 109 // If we're doing a full repaint m_layoutState will be 0, but in that case layoutDelta doesn't matter. 110 LayoutSize layoutDelta() const 111 { 112 return m_layoutState ? m_layoutState->m_layoutDelta : LayoutSize(); 113 } 114 void addLayoutDelta(const LayoutSize& delta) 115 { 116 if (m_layoutState) { 117 m_layoutState->m_layoutDelta += delta; 118#if !ASSERT_DISABLED && ENABLE(SATURATED_LAYOUT_ARITHMETIC) 119 m_layoutState->m_layoutDeltaXSaturated |= m_layoutState->m_layoutDelta.width() == LayoutUnit::max() || m_layoutState->m_layoutDelta.width() == LayoutUnit::min(); 120 m_layoutState->m_layoutDeltaYSaturated |= m_layoutState->m_layoutDelta.height() == LayoutUnit::max() || m_layoutState->m_layoutDelta.height() == LayoutUnit::min(); 121#endif 122 } 123 } 124 125#if !ASSERT_DISABLED 126 bool layoutDeltaMatches(const LayoutSize& delta) 127 { 128 if (!m_layoutState) 129 return false; 130#if ENABLE(SATURATED_LAYOUT_ARITHMETIC) 131 return (delta.width() == m_layoutState->m_layoutDelta.width() || m_layoutState->m_layoutDeltaXSaturated) && (delta.height() == m_layoutState->m_layoutDelta.height() || m_layoutState->m_layoutDeltaYSaturated); 132#else 133 return delta == m_layoutState->m_layoutDelta; 134#endif 135 } 136#endif 137 138 bool doingFullRepaint() const { return frameView().needsFullRepaint(); } 139 140 // Subtree push/pop 141 void pushLayoutState(RenderObject&); 142 void popLayoutState(RenderObject&) { return popLayoutState(); } // Just doing this to keep popLayoutState() private and to make the subtree calls symmetrical. 143 144 bool shouldDisableLayoutStateForSubtree(RenderObject*) const; 145 146 // Returns true if layoutState should be used for its cached offset and clip. 147 bool layoutStateEnabled() const { return m_layoutStateDisableCount == 0 && m_layoutState; } 148 LayoutState* layoutState() const { return m_layoutState.get(); } 149 150 virtual void updateHitTestResult(HitTestResult&, const LayoutPoint&) override; 151 152 LayoutUnit pageLogicalHeight() const { return m_pageLogicalHeight; } 153 void setPageLogicalHeight(LayoutUnit height) 154 { 155 if (m_pageLogicalHeight != height) { 156 m_pageLogicalHeight = height; 157 m_pageLogicalHeightChanged = true; 158 } 159 } 160 LayoutUnit pageOrViewLogicalHeight() const; 161 162 // This method is used to assign a page number only when pagination modes have 163 // a block progression. This happens with vertical-rl books for example, but it 164 // doesn't happen for normal horizontal-tb books. This is a very specialized 165 // function and should not be mistaken for a general page number API. 166 unsigned pageNumberForBlockProgressionOffset(int offset) const; 167 168 unsigned pageCount() const; 169 170 // FIXME: These functions are deprecated. No code should be added that uses these. 171 int bestTruncatedAt() const { return m_legacyPrinting.m_bestTruncatedAt; } 172 void setBestTruncatedAt(int y, RenderBoxModelObject* forRenderer, bool forcedBreak = false); 173 int truncatedAt() const { return m_legacyPrinting.m_truncatedAt; } 174 void setTruncatedAt(int y) 175 { 176 m_legacyPrinting.m_truncatedAt = y; 177 m_legacyPrinting.m_bestTruncatedAt = 0; 178 m_legacyPrinting.m_truncatorWidth = 0; 179 m_legacyPrinting.m_forcedPageBreak = false; 180 } 181 const IntRect& printRect() const { return m_legacyPrinting.m_printRect; } 182 void setPrintRect(const IntRect& r) { m_legacyPrinting.m_printRect = r; } 183 // End deprecated functions. 184 185 // Notification that this view moved into or out of a native window. 186 void setIsInWindow(bool); 187 188 RenderLayerCompositor& compositor(); 189 bool usesCompositing() const; 190 191 IntRect unscaledDocumentRect() const; 192 LayoutRect unextendedBackgroundRect(RenderBox* backgroundRenderer) const; 193 LayoutRect backgroundRect(RenderBox* backgroundRenderer) const; 194 195 IntRect documentRect() const; 196 197 // Renderer that paints the root background has background-images which all have background-attachment: fixed. 198 bool rootBackgroundIsEntirelyFixed() const; 199 200 bool hasRenderNamedFlowThreads() const; 201 bool checkTwoPassLayoutForAutoHeightRegions() const; 202 FlowThreadController& flowThreadController(); 203 204 virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle) override; 205 206 IntervalArena* intervalArena(); 207 208 IntSize viewportSizeForCSSViewportUnits() const; 209 210 void setRenderQuoteHead(RenderQuote* head) { m_renderQuoteHead = head; } 211 RenderQuote* renderQuoteHead() const { return m_renderQuoteHead; } 212 213 // FIXME: This is a work around because the current implementation of counters 214 // requires walking the entire tree repeatedly and most pages don't actually use either 215 // feature so we shouldn't take the performance hit when not needed. Long term we should 216 // rewrite the counter and quotes code. 217 void addRenderCounter() { m_renderCounterCount++; } 218 void removeRenderCounter() { ASSERT(m_renderCounterCount > 0); m_renderCounterCount--; } 219 bool hasRenderCounters() { return m_renderCounterCount; } 220 221 IntRect pixelSnappedLayoutOverflowRect() const { return pixelSnappedIntRect(layoutOverflowRect()); } 222 223 ImageQualityController& imageQualityController(); 224 225#if ENABLE(CSS_FILTERS) 226 void setHasSoftwareFilters(bool hasSoftwareFilters) { m_hasSoftwareFilters = hasSoftwareFilters; } 227 bool hasSoftwareFilters() const { return m_hasSoftwareFilters; } 228#endif 229 230 uint64_t rendererCount() const { return m_rendererCount; } 231 void didCreateRenderer() { ++m_rendererCount; } 232 void didDestroyRenderer() { --m_rendererCount; } 233 234 void resumePausedImageAnimationsIfNeeded(); 235 void addRendererWithPausedImageAnimations(RenderElement&); 236 void removeRendererWithPausedImageAnimations(RenderElement&); 237 238 class RepaintRegionAccumulator { 239 WTF_MAKE_NONCOPYABLE(RepaintRegionAccumulator); 240 public: 241 RepaintRegionAccumulator(RenderView*); 242 ~RepaintRegionAccumulator(); 243 244 private: 245 RenderView* m_rootView; 246 bool m_wasAccumulatingRepaintRegion; 247 }; 248 249 void scheduleLazyRepaint(RenderBox&); 250 void unscheduleLazyRepaint(RenderBox&); 251 252protected: 253 virtual void mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState&, MapCoordinatesFlags = ApplyContainerFlip, bool* wasFixed = 0) const override; 254 virtual const RenderObject* pushMappingToContainer(const RenderLayerModelObject* ancestorToStopAt, RenderGeometryMap&) const override; 255 virtual void mapAbsoluteToLocalPoint(MapCoordinatesFlags, TransformState&) const override; 256 virtual bool requiresColumns(int desiredColumnCount) const override; 257 258private: 259 void initializeLayoutState(LayoutState&); 260 261 virtual void computeColumnCountAndWidth() override; 262 263 bool shouldRepaint(const LayoutRect&) const; 264 void flushAccumulatedRepaintRegion() const; 265 266 // These functions may only be accessed by LayoutStateMaintainer. 267 bool pushLayoutState(RenderBox& renderer, const LayoutSize& offset, LayoutUnit pageHeight = 0, bool pageHeightChanged = false) 268 { 269 // We push LayoutState even if layoutState is disabled because it stores layoutDelta too. 270 if (!doingFullRepaint() || m_layoutState->isPaginated() || renderer.flowThreadContainingBlock() 271 || m_layoutState->lineGrid() || (renderer.style().lineGrid() != RenderStyle::initialLineGrid() && renderer.isRenderBlockFlow())) { 272 m_layoutState = std::make_unique<LayoutState>(WTF::move(m_layoutState), &renderer, offset, pageHeight, pageHeightChanged); 273 pushLayoutStateForCurrentFlowThread(renderer); 274 return true; 275 } 276 return false; 277 } 278 279 void popLayoutState() 280 { 281 popLayoutStateForCurrentFlowThread(); 282 m_layoutState = WTF::move(m_layoutState->m_next); 283 } 284 285 // Suspends the LayoutState optimization. Used under transforms that cannot be represented by 286 // LayoutState (common in SVG) and when manipulating the render tree during layout in ways 287 // that can trigger repaint of a non-child (e.g. when a list item moves its list marker around). 288 // Note that even when disabled, LayoutState is still used to store layoutDelta. 289 // These functions may only be accessed by LayoutStateMaintainer or LayoutStateDisabler. 290 void disableLayoutState() { m_layoutStateDisableCount++; } 291 void enableLayoutState() { ASSERT(m_layoutStateDisableCount > 0); m_layoutStateDisableCount--; } 292 293 void layoutContent(const LayoutState&); 294 void layoutContentInAutoLogicalHeightRegions(const LayoutState&); 295 void layoutContentToComputeOverflowInRegions(const LayoutState&); 296#ifndef NDEBUG 297 void checkLayoutState(const LayoutState&); 298#endif 299 300 void pushLayoutStateForCurrentFlowThread(const RenderObject&); 301 void popLayoutStateForCurrentFlowThread(); 302 303 friend class LayoutStateMaintainer; 304 friend class LayoutStateDisabler; 305 306 void splitSelectionBetweenSubtrees(RenderObject* start, int startPos, RenderObject* end, int endPos, SelectionRepaintMode blockRepaintMode); 307 void setSubtreeSelection(SelectionSubtreeRoot&, RenderObject* start, int startPos, RenderObject* end, int endPos, SelectionRepaintMode); 308 LayoutRect subtreeSelectionBounds(const SelectionSubtreeRoot&, bool clipToVisibleContent = true) const; 309 void repaintSubtreeSelection(const SelectionSubtreeRoot&) const; 310 311private: 312 FrameView& m_frameView; 313 314 RenderObject* m_selectionStart; 315 RenderObject* m_selectionEnd; 316 int m_selectionStartPos; 317 int m_selectionEndPos; 318 319 uint64_t m_rendererCount; 320 321 mutable std::unique_ptr<Region> m_accumulatedRepaintRegion; 322 323 // FIXME: Only used by embedded WebViews inside AppKit NSViews. Find a way to remove. 324 struct LegacyPrinting { 325 LegacyPrinting() 326 : m_bestTruncatedAt(0) 327 , m_truncatedAt(0) 328 , m_truncatorWidth(0) 329 , m_forcedPageBreak(false) 330 { } 331 332 int m_bestTruncatedAt; 333 int m_truncatedAt; 334 int m_truncatorWidth; 335 IntRect m_printRect; 336 bool m_forcedPageBreak; 337 }; 338 LegacyPrinting m_legacyPrinting; 339 // End deprecated members. 340 341 int m_maximalOutlineSize; // Used to apply a fudge factor to dirty-rect checks on blocks/tables. 342 343 bool shouldUsePrintingLayout() const; 344 345 void lazyRepaintTimerFired(Timer<RenderView>&); 346 347 Timer<RenderView> m_lazyRepaintTimer; 348 HashSet<RenderBox*> m_renderersNeedingLazyRepaint; 349 350 std::unique_ptr<ImageQualityController> m_imageQualityController; 351 LayoutUnit m_pageLogicalHeight; 352 bool m_pageLogicalHeightChanged; 353 std::unique_ptr<LayoutState> m_layoutState; 354 unsigned m_layoutStateDisableCount; 355 std::unique_ptr<RenderLayerCompositor> m_compositor; 356 std::unique_ptr<FlowThreadController> m_flowThreadController; 357 RefPtr<IntervalArena> m_intervalArena; 358 359 RenderQuote* m_renderQuoteHead; 360 unsigned m_renderCounterCount; 361 362 bool m_selectionWasCaret; 363#if ENABLE(CSS_FILTERS) 364 bool m_hasSoftwareFilters; 365#endif 366 367 HashSet<RenderElement*> m_renderersWithPausedImageAnimation; 368 369#if ENABLE(SERVICE_CONTROLS) 370 SelectionRectGatherer m_selectionRectGatherer; 371#endif 372}; 373 374RENDER_OBJECT_TYPE_CASTS(RenderView, isRenderView()) 375 376// Stack-based class to assist with LayoutState push/pop 377class LayoutStateMaintainer { 378 WTF_MAKE_NONCOPYABLE(LayoutStateMaintainer); 379public: 380 // Constructor to push now. 381 explicit LayoutStateMaintainer(RenderView& view, RenderBox& root, LayoutSize offset, bool disableState = false, LayoutUnit pageHeight = 0, bool pageHeightChanged = false) 382 : m_view(view) 383 , m_disabled(disableState) 384 , m_didStart(false) 385 , m_didEnd(false) 386 , m_didCreateLayoutState(false) 387 { 388 push(root, offset, pageHeight, pageHeightChanged); 389 } 390 391 // Constructor to maybe push later. 392 explicit LayoutStateMaintainer(RenderView& view) 393 : m_view(view) 394 , m_disabled(false) 395 , m_didStart(false) 396 , m_didEnd(false) 397 , m_didCreateLayoutState(false) 398 { 399 } 400 401 ~LayoutStateMaintainer() 402 { 403 ASSERT(m_didStart == m_didEnd); // if this fires, it means that someone did a push(), but forgot to pop(). 404 } 405 406 void push(RenderBox& root, LayoutSize offset, LayoutUnit pageHeight = 0, bool pageHeightChanged = false) 407 { 408 ASSERT(!m_didStart); 409 // We push state even if disabled, because we still need to store layoutDelta 410 m_didCreateLayoutState = m_view.pushLayoutState(root, offset, pageHeight, pageHeightChanged); 411 if (m_disabled && m_didCreateLayoutState) 412 m_view.disableLayoutState(); 413 m_didStart = true; 414 } 415 416 void pop() 417 { 418 if (m_didStart) { 419 ASSERT(!m_didEnd); 420 if (m_didCreateLayoutState) { 421 m_view.popLayoutState(); 422 if (m_disabled) 423 m_view.enableLayoutState(); 424 } 425 426 m_didEnd = true; 427 } 428 } 429 430 bool didPush() const { return m_didStart; } 431 432private: 433 RenderView& m_view; 434 bool m_disabled : 1; // true if the offset and clip part of layoutState is disabled 435 bool m_didStart : 1; // true if we did a push or disable 436 bool m_didEnd : 1; // true if we popped or re-enabled 437 bool m_didCreateLayoutState : 1; // true if we actually made a layout state. 438}; 439 440class LayoutStateDisabler { 441 WTF_MAKE_NONCOPYABLE(LayoutStateDisabler); 442public: 443 LayoutStateDisabler(RenderView* view) 444 : m_view(view) 445 { 446 if (m_view) 447 m_view->disableLayoutState(); 448 } 449 450 ~LayoutStateDisabler() 451 { 452 if (m_view) 453 m_view->enableLayoutState(); 454 } 455private: 456 RenderView* m_view; 457}; 458 459} // namespace WebCore 460 461#endif // RenderView_h 462