From cad810f21b803229eb11403f9209855525a25d57 Mon Sep 17 00:00:00 2001 From: Steve Block Date: Fri, 6 May 2011 11:45:16 +0100 Subject: Merge WebKit at r75315: Initial merge by git. Change-Id: I570314b346ce101c935ed22a626b48c2af266b84 --- Source/WebCore/rendering/RenderFrameSet.cpp | 890 ++++++++++++++++++++++++++++ 1 file changed, 890 insertions(+) create mode 100644 Source/WebCore/rendering/RenderFrameSet.cpp (limited to 'Source/WebCore/rendering/RenderFrameSet.cpp') diff --git a/Source/WebCore/rendering/RenderFrameSet.cpp b/Source/WebCore/rendering/RenderFrameSet.cpp new file mode 100644 index 0000000..600d65e --- /dev/null +++ b/Source/WebCore/rendering/RenderFrameSet.cpp @@ -0,0 +1,890 @@ +/** + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 2000 Simon Hausmann + * (C) 2000 Stefan Schimanski (1Stein@gmx.de) + * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" +#include "RenderFrameSet.h" + +#include "Document.h" +#include "EventHandler.h" +#include "EventNames.h" +#include "Frame.h" +#include "FrameView.h" +#include "GraphicsContext.h" +#include "HTMLFrameSetElement.h" +#include "HitTestRequest.h" +#include "HitTestResult.h" +#include "MouseEvent.h" +#include "RenderFrame.h" +#include "RenderView.h" +#include "Settings.h" + +namespace WebCore { + +RenderFrameSet::RenderFrameSet(HTMLFrameSetElement* frameSet) + : RenderBox(frameSet) + , m_isResizing(false) + , m_isChildResizing(false) +#ifdef ANDROID_FLATTEN_FRAMESET + , m_gridCalculated(false) +#endif +{ + setInline(false); +} + +RenderFrameSet::~RenderFrameSet() +{ +} + +RenderFrameSet::GridAxis::GridAxis() + : m_splitBeingResized(noSplit) +{ +} + +inline HTMLFrameSetElement* RenderFrameSet::frameSet() const +{ + return static_cast(node()); +} + +static Color borderStartEdgeColor() +{ + return Color(170, 170, 170); +} + +static Color borderEndEdgeColor() +{ + return Color::black; +} + +static Color borderFillColor() +{ + return Color(208, 208, 208); +} + +void RenderFrameSet::paintColumnBorder(const PaintInfo& paintInfo, const IntRect& borderRect) +{ + if (!paintInfo.rect.intersects(borderRect)) + return; + + // FIXME: We should do something clever when borders from distinct framesets meet at a join. + + // Fill first. + GraphicsContext* context = paintInfo.context; + ColorSpace colorSpace = style()->colorSpace(); + context->fillRect(borderRect, frameSet()->hasBorderColor() ? style()->visitedDependentColor(CSSPropertyBorderLeftColor) : borderFillColor(), colorSpace); + + // Now stroke the edges but only if we have enough room to paint both edges with a little + // bit of the fill color showing through. + if (borderRect.width() >= 3) { + context->fillRect(IntRect(borderRect.topLeft(), IntSize(1, height())), borderStartEdgeColor(), colorSpace); + context->fillRect(IntRect(borderRect.topRight(), IntSize(1, height())), borderEndEdgeColor(), colorSpace); + } +} + +void RenderFrameSet::paintRowBorder(const PaintInfo& paintInfo, const IntRect& borderRect) +{ + if (!paintInfo.rect.intersects(borderRect)) + return; + + // FIXME: We should do something clever when borders from distinct framesets meet at a join. + + // Fill first. + GraphicsContext* context = paintInfo.context; + ColorSpace colorSpace = style()->colorSpace(); + context->fillRect(borderRect, frameSet()->hasBorderColor() ? style()->visitedDependentColor(CSSPropertyBorderLeftColor) : borderFillColor(), colorSpace); + + // Now stroke the edges but only if we have enough room to paint both edges with a little + // bit of the fill color showing through. + if (borderRect.height() >= 3) { + context->fillRect(IntRect(borderRect.topLeft(), IntSize(width(), 1)), borderStartEdgeColor(), colorSpace); + context->fillRect(IntRect(borderRect.bottomLeft(), IntSize(width(), 1)), borderEndEdgeColor(), colorSpace); + } +} + +void RenderFrameSet::paint(PaintInfo& paintInfo, int tx, int ty) +{ + if (paintInfo.phase != PaintPhaseForeground) + return; + + RenderObject* child = firstChild(); + if (!child) + return; + + // Add in our offsets. + tx += x(); + ty += y(); + + int rows = frameSet()->totalRows(); + int cols = frameSet()->totalCols(); + int borderThickness = frameSet()->border(); + + int yPos = 0; + for (int r = 0; r < rows; r++) { + int xPos = 0; + for (int c = 0; c < cols; c++) { + child->paint(paintInfo, tx, ty); + xPos += m_cols.m_sizes[c]; + if (borderThickness && m_cols.m_allowBorder[c + 1]) { + paintColumnBorder(paintInfo, IntRect(tx + xPos, ty + yPos, borderThickness, height())); + xPos += borderThickness; + } + child = child->nextSibling(); + if (!child) + return; + } + yPos += m_rows.m_sizes[r]; + if (borderThickness && m_rows.m_allowBorder[r + 1]) { + paintRowBorder(paintInfo, IntRect(tx, ty + yPos, width(), borderThickness)); + yPos += borderThickness; + } + } +} + +bool RenderFrameSet::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, + int x, int y, int tx, int ty, HitTestAction action) +{ + if (action != HitTestForeground) + return false; + + bool inside = RenderBox::nodeAtPoint(request, result, x, y, tx, ty, action) + || m_isResizing; + + if (inside && frameSet()->noResize() + && !request.readOnly() && !result.innerNode()) { + result.setInnerNode(node()); + result.setInnerNonSharedNode(node()); + } + + return inside || m_isChildResizing; +} + +void RenderFrameSet::GridAxis::resize(int size) +{ + m_sizes.resize(size); + m_deltas.resize(size); + m_deltas.fill(0); + + // To track edges for resizability and borders, we need to be (size + 1). This is because a parent frameset + // may ask us for information about our left/top/right/bottom edges in order to make its own decisions about + // what to do. We are capable of tainting that parent frameset's borders, so we have to cache this info. + m_preventResize.resize(size + 1); + m_allowBorder.resize(size + 1); +} + +void RenderFrameSet::layOutAxis(GridAxis& axis, const Length* grid, int availableLen) +{ + availableLen = max(availableLen, 0); + + int* gridLayout = axis.m_sizes.data(); + + if (!grid) { + gridLayout[0] = availableLen; + return; + } + + int gridLen = axis.m_sizes.size(); + ASSERT(gridLen); + + int totalRelative = 0; + int totalFixed = 0; + int totalPercent = 0; + int countRelative = 0; + int countFixed = 0; + int countPercent = 0; + + // First we need to investigate how many columns of each type we have and + // how much space these columns are going to require. + for (int i = 0; i < gridLen; ++i) { + // Count the total length of all of the fixed columns/rows -> totalFixed + // Count the number of columns/rows which are fixed -> countFixed + if (grid[i].isFixed()) { + gridLayout[i] = max(grid[i].value(), 0); + totalFixed += gridLayout[i]; + countFixed++; + } + + // Count the total percentage of all of the percentage columns/rows -> totalPercent + // Count the number of columns/rows which are percentages -> countPercent + if (grid[i].isPercent()) { + gridLayout[i] = max(grid[i].calcValue(availableLen), 0); + totalPercent += gridLayout[i]; + countPercent++; + } + + // Count the total relative of all the relative columns/rows -> totalRelative + // Count the number of columns/rows which are relative -> countRelative + if (grid[i].isRelative()) { + totalRelative += max(grid[i].value(), 1); + countRelative++; + } + } + + int remainingLen = availableLen; + + // Fixed columns/rows are our first priority. If there is not enough space to fit all fixed + // columns/rows we need to proportionally adjust their size. + if (totalFixed > remainingLen) { + int remainingFixed = remainingLen; + + for (int i = 0; i < gridLen; ++i) { + if (grid[i].isFixed()) { + gridLayout[i] = (gridLayout[i] * remainingFixed) / totalFixed; + remainingLen -= gridLayout[i]; + } + } + } else + remainingLen -= totalFixed; + + // Percentage columns/rows are our second priority. Divide the remaining space proportionally + // over all percentage columns/rows. IMPORTANT: the size of each column/row is not relative + // to 100%, but to the total percentage. For example, if there are three columns, each of 75%, + // and the available space is 300px, each column will become 100px in width. + if (totalPercent > remainingLen) { + int remainingPercent = remainingLen; + + for (int i = 0; i < gridLen; ++i) { + if (grid[i].isPercent()) { + gridLayout[i] = (gridLayout[i] * remainingPercent) / totalPercent; + remainingLen -= gridLayout[i]; + } + } + } else + remainingLen -= totalPercent; + + // Relative columns/rows are our last priority. Divide the remaining space proportionally + // over all relative columns/rows. IMPORTANT: the relative value of 0* is treated as 1*. + if (countRelative) { + int lastRelative = 0; + int remainingRelative = remainingLen; + + for (int i = 0; i < gridLen; ++i) { + if (grid[i].isRelative()) { + gridLayout[i] = (max(grid[i].value(), 1) * remainingRelative) / totalRelative; + remainingLen -= gridLayout[i]; + lastRelative = i; + } + } + + // If we could not evenly distribute the available space of all of the relative + // columns/rows, the remainder will be added to the last column/row. + // For example: if we have a space of 100px and three columns (*,*,*), the remainder will + // be 1px and will be added to the last column: 33px, 33px, 34px. + if (remainingLen) { + gridLayout[lastRelative] += remainingLen; + remainingLen = 0; + } + } + + // If we still have some left over space we need to divide it over the already existing + // columns/rows + if (remainingLen) { + // Our first priority is to spread if over the percentage columns. The remaining + // space is spread evenly, for example: if we have a space of 100px, the columns + // definition of 25%,25% used to result in two columns of 25px. After this the + // columns will each be 50px in width. + if (countPercent && totalPercent) { + int remainingPercent = remainingLen; + int changePercent = 0; + + for (int i = 0; i < gridLen; ++i) { + if (grid[i].isPercent()) { + changePercent = (remainingPercent * gridLayout[i]) / totalPercent; + gridLayout[i] += changePercent; + remainingLen -= changePercent; + } + } + } else if (totalFixed) { + // Our last priority is to spread the remaining space over the fixed columns. + // For example if we have 100px of space and two column of each 40px, both + // columns will become exactly 50px. + int remainingFixed = remainingLen; + int changeFixed = 0; + + for (int i = 0; i < gridLen; ++i) { + if (grid[i].isFixed()) { + changeFixed = (remainingFixed * gridLayout[i]) / totalFixed; + gridLayout[i] += changeFixed; + remainingLen -= changeFixed; + } + } + } + } + + // If we still have some left over space we probably ended up with a remainder of + // a division. We cannot spread it evenly anymore. If we have any percentage + // columns/rows simply spread the remainder equally over all available percentage columns, + // regardless of their size. + if (remainingLen && countPercent) { + int remainingPercent = remainingLen; + int changePercent = 0; + + for (int i = 0; i < gridLen; ++i) { + if (grid[i].isPercent()) { + changePercent = remainingPercent / countPercent; + gridLayout[i] += changePercent; + remainingLen -= changePercent; + } + } + } + + // If we don't have any percentage columns/rows we only have fixed columns. Spread + // the remainder equally over all fixed columns/rows. + else if (remainingLen && countFixed) { + int remainingFixed = remainingLen; + int changeFixed = 0; + + for (int i = 0; i < gridLen; ++i) { + if (grid[i].isFixed()) { + changeFixed = remainingFixed / countFixed; + gridLayout[i] += changeFixed; + remainingLen -= changeFixed; + } + } + } + + // Still some left over. Add it to the last column, because it is impossible + // spread it evenly or equally. + if (remainingLen) + gridLayout[gridLen - 1] += remainingLen; + + // now we have the final layout, distribute the delta over it + bool worked = true; + int* gridDelta = axis.m_deltas.data(); + for (int i = 0; i < gridLen; ++i) { + if (gridLayout[i] && gridLayout[i] + gridDelta[i] <= 0) + worked = false; + gridLayout[i] += gridDelta[i]; + } + // if the deltas broke something, undo them + if (!worked) { + for (int i = 0; i < gridLen; ++i) + gridLayout[i] -= gridDelta[i]; + axis.m_deltas.fill(0); + } +} + +void RenderFrameSet::fillFromEdgeInfo(const FrameEdgeInfo& edgeInfo, int r, int c) +{ + if (edgeInfo.allowBorder(LeftFrameEdge)) + m_cols.m_allowBorder[c] = true; + if (edgeInfo.allowBorder(RightFrameEdge)) + m_cols.m_allowBorder[c + 1] = true; + if (edgeInfo.preventResize(LeftFrameEdge)) + m_cols.m_preventResize[c] = true; + if (edgeInfo.preventResize(RightFrameEdge)) + m_cols.m_preventResize[c + 1] = true; + + if (edgeInfo.allowBorder(TopFrameEdge)) + m_rows.m_allowBorder[r] = true; + if (edgeInfo.allowBorder(BottomFrameEdge)) + m_rows.m_allowBorder[r + 1] = true; + if (edgeInfo.preventResize(TopFrameEdge)) + m_rows.m_preventResize[r] = true; + if (edgeInfo.preventResize(BottomFrameEdge)) + m_rows.m_preventResize[r + 1] = true; +} + +void RenderFrameSet::computeEdgeInfo() +{ + m_rows.m_preventResize.fill(frameSet()->noResize()); + m_rows.m_allowBorder.fill(false); + m_cols.m_preventResize.fill(frameSet()->noResize()); + m_cols.m_allowBorder.fill(false); + + RenderObject* child = firstChild(); + if (!child) + return; + + int rows = frameSet()->totalRows(); + int cols = frameSet()->totalCols(); + for (int r = 0; r < rows; ++r) { + for (int c = 0; c < cols; ++c) { + FrameEdgeInfo edgeInfo; + if (child->isFrameSet()) + edgeInfo = toRenderFrameSet(child)->edgeInfo(); + else + edgeInfo = toRenderFrame(child)->edgeInfo(); + fillFromEdgeInfo(edgeInfo, r, c); + child = child->nextSibling(); + if (!child) + return; + } + } +} + +FrameEdgeInfo RenderFrameSet::edgeInfo() const +{ + FrameEdgeInfo result(frameSet()->noResize(), true); + + int rows = frameSet()->totalRows(); + int cols = frameSet()->totalCols(); + if (rows && cols) { + result.setPreventResize(LeftFrameEdge, m_cols.m_preventResize[0]); + result.setAllowBorder(LeftFrameEdge, m_cols.m_allowBorder[0]); + result.setPreventResize(RightFrameEdge, m_cols.m_preventResize[cols]); + result.setAllowBorder(RightFrameEdge, m_cols.m_allowBorder[cols]); + result.setPreventResize(TopFrameEdge, m_rows.m_preventResize[0]); + result.setAllowBorder(TopFrameEdge, m_rows.m_allowBorder[0]); + result.setPreventResize(BottomFrameEdge, m_rows.m_preventResize[rows]); + result.setAllowBorder(BottomFrameEdge, m_rows.m_allowBorder[rows]); + } + + return result; +} + +void RenderFrameSet::layout() +{ + ASSERT(needsLayout()); + + bool doFullRepaint = selfNeedsLayout() && checkForRepaintDuringLayout(); + IntRect oldBounds; + if (doFullRepaint) + oldBounds = absoluteClippedOverflowRect(); + + if (!parent()->isFrameSet() && !document()->printing()) { +#ifdef ANDROID_FLATTEN_FRAMESET + // Force a grid recalc. + m_gridCalculated = false; +#endif + setWidth(view()->viewWidth()); + setHeight(view()->viewHeight()); + } + + size_t cols = frameSet()->totalCols(); + size_t rows = frameSet()->totalRows(); + + if (m_rows.m_sizes.size() != rows || m_cols.m_sizes.size() != cols) { + m_rows.resize(rows); + m_cols.resize(cols); +#ifdef ANDROID_FLATTEN_FRAMESET + m_gridCalculated = false; +#endif + } + +#ifdef ANDROID_FLATTEN_FRAMESET + if (!m_gridCalculated) { + m_gridCalculated = true; + // Make all the child framesets recalculate their grid. + RenderObject* child = firstChild(); + for (; child; child = child->nextSibling()) { + if (child->isFrameSet()) + static_cast(child)->setGridNeedsLayout(); + } +#endif + int borderThickness = frameSet()->border(); + layOutAxis(m_rows, frameSet()->rowLengths(), height() - (rows - 1) * borderThickness); + layOutAxis(m_cols, frameSet()->colLengths(), width() - (cols - 1) * borderThickness); +#ifdef ANDROID_FLATTEN_FRAMESET + } +#endif + + if (flattenFrameSet()) + positionFramesWithFlattening(); + else + positionFrames(); + + RenderBox::layout(); + + computeEdgeInfo(); + + if (doFullRepaint) { + view()->repaintViewRectangle(oldBounds); + IntRect newBounds = absoluteClippedOverflowRect(); + if (newBounds != oldBounds) + view()->repaintViewRectangle(newBounds); + } + + setNeedsLayout(false); +} + +void RenderFrameSet::positionFrames() +{ + RenderBox* child = firstChildBox(); + if (!child) + return; + + int rows = frameSet()->totalRows(); + int cols = frameSet()->totalCols(); + + int yPos = 0; + int borderThickness = frameSet()->border(); +#ifdef ANDROID_FLATTEN_FRAMESET + // Keep track of the maximum width of a row which will become the maximum width of the frameset. + int maxWidth = 0; + const Length* rowLengths = frameSet()->rowLengths(); + const Length* colLengths = frameSet()->colLengths(); + + for (int r = 0; r < rows && child; r++) { + int xPos = 0; + int height = m_rows.m_sizes[r]; + int rowHeight = -1; + if (rowLengths) { + Length l = rowLengths[r]; + if (l.isFixed()) + rowHeight = l.value(); + } + for (int c = 0; c < cols && child; c++) { + child->setX(xPos); + child->setY(yPos); + child->setWidth(m_cols.m_sizes[c]); + child->setHeight(height); + int colWidth = -1; + if (colLengths) { + Length l = colLengths[c]; + if (l.isFixed()) + colWidth = l.value(); + } + if (colWidth && rowHeight) { + child->setNeedsLayout(true); + child->layout(); + } else { + child->layoutIfNeeded(); + } + + ASSERT(child->width() >= m_cols.m_sizes[c]); + m_cols.m_sizes[c] = child->width(); + + height = max(child->height(), height); + xPos += child->width() + borderThickness; + child = (RenderBox*)child->nextSibling(); + } + ASSERT(height >= m_rows.m_sizes[r]); + m_rows.m_sizes[r] = height; + maxWidth = max(xPos, maxWidth); + yPos += height + borderThickness; + } + + // Compute a new width and height according to the positioning of each expanded child frame. + // Note: we subtract borderThickness because we only count borders between frames. + int newWidth = maxWidth - borderThickness; + int newHeight = yPos - borderThickness; + + // Distribute the extra width and height evenly across the grid. + int dWidth = (width() - newWidth) / cols; + int dHeight = (height() - newHeight) / rows; + if (dWidth > 0) { + int availableWidth = width() - (cols - 1) * borderThickness; + for (int c = 0; c < cols; c++) + availableWidth -= m_cols.m_sizes[c] += dWidth; + // If the extra width did not distribute evenly, add the remainder to + // the last column. + if (availableWidth) + m_cols.m_sizes[cols - 1] += availableWidth; + } + if (dHeight > 0) { + int availableHeight = height() - (rows - 1) * borderThickness; + for (int r = 0; r < rows; r++) + availableHeight -= m_rows.m_sizes[r] += dHeight; + // If the extra height did not distribute evenly, add the remainder to + // the last row. + if (availableHeight) + m_rows.m_sizes[rows - 1] += availableHeight; + } + // Ensure the rows and columns are filled by falling through to the normal + // layout + setHeight(max(height(), newHeight)); + setWidth(max(width(), newWidth)); + child = (RenderBox*)firstChild(); + yPos = 0; +#endif // ANDROID_FLATTEN_FRAMESET + + for (int r = 0; r < rows; r++) { + int xPos = 0; + int height = m_rows.m_sizes[r]; + for (int c = 0; c < cols; c++) { + child->setLocation(xPos, yPos); + int width = m_cols.m_sizes[c]; + + // has to be resized and itself resize its contents + if (width != child->width() || height != child->height()) { + child->setWidth(width); + child->setHeight(height); + child->setNeedsLayout(true); + child->layout(); + } + + xPos += width + borderThickness; + + child = child->nextSiblingBox(); + if (!child) + return; + } + yPos += height + borderThickness; + } + + // all the remaining frames are hidden to avoid ugly spurious unflowed frames + for (; child; child = child->nextSiblingBox()) { + child->setWidth(0); + child->setHeight(0); + child->setNeedsLayout(false); + } +} + +void RenderFrameSet::positionFramesWithFlattening() +{ + RenderBox* child = firstChildBox(); + if (!child) + return; + + int rows = frameSet()->totalRows(); + int cols = frameSet()->totalCols(); + + int borderThickness = frameSet()->border(); + bool repaintNeeded = false; + + // calculate frameset height based on actual content height to eliminate scrolling + bool out = false; + for (int r = 0; r < rows && !out; r++) { + int extra = 0; + int height = m_rows.m_sizes[r]; + + for (int c = 0; c < cols; c++) { + IntRect oldFrameRect = child->frameRect(); + + int width = m_cols.m_sizes[c]; + + bool fixedWidth = frameSet()->colLengths() && frameSet()->colLengths()[c].isFixed(); + bool fixedHeight = frameSet()->rowLengths() && frameSet()->rowLengths()[r].isFixed(); + + // has to be resized and itself resize its contents + if (!fixedWidth) + child->setWidth(width ? width + extra / (cols - c) : 0); + else + child->setWidth(width); + child->setHeight(height); + + child->setNeedsLayout(true); + + if (child->isFrameSet()) + toRenderFrameSet(child)->layout(); + else + toRenderFrame(child)->layoutWithFlattening(fixedWidth, fixedHeight); + + if (child->height() > m_rows.m_sizes[r]) + m_rows.m_sizes[r] = child->height(); + if (child->width() > m_cols.m_sizes[c]) + m_cols.m_sizes[c] = child->width(); + + if (child->frameRect() != oldFrameRect) + repaintNeeded = true; + + // difference between calculated frame width and the width it actually decides to have + extra += width - m_cols.m_sizes[c]; + + child = child->nextSiblingBox(); + if (!child) { + out = true; + break; + } + } + } + + int xPos = 0; + int yPos = 0; + out = false; + child = firstChildBox(); + for (int r = 0; r < rows && !out; r++) { + xPos = 0; + for (int c = 0; c < cols; c++) { + // ensure the rows and columns are filled + IntRect oldRect = child->frameRect(); + + child->setLocation(xPos, yPos); + child->setHeight(m_rows.m_sizes[r]); + child->setWidth(m_cols.m_sizes[c]); + + if (child->frameRect() != oldRect) { + repaintNeeded = true; + + // update to final size + child->setNeedsLayout(true); + if (child->isFrameSet()) + toRenderFrameSet(child)->layout(); + else + toRenderFrame(child)->layoutWithFlattening(true, true); + } + + xPos += m_cols.m_sizes[c] + borderThickness; + child = child->nextSiblingBox(); + if (!child) { + out = true; + break; + } + } + yPos += m_rows.m_sizes[r] + borderThickness; + } + + setWidth(xPos - borderThickness); + setHeight(yPos - borderThickness); + + if (repaintNeeded) + repaint(); + + // all the remaining frames are hidden to avoid ugly spurious unflowed frames + for (; child; child = child->nextSiblingBox()) { + child->setWidth(0); + child->setHeight(0); + child->setNeedsLayout(false); + } +} + +bool RenderFrameSet::flattenFrameSet() const +{ + return frame() && frame()->settings()->frameFlatteningEnabled(); +} + +void RenderFrameSet::startResizing(GridAxis& axis, int position) +{ + int split = hitTestSplit(axis, position); + if (split == noSplit || !axis.m_allowBorder[split] || axis.m_preventResize[split]) { + axis.m_splitBeingResized = noSplit; + return; + } + axis.m_splitBeingResized = split; + axis.m_splitResizeOffset = position - splitPosition(axis, split); +} + +void RenderFrameSet::continueResizing(GridAxis& axis, int position) +{ + if (needsLayout()) + return; + if (axis.m_splitBeingResized == noSplit) + return; + int currentSplitPosition = splitPosition(axis, axis.m_splitBeingResized); + int delta = (position - currentSplitPosition) - axis.m_splitResizeOffset; + if (delta == 0) + return; + axis.m_deltas[axis.m_splitBeingResized - 1] += delta; + axis.m_deltas[axis.m_splitBeingResized] -= delta; + setNeedsLayout(true); +} + +bool RenderFrameSet::userResize(MouseEvent* evt) +{ + if (flattenFrameSet()) + return false; + + if (!m_isResizing) { + if (needsLayout()) + return false; + if (evt->type() == eventNames().mousedownEvent && evt->button() == LeftButton) { + FloatPoint pos = localToAbsolute(); + startResizing(m_cols, evt->absoluteLocation().x() - pos.x()); + startResizing(m_rows, evt->absoluteLocation().y() - pos.y()); + if (m_cols.m_splitBeingResized != noSplit || m_rows.m_splitBeingResized != noSplit) { + setIsResizing(true); + return true; + } + } + } else { + if (evt->type() == eventNames().mousemoveEvent || (evt->type() == eventNames().mouseupEvent && evt->button() == LeftButton)) { + FloatPoint pos = localToAbsolute(); + continueResizing(m_cols, evt->absoluteLocation().x() - pos.x()); + continueResizing(m_rows, evt->absoluteLocation().y() - pos.y()); + if (evt->type() == eventNames().mouseupEvent && evt->button() == LeftButton) { + setIsResizing(false); + return true; + } + } + } + + return false; +} + +void RenderFrameSet::setIsResizing(bool isResizing) +{ + m_isResizing = isResizing; + for (RenderObject* ancestor = parent(); ancestor; ancestor = ancestor->parent()) { + if (ancestor->isFrameSet()) + toRenderFrameSet(ancestor)->m_isChildResizing = isResizing; + } + if (Frame* frame = this->frame()) + frame->eventHandler()->setResizingFrameSet(isResizing ? frameSet() : 0); +} + +bool RenderFrameSet::isResizingRow() const +{ + return m_isResizing && m_rows.m_splitBeingResized != noSplit; +} + +bool RenderFrameSet::isResizingColumn() const +{ + return m_isResizing && m_cols.m_splitBeingResized != noSplit; +} + +bool RenderFrameSet::canResizeRow(const IntPoint& p) const +{ + int r = hitTestSplit(m_rows, p.y()); + return r != noSplit && m_rows.m_allowBorder[r] && !m_rows.m_preventResize[r]; +} + +bool RenderFrameSet::canResizeColumn(const IntPoint& p) const +{ + int c = hitTestSplit(m_cols, p.x()); + return c != noSplit && m_cols.m_allowBorder[c] && !m_cols.m_preventResize[c]; +} + +int RenderFrameSet::splitPosition(const GridAxis& axis, int split) const +{ + if (needsLayout()) + return 0; + + int borderThickness = frameSet()->border(); + + int size = axis.m_sizes.size(); + if (!size) + return 0; + + int position = 0; + for (int i = 0; i < split && i < size; ++i) + position += axis.m_sizes[i] + borderThickness; + return position - borderThickness; +} + +int RenderFrameSet::hitTestSplit(const GridAxis& axis, int position) const +{ + if (needsLayout()) + return noSplit; + + int borderThickness = frameSet()->border(); + if (borderThickness <= 0) + return noSplit; + + size_t size = axis.m_sizes.size(); + if (!size) + return noSplit; + + int splitPosition = axis.m_sizes[0]; + for (size_t i = 1; i < size; ++i) { + if (position >= splitPosition && position < splitPosition + borderThickness) + return i; + splitPosition += borderThickness + axis.m_sizes[i]; + } + return noSplit; +} + +bool RenderFrameSet::isChildAllowed(RenderObject* child, RenderStyle*) const +{ + return child->isFrame() || child->isFrameSet(); +} + +} // namespace WebCore -- cgit v1.1