Make FloatingObjects own it's FloatingObject instances
[WebKit-https.git] / Source / WebCore / rendering / FloatingObjects.cpp
1 /*
2  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3  *           (C) 1999 Antti Koivisto (koivisto@kde.org)
4  *           (C) 2007 David Smith (catfish.man@gmail.com)
5  * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
6  * Copyright (C) Research In Motion Limited 2010. All rights reserved.
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public License
19  * along with this library; see the file COPYING.LIB.  If not, write to
20  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21  * Boston, MA 02110-1301, USA.
22  */
23
24 #include "config.h"
25 #include "FloatingObjects.h"
26
27 #include "RenderBlock.h"
28 #include "RenderBox.h"
29 #include "RenderView.h"
30
31 using namespace std;
32 using namespace WTF;
33
34 namespace WebCore {
35
36 struct SameSizeAsFloatingObject {
37     void* pointers[2];
38     LayoutRect rect;
39     int paginationStrut;
40     uint32_t bitfields : 8;
41 };
42
43 COMPILE_ASSERT(sizeof(FloatingObject) == sizeof(SameSizeAsFloatingObject), FloatingObject_should_stay_small);
44
45 FloatingObject::FloatingObject(RenderBox* renderer)
46     : m_renderer(renderer)
47     , m_originatingLine(0)
48     , m_paginationStrut(0)
49     , m_shouldPaint(true)
50     , m_isDescendant(false)
51     , m_isPlaced(false)
52 #ifndef NDEBUG
53     , m_isInPlacedTree(false)
54 #endif
55 {
56     EFloat type = renderer->style()->floating();
57     ASSERT(type != NoFloat);
58     if (type == LeftFloat)
59         m_type = FloatLeft;
60     else if (type == RightFloat)
61         m_type = FloatRight;
62 }
63
64 FloatingObject::FloatingObject(RenderBox* renderer, Type type, const LayoutRect& frameRect, bool shouldPaint, bool isDescendant)
65     : m_renderer(renderer)
66     , m_originatingLine(0)
67     , m_frameRect(frameRect)
68     , m_paginationStrut(0)
69     , m_type(type)
70     , m_shouldPaint(shouldPaint)
71     , m_isDescendant(isDescendant)
72     , m_isPlaced(true)
73 #ifndef NDEBUG
74     , m_isInPlacedTree(false)
75 #endif
76 {
77 }
78
79 PassOwnPtr<FloatingObject> FloatingObject::create(RenderBox* renderer)
80 {
81     OwnPtr<FloatingObject> newObj = adoptPtr(new FloatingObject(renderer));
82     newObj->setShouldPaint(!renderer->hasSelfPaintingLayer()); // If a layer exists, the float will paint itself. Otherwise someone else will.
83     newObj->setIsDescendant(true);
84
85     return newObj.release();
86 }
87
88 PassOwnPtr<FloatingObject> FloatingObject::copyToNewContainer(LayoutSize offset, bool shouldPaint, bool isDescendant) const
89 {
90     return adoptPtr(new FloatingObject(renderer(), type(), LayoutRect(frameRect().location() - offset, frameRect().size()), shouldPaint, isDescendant));
91 }
92
93 PassOwnPtr<FloatingObject> FloatingObject::unsafeClone() const
94 {
95     OwnPtr<FloatingObject> cloneObject = adoptPtr(new FloatingObject(renderer(), type(), m_frameRect, m_shouldPaint, m_isDescendant));
96     cloneObject->m_originatingLine = m_originatingLine;
97     cloneObject->m_paginationStrut = m_paginationStrut;
98     cloneObject->m_isPlaced = m_isPlaced;
99     return cloneObject.release();
100 }
101
102 template <FloatingObject::Type FloatTypeValue>
103 class ComputeFloatOffsetAdapter {
104 public:
105     typedef FloatingObjectInterval IntervalType;
106
107     ComputeFloatOffsetAdapter(const RenderBlock* renderer, int lineTop, int lineBottom, LayoutUnit& offset)
108         : m_renderer(renderer)
109         , m_lineTop(lineTop)
110         , m_lineBottom(lineBottom)
111         , m_offset(offset)
112         , m_outermostFloat(0)
113     {
114     }
115
116     int lowValue() const { return m_lineTop; }
117     int highValue() const { return m_lineBottom; }
118     void collectIfNeeded(const IntervalType&);
119
120 #if ENABLE(CSS_SHAPES)
121     // When computing the offset caused by the floats on a given line, if
122     // the outermost float on that line has a shape-outside, the inline
123     // content that butts up against that float must be positioned using
124     // the contours of the shape, not the margin box of the float.
125     const FloatingObject* outermostFloat() const { return m_outermostFloat; }
126 #endif
127
128     LayoutUnit getHeightRemaining() const;
129
130 private:
131     bool updateOffsetIfNeeded(const FloatingObject*);
132
133     const RenderBlock* m_renderer;
134     int m_lineTop;
135     int m_lineBottom;
136     LayoutUnit& m_offset;
137     const FloatingObject* m_outermostFloat;
138 };
139
140 FloatingObjects::FloatingObjects(const RenderBlock* renderer, bool horizontalWritingMode)
141     : m_placedFloatsTree(UninitializedTree)
142     , m_leftObjectsCount(0)
143     , m_rightObjectsCount(0)
144     , m_horizontalWritingMode(horizontalWritingMode)
145     , m_renderer(renderer)
146 {
147 }
148
149 FloatingObjects::~FloatingObjects()
150 {
151     // FIXME: m_set should use OwnPtr instead.
152     deleteAllValues(m_set);
153 }
154
155 void FloatingObjects::clearLineBoxTreePointers()
156 {
157     // Clear references to originating lines, since the lines are being deleted
158     FloatingObjectSetIterator end = m_set.end();
159     for (FloatingObjectSetIterator it = m_set.begin(); it != end; ++it) {
160         ASSERT(!((*it)->originatingLine()) || &((*it)->originatingLine()->renderer()) == m_renderer);
161         (*it)->setOriginatingLine(0);
162     }
163 }
164
165 void FloatingObjects::clear()
166 {
167     deleteAllValues(m_set);
168     m_set.clear();
169     m_placedFloatsTree.clear();
170     m_leftObjectsCount = 0;
171     m_rightObjectsCount = 0;
172 }
173
174 void FloatingObjects::moveAllToFloatInfoMap(RendererToFloatInfoMap& map)
175 {
176     FloatingObjectSetIterator end = m_set.end();
177     for (FloatingObjectSetIterator it = m_set.begin(); it != end; ++it) {
178         FloatingObject* f = *it;
179         map.add(f->renderer(), f);
180     }
181     // clear set before clearing this because we don't want to delete all of
182     // the objects we have just transferred.
183     m_set.clear();
184     clear();
185 }
186
187 void FloatingObjects::increaseObjectsCount(FloatingObject::Type type)
188 {
189     if (type == FloatingObject::FloatLeft)
190         m_leftObjectsCount++;
191     else
192         m_rightObjectsCount++;
193 }
194
195 void FloatingObjects::decreaseObjectsCount(FloatingObject::Type type)
196 {
197     if (type == FloatingObject::FloatLeft)
198         m_leftObjectsCount--;
199     else
200         m_rightObjectsCount--;
201 }
202
203 FloatingObjectInterval FloatingObjects::intervalForFloatingObject(FloatingObject* floatingObject)
204 {
205     if (m_horizontalWritingMode)
206         return FloatingObjectInterval(floatingObject->frameRect().y(), floatingObject->frameRect().maxY(), floatingObject);
207     return FloatingObjectInterval(floatingObject->frameRect().x(), floatingObject->frameRect().maxX(), floatingObject);
208 }
209
210 void FloatingObjects::addPlacedObject(FloatingObject* floatingObject)
211 {
212     ASSERT(!floatingObject->isInPlacedTree());
213
214     floatingObject->setIsPlaced(true);
215     if (m_placedFloatsTree.isInitialized())
216         m_placedFloatsTree.add(intervalForFloatingObject(floatingObject));
217
218 #ifndef NDEBUG
219     floatingObject->setIsInPlacedTree(true);
220 #endif
221 }
222
223 void FloatingObjects::removePlacedObject(FloatingObject* floatingObject)
224 {
225     ASSERT(floatingObject->isPlaced() && floatingObject->isInPlacedTree());
226
227     if (m_placedFloatsTree.isInitialized()) {
228         bool removed = m_placedFloatsTree.remove(intervalForFloatingObject(floatingObject));
229         ASSERT_UNUSED(removed, removed);
230     }
231
232     floatingObject->setIsPlaced(false);
233 #ifndef NDEBUG
234     floatingObject->setIsInPlacedTree(false);
235 #endif
236 }
237
238 FloatingObject* FloatingObjects::add(PassOwnPtr<FloatingObject> floatingObject)
239 {
240     FloatingObject* newObject = floatingObject.leakPtr();
241     increaseObjectsCount(newObject->type());
242     m_set.add(newObject);
243     if (newObject->isPlaced())
244         addPlacedObject(newObject);
245     return newObject;
246 }
247
248 void FloatingObjects::remove(FloatingObject* floatingObject)
249 {
250     decreaseObjectsCount(floatingObject->type());
251     m_set.remove(floatingObject);
252     ASSERT(floatingObject->isPlaced() || !floatingObject->isInPlacedTree());
253     if (floatingObject->isPlaced())
254         removePlacedObject(floatingObject);
255     ASSERT(!floatingObject->originatingLine());
256     delete floatingObject;
257 }
258
259 void FloatingObjects::computePlacedFloatsTree()
260 {
261     ASSERT(!m_placedFloatsTree.isInitialized());
262     if (m_set.isEmpty())
263         return;
264     m_placedFloatsTree.initIfNeeded(m_renderer->view().intervalArena());
265     FloatingObjectSetIterator it = m_set.begin();
266     FloatingObjectSetIterator end = m_set.end();
267     for (; it != end; ++it) {
268         FloatingObject* floatingObject = *it;
269         if (floatingObject->isPlaced())
270             m_placedFloatsTree.add(intervalForFloatingObject(floatingObject));
271     }
272 }
273
274 LayoutUnit FloatingObjects::logicalLeftOffset(LayoutUnit fixedOffset, LayoutUnit logicalTop, LayoutUnit logicalHeight, ShapeOutsideFloatOffsetMode offsetMode, LayoutUnit *heightRemaining)
275 {
276 #if !ENABLE(CSS_SHAPES)
277     UNUSED_PARAM(offsetMode);
278 #endif
279
280     LayoutUnit offset = fixedOffset;
281     ComputeFloatOffsetAdapter<FloatingObject::FloatLeft> adapter(m_renderer, roundToInt(logicalTop), roundToInt(logicalTop + logicalHeight), offset);
282     placedFloatsTree().allOverlapsWithAdapter(adapter);
283
284     if (heightRemaining)
285         *heightRemaining = adapter.getHeightRemaining();
286
287 #if ENABLE(CSS_SHAPES)
288     const FloatingObject* outermostFloat = adapter.outermostFloat();
289     if (offsetMode == ShapeOutsideFloatShapeOffset && outermostFloat) {
290         if (ShapeOutsideInfo* shapeOutside = outermostFloat->renderer()->shapeOutsideInfo()) {
291             shapeOutside->computeSegmentsForContainingBlockLine(logicalTop, outermostFloat->logicalTop(m_horizontalWritingMode), logicalHeight);
292             offset += shapeOutside->rightSegmentMarginBoxDelta();
293         }
294     }
295 #endif
296
297     return offset;
298 }
299
300 LayoutUnit FloatingObjects::logicalRightOffset(LayoutUnit fixedOffset, LayoutUnit logicalTop, LayoutUnit logicalHeight, ShapeOutsideFloatOffsetMode offsetMode, LayoutUnit *heightRemaining)
301 {
302 #if !ENABLE(CSS_SHAPES)
303     UNUSED_PARAM(offsetMode);
304 #endif
305
306     LayoutUnit offset = fixedOffset;
307     ComputeFloatOffsetAdapter<FloatingObject::FloatRight> adapter(m_renderer, roundToInt(logicalTop), roundToInt(logicalTop + logicalHeight), offset);
308     placedFloatsTree().allOverlapsWithAdapter(adapter);
309
310     if (heightRemaining)
311         *heightRemaining = adapter.getHeightRemaining();
312
313 #if ENABLE(CSS_SHAPES)
314     const FloatingObject* outermostFloat = adapter.outermostFloat();
315     if (offsetMode == ShapeOutsideFloatShapeOffset && outermostFloat) {
316         if (ShapeOutsideInfo* shapeOutside = outermostFloat->renderer()->shapeOutsideInfo()) {
317             shapeOutside->computeSegmentsForContainingBlockLine(logicalTop, outermostFloat->logicalTop(m_horizontalWritingMode), logicalHeight);
318             offset += shapeOutside->leftSegmentMarginBoxDelta();
319         }
320     }
321 #endif
322
323     return min(fixedOffset, offset);
324 }
325
326 inline static bool rangesIntersect(int floatTop, int floatBottom, int objectTop, int objectBottom)
327 {
328     if (objectTop >= floatBottom || objectBottom < floatTop)
329         return false;
330
331     // The top of the object overlaps the float
332     if (objectTop >= floatTop)
333         return true;
334
335     // The object encloses the float
336     if (objectTop < floatTop && objectBottom > floatBottom)
337         return true;
338
339     // The bottom of the object overlaps the float
340     if (objectBottom > objectTop && objectBottom > floatTop && objectBottom <= floatBottom)
341         return true;
342
343     return false;
344 }
345
346 template<>
347 inline bool ComputeFloatOffsetAdapter<FloatingObject::FloatLeft>::updateOffsetIfNeeded(const FloatingObject* floatingObject)
348 {
349     LayoutUnit logicalRight = floatingObject->logicalRight(m_renderer->isHorizontalWritingMode());
350     if (logicalRight > m_offset) {
351         m_offset = logicalRight;
352         return true;
353     }
354     return false;
355 }
356
357 template<>
358 inline bool ComputeFloatOffsetAdapter<FloatingObject::FloatRight>::updateOffsetIfNeeded(const FloatingObject* floatingObject)
359 {
360     LayoutUnit logicalLeft = floatingObject->logicalLeft(m_renderer->isHorizontalWritingMode());
361     if (logicalLeft < m_offset) {
362         m_offset = logicalLeft;
363         return true;
364     }
365     return false;
366 }
367
368 template <FloatingObject::Type FloatTypeValue>
369 inline void ComputeFloatOffsetAdapter<FloatTypeValue>::collectIfNeeded(const IntervalType& interval)
370 {
371     const FloatingObject* floatingObject = interval.data();
372     if (floatingObject->type() != FloatTypeValue || !rangesIntersect(interval.low(), interval.high(), m_lineTop, m_lineBottom))
373         return;
374
375     // All the objects returned from the tree should be already placed.
376     ASSERT(floatingObject->isPlaced());
377     ASSERT(rangesIntersect(floatingObject->pixelSnappedLogicalTop(m_renderer->isHorizontalWritingMode()), floatingObject->pixelSnappedLogicalBottom(m_renderer->isHorizontalWritingMode()), m_lineTop, m_lineBottom));
378
379     bool floatIsNewExtreme = updateOffsetIfNeeded(floatingObject);
380     if (floatIsNewExtreme)
381         m_outermostFloat = floatingObject;
382 }
383
384 template <FloatingObject::Type FloatTypeValue>
385 LayoutUnit ComputeFloatOffsetAdapter<FloatTypeValue>::getHeightRemaining() const
386 {
387     return m_outermostFloat ? m_outermostFloat->logicalBottom(m_renderer->isHorizontalWritingMode()) - m_lineTop : LayoutUnit(1);
388 }
389
390 #ifndef NDEBUG
391 // These helpers are only used by the PODIntervalTree for debugging purposes.
392 String ValueToString<int>::string(const int value)
393 {
394     return String::number(value);
395 }
396
397 String ValueToString<FloatingObject*>::string(const FloatingObject* floatingObject)
398 {
399     return String::format("%p (%ix%i %ix%i)", floatingObject, floatingObject->frameRect().x().toInt(), floatingObject->frameRect().y().toInt(), floatingObject->frameRect().maxX().toInt(), floatingObject->frameRect().maxY().toInt());
400 }
401 #endif
402
403
404 } // namespace WebCore