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