Home | History | Annotate | Download | only in rendering
      1 /*
      2  * Copyright (C) 1999 Lars Knoll (knoll (at) kde.org)
      3  *           (C) 1999 Antti Koivisto (koivisto (at) kde.org)
      4  *           (C) 2007 David Smith (catfish.man (at) 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 "core/rendering/FloatingObjects.h"
     26 
     27 #include "core/rendering/RenderBlockFlow.h"
     28 #include "core/rendering/RenderBox.h"
     29 #include "core/rendering/RenderView.h"
     30 
     31 using namespace WTF;
     32 
     33 namespace blink {
     34 
     35 struct SameSizeAsFloatingObject {
     36     void* pointers[2];
     37     LayoutRect rect;
     38     int paginationStrut;
     39     uint32_t bitfields : 8;
     40 };
     41 
     42 COMPILE_ASSERT(sizeof(FloatingObject) == sizeof(SameSizeAsFloatingObject), FloatingObject_should_stay_small);
     43 
     44 FloatingObject::FloatingObject(RenderBox* renderer)
     45     : m_renderer(renderer)
     46     , m_originatingLine(0)
     47     , m_paginationStrut(0)
     48     , m_shouldPaint(true)
     49     , m_isDescendant(false)
     50     , m_isPlaced(false)
     51 #if ENABLE(ASSERT)
     52     , m_isInPlacedTree(false)
     53 #endif
     54 {
     55     EFloat type = renderer->style()->floating();
     56     ASSERT(type != NoFloat);
     57     if (type == LeftFloat)
     58         m_type = FloatLeft;
     59     else if (type == RightFloat)
     60         m_type = FloatRight;
     61 }
     62 
     63 FloatingObject::FloatingObject(RenderBox* renderer, Type type, const LayoutRect& frameRect, bool shouldPaint, bool isDescendant)
     64     : m_renderer(renderer)
     65     , m_originatingLine(0)
     66     , m_frameRect(frameRect)
     67     , m_paginationStrut(0)
     68     , m_type(type)
     69     , m_shouldPaint(shouldPaint)
     70     , m_isDescendant(isDescendant)
     71     , m_isPlaced(true)
     72 #if ENABLE(ASSERT)
     73     , m_isInPlacedTree(false)
     74 #endif
     75 {
     76 }
     77 
     78 PassOwnPtr<FloatingObject> FloatingObject::create(RenderBox* renderer)
     79 {
     80     OwnPtr<FloatingObject> newObj = adoptPtr(new FloatingObject(renderer));
     81     newObj->setShouldPaint(!renderer->hasSelfPaintingLayer()); // If a layer exists, the float will paint itself. Otherwise someone else will.
     82     newObj->setIsDescendant(true);
     83 
     84     return newObj.release();
     85 }
     86 
     87 PassOwnPtr<FloatingObject> FloatingObject::copyToNewContainer(LayoutSize offset, bool shouldPaint, bool isDescendant) const
     88 {
     89     return adoptPtr(new FloatingObject(renderer(), type(), LayoutRect(frameRect().location() - offset, frameRect().size()), shouldPaint, isDescendant));
     90 }
     91 
     92 PassOwnPtr<FloatingObject> FloatingObject::unsafeClone() const
     93 {
     94     OwnPtr<FloatingObject> cloneObject = adoptPtr(new FloatingObject(renderer(), type(), m_frameRect, m_shouldPaint, m_isDescendant));
     95     cloneObject->m_paginationStrut = m_paginationStrut;
     96     cloneObject->m_isPlaced = m_isPlaced;
     97     return cloneObject.release();
     98 }
     99 
    100 template <FloatingObject::Type FloatTypeValue>
    101 class ComputeFloatOffsetAdapter {
    102 public:
    103     typedef FloatingObjectInterval IntervalType;
    104 
    105     ComputeFloatOffsetAdapter(const RenderBlockFlow* renderer, int lineTop, int lineBottom, LayoutUnit offset)
    106         : m_renderer(renderer)
    107         , m_lineTop(lineTop)
    108         , m_lineBottom(lineBottom)
    109         , m_offset(offset)
    110         , m_outermostFloat(0)
    111     {
    112     }
    113 
    114     virtual ~ComputeFloatOffsetAdapter() { }
    115 
    116     int lowValue() const { return m_lineTop; }
    117     int highValue() const { return m_lineBottom; }
    118     void collectIfNeeded(const IntervalType&);
    119 
    120     LayoutUnit offset() const { return m_offset; }
    121 
    122 protected:
    123     virtual bool updateOffsetIfNeeded(const FloatingObject&) = 0;
    124 
    125     const RenderBlockFlow* m_renderer;
    126     int m_lineTop;
    127     int m_lineBottom;
    128     LayoutUnit m_offset;
    129     const FloatingObject* m_outermostFloat;
    130 };
    131 
    132 template <FloatingObject::Type FloatTypeValue>
    133 class ComputeFloatOffsetForFloatLayoutAdapter : public ComputeFloatOffsetAdapter<FloatTypeValue> {
    134 public:
    135     ComputeFloatOffsetForFloatLayoutAdapter(const RenderBlockFlow* renderer, LayoutUnit lineTop, LayoutUnit lineBottom, LayoutUnit offset)
    136         : ComputeFloatOffsetAdapter<FloatTypeValue>(renderer, lineTop, lineBottom, offset)
    137     {
    138     }
    139 
    140     virtual ~ComputeFloatOffsetForFloatLayoutAdapter() { }
    141 
    142     LayoutUnit heightRemaining() const;
    143 
    144 protected:
    145     virtual bool updateOffsetIfNeeded(const FloatingObject&) OVERRIDE FINAL;
    146 };
    147 
    148 template <FloatingObject::Type FloatTypeValue>
    149 class ComputeFloatOffsetForLineLayoutAdapter : public ComputeFloatOffsetAdapter<FloatTypeValue> {
    150 public:
    151     ComputeFloatOffsetForLineLayoutAdapter(const RenderBlockFlow* renderer, LayoutUnit lineTop, LayoutUnit lineBottom, LayoutUnit offset)
    152         : ComputeFloatOffsetAdapter<FloatTypeValue>(renderer, lineTop, lineBottom, offset)
    153     {
    154     }
    155 
    156     virtual ~ComputeFloatOffsetForLineLayoutAdapter() { }
    157 
    158 protected:
    159     virtual bool updateOffsetIfNeeded(const FloatingObject&) OVERRIDE FINAL;
    160 };
    161 
    162 
    163 FloatingObjects::~FloatingObjects()
    164 {
    165 }
    166 void FloatingObjects::clearLineBoxTreePointers()
    167 {
    168     // Clear references to originating lines, since the lines are being deleted
    169     FloatingObjectSetIterator end = m_set.end();
    170     for (FloatingObjectSetIterator it = m_set.begin(); it != end; ++it) {
    171         ASSERT(!((*it)->originatingLine()) || (*it)->originatingLine()->renderer() == m_renderer);
    172         (*it)->setOriginatingLine(0);
    173     }
    174 }
    175 
    176 FloatingObjects::FloatingObjects(const RenderBlockFlow* renderer, bool horizontalWritingMode)
    177     : m_placedFloatsTree(UninitializedTree)
    178     , m_leftObjectsCount(0)
    179     , m_rightObjectsCount(0)
    180     , m_horizontalWritingMode(horizontalWritingMode)
    181     , m_renderer(renderer)
    182     , m_cachedHorizontalWritingMode(false)
    183 {
    184 }
    185 
    186 void FloatingObjects::clear()
    187 {
    188     m_set.clear();
    189     m_placedFloatsTree.clear();
    190     m_leftObjectsCount = 0;
    191     m_rightObjectsCount = 0;
    192     markLowestFloatLogicalBottomCacheAsDirty();
    193 }
    194 
    195 LayoutUnit FloatingObjects::lowestFloatLogicalBottom(FloatingObject::Type floatType)
    196 {
    197     bool isInHorizontalWritingMode = m_horizontalWritingMode;
    198     if (floatType != FloatingObject::FloatLeftRight) {
    199         if (hasLowestFloatLogicalBottomCached(isInHorizontalWritingMode, floatType))
    200             return getCachedlowestFloatLogicalBottom(floatType);
    201     } else {
    202         if (hasLowestFloatLogicalBottomCached(isInHorizontalWritingMode, FloatingObject::FloatLeft) && hasLowestFloatLogicalBottomCached(isInHorizontalWritingMode, FloatingObject::FloatRight)) {
    203             return std::max(getCachedlowestFloatLogicalBottom(FloatingObject::FloatLeft),
    204                 getCachedlowestFloatLogicalBottom(FloatingObject::FloatRight));
    205         }
    206     }
    207 
    208     LayoutUnit lowestFloatBottom = 0;
    209     const FloatingObjectSet& floatingObjectSet = set();
    210     FloatingObjectSetIterator end = floatingObjectSet.end();
    211     if (floatType == FloatingObject::FloatLeftRight) {
    212         LayoutUnit lowestFloatBottomLeft = 0;
    213         LayoutUnit lowestFloatBottomRight = 0;
    214         for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) {
    215             FloatingObject* floatingObject = it->get();
    216             if (floatingObject->isPlaced()) {
    217                 FloatingObject::Type curType = floatingObject->type();
    218                 LayoutUnit curFloatLogicalBottom = m_renderer->logicalBottomForFloat(floatingObject);
    219                 if (curType & FloatingObject::FloatLeft)
    220                     lowestFloatBottomLeft = std::max(lowestFloatBottomLeft, curFloatLogicalBottom);
    221                 if (curType & FloatingObject::FloatRight)
    222                     lowestFloatBottomRight = std::max(lowestFloatBottomRight, curFloatLogicalBottom);
    223             }
    224         }
    225         lowestFloatBottom = std::max(lowestFloatBottomLeft, lowestFloatBottomRight);
    226         setCachedLowestFloatLogicalBottom(isInHorizontalWritingMode, FloatingObject::FloatLeft, lowestFloatBottomLeft);
    227         setCachedLowestFloatLogicalBottom(isInHorizontalWritingMode, FloatingObject::FloatRight, lowestFloatBottomRight);
    228     } else {
    229         for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) {
    230             FloatingObject* floatingObject = it->get();
    231             if (floatingObject->isPlaced() && floatingObject->type() == floatType)
    232                 lowestFloatBottom = std::max(lowestFloatBottom, m_renderer->logicalBottomForFloat(floatingObject));
    233         }
    234         setCachedLowestFloatLogicalBottom(isInHorizontalWritingMode, floatType, lowestFloatBottom);
    235     }
    236 
    237     return lowestFloatBottom;
    238 }
    239 
    240 bool FloatingObjects::hasLowestFloatLogicalBottomCached(bool isHorizontal, FloatingObject::Type type) const
    241 {
    242     int floatIndex = static_cast<int>(type) - 1;
    243     ASSERT(floatIndex < static_cast<int>(sizeof(m_lowestFloatBottomCache) / sizeof(FloatBottomCachedValue)));
    244     ASSERT(floatIndex >= 0);
    245     return (m_cachedHorizontalWritingMode == isHorizontal && !m_lowestFloatBottomCache[floatIndex].dirty);
    246 }
    247 
    248 LayoutUnit FloatingObjects::getCachedlowestFloatLogicalBottom(FloatingObject::Type type) const
    249 {
    250     int floatIndex = static_cast<int>(type) - 1;
    251     ASSERT(floatIndex < static_cast<int>(sizeof(m_lowestFloatBottomCache) / sizeof(FloatBottomCachedValue)));
    252     ASSERT(floatIndex >= 0);
    253     return m_lowestFloatBottomCache[floatIndex].value;
    254 }
    255 
    256 void FloatingObjects::setCachedLowestFloatLogicalBottom(bool isHorizontal, FloatingObject::Type type, LayoutUnit value)
    257 {
    258     int floatIndex = static_cast<int>(type) - 1;
    259     ASSERT(floatIndex < static_cast<int>(sizeof(m_lowestFloatBottomCache) / sizeof(FloatBottomCachedValue)));
    260     ASSERT(floatIndex >= 0);
    261     m_cachedHorizontalWritingMode = isHorizontal;
    262     m_lowestFloatBottomCache[floatIndex].value = value;
    263     m_lowestFloatBottomCache[floatIndex].dirty = false;
    264 }
    265 
    266 void FloatingObjects::markLowestFloatLogicalBottomCacheAsDirty()
    267 {
    268     for (size_t i = 0; i < sizeof(m_lowestFloatBottomCache) / sizeof(FloatBottomCachedValue); ++i)
    269         m_lowestFloatBottomCache[i].dirty = true;
    270 }
    271 
    272 void FloatingObjects::moveAllToFloatInfoMap(RendererToFloatInfoMap& map)
    273 {
    274     while (!m_set.isEmpty()) {
    275         OwnPtr<FloatingObject> floatingObject = m_set.takeFirst();
    276         RenderBox* renderer = floatingObject->renderer();
    277         map.add(renderer, floatingObject.release());
    278     }
    279     clear();
    280 }
    281 
    282 inline void FloatingObjects::increaseObjectsCount(FloatingObject::Type type)
    283 {
    284     if (type == FloatingObject::FloatLeft)
    285         m_leftObjectsCount++;
    286     else
    287         m_rightObjectsCount++;
    288 }
    289 
    290 inline void FloatingObjects::decreaseObjectsCount(FloatingObject::Type type)
    291 {
    292     if (type == FloatingObject::FloatLeft)
    293         m_leftObjectsCount--;
    294     else
    295         m_rightObjectsCount--;
    296 }
    297 
    298 inline FloatingObjectInterval FloatingObjects::intervalForFloatingObject(FloatingObject* floatingObject)
    299 {
    300     if (m_horizontalWritingMode)
    301         return FloatingObjectInterval(floatingObject->frameRect().pixelSnappedY(), floatingObject->frameRect().pixelSnappedMaxY(), floatingObject);
    302     return FloatingObjectInterval(floatingObject->frameRect().pixelSnappedX(), floatingObject->frameRect().pixelSnappedMaxX(), floatingObject);
    303 }
    304 
    305 void FloatingObjects::addPlacedObject(FloatingObject* floatingObject)
    306 {
    307     ASSERT(!floatingObject->isInPlacedTree());
    308 
    309     floatingObject->setIsPlaced(true);
    310     if (m_placedFloatsTree.isInitialized())
    311         m_placedFloatsTree.add(intervalForFloatingObject(floatingObject));
    312 
    313 #if ENABLE(ASSERT)
    314     floatingObject->setIsInPlacedTree(true);
    315 #endif
    316     markLowestFloatLogicalBottomCacheAsDirty();
    317 }
    318 
    319 void FloatingObjects::removePlacedObject(FloatingObject* floatingObject)
    320 {
    321     ASSERT(floatingObject->isPlaced() && floatingObject->isInPlacedTree());
    322 
    323     if (m_placedFloatsTree.isInitialized()) {
    324         bool removed = m_placedFloatsTree.remove(intervalForFloatingObject(floatingObject));
    325         ASSERT_UNUSED(removed, removed);
    326     }
    327 
    328     floatingObject->setIsPlaced(false);
    329 #if ENABLE(ASSERT)
    330     floatingObject->setIsInPlacedTree(false);
    331 #endif
    332     markLowestFloatLogicalBottomCacheAsDirty();
    333 }
    334 
    335 FloatingObject* FloatingObjects::add(PassOwnPtr<FloatingObject> floatingObject)
    336 {
    337     FloatingObject* newObject = floatingObject.leakPtr();
    338     increaseObjectsCount(newObject->type());
    339     m_set.add(adoptPtr(newObject));
    340     if (newObject->isPlaced())
    341         addPlacedObject(newObject);
    342     markLowestFloatLogicalBottomCacheAsDirty();
    343     return newObject;
    344 }
    345 
    346 void FloatingObjects::remove(FloatingObject* toBeRemoved)
    347 {
    348     decreaseObjectsCount(toBeRemoved->type());
    349     OwnPtr<FloatingObject> floatingObject = m_set.take(toBeRemoved);
    350     ASSERT(floatingObject->isPlaced() || !floatingObject->isInPlacedTree());
    351     if (floatingObject->isPlaced())
    352         removePlacedObject(floatingObject.get());
    353     markLowestFloatLogicalBottomCacheAsDirty();
    354     ASSERT(!floatingObject->originatingLine());
    355 }
    356 
    357 void FloatingObjects::computePlacedFloatsTree()
    358 {
    359     ASSERT(!m_placedFloatsTree.isInitialized());
    360     if (m_set.isEmpty())
    361         return;
    362     m_placedFloatsTree.initIfNeeded(m_renderer->view()->intervalArena());
    363     FloatingObjectSetIterator it = m_set.begin();
    364     FloatingObjectSetIterator end = m_set.end();
    365     for (; it != end; ++it) {
    366         FloatingObject* floatingObject = it->get();
    367         if (floatingObject->isPlaced())
    368             m_placedFloatsTree.add(intervalForFloatingObject(floatingObject));
    369     }
    370 }
    371 
    372 LayoutUnit FloatingObjects::logicalLeftOffsetForPositioningFloat(LayoutUnit fixedOffset, LayoutUnit logicalTop, LayoutUnit *heightRemaining)
    373 {
    374     int logicalTopAsInt = roundToInt(logicalTop);
    375     ComputeFloatOffsetForFloatLayoutAdapter<FloatingObject::FloatLeft> adapter(m_renderer, logicalTopAsInt, logicalTopAsInt, fixedOffset);
    376     placedFloatsTree().allOverlapsWithAdapter(adapter);
    377 
    378     if (heightRemaining)
    379         *heightRemaining = adapter.heightRemaining();
    380 
    381     return adapter.offset();
    382 }
    383 
    384 LayoutUnit FloatingObjects::logicalRightOffsetForPositioningFloat(LayoutUnit fixedOffset, LayoutUnit logicalTop, LayoutUnit *heightRemaining)
    385 {
    386     int logicalTopAsInt = roundToInt(logicalTop);
    387     ComputeFloatOffsetForFloatLayoutAdapter<FloatingObject::FloatRight> adapter(m_renderer, logicalTopAsInt, logicalTopAsInt, fixedOffset);
    388     placedFloatsTree().allOverlapsWithAdapter(adapter);
    389 
    390     if (heightRemaining)
    391         *heightRemaining = adapter.heightRemaining();
    392 
    393     return std::min(fixedOffset, adapter.offset());
    394 }
    395 
    396 LayoutUnit FloatingObjects::logicalLeftOffset(LayoutUnit fixedOffset, LayoutUnit logicalTop, LayoutUnit logicalHeight)
    397 {
    398     ComputeFloatOffsetForLineLayoutAdapter<FloatingObject::FloatLeft> adapter(m_renderer, roundToInt(logicalTop), roundToInt(logicalTop + logicalHeight), fixedOffset);
    399     placedFloatsTree().allOverlapsWithAdapter(adapter);
    400 
    401     return adapter.offset();
    402 }
    403 
    404 LayoutUnit FloatingObjects::logicalRightOffset(LayoutUnit fixedOffset, LayoutUnit logicalTop, LayoutUnit logicalHeight)
    405 {
    406     ComputeFloatOffsetForLineLayoutAdapter<FloatingObject::FloatRight> adapter(m_renderer, roundToInt(logicalTop), roundToInt(logicalTop + logicalHeight), fixedOffset);
    407     placedFloatsTree().allOverlapsWithAdapter(adapter);
    408 
    409     return std::min(fixedOffset, adapter.offset());
    410 }
    411 
    412 FloatingObjects::FloatBottomCachedValue::FloatBottomCachedValue()
    413     : value(0)
    414     , dirty(true)
    415 {
    416 }
    417 
    418 inline static bool rangesIntersect(int floatTop, int floatBottom, int objectTop, int objectBottom)
    419 {
    420     if (objectTop >= floatBottom || objectBottom < floatTop)
    421         return false;
    422 
    423     // The top of the object overlaps the float
    424     if (objectTop >= floatTop)
    425         return true;
    426 
    427     // The object encloses the float
    428     if (objectTop < floatTop && objectBottom > floatBottom)
    429         return true;
    430 
    431     // The bottom of the object overlaps the float
    432     if (objectBottom > objectTop && objectBottom > floatTop && objectBottom <= floatBottom)
    433         return true;
    434 
    435     return false;
    436 }
    437 
    438 template<>
    439 inline bool ComputeFloatOffsetForFloatLayoutAdapter<FloatingObject::FloatLeft>::updateOffsetIfNeeded(const FloatingObject& floatingObject)
    440 {
    441     LayoutUnit logicalRight = m_renderer->logicalRightForFloat(&floatingObject);
    442     if (logicalRight > m_offset) {
    443         m_offset = logicalRight;
    444         return true;
    445     }
    446     return false;
    447 }
    448 
    449 template<>
    450 inline bool ComputeFloatOffsetForFloatLayoutAdapter<FloatingObject::FloatRight>::updateOffsetIfNeeded(const FloatingObject& floatingObject)
    451 {
    452     LayoutUnit logicalLeft = m_renderer->logicalLeftForFloat(&floatingObject);
    453     if (logicalLeft < m_offset) {
    454         m_offset = logicalLeft;
    455         return true;
    456     }
    457     return false;
    458 }
    459 
    460 template <FloatingObject::Type FloatTypeValue>
    461 LayoutUnit ComputeFloatOffsetForFloatLayoutAdapter<FloatTypeValue>::heightRemaining() const
    462 {
    463     return this->m_outermostFloat ? this->m_renderer->logicalBottomForFloat(this->m_outermostFloat) - this->m_lineTop : LayoutUnit(1);
    464 }
    465 
    466 template <FloatingObject::Type FloatTypeValue>
    467 inline void ComputeFloatOffsetAdapter<FloatTypeValue>::collectIfNeeded(const IntervalType& interval)
    468 {
    469     const FloatingObject* floatingObject = interval.data();
    470     if (floatingObject->type() != FloatTypeValue || !rangesIntersect(interval.low(), interval.high(), m_lineTop, m_lineBottom))
    471         return;
    472 
    473     // Make sure the float hasn't changed since it was added to the placed floats tree.
    474     ASSERT(floatingObject->isPlaced());
    475     ASSERT(interval.low() == m_renderer->pixelSnappedLogicalTopForFloat(floatingObject));
    476     ASSERT(interval.high() == m_renderer->pixelSnappedLogicalBottomForFloat(floatingObject));
    477 
    478     bool floatIsNewExtreme = updateOffsetIfNeeded(*floatingObject);
    479     if (floatIsNewExtreme)
    480         m_outermostFloat = floatingObject;
    481 }
    482 
    483 template<>
    484 inline bool ComputeFloatOffsetForLineLayoutAdapter<FloatingObject::FloatLeft>::updateOffsetIfNeeded(const FloatingObject& floatingObject)
    485 {
    486     LayoutUnit logicalRight = m_renderer->logicalRightForFloat(&floatingObject);
    487     if (ShapeOutsideInfo* shapeOutside = floatingObject.renderer()->shapeOutsideInfo()) {
    488         ShapeOutsideDeltas shapeDeltas = shapeOutside->computeDeltasForContainingBlockLine(*m_renderer, floatingObject, m_lineTop, m_lineBottom - m_lineTop);
    489         if (!shapeDeltas.lineOverlapsShape())
    490             return false;
    491 
    492         logicalRight += shapeDeltas.rightMarginBoxDelta();
    493     }
    494     if (logicalRight > m_offset) {
    495         m_offset = logicalRight;
    496         return true;
    497     }
    498 
    499     return false;
    500 }
    501 
    502 template<>
    503 inline bool ComputeFloatOffsetForLineLayoutAdapter<FloatingObject::FloatRight>::updateOffsetIfNeeded(const FloatingObject& floatingObject)
    504 {
    505     LayoutUnit logicalLeft = m_renderer->logicalLeftForFloat(&floatingObject);
    506     if (ShapeOutsideInfo* shapeOutside = floatingObject.renderer()->shapeOutsideInfo()) {
    507         ShapeOutsideDeltas shapeDeltas = shapeOutside->computeDeltasForContainingBlockLine(*m_renderer, floatingObject, m_lineTop, m_lineBottom - m_lineTop);
    508         if (!shapeDeltas.lineOverlapsShape())
    509             return false;
    510 
    511         logicalLeft += shapeDeltas.leftMarginBoxDelta();
    512     }
    513     if (logicalLeft < m_offset) {
    514         m_offset = logicalLeft;
    515         return true;
    516     }
    517 
    518     return false;
    519 }
    520 
    521 #ifndef NDEBUG
    522 // These helpers are only used by the PODIntervalTree for debugging purposes.
    523 String ValueToString<int>::string(const int value)
    524 {
    525     return String::number(value);
    526 }
    527 
    528 String ValueToString<FloatingObject*>::string(const FloatingObject* floatingObject)
    529 {
    530     return String::format("%p (%dx%d %dx%d)", floatingObject, floatingObject->frameRect().pixelSnappedX(), floatingObject->frameRect().pixelSnappedY(), floatingObject->frameRect().pixelSnappedMaxX(), floatingObject->frameRect().pixelSnappedMaxY());
    531 }
    532 #endif
    533 
    534 
    535 } // namespace blink
    536