Fix the issue that Web Audio test case fails on PR3.
[framework/web/webkit-efl.git] / Source / WebCore / rendering / RenderMultiColumnBlock.cpp
1 /*
2  * Copyright (C) 2012 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 COMPUTER, 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 "RenderMultiColumnBlock.h"
28 #include "RenderMultiColumnFlowThread.h"
29 #include "RenderMultiColumnSet.h"
30
31 using namespace std;
32
33 namespace WebCore {
34
35 RenderMultiColumnBlock::RenderMultiColumnBlock(Node* node)
36     : RenderBlock(node)
37     , m_flowThread(0)
38     , m_columnCount(1)
39     , m_columnWidth(ZERO_LAYOUT_UNIT)
40     , m_columnHeight(ZERO_LAYOUT_UNIT)
41 {
42 }
43
44 void RenderMultiColumnBlock::computeColumnCountAndWidth()
45 {
46     // Calculate our column width and column count.
47     // FIXME: Can overflow on fast/block/float/float-not-removed-from-next-sibling4.html, see https://bugs.webkit.org/show_bug.cgi?id=68744
48     m_columnCount = 1;
49     m_columnWidth = contentLogicalWidth();
50     
51     ASSERT(!style()->hasAutoColumnCount() || !style()->hasAutoColumnWidth());
52
53     LayoutUnit availWidth = m_columnWidth;
54     LayoutUnit colGap = columnGap();
55     LayoutUnit colWidth = max<LayoutUnit>(1, LayoutUnit(style()->columnWidth()));
56     int colCount = max<int>(1, style()->columnCount());
57
58     if (style()->hasAutoColumnWidth() && !style()->hasAutoColumnCount()) {
59         m_columnCount = colCount;
60         m_columnWidth = max<LayoutUnit>(0, (availWidth - ((m_columnCount - 1) * colGap)) / m_columnCount);
61     } else if (!style()->hasAutoColumnWidth() && style()->hasAutoColumnCount()) {
62         m_columnCount = max<LayoutUnit>(1, (availWidth + colGap) / (colWidth + colGap));
63         m_columnWidth = ((availWidth + colGap) / m_columnCount) - colGap;
64     } else {
65         m_columnCount = max<LayoutUnit>(min<LayoutUnit>(colCount, (availWidth + colGap) / (colWidth + colGap)), 1);
66         m_columnWidth = ((availWidth + colGap) / m_columnCount) - colGap;
67     }
68 }
69
70 bool RenderMultiColumnBlock::recomputeLogicalWidth()
71 {
72     bool relayoutChildren = RenderBlock::recomputeLogicalWidth();
73     LayoutUnit oldColumnWidth = m_columnWidth;
74     computeColumnCountAndWidth();
75     if (m_columnWidth != oldColumnWidth)
76         relayoutChildren = true;
77     return relayoutChildren;
78 }
79
80 void RenderMultiColumnBlock::checkForPaginationLogicalHeightChange(LayoutUnit& pageLogicalHeight, bool& pageLogicalHeightChanged, bool& hasSpecifiedPageLogicalHeight)
81 {
82     // We need to go ahead and set our explicit page height if one exists, so that we can
83     // avoid doing multiple layout passes.
84     computeLogicalHeight();
85     LayoutUnit newContentLogicalHeight = contentLogicalHeight();
86     if (newContentLogicalHeight > ZERO_LAYOUT_UNIT) {
87         pageLogicalHeight = newContentLogicalHeight;
88         hasSpecifiedPageLogicalHeight = true;
89     }
90     setLogicalHeight(ZERO_LAYOUT_UNIT);
91
92     if (columnHeight() != pageLogicalHeight && everHadLayout()) {
93         setColumnHeight(pageLogicalHeight);
94         pageLogicalHeightChanged = true;
95     }
96     
97     // Set up our column sets.
98     ensureColumnSets();
99 }
100
101 bool RenderMultiColumnBlock::relayoutForPagination(bool, LayoutUnit, LayoutStateMaintainer&)
102 {
103     // FIXME: Implement.
104     return false;
105 }
106
107 void RenderMultiColumnBlock::addChild(RenderObject* newChild, RenderObject* beforeChild)
108 {
109     if (!m_flowThread) {
110         m_flowThread = new (renderArena()) RenderMultiColumnFlowThread(document());
111         m_flowThread->setStyle(RenderStyle::createAnonymousStyleWithDisplay(style(), BLOCK));
112         RenderBlock::addChild(m_flowThread); // Always put the flow thread at the end.
113     }
114
115     // Column sets are siblings of the flow thread. All children designed to be in the columns, however, are part
116     // of the flow thread itself.
117     if (newChild->isRenderMultiColumnSet())
118         RenderBlock::addChild(newChild, beforeChild);
119     else
120         m_flowThread->addChild(newChild, beforeChild);
121 }
122
123 void RenderMultiColumnBlock::ensureColumnSets()
124 {
125     // This function ensures we have the correct column set information before we get into layout.
126     // For a simple multi-column layout in continuous media, only one column set child is required.
127     // Once a column is nested inside an enclosing pagination context, the number of column sets
128     // required becomes 2n-1, where n is the total number of nested pagination contexts. For example:
129     //
130     // Column layout with no enclosing pagination model = 2 * 1 - 1 = 1 column set.
131     // Columns inside pages = 2 * 2 - 1 = 3 column sets (bottom of first page, all the subsequent pages, then the last page).
132     // Columns inside columns inside pages = 2 * 3 - 1 = 5 column sets.
133     //
134     // In addition, column spans will force a column set to "split" into before/after sets around the spanning region.
135     //
136     // Finally, we will need to deal with columns inside regions. If regions have variable widths, then there will need
137     // to be unique column sets created inside any region whose width is different from its surrounding regions. This is
138     // actually pretty similar to the spanning case, in that we break up the column sets whenever the width varies.
139     //
140     // FIXME: For now just make one column set. This matches the old multi-column code.
141     // Right now our goal is just feature parity with the old multi-column code so that we can switch over to the
142     // new code as soon as possible.
143     if (flowThread() && !firstChild()->isRenderMultiColumnSet()) {
144         RenderMultiColumnSet* columnSet = new (renderArena()) RenderMultiColumnSet(document(), flowThread());
145         columnSet->setStyle(RenderStyle::createAnonymousStyleWithDisplay(style(), BLOCK));
146         RenderBlock::addChild(columnSet, firstChild());
147         flowThread()->addRegionToThread(columnSet);
148     }
149 }
150
151 const char* RenderMultiColumnBlock::renderName() const
152 {    
153     if (isFloating())
154         return "RenderMultiColumnBlock (floating)";
155     if (isOutOfFlowPositioned())
156         return "RenderMultiColumnBlock (positioned)";
157     if (isAnonymousBlock())
158         return "RenderMultiColumnBlock (anonymous)";
159     if (isAnonymous())
160         return "RenderMultiColumnBlock (generated)";
161     if (isRelPositioned())
162         return "RenderMultiColumnBlock (relative positioned)";
163     return "RenderMultiColumnBlock";
164 }
165
166 }