source: webkit/trunk/WebCore/rendering/RenderFrameSet.cpp@ 59956

Last change on this file since 59956 was 59956, checked in by [email protected], 15 years ago

WebCore: https://bugs.webkit.org/show_bug.cgi?id=39420, :visited not working with background-color.

Reviewed by Dan Bernstein.

Make the RenderStyle color accessors private. This forces callers to use visitedDependentColor
instead (or to make the decision to become friends of the RenderStyle class in order to get access
to the real style information).

Modified history/self-is-visited.html to also test background colors.

  • WebCore.base.exp:
  • accessibility/AccessibilityTable.cpp:

(WebCore::AccessibilityTable::isTableExposableThroughAccessibility):

  • accessibility/mac/AccessibilityObjectWrapper.mm:

(AXAttributeStringSetStyle):

  • css/CSSComputedStyleDeclaration.cpp:

(WebCore::CSSComputedStyleDeclaration::currentColorOrValidColor):

  • css/CSSComputedStyleDeclaration.h:
  • css/SVGCSSStyleSelector.cpp:

(WebCore::colorFromSVGColorCSSValue):

  • editing/ApplyStyleCommand.cpp:

(WebCore::ApplyStyleCommand::editingStyleAtPosition):
(WebCore::prepareEditingStyleToApplyAt):
(WebCore::removeStylesAddedByNode):
(WebCore::fontColorChangesComputedStyle):
(WebCore::ApplyStyleCommand::addInlineStyleIfNeeded):

  • editing/ApplyStyleCommand.h:

(WebCore::):

  • editing/CompositeEditCommand.cpp:

(WebCore::CompositeEditCommand::moveParagraphs):
(WebCore::CompositeEditCommand::breakOutOfEmptyListItem):

  • editing/DeleteButtonController.cpp:

(WebCore::isDeletableElement):

  • editing/DeleteSelectionCommand.cpp:

(WebCore::DeleteSelectionCommand::saveTypingStyleState):

  • editing/InsertParagraphSeparatorCommand.cpp:

(WebCore::InsertParagraphSeparatorCommand::calculateStyleBeforeInsertion):

  • editing/RemoveFormatCommand.cpp:

(WebCore::RemoveFormatCommand::doApply):

  • editing/ReplaceSelectionCommand.cpp:

(WebCore::handleStyleSpansBeforeInsertion):
(WebCore::ReplaceSelectionCommand::handleStyleSpans):
(WebCore::ReplaceSelectionCommand::doApply):

  • editing/SelectionController.cpp:

(WebCore::SelectionController::paintCaret):

  • editing/markup.cpp:

(WebCore::createMarkup):

  • page/animation/AnimationBase.cpp:

(WebCore::AnimationBase::ensurePropertyMap):

  • page/animation/AnimationBase.h:
  • page/mac/FrameMac.mm:

(WebCore::Frame::fontAttributesForSelectionStart):

  • rendering/EllipsisBox.cpp:

(WebCore::EllipsisBox::paint):
(WebCore::EllipsisBox::paintSelection):

  • rendering/InlineTextBox.cpp:

(WebCore::InlineTextBox::paint):

  • rendering/RenderBox.cpp:

(WebCore::RenderBox::styleDidChange):
(WebCore::RenderBox::paintRootBoxDecorations):
(WebCore::RenderBox::paintBoxDecorationsWithSize):

  • rendering/RenderBoxModelObject.cpp:

(WebCore::RenderBoxModelObject::paintBoxShadow):

  • rendering/RenderFieldset.cpp:

(WebCore::RenderFieldset::paintBoxDecorations):

  • rendering/RenderFileUploadControl.cpp:

(WebCore::RenderFileUploadControl::paintObject):

  • rendering/RenderFrameSet.cpp:

(WebCore::RenderFrameSet::paintColumnBorder):
(WebCore::RenderFrameSet::paintRowBorder):

  • rendering/RenderImage.cpp:

(WebCore::RenderImage::paintReplaced):

  • rendering/RenderLayerBacking.cpp:

(WebCore::RenderLayerBacking::rendererBackgroundColor):

  • rendering/RenderLayerBacking.h:
  • rendering/RenderListBox.cpp:

(WebCore::RenderListBox::paintItemForeground):
(WebCore::RenderListBox::paintItemBackground):

  • rendering/RenderListMarker.cpp:

(WebCore::RenderListMarker::paint):

  • rendering/RenderMenuList.cpp:

(WebCore::RenderMenuList::itemStyle):
(WebCore::RenderMenuList::itemBackgroundColor):
(WebCore::RenderMenuList::menuStyle):

  • rendering/RenderObject.cpp:

(WebCore::RenderObject::selectionBackgroundColor):
(WebCore::RenderObject::selectionForegroundColor):

  • rendering/RenderSVGResource.cpp:

(WebCore::RenderSVGResource::adjustColorForPseudoRules):
(WebCore::RenderSVGResource::fillPaintingResource):
(WebCore::RenderSVGResource::strokePaintingResource):

  • rendering/RenderSVGResource.h:
  • rendering/RenderTable.cpp:

(WebCore::RenderTable::paintBoxDecorations):

  • rendering/RenderTable.h:

