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.
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.
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.
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.
25 #include "core/rendering/FloatingObjects.h"
27 #include "core/rendering/RenderBlockFlow.h"
28 #include "core/rendering/RenderBox.h"
29 #include "core/rendering/RenderView.h"
36 struct SameSizeAsFloatingObject {
40 uint32_t bitfields : 8;
43 COMPILE_ASSERT(sizeof(FloatingObject) == sizeof(SameSizeAsFloatingObject), FloatingObject_should_stay_small);
45 FloatingObject::FloatingObject(RenderBox* renderer)
46 : m_renderer(renderer)
47 , m_originatingLine(0)
48 , m_paginationStrut(0)
50 , m_isDescendant(false)
53 , m_isInPlacedTree(false)
56 EFloat type = renderer->style()->floating();
57 ASSERT(type != NoFloat);
58 if (type == LeftFloat)
60 else if (type == RightFloat)
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)
70 , m_shouldPaint(shouldPaint)
71 , m_isDescendant(isDescendant)
74 , m_isInPlacedTree(false)
79 PassOwnPtr<FloatingObject> FloatingObject::create(RenderBox* renderer)
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);
85 return newObj.release();
88 PassOwnPtr<FloatingObject> FloatingObject::copyToNewContainer(LayoutSize offset, bool shouldPaint, bool isDescendant) const
90 return adoptPtr(new FloatingObject(renderer(), type(), LayoutRect(frameRect().location() - offset, frameRect().size()), shouldPaint, isDescendant));
93 PassOwnPtr<FloatingObject> FloatingObject::unsafeClone() const
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();
102 template <FloatingObject::Type FloatTypeValue>
103 class ComputeFloatOffsetAdapter {
105 typedef FloatingObjectInterval IntervalType;
107 ComputeFloatOffsetAdapter(const RenderBlockFlow* renderer, int lineTop, int lineBottom, LayoutUnit offset)
108 : m_renderer(renderer)
110 , m_lineBottom(lineBottom)
112 , m_outermostFloat(0)
116 int lowValue() const { return m_lineTop; }
117 int highValue() const { return m_lineBottom; }
118 void collectIfNeeded(const IntervalType&);
120 LayoutUnit offset() const { return m_offset; }
121 LayoutUnit shapeOffset() const;
122 LayoutUnit heightRemaining() const;
125 bool updateOffsetIfNeeded(const FloatingObject*);
127 const RenderBlockFlow* m_renderer;
131 const FloatingObject* m_outermostFloat;
135 FloatingObjects::~FloatingObjects()
137 // FIXME: m_set should use OwnPtr instead.
138 deleteAllValues(m_set);
140 void FloatingObjects::clearLineBoxTreePointers()
142 // Clear references to originating lines, since the lines are being deleted
143 FloatingObjectSetIterator end = m_set.end();
144 for (FloatingObjectSetIterator it = m_set.begin(); it != end; ++it) {
145 ASSERT(!((*it)->originatingLine()) || (*it)->originatingLine()->renderer() == m_renderer);
146 (*it)->setOriginatingLine(0);
151 inline bool ComputeFloatOffsetAdapter<FloatingObject::FloatLeft>::updateOffsetIfNeeded(const FloatingObject* floatingObject)
153 LayoutUnit logicalRight = m_renderer->logicalRightForFloat(floatingObject);
154 if (logicalRight > m_offset) {
155 m_offset = logicalRight;
161 FloatingObjects::FloatingObjects(const RenderBlockFlow* renderer, bool horizontalWritingMode)
162 : m_placedFloatsTree(UninitializedTree)
163 , m_leftObjectsCount(0)
164 , m_rightObjectsCount(0)
165 , m_horizontalWritingMode(horizontalWritingMode)
166 , m_renderer(renderer)
167 , m_cachedHorizontalWritingMode(false)
171 void FloatingObjects::clear()
173 deleteAllValues(m_set);
175 m_placedFloatsTree.clear();
176 m_leftObjectsCount = 0;
177 m_rightObjectsCount = 0;
178 markLowestFloatLogicalBottomCacheAsDirty();
181 LayoutUnit FloatingObjects::lowestFloatLogicalBottom(FloatingObject::Type floatType)
183 bool isInHorizontalWritingMode = m_horizontalWritingMode;
184 if (floatType != FloatingObject::FloatLeftRight) {
185 if (hasLowestFloatLogicalBottomCached(isInHorizontalWritingMode, floatType))
186 return getCachedlowestFloatLogicalBottom(floatType);
188 if (hasLowestFloatLogicalBottomCached(isInHorizontalWritingMode, FloatingObject::FloatLeft) && hasLowestFloatLogicalBottomCached(isInHorizontalWritingMode, FloatingObject::FloatRight)) {
189 return max(getCachedlowestFloatLogicalBottom(FloatingObject::FloatLeft),
190 getCachedlowestFloatLogicalBottom(FloatingObject::FloatRight));
194 LayoutUnit lowestFloatBottom = 0;
195 const FloatingObjectSet& floatingObjectSet = set();
196 FloatingObjectSetIterator end = floatingObjectSet.end();
197 if (floatType == FloatingObject::FloatLeftRight) {
198 LayoutUnit lowestFloatBottomLeft = 0;
199 LayoutUnit lowestFloatBottomRight = 0;
200 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) {
201 FloatingObject* floatingObject = *it;
202 if (floatingObject->isPlaced()) {
203 FloatingObject::Type curType = floatingObject->type();
204 LayoutUnit curFloatLogicalBottom = m_renderer->logicalBottomForFloat(floatingObject);
205 if (curType & FloatingObject::FloatLeft)
206 lowestFloatBottomLeft = max(lowestFloatBottomLeft, curFloatLogicalBottom);
207 if (curType & FloatingObject::FloatRight)
208 lowestFloatBottomRight = max(lowestFloatBottomRight, curFloatLogicalBottom);
211 lowestFloatBottom = max(lowestFloatBottomLeft, lowestFloatBottomRight);
212 setCachedLowestFloatLogicalBottom(isInHorizontalWritingMode, FloatingObject::FloatLeft, lowestFloatBottomLeft);
213 setCachedLowestFloatLogicalBottom(isInHorizontalWritingMode, FloatingObject::FloatRight, lowestFloatBottomRight);
215 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) {
216 FloatingObject* floatingObject = *it;
217 if (floatingObject->isPlaced() && floatingObject->type() == floatType)
218 lowestFloatBottom = max(lowestFloatBottom, m_renderer->logicalBottomForFloat(floatingObject));
220 setCachedLowestFloatLogicalBottom(isInHorizontalWritingMode, floatType, lowestFloatBottom);
223 return lowestFloatBottom;
226 bool FloatingObjects::hasLowestFloatLogicalBottomCached(bool isHorizontal, FloatingObject::Type type) const
228 int floatIndex = static_cast<int>(type) - 1;
229 ASSERT(floatIndex < static_cast<int>(sizeof(m_lowestFloatBottomCache) / sizeof(FloatBottomCachedValue)));
230 ASSERT(floatIndex >= 0);
231 return (m_cachedHorizontalWritingMode == isHorizontal && !m_lowestFloatBottomCache[floatIndex].dirty);
234 LayoutUnit FloatingObjects::getCachedlowestFloatLogicalBottom(FloatingObject::Type type) const
236 int floatIndex = static_cast<int>(type) - 1;
237 ASSERT(floatIndex < static_cast<int>(sizeof(m_lowestFloatBottomCache) / sizeof(FloatBottomCachedValue)));
238 ASSERT(floatIndex >= 0);
239 return m_lowestFloatBottomCache[floatIndex].value;
242 void FloatingObjects::setCachedLowestFloatLogicalBottom(bool isHorizontal, FloatingObject::Type type, LayoutUnit value)
244 int floatIndex = static_cast<int>(type) - 1;
245 ASSERT(floatIndex < static_cast<int>(sizeof(m_lowestFloatBottomCache) / sizeof(FloatBottomCachedValue)));
246 ASSERT(floatIndex >= 0);
247 m_cachedHorizontalWritingMode = isHorizontal;
248 m_lowestFloatBottomCache[floatIndex].value = value;
249 m_lowestFloatBottomCache[floatIndex].dirty = false;
252 void FloatingObjects::markLowestFloatLogicalBottomCacheAsDirty()
254 for (size_t i = 0; i < sizeof(m_lowestFloatBottomCache) / sizeof(FloatBottomCachedValue); ++i)
255 m_lowestFloatBottomCache[i].dirty = true;
258 void FloatingObjects::moveAllToFloatInfoMap(RendererToFloatInfoMap& map)
260 FloatingObjectSetIterator end = m_set.end();
261 for (FloatingObjectSetIterator it = m_set.begin(); it != end; ++it)
262 map.add((*it)->renderer(), *it);
264 // clear set before clearing this because we don't want to delete all of
265 // the objects we have just transferred.
270 inline void FloatingObjects::increaseObjectsCount(FloatingObject::Type type)
272 if (type == FloatingObject::FloatLeft)
273 m_leftObjectsCount++;
275 m_rightObjectsCount++;
278 inline void FloatingObjects::decreaseObjectsCount(FloatingObject::Type type)
280 if (type == FloatingObject::FloatLeft)
281 m_leftObjectsCount--;
283 m_rightObjectsCount--;
286 inline FloatingObjectInterval FloatingObjects::intervalForFloatingObject(FloatingObject* floatingObject)
288 if (m_horizontalWritingMode)
289 return FloatingObjectInterval(floatingObject->frameRect().pixelSnappedY(), floatingObject->frameRect().pixelSnappedMaxY(), floatingObject);
290 return FloatingObjectInterval(floatingObject->frameRect().pixelSnappedX(), floatingObject->frameRect().pixelSnappedMaxX(), floatingObject);
293 void FloatingObjects::addPlacedObject(FloatingObject* floatingObject)
295 ASSERT(!floatingObject->isInPlacedTree());
297 floatingObject->setIsPlaced(true);
298 if (m_placedFloatsTree.isInitialized())
299 m_placedFloatsTree.add(intervalForFloatingObject(floatingObject));
302 floatingObject->setIsInPlacedTree(true);
304 markLowestFloatLogicalBottomCacheAsDirty();
307 void FloatingObjects::removePlacedObject(FloatingObject* floatingObject)
309 ASSERT(floatingObject->isPlaced() && floatingObject->isInPlacedTree());
311 if (m_placedFloatsTree.isInitialized()) {
312 bool removed = m_placedFloatsTree.remove(intervalForFloatingObject(floatingObject));
313 ASSERT_UNUSED(removed, removed);
316 floatingObject->setIsPlaced(false);
318 floatingObject->setIsInPlacedTree(false);
320 markLowestFloatLogicalBottomCacheAsDirty();
323 FloatingObject* FloatingObjects::add(PassOwnPtr<FloatingObject> floatingObject)
325 FloatingObject* newObject = floatingObject.leakPtr();
326 increaseObjectsCount(newObject->type());
327 m_set.add(newObject);
328 if (newObject->isPlaced())
329 addPlacedObject(newObject);
330 markLowestFloatLogicalBottomCacheAsDirty();
334 void FloatingObjects::remove(FloatingObject* floatingObject)
336 decreaseObjectsCount(floatingObject->type());
337 m_set.remove(floatingObject);
338 ASSERT(floatingObject->isPlaced() || !floatingObject->isInPlacedTree());
339 if (floatingObject->isPlaced())
340 removePlacedObject(floatingObject);
341 markLowestFloatLogicalBottomCacheAsDirty();
342 ASSERT(!floatingObject->originatingLine());
343 delete floatingObject;
346 void FloatingObjects::computePlacedFloatsTree()
348 ASSERT(!m_placedFloatsTree.isInitialized());
351 m_placedFloatsTree.initIfNeeded(m_renderer->view()->intervalArena());
352 FloatingObjectSetIterator it = m_set.begin();
353 FloatingObjectSetIterator end = m_set.end();
354 for (; it != end; ++it) {
355 FloatingObject* floatingObject = *it;
356 if (floatingObject->isPlaced())
357 m_placedFloatsTree.add(intervalForFloatingObject(floatingObject));
361 static inline ShapeOutsideInfo* shapeInfoForFloat(const FloatingObject* floatingObject, const RenderBlockFlow* containingBlock, LayoutUnit lineTop, LayoutUnit lineBottom)
363 if (floatingObject) {
364 if (ShapeOutsideInfo* shapeOutside = floatingObject->renderer()->shapeOutsideInfo()) {
365 shapeOutside->updateDeltasForContainingBlockLine(containingBlock, floatingObject, lineTop, lineBottom - lineTop);
374 inline LayoutUnit ComputeFloatOffsetAdapter<FloatingObject::FloatLeft>::shapeOffset() const
376 if (ShapeOutsideInfo* shapeOutside = shapeInfoForFloat(m_outermostFloat, m_renderer, m_lineTop, m_lineBottom))
377 return m_offset + shapeOutside->rightMarginBoxDelta();
383 inline LayoutUnit ComputeFloatOffsetAdapter<FloatingObject::FloatRight>::shapeOffset() const
385 if (ShapeOutsideInfo* shapeOutside = shapeInfoForFloat(m_outermostFloat, m_renderer, m_lineTop, m_lineBottom))
386 return m_offset + shapeOutside->leftMarginBoxDelta();
391 LayoutUnit FloatingObjects::logicalLeftOffsetForPositioningFloat(LayoutUnit fixedOffset, LayoutUnit logicalTop, LayoutUnit *heightRemaining)
393 int logicalTopAsInt = roundToInt(logicalTop);
394 ComputeFloatOffsetAdapter<FloatingObject::FloatLeft> adapter(m_renderer, logicalTopAsInt, logicalTopAsInt, fixedOffset);
395 placedFloatsTree().allOverlapsWithAdapter(adapter);
398 *heightRemaining = adapter.heightRemaining();
400 return adapter.offset();
403 LayoutUnit FloatingObjects::logicalRightOffsetForPositioningFloat(LayoutUnit fixedOffset, LayoutUnit logicalTop, LayoutUnit *heightRemaining)
405 int logicalTopAsInt = roundToInt(logicalTop);
406 ComputeFloatOffsetAdapter<FloatingObject::FloatRight> adapter(m_renderer, logicalTopAsInt, logicalTopAsInt, fixedOffset);
407 placedFloatsTree().allOverlapsWithAdapter(adapter);
410 *heightRemaining = adapter.heightRemaining();
412 return min(fixedOffset, adapter.offset());
415 LayoutUnit FloatingObjects::logicalLeftOffset(LayoutUnit fixedOffset, LayoutUnit logicalTop, LayoutUnit logicalHeight)
417 ComputeFloatOffsetAdapter<FloatingObject::FloatLeft> adapter(m_renderer, roundToInt(logicalTop), roundToInt(logicalTop + logicalHeight), fixedOffset);
418 placedFloatsTree().allOverlapsWithAdapter(adapter);
420 return adapter.shapeOffset();
423 LayoutUnit FloatingObjects::logicalRightOffset(LayoutUnit fixedOffset, LayoutUnit logicalTop, LayoutUnit logicalHeight)
425 ComputeFloatOffsetAdapter<FloatingObject::FloatRight> adapter(m_renderer, roundToInt(logicalTop), roundToInt(logicalTop + logicalHeight), fixedOffset);
426 placedFloatsTree().allOverlapsWithAdapter(adapter);
428 return min(fixedOffset, adapter.shapeOffset());
431 FloatingObjects::FloatBottomCachedValue::FloatBottomCachedValue()
437 inline static bool rangesIntersect(int floatTop, int floatBottom, int objectTop, int objectBottom)
439 if (objectTop >= floatBottom || objectBottom < floatTop)
442 // The top of the object overlaps the float
443 if (objectTop >= floatTop)
446 // The object encloses the float
447 if (objectTop < floatTop && objectBottom > floatBottom)
450 // The bottom of the object overlaps the float
451 if (objectBottom > objectTop && objectBottom > floatTop && objectBottom <= floatBottom)
458 inline bool ComputeFloatOffsetAdapter<FloatingObject::FloatRight>::updateOffsetIfNeeded(const FloatingObject* floatingObject)
460 LayoutUnit logicalLeft = m_renderer->logicalLeftForFloat(floatingObject);
461 if (logicalLeft < m_offset) {
462 m_offset = logicalLeft;
468 template <FloatingObject::Type FloatTypeValue>
469 inline void ComputeFloatOffsetAdapter<FloatTypeValue>::collectIfNeeded(const IntervalType& interval)
471 const FloatingObject* floatingObject = interval.data();
472 if (floatingObject->type() != FloatTypeValue || !rangesIntersect(interval.low(), interval.high(), m_lineTop, m_lineBottom))
475 // Make sure the float hasn't changed since it was added to the placed floats tree.
476 ASSERT(floatingObject->isPlaced());
477 ASSERT(interval.low() == m_renderer->pixelSnappedLogicalTopForFloat(floatingObject));
478 ASSERT(interval.high() == m_renderer->pixelSnappedLogicalBottomForFloat(floatingObject));
480 bool floatIsNewExtreme = updateOffsetIfNeeded(floatingObject);
481 if (floatIsNewExtreme)
482 m_outermostFloat = floatingObject;
485 template <FloatingObject::Type FloatTypeValue>
486 LayoutUnit ComputeFloatOffsetAdapter<FloatTypeValue>::heightRemaining() const
488 return m_outermostFloat ? m_renderer->logicalBottomForFloat(m_outermostFloat) - m_lineTop : LayoutUnit(1);
492 // These helpers are only used by the PODIntervalTree for debugging purposes.
493 String ValueToString<int>::string(const int value)
495 return String::number(value);
498 String ValueToString<FloatingObject*>::string(const FloatingObject* floatingObject)
500 return String::format("%p (%dx%d %dx%d)", floatingObject, floatingObject->frameRect().pixelSnappedX(), floatingObject->frameRect().pixelSnappedY(), floatingObject->frameRect().pixelSnappedMaxX(), floatingObject->frameRect().pixelSnappedMaxY());
505 } // namespace WebCore