/** | |
* Copyright (C) 1999 Lars Knoll (knoll@kde.org) | |
* (C) 2000 Simon Hausmann <hausmann@kde.org> | |
* (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) | |
{ | |
setInline(false); | |
} | |
RenderFrameSet::~RenderFrameSet() | |
{ | |
} | |
RenderFrameSet::GridAxis::GridAxis() | |
: m_splitBeingResized(noSplit) | |
{ | |
} | |
inline HTMLFrameSetElement* RenderFrameSet::frameSet() const | |
{ | |
return static_cast<HTMLFrameSetElement*>(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()->borderLeftColor() : 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()->borderLeftColor() : 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()) { | |
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); | |
} | |
int borderThickness = frameSet()->border(); | |
layOutAxis(m_rows, frameSet()->rowLengths(), height() - (rows - 1) * borderThickness); | |
layOutAxis(m_cols, frameSet()->colLengths(), width() - (cols - 1) * borderThickness); | |
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(); | |
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 document()->frame() && document()->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 = document()->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 |