1/*
2 * Copyright (C) 1999 Lars Knoll (knoll@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 "FrameView.h"
26#include "LayoutState.h"
27#include "PODFreeListArena.h"
28#include "RenderBlock.h"
29#include <wtf/OwnPtr.h>
30
31namespace WebCore {
32
33class FlowThreadController;
34class RenderQuote;
35class RenderWidget;
36
37#if USE(ACCELERATED_COMPOSITING)
38class RenderLayerCompositor;
39#endif
40
41#if ENABLE(CSS_SHADERS) && USE(3D_GRAPHICS)
42class CustomFilterGlobalContext;
43#endif
44
45class RenderView : public RenderBlock {
46public:
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 LayoutUnit availableLogicalHeight(AvailableLogicalHeightType) const OVERRIDE;
66
67    // The same as the FrameView's layoutHeight/layoutWidth but with null check guards.
68    int viewHeight() const;
69    int viewWidth() const;
70    int viewLogicalWidth() const { return style()->isHorizontalWritingMode() ? viewWidth() : viewHeight(); }
71    int viewLogicalHeight() const;
72
73    float zoomFactor() const;
74
75    FrameView* frameView() const { return m_frameView; }
76
77    virtual void computeRectForRepaint(const RenderLayerModelObject* repaintContainer, LayoutRect&, bool fixed = false) const OVERRIDE;
78    void repaintViewRectangle(const LayoutRect&, bool immediate = false) const;
79    // Repaint the view, and all composited layers that intersect the given absolute rectangle.
80    // FIXME: ideally we'd never have to do this, if all repaints are container-relative.
81    void repaintRectangleInViewAndCompositedLayers(const LayoutRect&, bool immediate = false);
82    void repaintViewAndCompositedLayers();
83
84    virtual void paint(PaintInfo&, const LayoutPoint&);
85    virtual void paintBoxDecorations(PaintInfo&, const LayoutPoint&) OVERRIDE;
86
87    enum SelectionRepaintMode { RepaintNewXOROld, RepaintNewMinusOld, RepaintNothing };
88    void setSelection(RenderObject* start, int startPos, RenderObject* end, int endPos, SelectionRepaintMode = RepaintNewXOROld);
89    void getSelection(RenderObject*& startRenderer, int& startOffset, RenderObject*& endRenderer, int& endOffset) const;
90    void clearSelection();
91    RenderObject* selectionStart() const { return m_selectionStart; }
92    RenderObject* selectionEnd() const { return m_selectionEnd; }
93    IntRect selectionBounds(bool clipToVisibleContent = true) const;
94    void selectionStartEnd(int& startPos, int& endPos) const;
95    void repaintSelection() const;
96
97    bool printing() const;
98
99    virtual void absoluteRects(Vector<IntRect>&, const LayoutPoint& accumulatedOffset) const;
100    virtual void absoluteQuads(Vector<FloatQuad>&, bool* wasFixed) const;
101
102#if USE(ACCELERATED_COMPOSITING)
103    void setMaximalOutlineSize(int o);
104#else
105    void setMaximalOutlineSize(int o) { m_maximalOutlineSize = o; }
106#endif
107    int maximalOutlineSize() const { return m_maximalOutlineSize; }
108
109    virtual LayoutRect viewRect() const OVERRIDE;
110
111    void updateWidgetPositions();
112    void addWidget(RenderWidget*);
113    void removeWidget(RenderWidget*);
114
115    void notifyWidgets(WidgetNotification);
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 && ENABLE(SATURATED_LAYOUT_ARITHMETIC)
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#if ENABLE(SATURATED_LAYOUT_ARITHMETIC)
141        return (delta.width() == m_layoutState->m_layoutDelta.width() || m_layoutState->m_layoutDeltaXSaturated) && (delta.height() == m_layoutState->m_layoutDelta.height() || m_layoutState->m_layoutDeltaYSaturated);
142#else
143        return delta == m_layoutState->m_layoutDelta;
144#endif
145    }
146#endif
147
148    bool doingFullRepaint() const { return m_frameView->needsFullRepaint(); }
149
150    // Subtree push/pop
151    void pushLayoutState(RenderObject*);
152    void popLayoutState(RenderObject*) { return popLayoutState(); } // Just doing this to keep popLayoutState() private and to make the subtree calls symmetrical.
153
154    bool shouldDisableLayoutStateForSubtree(RenderObject*) const;
155
156    // Returns true if layoutState should be used for its cached offset and clip.
157    bool layoutStateEnabled() const { return m_layoutStateDisableCount == 0 && m_layoutState; }
158    LayoutState* layoutState() const { return m_layoutState; }
159
160    virtual void updateHitTestResult(HitTestResult&, const LayoutPoint&);
161
162    LayoutUnit pageLogicalHeight() const { return m_pageLogicalHeight; }
163    void setPageLogicalHeight(LayoutUnit height)
164    {
165        if (m_pageLogicalHeight != height) {
166            m_pageLogicalHeight = height;
167            m_pageLogicalHeightChanged = true;
168        }
169    }
170    LayoutUnit pageOrViewLogicalHeight() const;
171
172    // FIXME: These functions are deprecated. No code should be added that uses these.
173    int bestTruncatedAt() const { return m_legacyPrinting.m_bestTruncatedAt; }
174    void setBestTruncatedAt(int y, RenderBoxModelObject* forRenderer, bool forcedBreak = false);
175    int truncatedAt() const { return m_legacyPrinting.m_truncatedAt; }
176    void setTruncatedAt(int y)
177    {
178        m_legacyPrinting.m_truncatedAt = y;
179        m_legacyPrinting.m_bestTruncatedAt = 0;
180        m_legacyPrinting.m_truncatorWidth = 0;
181        m_legacyPrinting.m_forcedPageBreak = false;
182    }
183    const IntRect& printRect() const { return m_legacyPrinting.m_printRect; }
184    void setPrintRect(const IntRect& r) { m_legacyPrinting.m_printRect = r; }
185    // End deprecated functions.
186
187    // Notification that this view moved into or out of a native window.
188    void setIsInWindow(bool);
189
190#if USE(ACCELERATED_COMPOSITING)
191    RenderLayerCompositor* compositor();
192    bool usesCompositing() const;
193#endif
194
195#if ENABLE(CSS_SHADERS) && USE(3D_GRAPHICS)
196    CustomFilterGlobalContext* customFilterGlobalContext();
197#endif
198
199    IntRect unscaledDocumentRect() const;
200    LayoutRect backgroundRect(RenderBox* backgroundRenderer) const;
201
202    IntRect documentRect() const;
203
204    // Renderer that paints the root background has background-images which all have background-attachment: fixed.
205    bool rootBackgroundIsEntirelyFixed() const;
206
207    bool hasRenderNamedFlowThreads() const;
208    bool checkTwoPassLayoutForAutoHeightRegions() const;
209    FlowThreadController* flowThreadController();
210
211    void styleDidChange(StyleDifference, const RenderStyle* oldStyle);
212
213    IntervalArena* intervalArena();
214
215    IntSize viewportSize() const { return document()->viewportSize(); }
216
217    void setRenderQuoteHead(RenderQuote* head) { m_renderQuoteHead = head; }
218    RenderQuote* renderQuoteHead() const { return m_renderQuoteHead; }
219
220    // FIXME: This is a work around because the current implementation of counters
221    // requires walking the entire tree repeatedly and most pages don't actually use either
222    // feature so we shouldn't take the performance hit when not needed. Long term we should
223    // rewrite the counter and quotes code.
224    void addRenderCounter() { m_renderCounterCount++; }
225    void removeRenderCounter() { ASSERT(m_renderCounterCount > 0); m_renderCounterCount--; }
226    bool hasRenderCounters() { return m_renderCounterCount; }
227
228    virtual void addChild(RenderObject* newChild, RenderObject* beforeChild = 0) OVERRIDE;
229
230    IntRect pixelSnappedLayoutOverflowRect() const { return pixelSnappedIntRect(layoutOverflowRect()); }
231
232protected:
233    virtual void mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState&, MapCoordinatesFlags = ApplyContainerFlip, bool* wasFixed = 0) const OVERRIDE;
234    virtual const RenderObject* pushMappingToContainer(const RenderLayerModelObject* ancestorToStopAt, RenderGeometryMap&) const OVERRIDE;
235    virtual void mapAbsoluteToLocalPoint(MapCoordinatesFlags, TransformState&) const;
236    virtual bool requiresColumns(int desiredColumnCount) const OVERRIDE;
237
238private:
239    bool initializeLayoutState(LayoutState&);
240
241    virtual void calcColumnWidth() OVERRIDE;
242    virtual ColumnInfo::PaginationUnit paginationUnit() const OVERRIDE;
243
244    bool shouldRepaint(const LayoutRect&) const;
245
246    // These functions may only be accessed by LayoutStateMaintainer.
247    bool pushLayoutState(RenderBox* renderer, const LayoutSize& offset, LayoutUnit pageHeight = 0, bool pageHeightChanged = false, ColumnInfo* colInfo = 0)
248    {
249        // We push LayoutState even if layoutState is disabled because it stores layoutDelta too.
250        if (!doingFullRepaint() || m_layoutState->isPaginated() || renderer->hasColumns() || renderer->flowThreadContainingBlock()
251            || m_layoutState->lineGrid() || (renderer->style()->lineGrid() != RenderStyle::initialLineGrid() && renderer->isBlockFlow())
252#if ENABLE(CSS_SHAPES)
253            || (renderer->isRenderBlock() && toRenderBlock(renderer)->shapeInsideInfo())
254            || (m_layoutState->shapeInsideInfo() && renderer->isRenderBlock() && !toRenderBlock(renderer)->allowsShapeInsideInfoSharing())
255#endif
256            ) {
257            pushLayoutStateForCurrentFlowThread(renderer);
258            m_layoutState = new (renderArena()) LayoutState(m_layoutState, renderer, offset, pageHeight, pageHeightChanged, colInfo);
259            return true;
260        }
261        return false;
262    }
263
264    void popLayoutState()
265    {
266        LayoutState* state = m_layoutState;
267        m_layoutState = state->m_next;
268        state->destroy(renderArena());
269        popLayoutStateForCurrentFlowThread();
270    }
271
272    // Suspends the LayoutState optimization. Used under transforms that cannot be represented by
273    // LayoutState (common in SVG) and when manipulating the render tree during layout in ways
274    // that can trigger repaint of a non-child (e.g. when a list item moves its list marker around).
275    // Note that even when disabled, LayoutState is still used to store layoutDelta.
276    // These functions may only be accessed by LayoutStateMaintainer or LayoutStateDisabler.
277    void disableLayoutState() { m_layoutStateDisableCount++; }
278    void enableLayoutState() { ASSERT(m_layoutStateDisableCount > 0); m_layoutStateDisableCount--; }
279
280    void layoutContent(const LayoutState&);
281    void layoutContentInAutoLogicalHeightRegions(const LayoutState&);
282#ifndef NDEBUG
283    void checkLayoutState(const LayoutState&);
284#endif
285
286    size_t getRetainedWidgets(Vector<RenderWidget*>&);
287    void releaseWidgets(Vector<RenderWidget*>&);
288
289    void pushLayoutStateForCurrentFlowThread(const RenderObject*);
290    void popLayoutStateForCurrentFlowThread();
291
292    friend class LayoutStateMaintainer;
293    friend class LayoutStateDisabler;
294
295protected:
296    FrameView* m_frameView;
297
298    RenderObject* m_selectionStart;
299    RenderObject* m_selectionEnd;
300    int m_selectionStartPos;
301    int m_selectionEndPos;
302
303    // FIXME: Only used by embedded WebViews inside AppKit NSViews.  Find a way to remove.
304    struct LegacyPrinting {
305        LegacyPrinting()
306            : m_bestTruncatedAt(0)
307            , m_truncatedAt(0)
308            , m_truncatorWidth(0)
309            , m_forcedPageBreak(false)
310        { }
311
312        int m_bestTruncatedAt;
313        int m_truncatedAt;
314        int m_truncatorWidth;
315        IntRect m_printRect;
316        bool m_forcedPageBreak;
317    };
318    LegacyPrinting m_legacyPrinting;
319    // End deprecated members.
320
321    int m_maximalOutlineSize; // Used to apply a fudge factor to dirty-rect checks on blocks/tables.
322
323    typedef HashSet<RenderWidget*> RenderWidgetSet;
324    RenderWidgetSet m_widgets;
325
326private:
327    bool shouldUsePrintingLayout() const;
328
329    LayoutUnit m_pageLogicalHeight;
330    bool m_pageLogicalHeightChanged;
331    LayoutState* m_layoutState;
332    unsigned m_layoutStateDisableCount;
333#if USE(ACCELERATED_COMPOSITING)
334    OwnPtr<RenderLayerCompositor> m_compositor;
335#endif
336#if ENABLE(CSS_SHADERS) && USE(3D_GRAPHICS)
337    OwnPtr<CustomFilterGlobalContext> m_customFilterGlobalContext;
338#endif
339    OwnPtr<FlowThreadController> m_flowThreadController;
340    RefPtr<IntervalArena> m_intervalArena;
341
342    RenderQuote* m_renderQuoteHead;
343    unsigned m_renderCounterCount;
344
345    bool m_selectionWasCaret;
346};
347
348inline RenderView* toRenderView(RenderObject* object)
349{
350    ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isRenderView());
351    return static_cast<RenderView*>(object);
352}
353
354inline const RenderView* toRenderView(const RenderObject* object)
355{
356    ASSERT_WITH_SECURITY_IMPLICATION(!object || object->isRenderView());
357    return static_cast<const RenderView*>(object);
358}
359
360// This will catch anyone doing an unnecessary cast.
361void toRenderView(const RenderView*);
362
363ALWAYS_INLINE RenderView* Document::renderView() const
364{
365    return toRenderView(renderer());
366}
367
368// Stack-based class to assist with LayoutState push/pop
369class LayoutStateMaintainer {
370    WTF_MAKE_NONCOPYABLE(LayoutStateMaintainer);
371public:
372    // ctor to push now
373    LayoutStateMaintainer(RenderView* view, RenderBox* root, LayoutSize offset, bool disableState = false, LayoutUnit pageHeight = 0, bool pageHeightChanged = false, ColumnInfo* colInfo = 0)
374        : m_view(view)
375        , m_disabled(disableState)
376        , m_didStart(false)
377        , m_didEnd(false)
378        , m_didCreateLayoutState(false)
379    {
380        push(root, offset, pageHeight, pageHeightChanged, colInfo);
381    }
382
383    // ctor to maybe push later
384    LayoutStateMaintainer(RenderView* view)
385        : m_view(view)
386        , m_disabled(false)
387        , m_didStart(false)
388        , m_didEnd(false)
389        , m_didCreateLayoutState(false)
390    {
391    }
392
393    ~LayoutStateMaintainer()
394    {
395        ASSERT(m_didStart == m_didEnd);   // if this fires, it means that someone did a push(), but forgot to pop().
396    }
397
398    void push(RenderBox* root, LayoutSize offset, LayoutUnit pageHeight = 0, bool pageHeightChanged = false, ColumnInfo* colInfo = 0)
399    {
400        ASSERT(!m_didStart);
401        // We push state even if disabled, because we still need to store layoutDelta
402        m_didCreateLayoutState = m_view->pushLayoutState(root, offset, pageHeight, pageHeightChanged, colInfo);
403        if (m_disabled && m_didCreateLayoutState)
404            m_view->disableLayoutState();
405        m_didStart = true;
406    }
407
408    void pop()
409    {
410        if (m_didStart) {
411            ASSERT(!m_didEnd);
412            if (m_didCreateLayoutState) {
413                m_view->popLayoutState();
414                if (m_disabled)
415                    m_view->enableLayoutState();
416            }
417
418            m_didEnd = true;
419        }
420    }
421
422    bool didPush() const { return m_didStart; }
423
424private:
425    RenderView* m_view;
426    bool m_disabled : 1;        // true if the offset and clip part of layoutState is disabled
427    bool m_didStart : 1;        // true if we did a push or disable
428    bool m_didEnd : 1;          // true if we popped or re-enabled
429    bool m_didCreateLayoutState : 1; // true if we actually made a layout state.
430};
431
432class LayoutStateDisabler {
433    WTF_MAKE_NONCOPYABLE(LayoutStateDisabler);
434public:
435    LayoutStateDisabler(RenderView* view)
436        : m_view(view)
437    {
438        if (m_view)
439            m_view->disableLayoutState();
440    }
441
442    ~LayoutStateDisabler()
443    {
444        if (m_view)
445            m_view->enableLayoutState();
446    }
447private:
448    RenderView* m_view;
449};
450
451class FragmentationDisabler {
452    WTF_MAKE_NONCOPYABLE(FragmentationDisabler);
453public:
454    FragmentationDisabler(RenderObject* root);
455    ~FragmentationDisabler();
456private:
457    RenderObject* m_root;
458    RenderObject::FlowThreadState m_flowThreadState;
459    bool m_fragmenting;
460#ifndef NDEBUG
461    LayoutState* m_layoutState;
462#endif
463};
464
465} // namespace WebCore
466
467#endif // RenderView_h
468