~ubuntu-branches/ubuntu/raring/qtwebkit-source/raring-proposed

« back to all changes in this revision

Viewing changes to Source/WebCore/rendering/RenderFrameSet.cpp

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2013-02-18 14:24:18 UTC
  • Revision ID: package-import@ubuntu.com-20130218142418-eon0jmjg3nj438uy
Tags: upstream-2.3
ImportĀ upstreamĀ versionĀ 2.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 "Cursor.h"
 
28
#include "Document.h"
 
29
#include "EventHandler.h"
 
30
#include "EventNames.h"
 
31
#include "Frame.h"
 
32
#include "FrameView.h"
 
33
#include "GraphicsContext.h"
 
34
#include "HTMLFrameSetElement.h"
 
35
#include "HitTestRequest.h"
 
36
#include "HitTestResult.h"
 
37
#include "MouseEvent.h"
 
38
#include "PaintInfo.h"
 
39
#include "RenderFrame.h"
 
40
#include "RenderLayer.h"
 
41
#include "RenderView.h"
 
42
#include "Settings.h"
 
43
 
 
44
namespace WebCore {
 
45
 
 
46
RenderFrameSet::RenderFrameSet(HTMLFrameSetElement* frameSet)
 
47
    : RenderBox(frameSet)
 
48
    , m_isResizing(false)
 
49
    , m_isChildResizing(false)
 
50
{
 
51
    setInline(false);
 
52
}
 
53
 
 
54
RenderFrameSet::~RenderFrameSet()
 
55
{
 
56
}
 
57
 
 
58
RenderFrameSet::GridAxis::GridAxis()
 
59
    : m_splitBeingResized(noSplit)
 
60
{
 
61
}
 
62
 
 
63
inline HTMLFrameSetElement* RenderFrameSet::frameSet() const
 
64
{
 
65
    return static_cast<HTMLFrameSetElement*>(node());
 
66
}
 
67
 
 
68
static Color borderStartEdgeColor()
 
69
{
 
70
    return Color(170, 170, 170);
 
71
}
 
72
 
 
73
static Color borderEndEdgeColor()
 
74
{
 
75
    return Color::black;
 
76
}
 
77
 
 
78
static Color borderFillColor()
 
79
{
 
80
    return Color(208, 208, 208);
 
81
}
 
82
 
 
83
void RenderFrameSet::paintColumnBorder(const PaintInfo& paintInfo, const IntRect& borderRect)
 
84
{
 
85
    if (!paintInfo.rect.intersects(borderRect))
 
86
        return;
 
87
        
 
88
    // FIXME: We should do something clever when borders from distinct framesets meet at a join.
 
89
    
 
90
    // Fill first.
 
91
    GraphicsContext* context = paintInfo.context;
 
92
    ColorSpace colorSpace = style()->colorSpace();
 
93
    context->fillRect(borderRect, frameSet()->hasBorderColor() ? style()->visitedDependentColor(CSSPropertyBorderLeftColor) : borderFillColor(), colorSpace);
 
94
    
 
95
    // Now stroke the edges but only if we have enough room to paint both edges with a little
 
96
    // bit of the fill color showing through.
 
97
    if (borderRect.width() >= 3) {
 
98
        context->fillRect(IntRect(borderRect.location(), IntSize(1, height())), borderStartEdgeColor(), colorSpace);
 
99
        context->fillRect(IntRect(IntPoint(borderRect.maxX() - 1, borderRect.y()), IntSize(1, height())), borderEndEdgeColor(), colorSpace);
 
100
    }
 
101
}
 
102
 
 
103
void RenderFrameSet::paintRowBorder(const PaintInfo& paintInfo, const IntRect& borderRect)
 
104
{
 
105
    if (!paintInfo.rect.intersects(borderRect))
 
106
        return;
 
107
 
 
108
    // FIXME: We should do something clever when borders from distinct framesets meet at a join.
 
109
    
 
110
    // Fill first.
 
111
    GraphicsContext* context = paintInfo.context;
 
112
    ColorSpace colorSpace = style()->colorSpace();
 
113
    context->fillRect(borderRect, frameSet()->hasBorderColor() ? style()->visitedDependentColor(CSSPropertyBorderLeftColor) : borderFillColor(), colorSpace);
 
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.location(), IntSize(width(), 1)), borderStartEdgeColor(), colorSpace);
 
