Home | History | Annotate | Download | only in rendering
      1 /*
      2  * Copyright (C) 2007 Apple Inc.  All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions
      6  * are met:
      7  * 1. Redistributions of source code must retain the above copyright
      8  *    notice, this list of conditions and the following disclaimer.
      9  * 2. Redistributions in binary form must reproduce the above copyright
     10  *    notice, this list of conditions and the following disclaimer in the
     11  *    documentation and/or other materials provided with the distribution.
     12  *
     13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
     14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
     17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     24  */
     25 
     26 #include "config.h"
     27 #include "core/rendering/LayoutState.h"
     28 
     29 #include "core/rendering/RenderInline.h"
     30 #include "core/rendering/RenderLayer.h"
     31 #include "core/rendering/RenderView.h"
     32 #include "platform/Partitions.h"
     33 
     34 namespace blink {
     35 
     36 LayoutState::LayoutState(LayoutUnit pageLogicalHeight, bool pageLogicalHeightChanged, RenderView& view)
     37     : m_isPaginated(pageLogicalHeight)
     38     , m_pageLogicalHeightChanged(pageLogicalHeightChanged)
     39     , m_containingBlockLogicalWidthChanged(false)
     40     , m_columnInfo(0)
     41     , m_next(0)
     42     , m_pageLogicalHeight(pageLogicalHeight)
     43     , m_renderer(view)
     44 {
     45     ASSERT(!view.layoutState());
     46     view.pushLayoutState(*this);
     47 }
     48 
     49 LayoutState::LayoutState(RenderBox& renderer, const LayoutSize& offset, LayoutUnit pageLogicalHeight, bool pageLogicalHeightChanged, ColumnInfo* columnInfo, bool containingBlockLogicalWidthChanged)
     50     : m_containingBlockLogicalWidthChanged(containingBlockLogicalWidthChanged)
     51     , m_columnInfo(columnInfo)
     52     , m_next(renderer.view()->layoutState())
     53     , m_renderer(renderer)
     54 {
     55     renderer.view()->pushLayoutState(*this);
     56     bool fixed = renderer.isOutOfFlowPositioned() && renderer.style()->position() == FixedPosition;
     57     if (fixed) {
     58         // FIXME: This doesn't work correctly with transforms.
     59         FloatPoint fixedOffset = renderer.view()->localToAbsolute(FloatPoint(), IsFixed);
     60         m_layoutOffset = LayoutSize(fixedOffset.x(), fixedOffset.y()) + offset;
     61     } else {
     62         m_layoutOffset = m_next->m_layoutOffset + offset;
     63     }
     64 
     65     if (renderer.isOutOfFlowPositioned() && !fixed) {
     66         if (RenderObject* container = renderer.container()) {
     67             if (container->style()->hasInFlowPosition() && container->isRenderInline())
     68                 m_layoutOffset += toRenderInline(container)->offsetForInFlowPositionedInline(renderer);
     69         }
     70     }
     71     // If we establish a new page height, then cache the offset to the top of the first page.
     72     // We can compare this later on to figure out what part of the page we're actually on,
     73     if (pageLogicalHeight || m_columnInfo || renderer.isRenderFlowThread()) {
     74         m_pageLogicalHeight = pageLogicalHeight;
     75         bool isFlipped = renderer.style()->isFlippedBlocksWritingMode();
     76         m_pageOffset = LayoutSize(m_layoutOffset.width() + (!isFlipped ? renderer.borderLeft() + renderer.paddingLeft() : renderer.borderRight() + renderer.paddingRight()),
     77             m_layoutOffset.height() + (!isFlipped ? renderer.borderTop() + renderer.paddingTop() : renderer.borderBottom() + renderer.paddingBottom()));
     78         m_pageLogicalHeightChanged = pageLogicalHeightChanged;
     79         m_isPaginated = true;
     80     } else {
     81         // If we don't establish a new page height, then propagate the old page height and offset down.
     82         m_pageLogicalHeight = m_next->m_pageLogicalHeight;
     83         m_pageLogicalHeightChanged = m_next->m_pageLogicalHeightChanged;
     84         m_pageOffset = m_next->m_pageOffset;
     85 
     86         // Disable pagination for objects we don't support. For now this includes overflow:scroll/auto, inline blocks and
     87         // writing mode roots.
     88         if (renderer.isUnsplittableForPagination()) {
     89             m_pageLogicalHeight = 0;
     90             m_isPaginated = false;
     91         } else {
     92             m_isPaginated = m_pageLogicalHeight || m_next->m_columnInfo || renderer.flowThreadContainingBlock();
     93         }
     94     }
     95 
     96     if (!m_columnInfo)
     97         m_columnInfo = m_next->m_columnInfo;
     98 
     99     // FIXME: <http://bugs.webkit.org/show_bug.cgi?id=13443> Apply control clip if present.
    100 }
    101 
    102 LayoutState::LayoutState(RenderObject& root)
    103     : m_isPaginated(false)
    104     , m_pageLogicalHeightChanged(false)
    105     , m_containingBlockLogicalWidthChanged(false)
    106     , m_columnInfo(0)
    107     , m_next(root.view()->layoutState())
    108     , m_pageLogicalHeight(0)
    109     , m_renderer(root)
    110 {
    111     // FIXME: Why does RenderTableSection create this wonky LayoutState?
    112     ASSERT(!m_next || root.isTableSection());
    113     // We'll end up pushing in RenderView itself, so don't bother adding it.
    114     if (root.isRenderView())
    115         return;
    116 
    117     root.view()->pushLayoutState(*this);
    118 
    119     RenderObject* container = root.container();
    120     FloatPoint absContentPoint = container->localToAbsolute(FloatPoint(), UseTransforms);
    121     m_layoutOffset = LayoutSize(absContentPoint.x(), absContentPoint.y());
    122 }
    123 
    124 LayoutState::~LayoutState()
    125 {
    126     if (m_renderer.view()->layoutState()) {
    127         ASSERT(m_renderer.view()->layoutState() == this);
    128         m_renderer.view()->popLayoutState();
    129     }
    130 }
    131 
    132 void LayoutState::clearPaginationInformation()
    133 {
    134     m_pageLogicalHeight = m_next->m_pageLogicalHeight;
    135     m_pageOffset = m_next->m_pageOffset;
    136     m_columnInfo = m_next->m_columnInfo;
    137 }
    138 
    139 LayoutUnit LayoutState::pageLogicalOffset(const RenderBox& child, const LayoutUnit& childLogicalOffset) const
    140 {
    141     if (child.isHorizontalWritingMode())
    142         return m_layoutOffset.height() + childLogicalOffset - m_pageOffset.height();
    143     return m_layoutOffset.width() + childLogicalOffset - m_pageOffset.width();
    144 }
    145 
    146 void LayoutState::addForcedColumnBreak(const RenderBox& child, const LayoutUnit& childLogicalOffset)
    147 {
    148     if (!m_columnInfo || m_columnInfo->columnHeight())
    149         return;
    150     m_columnInfo->addForcedBreak(pageLogicalOffset(child, childLogicalOffset));
    151 }
    152 
    153 } // namespace blink
    154