(WebCore::RenderTable::bgColor):

  • rendering/RenderTableCell.cpp:

(WebCore::RenderTableCell::paintBackgroundsBehindCell):

  • rendering/RenderTextControl.cpp:

(WebCore::RenderTextControl::adjustInnerTextStyle):

  • rendering/RenderTextControlSingleLine.cpp:

(WebCore::RenderTextControlSingleLine::menuStyle):

  • rendering/RenderTheme.cpp:

(WebCore::RenderTheme::isControlStyled):

  • rendering/RenderThemeMac.mm:

(WebCore::RenderThemeMac::paintMenuListButton):

  • rendering/RenderTreeAsText.cpp:

(WebCore::RenderTreeAsText::writeRenderObject):
(WebCore::write):

  • rendering/RenderTreeAsText.h:
  • rendering/SVGInlineTextBox.cpp:

(WebCore::SVGInlineTextBox::paintSelection):

  • rendering/SVGRenderTreeAsText.cpp:

(WebCore::writeRenderSVGTextBox):

  • rendering/style/RenderStyle.cpp:

(WebCore::RenderStyle::colorIncludingFallback):
(WebCore::RenderStyle::visitedDependentColor):

  • rendering/style/RenderStyle.h:

(WebCore::):
(WebCore::InheritedFlags::hasBackground):
(WebCore::InheritedFlags::borderLeftStyle):
(WebCore::InheritedFlags::borderRightStyle):
(WebCore::InheritedFlags::borderTopStyle):
(WebCore::InheritedFlags::borderBottomStyle):
(WebCore::InheritedFlags::textShadow):
(WebCore::InheritedFlags::textStrokeWidth):
(WebCore::InheritedFlags::hasNormalColumnGap):
(WebCore::InheritedFlags::borderLeftColor):
(WebCore::InheritedFlags::borderRightColor):
(WebCore::InheritedFlags::borderTopColor):
(WebCore::InheritedFlags::borderBottomColor):
(WebCore::InheritedFlags::backgroundColor):
(WebCore::InheritedFlags::color):
(WebCore::InheritedFlags::columnRuleColor):
(WebCore::InheritedFlags::outlineColor):
(WebCore::InheritedFlags::textFillColor):
(WebCore::InheritedFlags::textStrokeColor):

  • svg/SVGAnimationElement.cpp:

(WebCore::adjustForCurrentColor):

WebKit/mac: https://bugs.webkit.org/show_bug.cgi?id=39420

Reviewed by Dan Bernstein.

Make sure everyone who needs to is using visitedDependentColor rather than accessing styles
directly.

  • Misc/WebNSAttributedStringExtras.mm:

(+[NSAttributedString _web_attributedStringFromRange:]):

  • WebView/WebFrame.mm:

(-[WebFrame _bodyBackgroundColor]):

  • Property svn:eol-style set to native
File size: 25.8 KB
Line 
1/**
2 * Copyright (C) 1999 Lars Knoll ([email protected])
3 * (C) 2000 Simon Hausmann <[email protected]>
4 * (C) 2000 Stefan Schimanski ([email protected])
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
41namespace WebCore {
42
43RenderFrameSet::RenderFrameSet(HTMLFrameSetElement* frameSet)
44 : RenderBox(frameSet)
45 , m_isResizing(false)
46 , m_isChildResizing(false)
47{
48 setInline(false);
49}
50
51RenderFrameSet::~RenderFrameSet()
52{
53}
54
55RenderFrameSet::GridAxis::GridAxis()
56 : m_splitBeingResized(noSplit)
57{
58}
59
60inline HTMLFrameSetElement* RenderFrameSet::frameSet() const
61{
62 return static_cast<HTMLFrameSetElement*>(node());
63}
64
65static Color borderStartEdgeColor()
66{
67 return Color(170, 170, 170);
68}
69
70static Color borderEndEdgeColor()
71{
72 return Color::black;
73}
74
75static Color borderFillColor()
76{
77 return Color(208, 208, 208);
78}
79
80void 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
100void 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
120void 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
159bool 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
177void 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
190void 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
382void 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
403void 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
431FrameEdgeInfo 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
451void 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
496void 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
539void 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
647bool RenderFrameSet::flattenFrameSet() const
648{
649 return document()->frame() && document()->frame()->settings()->frameFlatteningEnabled();
650}
651
652void 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
663void 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
678bool 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
710void 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 = document()->frame())
718 frame->eventHandler()->setResizingFrameSet(isResizing ? frameSet() : 0);
719}
720
721bool RenderFrameSet::isResizingRow() const
722{
723 return m_isResizing && m_rows.m_splitBeingResized != noSplit;
724}
725
726bool RenderFrameSet::isResizingColumn() const
727{
728 return m_isResizing && m_cols.m_splitBeingResized != noSplit;
729}
730
731bool 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
737bool 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
743int 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
760int 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
782bool RenderFrameSet::isChildAllowed(RenderObject* child, RenderStyle*) const
783{
784 return child->isFrame() || child->isFrameSet();
785}
786
787} // namespace WebCore
Note: See TracBrowser for help on using the repository browser.