119
        context->fillRect(IntRect(IntPoint(borderRect.x(), borderRect.maxY() - 1), IntSize(width(), 1)), borderEndEdgeColor(), colorSpace);
 
120
    }
 
121
}
 
122
 
 
123
void RenderFrameSet::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
 
124
{
 
125
    if (paintInfo.phase != PaintPhaseForeground)
 
126
        return;
 
127
    
 
128
    RenderObject* child = firstChild();
 
129
    if (!child)
 
130
        return;
 
131
 
 
132
    LayoutPoint adjustedPaintOffset = paintOffset + location();
 
133
 
 
134
    int rows = frameSet()->totalRows();
 
135
    int cols = frameSet()->totalCols();
 
136
    LayoutUnit borderThickness = frameSet()->border();
 
137
    
 
138
    LayoutUnit yPos = 0;
 
139
    for (int r = 0; r < rows; r++) {
 
140
        LayoutUnit xPos = 0;
 
141
        for (int c = 0; c < cols; c++) {
 
142
            child->paint(paintInfo, adjustedPaintOffset);
 
143
            xPos += m_cols.m_sizes[c];
 
144
            if (borderThickness && m_cols.m_allowBorder[c + 1]) {
 
145
                paintColumnBorder(paintInfo, pixelSnappedIntRect(LayoutRect(adjustedPaintOffset.x() + xPos, adjustedPaintOffset.y() + yPos, borderThickness, height())));
 
146
                xPos += borderThickness;
 
147
            }
 
148
            child = child->nextSibling();
 
149
            if (!child)
 
150
                return;
 
151
        }
 
152
        yPos += m_rows.m_sizes[r];
 
153
        if (borderThickness && m_rows.m_allowBorder[r + 1]) {
 
154
            paintRowBorder(paintInfo, pixelSnappedIntRect(LayoutRect(adjustedPaintOffset.x(), adjustedPaintOffset.y() + yPos, width(), borderThickness)));
 
155
            yPos += borderThickness;
 
156
        }
 
157
    }
 
158
}
 
159
 
 
160
bool RenderFrameSet::nodeAtPoint(const HitTestRequest& request, HitTestResult& result,
 
161
    const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction action)
 
162
{
 
163
    if (action != HitTestForeground)
 
164
        return false;
 
165
 
 
166
    bool inside = RenderBox::nodeAtPoint(request, result, locationInContainer, accumulatedOffset, action)
 
167
        || m_isResizing;
 
168
 
 
169
    if (inside && frameSet()->noResize()
 
170
            && !request.readOnly() && !result.innerNode() && !request.touchMove()) {
 
171
        result.setInnerNode(node());
 
172
        result.setInnerNonSharedNode(node());
 
173
    }
 
174
 
 
175
    return inside || m_isChildResizing;
 
176
}
 
177
 
 
178
void RenderFrameSet::GridAxis::resize(int size)
 
179
{
 
180
    m_sizes.resize(size);
 
181
    m_deltas.resize(size);
 
182
    m_deltas.fill(0);
 
183
    
 
184
    // To track edges for resizability and borders, we need to be (size + 1). This is because a parent frameset
 
185
    // may ask us for information about our left/top/right/bottom edges in order to make its own decisions about
 
186
    // what to do. We are capable of tainting that parent frameset's borders, so we have to cache this info.
 
187
    m_preventResize.resize(size + 1);
 
188
    m_allowBorder.resize(size + 1);
 
189
}
 
190
 
 
191
void RenderFrameSet::layOutAxis(GridAxis& axis, const Length* grid, int availableLen)
 
