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 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 RenderBlockFlow* 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     LayoutUnit offset() const { return m_offset; }
    121     LayoutUnit shapeOffset() const;
    122     LayoutUnit heightRemaining() const;
    123 
    124 private:
    125     bool updateOffsetIfNeeded(const FloatingObject*);
    126 
    127     const RenderBlockFlow* m_renderer;
    128     int m_lineTop;
    129     int m_lineBottom;
    130     LayoutUnit m_offset;
    131     const FloatingObject* m_outermostFloat;
    132 };
    133 
    134 
    135 FloatingObjects::~FloatingObjects()
    136 {
    137     // FIXME: m_set should use OwnPtr instead.
    138     deleteAllValues(m_set);
    139 }
    140 void FloatingObjects::clearLineBoxTreePointers()
    141 {
    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);
    147     }
    148 }
    149 
    150 template<>
    151 inline bool ComputeFloatOffsetAdapter<FloatingObject::FloatLeft>::updateOffsetIfNeeded(const FloatingObject* floatingObject)
    152 {
    153     LayoutUnit logicalRight = m_renderer->logicalRightForFloat(floatingObject);
    154     if (logicalRight > m_offset) {
    155         m_offset = logicalRight;
    156         return true;
    157     }
    158     return false;
    159 }
    160 
    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)
    168 {
    169 }
    170 
    171 void FloatingObjects::clear()
    172 {
    173     deleteAllValues(m_set);
    174     m_set.clear();
    175     m_placedFloatsTree.clear();
    176     m_leftObjectsCount = 0;
    177     m_rightObjectsCount = 0;
    178     markLowestFloatLogicalBottomCacheAsDirty();
    179 }
    180 
    181 LayoutUnit FloatingObjects::lowestFloatLogicalBottom(FloatingObject::Type floatType)
    182 {
    183     bool isInHorizontalWritingMode = m_horizontalWritingMode;
    184     if (floatType != FloatingObject::FloatLeftRight) {
    185         if (hasLowestFloatLogicalBottomCached(isInHorizontalWritingMode, floatType))
    186             return getCachedlowestFloatLogicalBottom(floatType);
    187     } else {
    188         if (hasLowestFloatLogicalBottomCached(isInHorizontalWritingMode, FloatingObject::FloatLeft) && hasLowestFloatLogicalBottomCached(isInHorizontalWritingMode, FloatingObject::FloatRight)) {
    189             return max(getCachedlowestFloatLogicalBottom(FloatingObject::FloatLeft),
    190                 getCachedlowestFloatLogicalBottom(FloatingObject::FloatRight));
    191         }
    192     }
    193 
    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);
    209             }
    210         }
    211         lowestFloatBottom = max(lowestFloatBottomLeft, lowestFloatBottomRight);
    212         setCachedLowestFloatLogicalBottom(isInHorizontalWritingMode, FloatingObject::FloatLeft, lowestFloatBottomLeft);
    213         setCachedLowestFloatLogicalBottom(isInHorizontalWritingMode, FloatingObject::FloatRight, lowestFloatBottomRight);
    214     } else {
    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));
    219         }
    220         setCachedLowestFloatLogicalBottom(isInHorizontalWritingMode, floatType, lowestFloatBottom);
    221     }
    222 
    223     return lowestFloatBottom;
    224 }
    225 
    226 bool FloatingObjects::hasLowestFloatLogicalBottomCached(bool isHorizontal, FloatingObject::Type type) const
    227 {
    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);
    232 }
    233 
    234 LayoutUnit FloatingObjects::getCachedlowestFloatLogicalBottom(FloatingObject::Type type) const
    235 {
    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;
    240 }
    241 
    242 void FloatingObjects::setCachedLowestFloatLogicalBottom(bool isHorizontal, FloatingObject::Type type, LayoutUnit value)
    243 {
    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;
    250 }
    251 
    252 void FloatingObjects::markLowestFloatLogicalBottomCacheAsDirty()
    253 {
    254     for (size_t i = 0; i < sizeof(m_lowestFloatBottomCache) / sizeof(FloatBottomCachedValue); ++i)
    255         m_lowestFloatBottomCache[i].dirty = true;
    256 }
    257 
    258 void FloatingObjects::moveAllToFloatInfoMap(RendererToFloatInfoMap& map)
    259 {
    260     FloatingObjectSetIterator end = m_set.end();
    261     for (FloatingObjectSetIterator it = m_set.begin(); it != end; ++it)
    262         map.add((*it)->renderer(), *it);
    263 
    264     // clear set before clearing this because we don't want to delete all of
    265     // the objects we have just transferred.
    266     m_set.clear();
    267     clear();
    268 }
    269 
    270 inline void FloatingObjects::increaseObjectsCount(FloatingObject::Type type)
    271 {
    272     if (type == FloatingObject::FloatLeft)
    273         m_leftObjectsCount++;
    274     else
    275         m_rightObjectsCount++;
    276 }
    277 
    278 inline void FloatingObjects::decreaseObjectsCount(FloatingObject::Type type)
    279 {
    280     if (type == FloatingObject::FloatLeft)
    281         m_leftObjectsCount--;
    282     else
    283         m_rightObjectsCount--;
    284 }
    285 
    286 inline FloatingObjectInterval FloatingObjects::intervalForFloatingObject(FloatingObject* floatingObject)
    287 {
    288     if (m_horizontalWritingMode)
    289         return FloatingObjectInterval(floatingObject->frameRect().pixelSnappedY(), floatingObject->frameRect().pixelSnappedMaxY(), floatingObject);
    290     return FloatingObjectInterval(floatingObject->frameRect().pixelSnappedX(), floatingObject->frameRect().pixelSnappedMaxX(), floatingObject);
    291 }
    292 
    293 void FloatingObjects::addPlacedObject(FloatingObject* floatingObject)
    294 {
    295     ASSERT(!floatingObject->isInPlacedTree());
    296 
    297     floatingObject->setIsPlaced(true);
    298     if (m_placedFloatsTree.isInitialized())
    299         m_placedFloatsTree.add(intervalForFloatingObject(floatingObject));
    300 
    301 #ifndef NDEBUG
    302     floatingObject->setIsInPlacedTree(true);
    303 #endif
    304     markLowestFloatLogicalBottomCacheAsDirty();
    305 }
    306 
    307 void FloatingObjects::removePlacedObject(FloatingObject* floatingObject)
    308 {
    309     ASSERT(floatingObject->isPlaced() && floatingObject->isInPlacedTree());
    310 
    311     if (m_placedFloatsTree.isInitialized()) {
    312         bool removed = m_placedFloatsTree.remove(intervalForFloatingObject(floatingObject));
    313         ASSERT_UNUSED(removed, removed);
    314     }
    315 
    316     floatingObject->setIsPlaced(false);
    317 #ifndef NDEBUG
    318     floatingObject->setIsInPlacedTree(false);
    319 #endif
    320     markLowestFloatLogicalBottomCacheAsDirty();
    321 }
    322 
    323 FloatingObject* FloatingObjects::add(PassOwnPtr<FloatingObject> floatingObject)
    324 {
    325     FloatingObject* newObject = floatingObject.leakPtr();
    326     increaseObjectsCount(newObject->type());
    327     m_set.add(newObject);
    328     if (newObject->isPlaced())
    329         addPlacedObject(newObject);
    330     markLowestFloatLogicalBottomCacheAsDirty();
    331     return newObject;
    332 }
    333 
    334 void FloatingObjects::remove(FloatingObject* floatingObject)
    335 {
    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;
    344 }
    345 
    346 void FloatingObjects::computePlacedFloatsTree()
    347 {
    348     ASSERT(!m_placedFloatsTree.isInitialized());
    349     if (m_set.isEmpty())
    350         return;
    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));
    358     }
    359 }
    360 
    361 static inline ShapeOutsideInfo* shapeInfoForFloat(const FloatingObject* floatingObject, const RenderBlockFlow* containingBlock, LayoutUnit lineTop, LayoutUnit lineBottom)
    362 {
    363     if (floatingObject) {
    364         if (ShapeOutsideInfo* shapeOutside = floatingObject->renderer()->shapeOutsideInfo()) {
    365             shapeOutside->updateDeltasForContainingBlockLine(containingBlock, floatingObject, lineTop, lineBottom - lineTop);
    366             return shapeOutside;
    367         }
    368     }
    369 
    370     return 0;
    371 }
    372 
    373 template<>
    374 inline LayoutUnit ComputeFloatOffsetAdapter<FloatingObject::FloatLeft>::shapeOffset() const
    375 {
    376     if (ShapeOutsideInfo* shapeOutside = shapeInfoForFloat(m_outermostFloat, m_renderer, m_lineTop, m_lineBottom))
    377         return m_offset + shapeOutside->rightMarginBoxDelta();
    378 
    379     return m_offset;
    380 }
    381 
    382 template<>
    383 inline LayoutUnit ComputeFloatOffsetAdapter<FloatingObject::FloatRight>::shapeOffset() const
    384 {
    385     if (ShapeOutsideInfo* shapeOutside = shapeInfoForFloat(m_outermostFloat, m_renderer, m_lineTop, m_lineBottom))
    386         return m_offset + shapeOutside->leftMarginBoxDelta();
    387 
    388     return m_offset;
    389 }
    390 
    391 LayoutUnit FloatingObjects::logicalLeftOffsetForPositioningFloat(LayoutUnit fixedOffset, LayoutUnit logicalTop, LayoutUnit *heightRemaining)
    392 {
    393     int logicalTopAsInt = roundToInt(logicalTop);
    394     ComputeFloatOffsetAdapter<FloatingObject::FloatLeft> adapter(m_renderer, logicalTopAsInt, logicalTopAsInt, fixedOffset);
    395     placedFloatsTree().allOverlapsWithAdapter(adapter);
    396 
    397     if (heightRemaining)
    398         *heightRemaining = adapter.heightRemaining();
    399 
    400     return adapter.offset();
    401 }
    402 
    403 LayoutUnit FloatingObjects::logicalRightOffsetForPositioningFloat(LayoutUnit fixedOffset, LayoutUnit logicalTop, LayoutUnit *heightRemaining)
    404 {
    405     int logicalTopAsInt = roundToInt(logicalTop);
    406     ComputeFloatOffsetAdapter<FloatingObject::FloatRight> adapter(m_renderer, logicalTopAsInt, logicalTopAsInt, fixedOffset);
    407     placedFloatsTree().allOverlapsWithAdapter(adapter);
    408 
    409     if (heightRemaining)
    410         *heightRemaining = adapter.heightRemaining();
    411 
    412     return min(fixedOffset, adapter.offset());
    413 }
    414 
    415 LayoutUnit FloatingObjects::logicalLeftOffset(LayoutUnit fixedOffset, LayoutUnit logicalTop, LayoutUnit logicalHeight)
    416 {
    417     ComputeFloatOffsetAdapter<FloatingObject::FloatLeft> adapter(m_renderer, roundToInt(logicalTop), roundToInt(logicalTop + logicalHeight), fixedOffset);
    418     placedFloatsTree().allOverlapsWithAdapter(adapter);
    419 
    420     return adapter.shapeOffset();
    421 }
    422 
    423 LayoutUnit FloatingObjects::logicalRightOffset(LayoutUnit fixedOffset, LayoutUnit logicalTop, LayoutUnit logicalHeight)
    424 {
    425     ComputeFloatOffsetAdapter<FloatingObject::FloatRight> adapter(m_renderer, roundToInt(logicalTop), roundToInt(logicalTop + logicalHeight), fixedOffset);
    426     placedFloatsTree().allOverlapsWithAdapter(adapter);
    427 
    428     return min(fixedOffset, adapter.shapeOffset());
    429 }
    430 
    431 FloatingObjects::FloatBottomCachedValue::FloatBottomCachedValue()
    432     : value(0)
    433     , dirty(true)
    434 {
    435 }
    436 
    437 inline static bool rangesIntersect(int floatTop, int floatBottom, int objectTop, int objectBottom)
    438 {
    439     if (objectTop >= floatBottom || objectBottom < floatTop)
    440         return false;
    441 
    442     // The top of the object overlaps the float
    443     if (objectTop >= floatTop)
    444         return true;
    445 
    446     // The object encloses the float
    447     if (objectTop < floatTop && objectBottom > floatBottom)
    448         return true;
    449 
    450     // The bottom of the object overlaps the float
    451     if (objectBottom > objectTop && objectBottom > floatTop && objectBottom <= floatBottom)
    452         return true;
    453 
    454     return false;
    455 }
    456 
    457 template<>
    458 inline bool ComputeFloatOffsetAdapter<FloatingObject::FloatRight>::updateOffsetIfNeeded(const FloatingObject* floatingObject)
    459 {
    460     LayoutUnit logicalLeft = m_renderer->logicalLeftForFloat(floatingObject);
    461     if (logicalLeft < m_offset) {
    462         m_offset = logicalLeft;
    463         return true;
    464     }
    465     return false;
    466 }
    467 
    468 template <FloatingObject::Type FloatTypeValue>
    469 inline void ComputeFloatOffsetAdapter<FloatTypeValue>::collectIfNeeded(const IntervalType& interval)
    470 {
    471     const FloatingObject* floatingObject = interval.data();
    472     if (floatingObject->type() != FloatTypeValue || !rangesIntersect(interval.low(), interval.high(), m_lineTop, m_lineBottom))
    473         return;
    474 
    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));
    479 
    480     bool floatIsNewExtreme = updateOffsetIfNeeded(floatingObject);
    481     if (floatIsNewExtreme)
    482         m_outermostFloat = floatingObject;
    483 }
    484 
    485 template <FloatingObject::Type FloatTypeValue>
    486 LayoutUnit ComputeFloatOffsetAdapter<FloatTypeValue>::heightRemaining() const
    487 {
    488     return m_outermostFloat ? m_renderer->logicalBottomForFloat(m_outermostFloat) - m_lineTop : LayoutUnit(1);
    489 }
    490 
    491 #ifndef NDEBUG
    492 // These helpers are only used by the PODIntervalTree for debugging purposes.
    493 String ValueToString<int>::string(const int value)
    494 {
    495     return String::number(value);
    496 }
    497 
    498 String ValueToString<FloatingObject*>::string(const FloatingObject* floatingObject)
    499 {
    500     return String::format("%p (%dx%d %dx%d)", floatingObject, floatingObject->frameRect().pixelSnappedX(), floatingObject->frameRect().pixelSnappedY(), floatingObject->frameRect().pixelSnappedMaxX(), floatingObject->frameRect().pixelSnappedMaxY());
    501 }
    502 #endif
    503 
    504 
    505 } // namespace WebCore
    506