343439555c08305732ebb7ccdb80384d92067b78
[WebKit-https.git] / Source / WebCore / rendering / LogicalSelectionOffsetCaches.h
1 /*
2  * Copyright (C) 2013 Apple Inc. All rights reserved.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public License
15  * along with this library; see the file COPYING.LIB.  If not, write to
16  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  *
19  */
20
21 #ifndef LogicalSelectionOffsetCaches_h
22 #define LogicalSelectionOffsetCaches_h
23
24 #include "RenderBlock.h"
25
26 namespace WebCore {
27
28 static inline bool isContainingBlockCandidateForAbsolutelyPositionedObject(RenderObject* object)
29 {
30     return object->style()->position() != StaticPosition
31         || (object->hasTransform() && object->isRenderBlock())
32 #if ENABLE(SVG)
33         || object->isSVGForeignObject()
34 #endif
35         || object->isRenderView();
36 }
37
38 static inline bool isNonRenderBlockInline(RenderObject* object)
39 {
40     return (object->isInline() && !object->isReplaced()) || !object->isRenderBlock();
41 }
42
43 static inline RenderObject* containingBlockForFixedPosition(RenderObject* parent)
44 {
45     RenderObject* object = parent;
46     while (object && !object->canContainFixedPositionObjects())
47         object = object->parent();
48     ASSERT(!object || !object->isAnonymousBlock());
49     return object;
50 }
51
52 static inline RenderObject* containingBlockForAbsolutePosition(RenderObject* parent)
53 {
54     RenderObject* object = parent;
55     while (object && !isContainingBlockCandidateForAbsolutelyPositionedObject(object))
56         object = object->parent();
57     
58     // For a relatively positioned inline, return its nearest non-anonymous containing block,
59     // not the inline itself, to avoid having a positioned objects list in all RenderInlines
60     // and use RenderBlock* as RenderObject::containingBlock's return type.
61     // Use RenderBlock::container() to obtain the inline.
62     if (object->isRenderInline())
63         object = object->containingBlock();
64     
65     while (object && object->isAnonymousBlock())
66         object = object->containingBlock();
67     
68     return object;
69 }
70
71 static inline RenderObject* containingBlockForObjectInFlow(RenderObject* parent)
72 {
73     RenderObject* object = parent;
74     while (object && isNonRenderBlockInline(object))
75         object = object->parent();
76     return object;
77 }
78
79 class LogicalSelectionOffsetCaches {
80 public:
81     class ContainingBlockInfo {
82     public:
83         ContainingBlockInfo()
84             : m_block(0)
85             , m_cache(0)
86             , m_hasFloatsOrFlowThreads(false)
87             , m_cachedLogicalLeftSelectionOffset(false)
88             , m_cachedLogicalRightSelectionOffset(false)
89         { }
90
91         void setBlock(RenderBlock* block, const LogicalSelectionOffsetCaches* cache)
92         {
93             m_block = block;
94             m_hasFloatsOrFlowThreads = m_hasFloatsOrFlowThreads || m_block->containsFloats() || m_block->flowThreadContainingBlock();
95             m_cache = cache;
96             m_cachedLogicalLeftSelectionOffset = false;
97             m_cachedLogicalRightSelectionOffset = false;
98         }
99
100         RenderBlock* block() const { return m_block; }
101         const LogicalSelectionOffsetCaches* cache() const { return m_cache; }
102
103         LayoutUnit logicalLeftSelectionOffset(RenderBlock* rootBlock, LayoutUnit position) const
104         {
105             ASSERT(m_cache);
106             if (m_hasFloatsOrFlowThreads || !m_cachedLogicalLeftSelectionOffset) {
107                 m_cachedLogicalLeftSelectionOffset = true;
108                 m_logicalLeftSelectionOffset = m_block->logicalLeftSelectionOffset(rootBlock, position, *m_cache);
109             } else
110                 ASSERT(m_logicalLeftSelectionOffset == m_block->logicalLeftSelectionOffset(rootBlock, position, *m_cache));
111             return m_logicalLeftSelectionOffset;
112         }
113
114         LayoutUnit logicalRightSelectionOffset(RenderBlock* rootBlock, LayoutUnit position) const
115         {
116             ASSERT(m_cache);
117             if (m_hasFloatsOrFlowThreads || !m_cachedLogicalRightSelectionOffset) {
118                 m_cachedLogicalRightSelectionOffset = true;
119                 m_logicalRightSelectionOffset = m_block->logicalRightSelectionOffset(rootBlock, position, *m_cache);
120             } else
121                 ASSERT(m_logicalRightSelectionOffset == m_block->logicalRightSelectionOffset(rootBlock, position, *m_cache));
122             return m_logicalRightSelectionOffset;
123         }
124
125     private:
126         RenderBlock* m_block;
127         const LogicalSelectionOffsetCaches* m_cache;
128         bool m_hasFloatsOrFlowThreads : 1;
129         mutable bool m_cachedLogicalLeftSelectionOffset : 1;
130         mutable bool m_cachedLogicalRightSelectionOffset : 1;
131         mutable LayoutUnit m_logicalLeftSelectionOffset;
132         mutable LayoutUnit m_logicalRightSelectionOffset;
133         
134     };
135
136     LogicalSelectionOffsetCaches(RenderBlock* rootBlock)
137     {
138         ASSERT(rootBlock->isSelectionRoot());
139         RenderObject* parent = rootBlock->parent();
140
141         // LogicalSelectionOffsetCaches should not be used on an orphaned tree.
142         m_containingBlockForFixedPosition.setBlock(toRenderBlock(containingBlockForFixedPosition(parent)), 0);
143         m_containingBlockForAbsolutePosition.setBlock(toRenderBlock(containingBlockForAbsolutePosition(parent)), 0);
144         m_containingBlockForInflowPosition.setBlock(toRenderBlock(containingBlockForObjectInFlow(parent)), 0);
145     }
146
147     LogicalSelectionOffsetCaches(RenderBlock* block, const LogicalSelectionOffsetCaches& cache)
148         : m_containingBlockForFixedPosition(cache.m_containingBlockForFixedPosition)
149         , m_containingBlockForAbsolutePosition(cache.m_containingBlockForAbsolutePosition)
150         , m_parentCache(&cache)
151     {
152         if (block->canContainFixedPositionObjects())
153             m_containingBlockForFixedPosition.setBlock(block, &cache);
154
155         if (isContainingBlockCandidateForAbsolutelyPositionedObject(block) && !block->isRenderInline() && !block->isAnonymousBlock())
156             m_containingBlockForFixedPosition.setBlock(block, &cache);
157
158         m_containingBlockForInflowPosition.setBlock(block, &cache);
159     }
160
161     const ContainingBlockInfo& containingBlockInfo(RenderBlock* block) const
162     {
163         EPosition position = block->style()->position();
164         if (position == FixedPosition) {
165             ASSERT(block->containingBlock() == m_containingBlockForFixedPosition.block());
166             return m_containingBlockForFixedPosition;
167         }
168         if (position == AbsolutePosition) {
169             ASSERT(block->containingBlock() == m_containingBlockForAbsolutePosition.block());
170             return m_containingBlockForAbsolutePosition;
171         }
172         ASSERT(block->containingBlock() == m_containingBlockForInflowPosition.block());
173         return m_containingBlockForInflowPosition;
174     }
175
176 private:
177     ContainingBlockInfo m_containingBlockForFixedPosition;
178     ContainingBlockInfo m_containingBlockForAbsolutePosition;
179     ContainingBlockInfo m_containingBlockForInflowPosition;
180     const LogicalSelectionOffsetCaches* m_parentCache;
181 };
182
183 } // namespace WebCore
184
185 #endif // LogicalSelectionOffsetCaches_h