192
{
 
193
    availableLen = max(availableLen, 0);
 
194
 
 
195
    int* gridLayout = axis.m_sizes.data();
 
196
 
 
197
    if (!grid) {
 
198
        gridLayout[0] = availableLen;
 
199
        return;
 
200
    }
 
201
 
 
202
    int gridLen = axis.m_sizes.size();
 
203
    ASSERT(gridLen);
 
204
 
 
205
    int totalRelative = 0;
 
206
    int totalFixed = 0;
 
207
    int totalPercent = 0;
 
208
    int countRelative = 0;
 
209
    int countFixed = 0;
 
210
    int countPercent = 0;
 
211
 
 
212
    // First we need to investigate how many columns of each type we have and
 
213
    // how much space these columns are going to require.
 
214
    for (int i = 0; i < gridLen; ++i) {
 
215
        // Count the total length of all of the fixed columns/rows -> totalFixed
 
216
        // Count the number of columns/rows which are fixed -> countFixed
 
217
        if (grid[i].isFixed()) {
 
218
            gridLayout[i] = max(grid[i].intValue(), 0);
 
219
            totalFixed += gridLayout[i];
 
220
            countFixed++;
 
221
        }
 
222
        
 
223
        // Count the total percentage of all of the percentage columns/rows -> totalPercent
 
224
        // Count the number of columns/rows which are percentages -> countPercent
 
225
        if (grid[i].isPercent()) {
 
226
            gridLayout[i] = max(intValueForLength(grid[i], availableLen), 0);
 
227
            totalPercent += gridLayout[i];
 
228
            countPercent++;
 
229
        }
 
230
 
 
231
        // Count the total relative of all the relative columns/rows -> totalRelative
 
232
        // Count the number of columns/rows which are relative -> countRelative
 
233
        if (grid[i].isRelative()) {
 
234
            totalRelative += max(grid[i].intValue(), 1);
 
235
            countRelative++;
 
236
        }            
 
237
    }
 
238
 
 
239
    int remainingLen = availableLen;
 
240
 
 
241
    // Fixed columns/rows are our first priority. If there is not enough space to fit all fixed
 
242
    // columns/rows we need to proportionally adjust their size. 
 
243
    if (totalFixed > remainingLen) {
 
244
        int remainingFixed = remainingLen;
 
245
 
 
246
        for (int i = 0; i < gridLen; ++i) {
 
247
            if (grid[i].isFixed()) {
 
248
                gridLayout[i] = (gridLayout[i] * remainingFixed) / totalFixed;
 
249
                remainingLen -= gridLayout[i];
 
250
            }
 
251
        }
 
252
    } else
 
253
        remainingLen -= totalFixed;
 
254
 
 
255
    // Percentage columns/rows are our second priority. Divide the remaining space proportionally 
 
256
    // over all percentage columns/rows. IMPORTANT: the size of each column/row is not relative 
 
257
    // to 100%, but to the total percentage. For example, if there are three columns, each of 75%,
 
258
    // and the available space is 300px, each column will become 100px in width.
 
259
    if (totalPercent > remainingLen) {
 
260
        int remainingPercent = remainingLen;
 
261
 
 
262
        for (int i = 0; i < gridLen; ++i) {
 
263
            if (grid[i].isPercent()) {
 
264
                gridLayout[i] = (gridLayout[i] * remainingPercent) / totalPercent;
 
265
                remainingLen -= gridLayout[i];
 
266
            }
 
267
        }
 
268
    } else
 
269
        remainingLen -= totalPercent;
 
270
 
 
271
    // Relative columns/rows are our last priority. Divide the remaining space proportionally
 
272
    // over all relative columns/rows. IMPORTANT: the relative value of 0* is treated as 1*.
 
273
    if (countRelative) {
 
274
        int lastRelative = 0;
 
275
        int remainingRelative = remainingLen;
 
276
 
 
277
        for (int i = 0; i < gridLen; ++i) {
 
278
            if (grid[i].isRelative()) {
 
279
                gridLayout[i] = (max(grid[i].intValue(), 1) * remainingRelative) / totalRelative;
 
280
                remainingLen -= gridLayout[i];
 
281
                lastRelative = i;
 
282
            }
 
283
        }
 
284
        
 
285
        // If we could not evenly distribute the available space of all of the relative  
 
286
        // columns/rows, the remainder will be added to the last column/row.
 
287
        // For example: if we have a space of 100px and three columns (*,*,*), the remainder will
 
288
        // be 1px and will be added to the last column: 33px, 33px, 34px.
 
289
        if (remainingLen) {
 
290
            gridLayout[lastRelative] += remainingLen;
 
291
            remainingLen = 0;
 
292
        }
 
293
    }
 
294
 
 
295
    // If we still have some left over space we need to divide it over the already existing
 
296
    // columns/rows
 
297
    if (remainingLen) {
 
298
        // Our first priority is to spread if over the percentage columns. The remaining
 
299
        // space is spread evenly, for example: if we have a space of 100px, the columns 
 
300
        // definition of 25%,25% used to result in two columns of 25px. After this the 
 
301
        // columns will each be 50px in width. 
 
302
        if (countPercent && totalPercent) {
 
303
            int remainingPercent = remainingLen;
 
304
            int changePercent = 0;
 
305
 
 
306
            for (int i = 0; i < gridLen; ++i) {
 
307
                if (grid[i].isPercent()) {
 
308
                    changePercent = (remainingPercent * gridLayout[i]) / totalPercent;
 
309
                    gridLayout[i] += changePercent;
 
310
                    remainingLen -= changePercent;
 
311
                }
 
312
            }
 
313
        } else if (totalFixed) {
 
314
            // Our last priority is to spread the remaining space over the fixed columns.
 
315
            // For example if we have 100px of space and two column of each 40px, both
 
316
            // columns will become exactly 50px.
 
317
            int remainingFixed = remainingLen;
 
318
            int changeFixed = 0;
 
319
 
 
320
            for (int i = 0; i < gridLen; ++i) {
 
321
                if (grid[i].isFixed()) {
 
322
                    changeFixed = (remainingFixed * gridLayout[i]) / totalFixed;
 
323
                    gridLayout[i] += changeFixed;
 
324
                    remainingLen -= changeFixed;
 
325
                } 
 
326
            }
 
327
        }
 
328
    }
 
329
    
 
330
    // If we still have some left over space we probably ended up with a remainder of
 
331
    // a division. We cannot spread it evenly anymore. If we have any percentage 
 
332
    // columns/rows simply spread the remainder equally over all available percentage columns, 
 
333
    // regardless of their size.
 
334
    if (remainingLen && countPercent) {
 
335
        int remainingPercent = remainingLen;
 
336
        int changePercent = 0;
 
337
 
 
338
        for (int i = 0; i < gridLen; ++i) {
 
339
            if (grid[i].isPercent()) {
 
340
                changePercent = remainingPercent / countPercent;
 
341
                gridLayout[i] += changePercent;
 
342
                remainingLen -= changePercent;
 
343
            }
 
344
        }
 
345
    } else if (remainingLen && countFixed) {
 
346
        // If we don't have any percentage columns/rows we only have
 
347
        // fixed columns. Spread the remainder equally over all fixed
 
348
        // columns/rows.
 
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::notifyFrameEdgeInfoChanged()
 
383
{
 
384
    if (needsLayout())
 
385
        return;
 
386
    // FIXME: We should only recompute the edge info with respect to the frame that changed
 
387
    // and its adjacent frame(s) instead of recomputing the edge info for the entire frameset.
 
388
    computeEdgeInfo();
 
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 = toRenderFrameSet(child)->edgeInfo();
 
430
            else
 
431
                edgeInfo = toRenderFrame(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
    StackStats::LayoutCheckPoint layoutCheckPoint;
 
463
    ASSERT(needsLayout());
 
464
 
 
465
    bool doFullRepaint = selfNeedsLayout() && checkForRepaintDuringLayout();
 
466
    LayoutRect oldBounds;
 
467
    if (doFullRepaint)
 
468
        oldBounds = absoluteClippedOverflowRect();
 
469
 
 
470
    if (!parent()->isFrameSet() && !document()->printing()) {
 
471
        setWidth(view()->viewWidth());
 
472
        setHeight(view()->viewHeight());
 
473
    }
 
474
 
 
475
    unsigned cols = frameSet()->totalCols();
 
476
    unsigned rows = frameSet()->totalRows();
 
477
 
 
478
    if (m_rows.m_sizes.size() != rows || m_cols.m_sizes.size() != cols) {
 
479
        m_rows.resize(rows);
 
480
        m_cols.resize(cols);
 
481
    }
 
482
 
 
483
    LayoutUnit borderThickness = frameSet()->border();
 
484
    layOutAxis(m_rows, frameSet()->rowLengths(), height() - (rows - 1) * borderThickness);
 
485
    layOutAxis(m_cols, frameSet()->colLengths(), width() - (cols - 1) * borderThickness);
 
486
 
 
487
    if (flattenFrameSet())
 
488
        positionFramesWithFlattening();
 
489
    else
 
490
        positionFrames();
 
491
 
 
492
    RenderBox::layout();
 
493
 
 
494
    computeEdgeInfo();
 
495
 
 
496
    if (doFullRepaint) {
 
497
        view()->repaintViewRectangle(oldBounds);
 
498
        LayoutRect newBounds = absoluteClippedOverflowRect();
 
499
        if (newBounds != oldBounds)
 
500
            view()->repaintViewRectangle(newBounds);
 
501
    }
 
502
 
 
503
    // If this FrameSet has a transform matrix then we need to recompute it
 
504
    // because the transform origin is a function the size of the RenderFrameSet
 
505
    // which may not be computed until it is attached to the render tree.
 
506
    if (layer() && hasTransform())
 
507
        layer()->updateTransform();
 
508
 
 
509
    setNeedsLayout(false);
 
510
}
 
511
 
 
512
void RenderFrameSet::positionFrames()
 
513
{
 
514
    RenderBox* child = firstChildBox();
 
515
    if (!child)
 
516
        return;
 
517
 
 
518
    int rows = frameSet()->totalRows();
 
519
    int cols = frameSet()->totalCols();
 
520
 
 
521
    int yPos = 0;
 
522
    int borderThickness = frameSet()->border();
 
523
    for (int r = 0; r < rows; r++) {
 
524
        int xPos = 0;
 
525
        int height = m_rows.m_sizes[r];
 
526
        for (int c = 0; c < cols; c++) {
 
527
            child->setLocation(IntPoint(xPos, yPos));
 
528
            int width = m_cols.m_sizes[c];
 
529
 
 
530
            // has to be resized and itself resize its contents
 
531
            if (width != child->width() || height != child->height()) {
 
532
                child->setWidth(width);
 
533
                child->setHeight(height);
 
534
                child->setNeedsLayout(true);
 
535
                child->layout();
 
536
            }
 
537
 
 
538
            xPos += width + borderThickness;
 
539
 
 
540
            child = child->nextSiblingBox();
 
541
            if (!child)
 
542
                return;
 
543
        }
 
544
        yPos += height + borderThickness;
 
545
    }
 
546
 
 
547
    // all the remaining frames are hidden to avoid ugly spurious unflowed frames
 
548
    for (; child; child = child->nextSiblingBox()) {
 
549
        child->setWidth(0);
 
550
        child->setHeight(0);
 
551
        child->setNeedsLayout(false);
 
552
    }
 
553
}
 
554
 
 
555
void RenderFrameSet::positionFramesWithFlattening()
 
556
{
 
557
    RenderBox* child = firstChildBox();
 
558
    if (!child)
 
559
        return;
 
560
 
 
561
    int rows = frameSet()->totalRows();
 
562
    int cols = frameSet()->totalCols();
 
563
 
 
564
    int borderThickness = frameSet()->border();
 
565
    bool repaintNeeded = false;
 
566
 
 
567
    // calculate frameset height based on actual content height to eliminate scrolling
 
568
    bool out = false;
 
569
    for (int r = 0; r < rows && !out; r++) {
 
570
        int extra = 0;
 
571
        int height = m_rows.m_sizes[r];
 
572
 
 
573
        for (int c = 0; c < cols; c++) {
 
574
            IntRect oldFrameRect = pixelSnappedIntRect(child->frameRect());
 
575
 
 
576
            int width = m_cols.m_sizes[c];
 
577
 
 
578
            bool fixedWidth = frameSet()->colLengths() && frameSet()->colLengths()[c].isFixed();
 
579
            bool fixedHeight = frameSet()->rowLengths() && frameSet()->rowLengths()[r].isFixed();
 
580
 
 
581
            // has to be resized and itself resize its contents
 
582
            if (!fixedWidth)
 
583
                child->setWidth(width ? width + extra / (cols - c) : 0);
 
584
            else
 
585
                child->setWidth(width);
 
586
            child->setHeight(height);
 
587
 
 
588
            child->setNeedsLayout(true);
 
589
 
 
590
            if (child->isFrameSet())
 
591
                toRenderFrameSet(child)->layout();
 
592
            else
 
593
                toRenderFrame(child)->layoutWithFlattening(fixedWidth, fixedHeight);
 
594
 
 
595
            if (child->height() > m_rows.m_sizes[r])
 
596
                m_rows.m_sizes[r] = child->height();
 
597
            if (child->width() > m_cols.m_sizes[c])
 
598
                m_cols.m_sizes[c] = child->width();
 
599
 
 
600
            if (child->frameRect() != oldFrameRect)
 
601
                repaintNeeded = true;
 
602
 
 
603
            // difference between calculated frame width and the width it actually decides to have
 
604
            extra += width - m_cols.m_sizes[c];
 
605
 
 
606
            child = child->nextSiblingBox();
 
607
            if (!child) {
 
608
                out = true;
 
609
                break;
 
610
            }
 
611
        }
 
612
    }
 
613
 
 
614
    int xPos = 0;
 
615
    int yPos = 0;
 
616
    out = false;
 
617
    child = firstChildBox();
 
618
    for (int r = 0; r < rows && !out; r++) {
 
619
        xPos = 0;
 
620
        for (int c = 0; c < cols; c++) {
 
621
            // ensure the rows and columns are filled
 
622
            IntRect oldRect = pixelSnappedIntRect(child->frameRect());
 
623
 
 
624
            child->setLocation(IntPoint(xPos, yPos));
 
625
            child->setHeight(m_rows.m_sizes[r]);
 
626
            child->setWidth(m_cols.m_sizes[c]);
 
627
 
 
628
            if (child->frameRect() != oldRect) {
 
629
                repaintNeeded = true;
 
630
 
 
631
                // update to final size
 
632
                child->setNeedsLayout(true);
 
633
                if (child->isFrameSet())
 
634
                    toRenderFrameSet(child)->layout();
 
635
                else
 
636
                    toRenderFrame(child)->layoutWithFlattening(true, true);
 
637
            }
 
638
 
 
639
            xPos += m_cols.m_sizes[c] + borderThickness;
 
640
            child = child->nextSiblingBox();
 
641
            if (!child) {
 
642
                out = true;
 
643
                break;
 
644
            }
 
645
        }
 
646
        yPos += m_rows.m_sizes[r] + borderThickness;
 
647
    }
 
648
 
 
649
    setWidth(xPos - borderThickness);
 
650
    setHeight(yPos - borderThickness);
 
651
 
 
652
    if (repaintNeeded)
 
653
        repaint();
 
654
 
 
655
    // all the remaining frames are hidden to avoid ugly spurious unflowed frames
 
656
    for (; child; child = child->nextSiblingBox()) {
 
657
        child->setWidth(0);
 
658
        child->setHeight(0);
 
659
        child->setNeedsLayout(false);
 
660
    }
 
661
}
 
662
 
 
663
bool RenderFrameSet::flattenFrameSet() const
 
664
{
 
665
    return frame() && frame()->settings() && frame()->settings()->frameFlatteningEnabled();
 
666
}
 
667
 
 
668
void RenderFrameSet::startResizing(GridAxis& axis, int position)
 
669
{
 
670
    int split = hitTestSplit(axis, position);
 
671
    if (split == noSplit || axis.m_preventResize[split]) {
 
672
        axis.m_splitBeingResized = noSplit;
 
673
        return;
 
674
    }
 
675
    axis.m_splitBeingResized = split;
 
676
    axis.m_splitResizeOffset = position - splitPosition(axis, split);
 
677
}
 
678
 
 
679
void RenderFrameSet::continueResizing(GridAxis& axis, int position)
 
680
{
 
681
    if (needsLayout())
 
682
        return;
 
683
    if (axis.m_splitBeingResized == noSplit)
 
684
        return;
 
685
    int currentSplitPosition = splitPosition(axis, axis.m_splitBeingResized);
 
686
    int delta = (position - currentSplitPosition) - axis.m_splitResizeOffset;
 
687
    if (!delta)
 
688
        return;
 
689
    axis.m_deltas[axis.m_splitBeingResized - 1] += delta;
 
690
    axis.m_deltas[axis.m_splitBeingResized] -= delta;
 
691
    setNeedsLayout(true);
 
692
}
 
693
 
 
694
bool RenderFrameSet::userResize(MouseEvent* evt)
 
695
{
 
696
    if (flattenFrameSet())
 
697
        return false;
 
698
 
 
699
    if (!m_isResizing) {
 
700
        if (needsLayout())
 
701
            return false;
 
702
        if (evt->type() == eventNames().mousedownEvent && evt->button() == LeftButton) {
 
703
            FloatPoint localPos = absoluteToLocal(evt->absoluteLocation(), UseTransforms | SnapOffsetForTransforms);
 
704
            startResizing(m_cols, localPos.x());
 
705
            startResizing(m_rows, localPos.y());
 
706
            if (m_cols.m_splitBeingResized != noSplit || m_rows.m_splitBeingResized != noSplit) {
 
707
                setIsResizing(true);
 
708
                return true;
 
709
            }
 
710
        }
 
711
    } else {
 
712
        if (evt->type() == eventNames().mousemoveEvent || (evt->type() == eventNames().mouseupEvent && evt->button() == LeftButton)) {
 
713
            FloatPoint localPos = absoluteToLocal(evt->absoluteLocation(), UseTransforms | SnapOffsetForTransforms);
 
714
            continueResizing(m_cols, localPos.x());
 
715
            continueResizing(m_rows, localPos.y());
 
716
            if (evt->type() == eventNames().mouseupEvent && evt->button() == LeftButton) {
 
717
                setIsResizing(false);
 
718
                return true;
 
719
            }
 
720
        }
 
721
    }
 
722
 
 
723
    return false;
 
724
}
 
725
 
 
726
void RenderFrameSet::setIsResizing(bool isResizing)
 
727
{
 
728
    m_isResizing = isResizing;
 
729
    for (RenderObject* ancestor = parent(); ancestor; ancestor = ancestor->parent()) {
 
730
        if (ancestor->isFrameSet())
 
731
            toRenderFrameSet(ancestor)->m_isChildResizing = isResizing;
 
732
    }
 
733
    if (Frame* frame = this->frame())
 
734
        frame->eventHandler()->setResizingFrameSet(isResizing ? frameSet() : 0);
 
735
}
 
736
 
 
737
bool RenderFrameSet::isResizingRow() const
 
738
{
 
739
    return m_isResizing && m_rows.m_splitBeingResized != noSplit;
 
740
}
 
741
 
 
742
bool RenderFrameSet::isResizingColumn() const
 
743
{
 
744
    return m_isResizing && m_cols.m_splitBeingResized != noSplit;
 
745
}
 
746
 
 
747
bool RenderFrameSet::canResizeRow(const IntPoint& p) const
 
748
{
 
749
    int r = hitTestSplit(m_rows, p.y());
 
750
    return r != noSplit && !m_rows.m_preventResize[r];
 
751
}
 
752
 
 
753
bool RenderFrameSet::canResizeColumn(const IntPoint& p) const
 
754
{
 
755
    int c = hitTestSplit(m_cols, p.x());
 
756
    return c != noSplit && !m_cols.m_preventResize[c];
 
757
}
 
758
 
 
759
int RenderFrameSet::splitPosition(const GridAxis& axis, int split) const
 
760
{
 
761
    if (needsLayout())
 
762
        return 0;
 
763
 
 
764
    int borderThickness = frameSet()->border();
 
765
 
 
766
    int size = axis.m_sizes.size();
 
767
    if (!size)
 
768
        return 0;
 
769
 
 
770
    int position = 0;
 
771
    for (int i = 0; i < split && i < size; ++i)
 
772
        position += axis.m_sizes[i] + borderThickness;
 
773
    return position - borderThickness;
 
774
}
 
775
 
 
776
int RenderFrameSet::hitTestSplit(const GridAxis& axis, int position) const
 
777
{
 
778
    if (needsLayout())
 
779
        return noSplit;
 
780
 
 
781
    int borderThickness = frameSet()->border();
 
782
    if (borderThickness <= 0)
 
783
        return noSplit;
 
784
 
 
785
    size_t size = axis.m_sizes.size();
 
786
    if (!size)
 
787
        return noSplit;
 
788
 
 
789
    int splitPosition = axis.m_sizes[0];
 
790
    for (size_t i = 1; i < size; ++i) {
 
791
        if (position >= splitPosition && position < splitPosition + borderThickness)
 
792
            return i;
 
793
        splitPosition += borderThickness + axis.m_sizes[i];
 
794
    }
 
795
    return noSplit;
 
796
}
 
797
 
 
798
bool RenderFrameSet::isChildAllowed(RenderObject* child, RenderStyle*) const
 
799
{
 
800
    return child->isFrame() || child->isFrameSet();
 
801
}
 
802
 
 
803
CursorDirective RenderFrameSet::getCursor(const LayoutPoint& point, Cursor& cursor) const
 
804
{
 
805
    IntPoint roundedPoint = roundedIntPoint(point);
 
806
    if (canResizeRow(roundedPoint)) {
 
807
        cursor = rowResizeCursor();
 
808
        return SetCursor;
 
809
    }
 
810
    if (canResizeColumn(roundedPoint)) {
 
811
        cursor = columnResizeCursor();
 
812
        return SetCursor;
 
813
    }
 
814
    return RenderBox::getCursor(point, cursor);
 
815
}
 
816
 
 
817
} // namespace WebCore