WebCore/rendering/RenderFrameSet.cpp
changeset 0 4f2f89ce4247
equal deleted inserted replaced
-1:000000000000 0:4f2f89ce4247
       
     1 /**
       
     2  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
       
     3  *           (C) 2000 Simon Hausmann <hausmann@kde.org>
       
     4  *           (C) 2000 Stefan Schimanski (1Stein@gmx.de)
       
     5  * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc.
       
     6  *
       
     7  * This library is free software; you can redistribute it and/or
       
     8  * modify it under the terms of the GNU Library General Public
       
     9  * License as published by the Free Software Foundation; either
       
    10  * version 2 of the License, or (at your option) any later version.
       
    11  *
       
    12  * This library is distributed in the hope that it will be useful,
       
    13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
       
    15  * Library General Public License for more details.
       
    16  *
       
    17  * You should have received a copy of the GNU Library General Public License
       
    18  * along with this library; see the file COPYING.LIB.  If not, write to
       
    19  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
       
    20  * Boston, MA 02110-1301, USA.
       
    21  *
       
    22  */
       
    23 
       
    24 #include "config.h"
       
    25 #include "RenderFrameSet.h"
       
    26 
       
    27 #include "Document.h"
       
    28 #include "EventHandler.h"
       
    29 #include "EventNames.h"
       
    30 #include "Frame.h"
       
    31 #include "FrameView.h"
       
    32 #include "GraphicsContext.h"
       
    33 #include "HTMLFrameSetElement.h"
       
    34 #include "HitTestRequest.h"
       
    35 #include "HitTestResult.h"
       
    36 #include "MouseEvent.h"
       
    37 #include "RenderFrame.h"
       
    38 #include "RenderView.h"
       
    39 #include "Settings.h"
       
    40 
       
    41 namespace WebCore {
       
    42 
       
    43 RenderFrameSet::RenderFrameSet(HTMLFrameSetElement* frameSet)
       
    44     : RenderBox(frameSet)
       
    45     , m_isResizing(false)
       
    46     , m_isChildResizing(false)
       
    47 {
       
    48     setInline(false);
       
    49 }
       
    50 
       
    51 RenderFrameSet::~RenderFrameSet()
       
    52 {
       
    53 }
       
    54 
       
    55 RenderFrameSet::GridAxis::GridAxis()
       
    56     : m_splitBeingResized(noSplit)
       
    57 {
       
    58 }
       
    59 
       
    60 inline HTMLFrameSetElement* RenderFrameSet::frameSet() const
       
    61 {
       
    62     return static_cast<HTMLFrameSetElement*>(node());
       
    63 }
       
    64 
       
    65 static Color borderStartEdgeColor()
       
    66 {
       
    67     return Color(170, 170, 170);
       
    68 }
       
    69 
       
    70 static Color borderEndEdgeColor()
       
    71 {
       
    72     return Color::black;
       
    73 }
       
    74 
       
    75 static Color borderFillColor()
       
    76 {
       
    77     return Color(208, 208, 208);
       
    78 }
       
    79 
       
    80 void RenderFrameSet::paintColumnBorder(const PaintInfo& paintInfo, const IntRect& borderRect)
       
    81 {
       
    82     if (!paintInfo.rect.intersects(borderRect))
       
    83         return;
       
    84         
       
    85     // FIXME: We should do something clever when borders from distinct framesets meet at a join.
       
    86     
       
    87     // Fill first.
       
    88     GraphicsContext* context = paintInfo.context;
       
    89     ColorSpace colorSpace = style()->colorSpace();
       
    90     context->fillRect(borderRect, frameSet()->hasBorderColor() ? style()->visitedDependentColor(CSSPropertyBorderLeftColor) : borderFillColor(), colorSpace);
       
    91     
       
    92     // Now stroke the edges but only if we have enough room to paint both edges with a little
       
    93     // bit of the fill color showing through.
       
    94     if (borderRect.width() >= 3) {
       
    95         context->fillRect(IntRect(borderRect.topLeft(), IntSize(1, height())), borderStartEdgeColor(), colorSpace);
       
    96         context->fillRect(IntRect(borderRect.topRight(), IntSize(1, height())), borderEndEdgeColor(), colorSpace);
       
    97     }
       
    98 }
       
    99 
       
   100 void RenderFrameSet::paintRowBorder(const PaintInfo& paintInfo, const IntRect& borderRect)
       
   101 {
       
   102     if (!paintInfo.rect.intersects(borderRect))
       
   103         return;
       
   104 
       
   105     // FIXME: We should do something clever when borders from distinct framesets meet at a join.
       
   106     
       
   107     // Fill first.
       
   108     GraphicsContext* context = paintInfo.context;
       
   109     ColorSpace colorSpace = style()->colorSpace();
       
   110     context->fillRect(borderRect, frameSet()->hasBorderColor() ? style()->visitedDependentColor(CSSPropertyBorderLeftColor) : borderFillColor(), colorSpace);
       
   111 
       
   112     // Now stroke the edges but only if we have enough room to paint both edges with a little
       
   113     // bit of the fill color showing through.
       
   114     if (borderRect.height() >= 3) {
       
   115         context->fillRect(IntRect(borderRect.topLeft(), IntSize(width(), 1)), borderStartEdgeColor(), colorSpace);
       
   116         context->fillRect(IntRect(borderRect.bottomLeft(), IntSize(width(), 1)), borderEndEdgeColor(), colorSpace);
       
   117     }
       
   118 }
       
   119 
       
   120 void RenderFrameSet::paint(PaintInfo& paintInfo, int tx, int ty)
       
   121 {
       
   122     if (paintInfo.phase != PaintPhaseForeground)
       
   123         return;
       
   124     
       
   125     RenderObject* child = firstChild();
       
   126     if (!child)
       
   127         return;
       
   128 
       
   129     // Add in our offsets.
       
   130     tx += x();
       
   131     ty += y();
       
   132 
       
   133     int rows = frameSet()->totalRows();
       
   134     int cols = frameSet()->totalCols();
       
   135     int borderThickness = frameSet()->border();
       
   136     
       
   137     int yPos = 0;
       
   138     for (int r = 0; r < rows; r++) {
       
   139         int xPos = 0;
       
   140         for (int c = 0; c < cols; c++) {
       
   141             child->paint(paintInfo, tx, ty);
       
   142             xPos += m_cols.m_sizes[c];
       
   143             if (borderThickness && m_cols.m_allowBorder[c + 1]) {
       
   144                 paintColumnBorder(paintInfo, IntRect(tx + xPos, ty + yPos, borderThickness, height()));
       
   145                 xPos += borderThickness;
       
   146             }
       
   147             child = child->nextSibling();
       
   148             if (!child)
       
   149                 return;
       
   150         }
       
   151         yPos += m_rows.m_sizes[r];
       
   152         if (borderThickness && m_rows.m_allowBorder[r + 1]) {
       
   153             paintRowBorder(paintInfo, IntRect(tx, ty + yPos, width(), borderThickness));
       
   154             yPos += borderThickness;
       
   155         }
       
   156     }
       
   157 }
       
   158 
       
   159 bool RenderFrameSet::nodeAtPoint(const HitTestRequest& request, HitTestResult& result,
       
   160     int x, int y, int tx, int ty, HitTestAction action)
       
   161 {
       
   162     if (action != HitTestForeground)
       
   163         return false;
       
   164 
       
   165     bool inside = RenderBox::nodeAtPoint(request, result, x, y, tx, ty, action)
       
   166         || m_isResizing;
       
   167 
       
   168     if (inside && frameSet()->noResize()
       
   169             && !request.readOnly() && !result.innerNode()) {
       
   170         result.setInnerNode(node());
       
   171         result.setInnerNonSharedNode(node());
       
   172     }
       
   173 
       
   174     return inside || m_isChildResizing;
       
   175 }
       
   176 
       
   177 void RenderFrameSet::GridAxis::resize(int size)
       
   178 {
       
   179     m_sizes.resize(size);
       
   180     m_deltas.resize(size);
       
   181     m_deltas.fill(0);
       
   182     
       
   183     // To track edges for resizability and borders, we need to be (size + 1).  This is because a parent frameset
       
   184     // may ask us for information about our left/top/right/bottom edges in order to make its own decisions about
       
   185     // what to do.  We are capable of tainting that parent frameset's borders, so we have to cache this info.
       
   186     m_preventResize.resize(size + 1);
       
   187     m_allowBorder.resize(size + 1);
       
   188 }
       
   189 
       
   190 void RenderFrameSet::layOutAxis(GridAxis& axis, const Length* grid, int availableLen)
       
   191 {
       
   192     availableLen = max(availableLen, 0);
       
   193 
       
   194     int* gridLayout = axis.m_sizes.data();
       
   195 
       
   196     if (!grid) {
       
   197         gridLayout[0] = availableLen;
       
   198         return;
       
   199     }
       
   200 
       
   201     int gridLen = axis.m_sizes.size();
       
   202     ASSERT(gridLen);
       
   203 
       
   204     int totalRelative = 0;
       
   205     int totalFixed = 0;
       
   206     int totalPercent = 0;
       
   207     int countRelative = 0;
       
   208     int countFixed = 0;
       
   209     int countPercent = 0;
       
   210 
       
   211     // First we need to investigate how many columns of each type we have and
       
   212     // how much space these columns are going to require.
       
   213     for (int i = 0; i < gridLen; ++i) {
       
   214         // Count the total length of all of the fixed columns/rows -> totalFixed
       
   215         // Count the number of columns/rows which are fixed -> countFixed
       
   216         if (grid[i].isFixed()) {
       
   217             gridLayout[i] = max(grid[i].value(), 0);
       
   218             totalFixed += gridLayout[i];
       
   219             countFixed++;
       
   220         }
       
   221         
       
   222         // Count the total percentage of all of the percentage columns/rows -> totalPercent
       
   223         // Count the number of columns/rows which are percentages -> countPercent
       
   224         if (grid[i].isPercent()) {
       
   225             gridLayout[i] = max(grid[i].calcValue(availableLen), 0);
       
   226             totalPercent += gridLayout[i];
       
   227             countPercent++;
       
   228         }
       
   229 
       
   230         // Count the total relative of all the relative columns/rows -> totalRelative
       
   231         // Count the number of columns/rows which are relative -> countRelative
       
   232         if (grid[i].isRelative()) {
       
   233             totalRelative += max(grid[i].value(), 1);
       
   234             countRelative++;
       
   235         }            
       
   236     }
       
   237 
       
   238     int remainingLen = availableLen;
       
   239 
       
   240     // Fixed columns/rows are our first priority. If there is not enough space to fit all fixed
       
   241     // columns/rows we need to proportionally adjust their size. 
       
   242     if (totalFixed > remainingLen) {
       
   243         int remainingFixed = remainingLen;
       
   244 
       
   245         for (int i = 0; i < gridLen; ++i) {
       
   246             if (grid[i].isFixed()) {
       
   247                 gridLayout[i] = (gridLayout[i] * remainingFixed) / totalFixed;
       
   248                 remainingLen -= gridLayout[i];
       
   249             }
       
   250         }
       
   251     } else
       
   252         remainingLen -= totalFixed;
       
   253 
       
   254     // Percentage columns/rows are our second priority. Divide the remaining space proportionally 
       
   255     // over all percentage columns/rows. IMPORTANT: the size of each column/row is not relative 
       
   256     // to 100%, but to the total percentage. For example, if there are three columns, each of 75%,
       
   257     // and the available space is 300px, each column will become 100px in width.
       
   258     if (totalPercent > remainingLen) {
       
   259         int remainingPercent = remainingLen;
       
   260 
       
   261         for (int i = 0; i < gridLen; ++i) {
       
   262             if (grid[i].isPercent()) {
       
   263                 gridLayout[i] = (gridLayout[i] * remainingPercent) / totalPercent;
       
   264                 remainingLen -= gridLayout[i];
       
   265             }
       
   266         }
       
   267     } else
       
   268         remainingLen -= totalPercent;
       
   269 
       
   270     // Relative columns/rows are our last priority. Divide the remaining space proportionally
       
   271     // over all relative columns/rows. IMPORTANT: the relative value of 0* is treated as 1*.
       
   272     if (countRelative) {
       
   273         int lastRelative = 0;
       
   274         int remainingRelative = remainingLen;
       
   275 
       
   276         for (int i = 0; i < gridLen; ++i) {
       
   277             if (grid[i].isRelative()) {
       
   278                 gridLayout[i] = (max(grid[i].value(), 1) * remainingRelative) / totalRelative;
       
   279                 remainingLen -= gridLayout[i];
       
   280                 lastRelative = i;
       
   281             }
       
   282         }
       
   283         
       
   284         // If we could not evenly distribute the available space of all of the relative  
       
   285         // columns/rows, the remainder will be added to the last column/row.
       
   286         // For example: if we have a space of 100px and three columns (*,*,*), the remainder will
       
   287         // be 1px and will be added to the last column: 33px, 33px, 34px.
       
   288         if (remainingLen) {
       
   289             gridLayout[lastRelative] += remainingLen;
       
   290             remainingLen = 0;
       
   291         }
       
   292     }
       
   293 
       
   294     // If we still have some left over space we need to divide it over the already existing
       
   295     // columns/rows
       
   296     if (remainingLen) {
       
   297         // Our first priority is to spread if over the percentage columns. The remaining
       
   298         // space is spread evenly, for example: if we have a space of 100px, the columns 
       
   299         // definition of 25%,25% used to result in two columns of 25px. After this the 
       
   300         // columns will each be 50px in width. 
       
   301         if (countPercent && totalPercent) {
       
   302             int remainingPercent = remainingLen;
       
   303             int changePercent = 0;
       
   304 
       
   305             for (int i = 0; i < gridLen; ++i) {
       
   306                 if (grid[i].isPercent()) {
       
   307                     changePercent = (remainingPercent * gridLayout[i]) / totalPercent;
       
   308                     gridLayout[i] += changePercent;
       
   309                     remainingLen -= changePercent;
       
   310                 }
       
   311             }
       
   312         } else if (totalFixed) {
       
   313             // Our last priority is to spread the remaining space over the fixed columns.
       
   314             // For example if we have 100px of space and two column of each 40px, both
       
   315             // columns will become exactly 50px.
       
   316             int remainingFixed = remainingLen;
       
   317             int changeFixed = 0;
       
   318 
       
   319             for (int i = 0; i < gridLen; ++i) {
       
   320                 if (grid[i].isFixed()) {
       
   321                     changeFixed = (remainingFixed * gridLayout[i]) / totalFixed;
       
   322                     gridLayout[i] += changeFixed;
       
   323                     remainingLen -= changeFixed;
       
   324                 } 
       
   325             }
       
   326         }
       
   327     }
       
   328     
       
   329     // If we still have some left over space we probably ended up with a remainder of
       
   330     // a division. We cannot spread it evenly anymore. If we have any percentage 
       
   331     // columns/rows simply spread the remainder equally over all available percentage columns, 
       
   332     // regardless of their size.
       
   333     if (remainingLen && countPercent) {
       
   334         int remainingPercent = remainingLen;
       
   335         int changePercent = 0;
       
   336 
       
   337         for (int i = 0; i < gridLen; ++i) {
       
   338             if (grid[i].isPercent()) {
       
   339                 changePercent = remainingPercent / countPercent;
       
   340                 gridLayout[i] += changePercent;
       
   341                 remainingLen -= changePercent;
       
   342             }
       
   343         }
       
   344     } 
       
   345     
       
   346     // If we don't have any percentage columns/rows we only have fixed columns. Spread
       
   347     // the remainder equally over all fixed columns/rows.
       
   348     else if (remainingLen && countFixed) {
       
   349         int remainingFixed = remainingLen;
       
   350         int changeFixed = 0;
       
   351         
       
   352         for (int i = 0; i < gridLen; ++i) {
       
   353             if (grid[i].isFixed()) {
       
   354                 changeFixed = remainingFixed / countFixed;
       
   355                 gridLayout[i] += changeFixed;
       
   356                 remainingLen -= changeFixed;
       
   357             }
       
   358         }
       
   359     }
       
   360 
       
   361     // Still some left over. Add it to the last column, because it is impossible
       
   362     // spread it evenly or equally.
       
   363     if (remainingLen)
       
   364         gridLayout[gridLen - 1] += remainingLen;
       
   365 
       
   366     // now we have the final layout, distribute the delta over it
       
   367     bool worked = true;
       
   368     int* gridDelta = axis.m_deltas.data();
       
   369     for (int i = 0; i < gridLen; ++i) {
       
   370         if (gridLayout[i] && gridLayout[i] + gridDelta[i] <= 0)
       
   371             worked = false;
       
   372         gridLayout[i] += gridDelta[i];
       
   373     }
       
   374     // if the deltas broke something, undo them
       
   375     if (!worked) {
       
   376         for (int i = 0; i < gridLen; ++i)
       
   377             gridLayout[i] -= gridDelta[i];
       
   378         axis.m_deltas.fill(0);
       
   379     }
       
   380 }
       
   381 
       
   382 void RenderFrameSet::fillFromEdgeInfo(const FrameEdgeInfo& edgeInfo, int r, int c)
       
   383 {
       
   384     if (edgeInfo.allowBorder(LeftFrameEdge))
       
   385         m_cols.m_allowBorder[c] = true;
       
   386     if (edgeInfo.allowBorder(RightFrameEdge))
       
   387         m_cols.m_allowBorder[c + 1] = true;
       
   388     if (edgeInfo.preventResize(LeftFrameEdge))
       
   389         m_cols.m_preventResize[c] = true;
       
   390     if (edgeInfo.preventResize(RightFrameEdge))
       
   391         m_cols.m_preventResize[c + 1] = true;
       
   392     
       
   393     if (edgeInfo.allowBorder(TopFrameEdge))
       
   394         m_rows.m_allowBorder[r] = true;
       
   395     if (edgeInfo.allowBorder(BottomFrameEdge))
       
   396         m_rows.m_allowBorder[r + 1] = true;
       
   397     if (edgeInfo.preventResize(TopFrameEdge))
       
   398         m_rows.m_preventResize[r] = true;
       
   399     if (edgeInfo.preventResize(BottomFrameEdge))
       
   400         m_rows.m_preventResize[r + 1] = true;
       
   401 }
       
   402 
       
   403 void RenderFrameSet::computeEdgeInfo()
       
   404 {
       
   405     m_rows.m_preventResize.fill(frameSet()->noResize());    
       
   406     m_rows.m_allowBorder.fill(false);
       
   407     m_cols.m_preventResize.fill(frameSet()->noResize());    
       
   408     m_cols.m_allowBorder.fill(false);
       
   409     
       
   410     RenderObject* child = firstChild();
       
   411     if (!child)
       
   412         return;
       
   413 
       
   414     int rows = frameSet()->totalRows();
       
   415     int cols = frameSet()->totalCols();
       
   416     for (int r = 0; r < rows; ++r) {
       
   417         for (int c = 0; c < cols; ++c) {
       
   418             FrameEdgeInfo edgeInfo;
       
   419             if (child->isFrameSet())
       
   420                 edgeInfo = toRenderFrameSet(child)->edgeInfo();
       
   421             else
       
   422                 edgeInfo = toRenderFrame(child)->edgeInfo();
       
   423             fillFromEdgeInfo(edgeInfo, r, c);
       
   424             child = child->nextSibling();
       
   425             if (!child)
       
   426                 return;
       
   427         }
       
   428     }
       
   429 }
       
   430 
       
   431 FrameEdgeInfo RenderFrameSet::edgeInfo() const
       
   432 {
       
   433     FrameEdgeInfo result(frameSet()->noResize(), true);
       
   434     
       
   435     int rows = frameSet()->totalRows();
       
   436     int cols = frameSet()->totalCols();
       
   437     if (rows && cols) {
       
   438         result.setPreventResize(LeftFrameEdge, m_cols.m_preventResize[0]);
       
   439         result.setAllowBorder(LeftFrameEdge, m_cols.m_allowBorder[0]);
       
   440         result.setPreventResize(RightFrameEdge, m_cols.m_preventResize[cols]);
       
   441         result.setAllowBorder(RightFrameEdge, m_cols.m_allowBorder[cols]);
       
   442         result.setPreventResize(TopFrameEdge, m_rows.m_preventResize[0]);
       
   443         result.setAllowBorder(TopFrameEdge, m_rows.m_allowBorder[0]);
       
   444         result.setPreventResize(BottomFrameEdge, m_rows.m_preventResize[rows]);
       
   445         result.setAllowBorder(BottomFrameEdge, m_rows.m_allowBorder[rows]);
       
   446     }
       
   447     
       
   448     return result;
       
   449 }
       
   450 
       
   451 void RenderFrameSet::layout()
       
   452 {
       
   453     ASSERT(needsLayout());
       
   454 
       
   455     bool doFullRepaint = selfNeedsLayout() && checkForRepaintDuringLayout();
       
   456     IntRect oldBounds;
       
   457     if (doFullRepaint)
       
   458         oldBounds = absoluteClippedOverflowRect();
       
   459 
       
   460     if (!parent()->isFrameSet() && !document()->printing()) {
       
   461         setWidth(view()->viewWidth());
       
   462         setHeight(view()->viewHeight());
       
   463     }
       
   464 
       
   465     size_t cols = frameSet()->totalCols();
       
   466     size_t rows = frameSet()->totalRows();
       
   467 
       
   468     if (m_rows.m_sizes.size() != rows || m_cols.m_sizes.size() != cols) {
       
   469         m_rows.resize(rows);
       
   470         m_cols.resize(cols);
       
   471     }
       
   472 
       
   473     int borderThickness = frameSet()->border();
       
   474     layOutAxis(m_rows, frameSet()->rowLengths(), height() - (rows - 1) * borderThickness);
       
   475     layOutAxis(m_cols, frameSet()->colLengths(), width() - (cols - 1) * borderThickness);
       
   476 
       
   477     if (flattenFrameSet())
       
   478         positionFramesWithFlattening();
       
   479     else
       
   480         positionFrames();
       
   481 
       
   482     RenderBox::layout();
       
   483 
       
   484     computeEdgeInfo();
       
   485 
       
   486     if (doFullRepaint) {
       
   487         view()->repaintViewRectangle(oldBounds);
       
   488         IntRect newBounds = absoluteClippedOverflowRect();
       
   489         if (newBounds != oldBounds)
       
   490             view()->repaintViewRectangle(newBounds);
       
   491     }
       
   492 
       
   493     setNeedsLayout(false);
       
   494 }
       
   495 
       
   496 void RenderFrameSet::positionFrames()
       
   497 {
       
   498     RenderBox* child = firstChildBox();
       
   499     if (!child)
       
   500         return;
       
   501 
       
   502     int rows = frameSet()->totalRows();
       
   503     int cols = frameSet()->totalCols();
       
   504 
       
   505     int yPos = 0;
       
   506     int borderThickness = frameSet()->border();
       
   507     for (int r = 0; r < rows; r++) {
       
   508         int xPos = 0;
       
   509         int height = m_rows.m_sizes[r];
       
   510         for (int c = 0; c < cols; c++) {
       
   511             child->setLocation(xPos, yPos);
       
   512             int width = m_cols.m_sizes[c];
       
   513 
       
   514             // has to be resized and itself resize its contents
       
   515             if (width != child->width() || height != child->height()) {
       
   516                 child->setWidth(width);
       
   517                 child->setHeight(height);
       
   518                 child->setNeedsLayout(true);
       
   519                 child->layout();
       
   520             }
       
   521 
       
   522             xPos += width + borderThickness;
       
   523 
       
   524             child = child->nextSiblingBox();
       
   525             if (!child)
       
   526                 return;
       
   527         }
       
   528         yPos += height + borderThickness;
       
   529     }
       
   530 
       
   531     // all the remaining frames are hidden to avoid ugly spurious unflowed frames
       
   532     for (; child; child = child->nextSiblingBox()) {
       
   533         child->setWidth(0);
       
   534         child->setHeight(0);
       
   535         child->setNeedsLayout(false);
       
   536     }
       
   537 }
       
   538 
       
   539 void RenderFrameSet::positionFramesWithFlattening()
       
   540 {
       
   541     RenderBox* child = firstChildBox();
       
   542     if (!child)
       
   543         return;
       
   544 
       
   545     int rows = frameSet()->totalRows();
       
   546     int cols = frameSet()->totalCols();
       
   547 
       
   548     int borderThickness = frameSet()->border();
       
   549     bool repaintNeeded = false;
       
   550 
       
   551     // calculate frameset height based on actual content height to eliminate scrolling
       
   552     bool out = false;
       
   553     for (int r = 0; r < rows && !out; r++) {
       
   554         int extra = 0;
       
   555         int height = m_rows.m_sizes[r];
       
   556 
       
   557         for (int c = 0; c < cols; c++) {
       
   558             IntRect oldFrameRect = child->frameRect();
       
   559 
       
   560             int width = m_cols.m_sizes[c];
       
   561 
       
   562             bool fixedWidth = frameSet()->colLengths() && frameSet()->colLengths()[c].isFixed();
       
   563             bool fixedHeight = frameSet()->rowLengths() && frameSet()->rowLengths()[r].isFixed();
       
   564 
       
   565             // has to be resized and itself resize its contents
       
   566             if (!fixedWidth)
       
   567                 child->setWidth(width ? width + extra / (cols - c) : 0);
       
   568             else
       
   569                 child->setWidth(width);
       
   570             child->setHeight(height);
       
   571 
       
   572             child->setNeedsLayout(true);
       
   573 
       
   574             if (child->isFrameSet())
       
   575                 toRenderFrameSet(child)->layout();
       
   576             else
       
   577                 toRenderFrame(child)->layoutWithFlattening(fixedWidth, fixedHeight);
       
   578 
       
   579             if (child->height() > m_rows.m_sizes[r])
       
   580                 m_rows.m_sizes[r] = child->height();
       
   581             if (child->width() > m_cols.m_sizes[c])
       
   582                 m_cols.m_sizes[c] = child->width();
       
   583 
       
   584             if (child->frameRect() != oldFrameRect)
       
   585                 repaintNeeded = true;
       
   586 
       
   587             // difference between calculated frame width and the width it actually decides to have
       
   588             extra += width - m_cols.m_sizes[c];
       
   589 
       
   590             child = child->nextSiblingBox();
       
   591             if (!child) {
       
   592                 out = true;
       
   593                 break;
       
   594             }
       
   595         }
       
   596     }
       
   597 
       
   598     int xPos = 0;
       
   599     int yPos = 0;
       
   600     out = false;
       
   601     child = firstChildBox();
       
   602     for (int r = 0; r < rows && !out; r++) {
       
   603         xPos = 0;
       
   604         for (int c = 0; c < cols; c++) {
       
   605             // ensure the rows and columns are filled
       
   606             IntRect oldRect = child->frameRect();
       
   607 
       
   608             child->setLocation(xPos, yPos);
       
   609             child->setHeight(m_rows.m_sizes[r]);
       
   610             child->setWidth(m_cols.m_sizes[c]);
       
   611 
       
   612             if (child->frameRect() != oldRect) {
       
   613                 repaintNeeded = true;
       
   614 
       
   615                 // update to final size
       
   616                 child->setNeedsLayout(true);
       
   617                 if (child->isFrameSet())
       
   618                     toRenderFrameSet(child)->layout();
       
   619                 else
       
   620                     toRenderFrame(child)->layoutWithFlattening(true, true);
       
   621             }
       
   622 
       
   623             xPos += m_cols.m_sizes[c] + borderThickness;
       
   624             child = child->nextSiblingBox();
       
   625             if (!child) {
       
   626                 out = true;
       
   627                 break;
       
   628             }
       
   629         }
       
   630         yPos += m_rows.m_sizes[r] + borderThickness;
       
   631     }
       
   632 
       
   633     setWidth(xPos - borderThickness);
       
   634     setHeight(yPos - borderThickness);
       
   635 
       
   636     if (repaintNeeded)
       
   637         repaint();
       
   638 
       
   639     // all the remaining frames are hidden to avoid ugly spurious unflowed frames
       
   640     for (; child; child = child->nextSiblingBox()) {
       
   641         child->setWidth(0);
       
   642         child->setHeight(0);
       
   643         child->setNeedsLayout(false);
       
   644     }
       
   645 }
       
   646 
       
   647 bool RenderFrameSet::flattenFrameSet() const
       
   648 {
       
   649     return frame() && frame()->settings()->frameFlatteningEnabled();
       
   650 }
       
   651 
       
   652 void RenderFrameSet::startResizing(GridAxis& axis, int position)
       
   653 {
       
   654     int split = hitTestSplit(axis, position);
       
   655     if (split == noSplit || !axis.m_allowBorder[split] || axis.m_preventResize[split]) {
       
   656         axis.m_splitBeingResized = noSplit;
       
   657         return;
       
   658     }
       
   659     axis.m_splitBeingResized = split;
       
   660     axis.m_splitResizeOffset = position - splitPosition(axis, split);
       
   661 }
       
   662 
       
   663 void RenderFrameSet::continueResizing(GridAxis& axis, int position)
       
   664 {
       
   665     if (needsLayout())
       
   666         return;
       
   667     if (axis.m_splitBeingResized == noSplit)
       
   668         return;
       
   669     int currentSplitPosition = splitPosition(axis, axis.m_splitBeingResized);
       
   670     int delta = (position - currentSplitPosition) - axis.m_splitResizeOffset;
       
   671     if (delta == 0)
       
   672         return;
       
   673     axis.m_deltas[axis.m_splitBeingResized - 1] += delta;
       
   674     axis.m_deltas[axis.m_splitBeingResized] -= delta;
       
   675     setNeedsLayout(true);
       
   676 }
       
   677 
       
   678 bool RenderFrameSet::userResize(MouseEvent* evt)
       
   679 {
       
   680     if (flattenFrameSet())
       
   681         return false;
       
   682 
       
   683     if (!m_isResizing) {
       
   684         if (needsLayout())
       
   685             return false;
       
   686         if (evt->type() == eventNames().mousedownEvent && evt->button() == LeftButton) {
       
   687             FloatPoint pos = localToAbsolute();
       
   688             startResizing(m_cols, evt->absoluteLocation().x() - pos.x());
       
   689             startResizing(m_rows, evt->absoluteLocation().y() - pos.y());
       
   690             if (m_cols.m_splitBeingResized != noSplit || m_rows.m_splitBeingResized != noSplit) {
       
   691                 setIsResizing(true);
       
   692                 return true;
       
   693             }
       
   694         }
       
   695     } else {
       
   696         if (evt->type() == eventNames().mousemoveEvent || (evt->type() == eventNames().mouseupEvent && evt->button() == LeftButton)) {
       
   697             FloatPoint pos = localToAbsolute();
       
   698             continueResizing(m_cols, evt->absoluteLocation().x() - pos.x());
       
   699             continueResizing(m_rows, evt->absoluteLocation().y() - pos.y());
       
   700             if (evt->type() == eventNames().mouseupEvent && evt->button() == LeftButton) {
       
   701                 setIsResizing(false);
       
   702                 return true;
       
   703             }
       
   704         }
       
   705     }
       
   706 
       
   707     return false;
       
   708 }
       
   709 
       
   710 void RenderFrameSet::setIsResizing(bool isResizing)
       
   711 {
       
   712     m_isResizing = isResizing;
       
   713     for (RenderObject* ancestor = parent(); ancestor; ancestor = ancestor->parent()) {
       
   714         if (ancestor->isFrameSet())
       
   715             toRenderFrameSet(ancestor)->m_isChildResizing = isResizing;
       
   716     }
       
   717     if (Frame* frame = this->frame())
       
   718         frame->eventHandler()->setResizingFrameSet(isResizing ? frameSet() : 0);
       
   719 }
       
   720 
       
   721 bool RenderFrameSet::isResizingRow() const
       
   722 {
       
   723     return m_isResizing && m_rows.m_splitBeingResized != noSplit;
       
   724 }
       
   725 
       
   726 bool RenderFrameSet::isResizingColumn() const
       
   727 {
       
   728     return m_isResizing && m_cols.m_splitBeingResized != noSplit;
       
   729 }
       
   730 
       
   731 bool RenderFrameSet::canResizeRow(const IntPoint& p) const
       
   732 {
       
   733     int r = hitTestSplit(m_rows, p.y());
       
   734     return r != noSplit && m_rows.m_allowBorder[r] && !m_rows.m_preventResize[r];
       
   735 }
       
   736 
       
   737 bool RenderFrameSet::canResizeColumn(const IntPoint& p) const
       
   738 {
       
   739     int c = hitTestSplit(m_cols, p.x());
       
   740     return c != noSplit && m_cols.m_allowBorder[c] && !m_cols.m_preventResize[c];
       
   741 }
       
   742 
       
   743 int RenderFrameSet::splitPosition(const GridAxis& axis, int split) const
       
   744 {
       
   745     if (needsLayout())
       
   746         return 0;
       
   747 
       
   748     int borderThickness = frameSet()->border();
       
   749 
       
   750     int size = axis.m_sizes.size();
       
   751     if (!size)
       
   752         return 0;
       
   753 
       
   754     int position = 0;
       
   755     for (int i = 0; i < split && i < size; ++i)
       
   756         position += axis.m_sizes[i] + borderThickness;
       
   757     return position - borderThickness;
       
   758 }
       
   759 
       
   760 int RenderFrameSet::hitTestSplit(const GridAxis& axis, int position) const
       
   761 {
       
   762     if (needsLayout())
       
   763         return noSplit;
       
   764 
       
   765     int borderThickness = frameSet()->border();
       
   766     if (borderThickness <= 0)
       
   767         return noSplit;
       
   768 
       
   769     size_t size = axis.m_sizes.size();
       
   770     if (!size)
       
   771         return noSplit;
       
   772 
       
   773     int splitPosition = axis.m_sizes[0];
       
   774     for (size_t i = 1; i < size; ++i) {
       
   775         if (position >= splitPosition && position < splitPosition + borderThickness)
       
   776             return i;
       
   777         splitPosition += borderThickness + axis.m_sizes[i];
       
   778     }
       
   779     return noSplit;
       
   780 }
       
   781 
       
   782 bool RenderFrameSet::isChildAllowed(RenderObject* child, RenderStyle*) const
       
   783 {
       
   784     return child->isFrame() || child->isFrameSet();
       
   785 }
       
   786 
       
   787 } // namespace WebCore