Reviewed by Geoff.
- <rdar://problem/4885227>
frame resizing is now live and no longer does direct drawing
* html/HTMLFrameSetElement.h: Made frameBorder() and noResize() const.
Added rowLengths() and colLengths() getters so that we don't have to
have RenderFrameSet as a friend. Stopped using bit fields.
* html/HTMLFrameSetElement.cpp:
(WebCore::HTMLFrameSetElement::defaultEventHandler): Removed now-uneeded
check for contextmenu events. Look at return value from userResize to
decide whether to mark the event as "default handled". In the case where
the event is handled, don't call through to the base class.
* rendering/RenderFrameSet.h: No longer mark HTMLFrameSetElement as a
friend. Made positionFrames and canResize private, and changed canResize
to take an IntPoint. Added isResizingRow, isResizingColumn, canResizeRow,
and canResizeColumn functions to be used soon for cursor feedback.
Removed override of non-virtual element() function and replaced it with
a private frameSet() inline function. Grouped all the data members for
each axis into a GridAxis class, and made one called m_cols and one called
m_rows. Used vectors for the resizable bits of this instead of new/delete
arrays. Added a constant named "noSplit" so we don't have to use -1
everywhere explicitly for this purpose. Renamed setResizing to
setIsResizing and made it private. Eliminated resizing() function.
Added new private helper functions, layOutAxis, findNonResizableSplits,
splitPosition, hitTestSplit, startResizing, and continueResizing.
Renamed m_resizing to m_isResizing, and m_clientResizing to
m_isChildResizing.
* rendering/RenderFrameSet.cpp:
(WebCore::RenderFrameSet::RenderFrameSet): Removed now-unneeded initialization
that is handled by the GridAxis and Vector constructors.
(WebCore::RenderFrameSet::~RenderFrameSet): Ditto (for destructors).
(WebCore::RenderFrameSet::GridAxis::GridAxis): Added.
(WebCore::RenderFrameSet::frameSet): Added. Inline function so we don't have
to cast the result of node() or element() everywhere.
(WebCore::RenderFrameSet::nodeAtPoint): Updated for name changes.
(WebCore::RenderFrameSet::GridAxis::resize): Added. Helper function to be used
in the layout function.
(WebCore::RenderFrameSet::layOutAxis): Added. Factored out the part of the
layout function that used to be inside a for loop for the two axes.
The algorithm is otherwise unchanged.
(WebCore::RenderFrameSet::findNonResizableSplits): Added. Factored out the
code that set up the "split variable" arrays from the layout function.
(WebCore::RenderFrameSet::layout): Moved the bulk of this function into the
new helpers. This allowed me to remove the use of goto.
(WebCore::RenderFrameSet::positionFrames): Updated for change to data structures.
Also added some more local variables for clarity.
(WebCore::RenderFrameSet::startResizing): Added. Code factored out of the
userResize function that handles mousedown events that might begin a resize.
(WebCore::RenderFrameSet::continueResizing): Added. Code factored out of the
userResize function that handles mouse events that continue a resize already
in progress, including mouseup events that end the resizing. Uses the new
splitPosition function so it can be used over and over again while resizing.
(WebCore::RenderFrameSet::userResize): Restructured to use the new helper
functions. Removed the direct drawing of a gray bar during mouse movement;
instead we do the resizing live.
(WebCore::RenderFrameSet::setIsResizing): Updated for name changes.
(WebCore::RenderFrameSet::isResizingRow): Added.
(WebCore::RenderFrameSet::isResizingColumn): Added.
(WebCore::RenderFrameSet::canResize): Changed to use hitTestSplit for clarity.
(WebCore::RenderFrameSet::canResizeRow): Added.
(WebCore::RenderFrameSet::canResizeColumn): Added.
(WebCore::RenderFrameSet::splitPosition): Added.
(WebCore::RenderFrameSet::hitTestSplit): Added. Contains the guts of the code
that was used both in canResize and userResize before -- now it's shared.
(WebCore::RenderFrameSet::dump): Updated for name changes.
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@18333 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/WebCore/ChangeLog b/WebCore/ChangeLog
index 4c69885..cb3a86b 100644
--- a/WebCore/ChangeLog
+++ b/WebCore/ChangeLog
@@ -1,3 +1,75 @@
+2006-12-19 Darin Adler <darin@apple.com>
+
+ Reviewed by Geoff.
+
+ - <rdar://problem/4885227>
+ frame resizing is now live and no longer does direct drawing
+
+ * html/HTMLFrameSetElement.h: Made frameBorder() and noResize() const.
+ Added rowLengths() and colLengths() getters so that we don't have to
+ have RenderFrameSet as a friend. Stopped using bit fields.
+
+ * html/HTMLFrameSetElement.cpp:
+ (WebCore::HTMLFrameSetElement::defaultEventHandler): Removed now-uneeded
+ check for contextmenu events. Look at return value from userResize to
+ decide whether to mark the event as "default handled". In the case where
+ the event is handled, don't call through to the base class.
+
+ * rendering/RenderFrameSet.h: No longer mark HTMLFrameSetElement as a
+ friend. Made positionFrames and canResize private, and changed canResize
+ to take an IntPoint. Added isResizingRow, isResizingColumn, canResizeRow,
+ and canResizeColumn functions to be used soon for cursor feedback.
+ Removed override of non-virtual element() function and replaced it with
+ a private frameSet() inline function. Grouped all the data members for
+ each axis into a GridAxis class, and made one called m_cols and one called
+ m_rows. Used vectors for the resizable bits of this instead of new/delete
+ arrays. Added a constant named "noSplit" so we don't have to use -1
+ everywhere explicitly for this purpose. Renamed setResizing to
+ setIsResizing and made it private. Eliminated resizing() function.
+ Added new private helper functions, layOutAxis, findNonResizableSplits,
+ splitPosition, hitTestSplit, startResizing, and continueResizing.
+ Renamed m_resizing to m_isResizing, and m_clientResizing to
+ m_isChildResizing.
+
+ * rendering/RenderFrameSet.cpp:
+ (WebCore::RenderFrameSet::RenderFrameSet): Removed now-unneeded initialization
+ that is handled by the GridAxis and Vector constructors.
+ (WebCore::RenderFrameSet::~RenderFrameSet): Ditto (for destructors).
+ (WebCore::RenderFrameSet::GridAxis::GridAxis): Added.
+ (WebCore::RenderFrameSet::frameSet): Added. Inline function so we don't have
+ to cast the result of node() or element() everywhere.
+ (WebCore::RenderFrameSet::nodeAtPoint): Updated for name changes.
+ (WebCore::RenderFrameSet::GridAxis::resize): Added. Helper function to be used
+ in the layout function.
+ (WebCore::RenderFrameSet::layOutAxis): Added. Factored out the part of the
+ layout function that used to be inside a for loop for the two axes.
+ The algorithm is otherwise unchanged.
+ (WebCore::RenderFrameSet::findNonResizableSplits): Added. Factored out the
+ code that set up the "split variable" arrays from the layout function.
+ (WebCore::RenderFrameSet::layout): Moved the bulk of this function into the
+ new helpers. This allowed me to remove the use of goto.
+ (WebCore::RenderFrameSet::positionFrames): Updated for change to data structures.
+ Also added some more local variables for clarity.
+ (WebCore::RenderFrameSet::startResizing): Added. Code factored out of the
+ userResize function that handles mousedown events that might begin a resize.
+ (WebCore::RenderFrameSet::continueResizing): Added. Code factored out of the
+ userResize function that handles mouse events that continue a resize already
+ in progress, including mouseup events that end the resizing. Uses the new
+ splitPosition function so it can be used over and over again while resizing.
+ (WebCore::RenderFrameSet::userResize): Restructured to use the new helper
+ functions. Removed the direct drawing of a gray bar during mouse movement;
+ instead we do the resizing live.
+ (WebCore::RenderFrameSet::setIsResizing): Updated for name changes.
+ (WebCore::RenderFrameSet::isResizingRow): Added.
+ (WebCore::RenderFrameSet::isResizingColumn): Added.
+ (WebCore::RenderFrameSet::canResize): Changed to use hitTestSplit for clarity.
+ (WebCore::RenderFrameSet::canResizeRow): Added.
+ (WebCore::RenderFrameSet::canResizeColumn): Added.
+ (WebCore::RenderFrameSet::splitPosition): Added.
+ (WebCore::RenderFrameSet::hitTestSplit): Added. Contains the guts of the code
+ that was used both in canResize and userResize before -- now it's shared.
+ (WebCore::RenderFrameSet::dump): Updated for name changes.
+
2006-12-19 Justin Garcia <justin.garcia@apple.com>
Reviewed by harrison
diff --git a/WebCore/html/HTMLFrameSetElement.cpp b/WebCore/html/HTMLFrameSetElement.cpp
index 90aa7d3..04bf051 100644
--- a/WebCore/html/HTMLFrameSetElement.cpp
+++ b/WebCore/html/HTMLFrameSetElement.cpp
@@ -138,11 +138,11 @@
void HTMLFrameSetElement::defaultEventHandler(Event* evt)
{
- if (evt->isMouseEvent() && evt->type() != contextmenuEvent && !noresize && renderer()) {
- static_cast<RenderFrameSet*>(renderer())->userResize(static_cast<MouseEvent*>(evt));
- evt->setDefaultHandled();
- }
-
+ if (evt->isMouseEvent() && !noresize && renderer())
+ if (static_cast<RenderFrameSet*>(renderer())->userResize(static_cast<MouseEvent*>(evt))) {
+ evt->setDefaultHandled();
+ return;
+ }
HTMLElement::defaultEventHandler(evt);
}
diff --git a/WebCore/html/HTMLFrameSetElement.h b/WebCore/html/HTMLFrameSetElement.h
index e77e702..036a5e6 100644
--- a/WebCore/html/HTMLFrameSetElement.h
+++ b/WebCore/html/HTMLFrameSetElement.h
@@ -30,9 +30,7 @@
namespace WebCore {
-class HTMLFrameSetElement : public HTMLElement
-{
- friend class RenderFrameSet;
+class HTMLFrameSetElement : public HTMLElement {
public:
HTMLFrameSetElement(Document*);
~HTMLFrameSetElement();
@@ -48,8 +46,8 @@
virtual void defaultEventHandler(Event*);
- bool frameBorder() { return frameborder; }
- bool noResize() { return noresize; }
+ bool frameBorder() const { return frameborder; }
+ bool noResize() const { return noresize; }
int totalRows() const { return m_totalRows; }
int totalCols() const { return m_totalCols; }
@@ -63,7 +61,10 @@
String rows() const;
void setRows(const String&);
-protected:
+ const Length* rowLengths() const { return m_rows; }
+ const Length* colLengths() const { return m_cols; }
+
+private:
Length* m_rows;
Length* m_cols;
@@ -71,9 +72,9 @@
int m_totalCols;
int m_border;
- bool frameborder : 1;
- bool frameBorderSet : 1;
- bool noresize : 1;
+ bool frameborder;
+ bool frameBorderSet;
+ bool noresize;
};
} //namespace
diff --git a/WebCore/rendering/RenderFrameSet.cpp b/WebCore/rendering/RenderFrameSet.cpp
index 953ffd9..4d5d614 100644
--- a/WebCore/rendering/RenderFrameSet.cpp
+++ b/WebCore/rendering/RenderFrameSet.cpp
@@ -26,15 +26,12 @@
#include "config.h"
#include "RenderFrameSet.h"
-#include "Cursor.h"
#include "Document.h"
#include "EventHandler.h"
#include "EventNames.h"
#include "Frame.h"
#include "FrameView.h"
-#include "GraphicsContext.h"
#include "HTMLFrameSetElement.h"
-#include "HTMLNames.h"
#include "HitTestRequest.h"
#include "HitTestResult.h"
#include "MouseEvent.h"
@@ -45,55 +42,280 @@
namespace WebCore {
using namespace EventNames;
-using namespace HTMLNames;
RenderFrameSet::RenderFrameSet(HTMLFrameSetElement* frameSet)
: RenderContainer(frameSet)
- , m_hSplitVar(0)
- , m_vSplitVar(0)
- , m_hSplit(-1)
- , m_vSplit(-1)
- , m_resizing(false)
- , m_clientResizing(false)
+ , m_isResizing(false)
+ , m_isChildResizing(false)
{
- // init RenderObject attributes
setInline(false);
-
- for (int k = 0; k < 2; ++k) {
- m_gridLen[k] = -1;
- m_gridDelta[k] = 0;
- m_gridLayout[k] = 0;
- }
}
RenderFrameSet::~RenderFrameSet()
{
- for (int k = 0; k < 2; ++k) {
- if (m_gridLayout[k])
- delete [] m_gridLayout[k];
- if (m_gridDelta[k])
- delete [] m_gridDelta[k];
- }
- if (m_hSplitVar)
- delete [] m_hSplitVar;
- if (m_vSplitVar)
- delete [] m_vSplitVar;
+}
+
+RenderFrameSet::GridAxis::GridAxis()
+ : m_splitBeingResized(noSplit)
+{
+}
+
+inline HTMLFrameSetElement* RenderFrameSet::frameSet() const
+{
+ return static_cast<HTMLFrameSetElement*>(node());
}
bool RenderFrameSet::nodeAtPoint(const HitTestRequest& request, HitTestResult& result,
- int _x, int _y, int _tx, int _ty, HitTestAction hitTestAction)
+ int x, int y, int tx, int ty, HitTestAction action)
{
- if (hitTestAction != HitTestForeground)
+ if (action != HitTestForeground)
return false;
- bool inside = RenderContainer::nodeAtPoint(request, result, _x, _y, _tx, _ty, hitTestAction) ||
- m_resizing || canResize(_x, _y);
- if (inside && element() && !element()->noResize() && !request.readonly && !result.innerNode()) {
- result.setInnerNode(element());
- result.setInnerNonSharedNode(element());
+ bool inside = RenderContainer::nodeAtPoint(request, result, x, y, tx, ty, action)
+ || m_isResizing || canResize(IntPoint(x, y));
+
+ if (inside && frameSet()->noResize()
+ && !request.readonly && !result.innerNode()) {
+ result.setInnerNode(node());
+ result.setInnerNonSharedNode(node());
}
- return inside || m_clientResizing;
+ return inside || m_isChildResizing;
+}
+
+void RenderFrameSet::GridAxis::resize(int size)
+{
+ m_sizes.resize(size);
+ m_deltas.resize(size);
+ m_deltas.fill(0);
+ m_isSplitResizable.resize(size);
+}
+
+void RenderFrameSet::layOutAxis(GridAxis& axis, const Length* grid, int availableLen)
+{
+ int* gridLayout = axis.m_sizes;
+
+ 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 can not 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;
+ 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::findNonResizableSplits()
+{
+ m_rows.m_isSplitResizable.fill(true);
+ m_cols.m_isSplitResizable.fill(true);
+
+ 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) {
+ bool fixed;
+ if (child->isFrameSet())
+ fixed = static_cast<RenderFrameSet*>(child)->frameSet()->noResize();
+ else
+ fixed = static_cast<RenderFrame*>(child)->element()->noResize();
+ if (fixed) {
+ if (cols > 1) {
+ if (c > 0)
+ m_cols.m_isSplitResizable[c - 1] = false;
+ m_cols.m_isSplitResizable[c] = false;
+ }
+ if (rows > 1) {
+ if (r > 0)
+ m_rows.m_isSplitResizable[r - 1] = false;
+ m_rows.m_isSplitResizable[r] = false;
+ }
+ }
+ child = child->nextSibling();
+ if (!child)
+ return;
+ }
+ }
}
void RenderFrameSet::layout()
@@ -107,313 +329,91 @@
m_height = v->visibleHeight();
}
- int remainingLen[2];
- remainingLen[1] = m_width - (element()->totalCols()-1)*element()->border();
- if (remainingLen[1] < 0)
- remainingLen[1] = 0;
- remainingLen[0] = m_height - (element()->totalRows()-1)*element()->border();
- if (remainingLen[0] < 0)
- remainingLen[0] = 0;
+ size_t cols = frameSet()->totalCols();
+ size_t rows = frameSet()->totalRows();
- int availableLen[2];
- availableLen[0] = remainingLen[0];
- availableLen[1] = remainingLen[1];
-
- if (m_gridLen[0] != element()->totalRows() || m_gridLen[1] != element()->totalCols()) {
- // number of rows or cols changed
- // need to zero out the deltas
- m_gridLen[0] = element()->totalRows();
- m_gridLen[1] = element()->totalCols();
- for (int k = 0; k < 2; ++k) {
- if (m_gridDelta[k]) delete [] m_gridDelta[k];
- m_gridDelta[k] = new int[m_gridLen[k]];
- if (m_gridLayout[k]) delete [] m_gridLayout[k];
- m_gridLayout[k] = new int[m_gridLen[k]];
- for (int i = 0; i < m_gridLen[k]; ++i)
- m_gridDelta[k][i] = 0;
- }
+ if (m_rows.m_sizes.size() != rows || m_cols.m_sizes.size() != cols) {
+ m_rows.resize(rows);
+ m_cols.resize(cols);
+ findNonResizableSplits();
}
- for (int k = 0; k < 2; ++k) {
- int totalRelative = 0;
- int totalFixed = 0;
- int totalPercent = 0;
- int countRelative = 0;
- int countFixed = 0;
- int countPercent = 0;
- int gridLen = m_gridLen[k];
- int* gridDelta = m_gridDelta[k];
- Length* grid = k ? element()->m_cols : element()->m_rows;
- int* gridLayout = m_gridLayout[k];
-
- if (grid) {
- assert(gridLen);
- // 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[k]), 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++;
- }
- }
-
- // 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[k]) {
- int remainingFixed = remainingLen[k];
-
- for (int i = 0; i < gridLen; ++i) {
- if (grid[i].isFixed()) {
- gridLayout[i] = (gridLayout[i] * remainingFixed) / totalFixed;
- remainingLen[k] -= gridLayout[i];
- }
- }
- } else
- remainingLen[k] -= 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[k]) {
- int remainingPercent = remainingLen[k];
-
- for (int i = 0; i < gridLen; ++i) {
- if (grid[i].isPercent()) {
- gridLayout[i] = (gridLayout[i] * remainingPercent) / totalPercent;
- remainingLen[k] -= gridLayout[i];
- }
- }
- } else
- remainingLen[k] -= 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[k];
-
- for (int i = 0; i < gridLen; ++i) {
- if (grid[i].isRelative()) {
- gridLayout[i] = (max(grid[i].value(), 1) * remainingRelative) / totalRelative;
- remainingLen[k] -= gridLayout[i];
- lastRelative = i;
- }
- }
-
- // If we could not evently 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[k]) {
- gridLayout[lastRelative] += remainingLen[k];
- remainingLen[k] = 0;
- }
- }
-
- // If we still have some left over space we need to divide it over the already existing
- // columns/rows
- if (remainingLen[k]) {
- // 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[k];
- int changePercent = 0;
-
- for (int i = 0; i < gridLen; ++i) {
- if (grid[i].isPercent()) {
- changePercent = (remainingPercent * gridLayout[i]) / totalPercent;
- gridLayout[i] += changePercent;
- remainingLen[k] -= 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[k];
- int changeFixed = 0;
-
- for (int i = 0; i < gridLen; ++i) {
- if (grid[i].isFixed()) {
- changeFixed = (remainingFixed * gridLayout[i]) / totalFixed;
- gridLayout[i] += changeFixed;
- remainingLen[k] -= changeFixed;
- }
- }
- }
- }
-
- // If we still have some left over space we probably ended up with a remainder of
- // a division. We can not 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[k] && countPercent) {
- int remainingPercent = remainingLen[k];
- int changePercent = 0;
-
- for (int i = 0; i < gridLen; ++i) {
- if (grid[i].isPercent()) {
- changePercent = remainingPercent / countPercent;
- gridLayout[i] += changePercent;
- remainingLen[k] -= 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[k] && countFixed) {
- int remainingFixed = remainingLen[k];
- int changeFixed = 0;
-
- for (int i = 0; i < gridLen; ++i) {
- if (grid[i].isFixed()) {
- changeFixed = remainingFixed / countFixed;
- gridLayout[i] += changeFixed;
- remainingLen[k] -= changeFixed;
- }
- }
- }
-
- // Still some left over... simply add it to the last column, because it is impossible
- // spread it evenly or equally.
- if (remainingLen[k])
- gridLayout[gridLen - 1] += remainingLen[k];
-
- // now we have the final layout, distribute the delta over it
- bool worked = true;
- for (int i = 0; i < gridLen; ++i) {
- if (gridLayout[i] && gridLayout[i] + gridDelta[i] <= 0)
- worked = false;
- gridLayout[i] += gridDelta[i];
- }
- // now the delta's broke something, undo it and reset deltas
- if (!worked) {
- for (int i = 0; i < gridLen; ++i) {
- gridLayout[i] -= gridDelta[i];
- gridDelta[i] = 0;
- }
- }
- }
- else
- gridLayout[0] = remainingLen[k];
- }
+ int borderThickness = frameSet()->border();
+ layOutAxis(m_rows, frameSet()->rowLengths(), m_height - (rows - 1) * borderThickness);
+ layOutAxis(m_cols, frameSet()->colLengths(), m_width - (cols - 1) * borderThickness);
positionFrames();
- RenderObject *child = firstChild();
- if (!child)
- goto end2;
-
- if (!m_hSplitVar && !m_vSplitVar) {
- if (!m_vSplitVar && element()->totalCols() > 1) {
- m_vSplitVar = new bool[element()->totalCols()];
- for (int i = 0; i < element()->totalCols(); i++) m_vSplitVar[i] = true;
- }
- if (!m_hSplitVar && element()->totalRows() > 1) {
- m_hSplitVar = new bool[element()->totalRows()];
- for (int i = 0; i < element()->totalRows(); i++) m_hSplitVar[i] = true;
- }
-
- for (int r = 0; r < element()->totalRows(); r++) {
- for (int c = 0; c < element()->totalCols(); c++) {
- bool fixed = false;
-
- if (child->isFrameSet())
- fixed = static_cast<RenderFrameSet*>(child)->element()->noResize();
- else
- fixed = static_cast<RenderFrame*>(child)->element()->noResize();
-
- if (fixed) {
- if (element()->totalCols() > 1) {
- if (c>0) m_vSplitVar[c-1] = false;
- m_vSplitVar[c] = false;
- }
- if (element()->totalRows() > 1) {
- if (r>0) m_hSplitVar[r-1] = false;
- m_hSplitVar[r] = false;
- }
- child = child->nextSibling();
- if (!child)
- goto end1;
- }
- }
- }
-
- }
- end1:
RenderContainer::layout();
- end2:
+
setNeedsLayout(false);
}
void RenderFrameSet::positionFrames()
{
- int r;
- int c;
-
- RenderObject *child = firstChild();
- if (!child)
- return;
-
- // Node *child = _first;
- // if (!child) return;
-
- int yPos = 0;
-
- for (r = 0; r < element()->totalRows(); r++) {
- int xPos = 0;
- for (c = 0; c < element()->totalCols(); c++) {
- child->setPos(xPos, yPos);
- // has to be resized and itself resize its contents
- if ((m_gridLayout[1][c] != child->width()) || (m_gridLayout[0][r] != child->height())) {
- child->setWidth(m_gridLayout[1][c]);
- child->setHeight(m_gridLayout[0][r]);
- child->setNeedsLayout(true);
- child->layout();
- }
-
- xPos += m_gridLayout[1][c] + element()->border();
- child = child->nextSibling();
-
- if (!child)
+ RenderObject* child = firstChild();
+ 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->setPos(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->nextSibling();
+ if (!child)
+ return;
+ }
+ yPos += height + borderThickness;
}
- yPos += m_gridLayout[0][r] + element()->border();
- }
+ // all the remaining frames are hidden to avoid ugly spurious unflowed frames
+ for (; child; child = child->nextSibling()) {
+ child->setWidth(0);
+ child->setHeight(0);
+ child->setNeedsLayout(false);
+ }
+}
- // all the remaining frames are hidden to avoid ugly
- // spurious unflowed frames
- while (child) {
- child->setWidth(0);
- child->setHeight(0);
- child->setNeedsLayout(false);
+void RenderFrameSet::startResizing(GridAxis& axis, int position)
+{
+ int split = hitTestSplit(axis, position);
+ if (split == noSplit || !axis.m_isSplitResizable[split]) {
+ axis.m_splitBeingResized = noSplit;
+ return;
+ }
+ axis.m_splitBeingResized = split;
+ axis.m_splitResizeOffset = position - splitPosition(axis, split);
+}
- child = child->nextSibling();
- }
+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;
+ axis.m_deltas[axis.m_splitBeingResized] += delta;
+ axis.m_deltas[axis.m_splitBeingResized + 1] -= delta;
+ setNeedsLayout(true);
}
bool RenderFrameSet::userResize(MouseEvent* evt)
@@ -421,144 +421,118 @@
if (needsLayout())
return false;
- bool res = false;
- int _x = evt->pageX();
- int _y = evt->pageY();
-
- if (!m_resizing && evt->type() == mousemoveEvent || evt->type() == mousedownEvent) {
- m_hSplit = -1;
- m_vSplit = -1;
- //bool resizePossible = true;
-
- // check if we're over a horizontal or vertical boundary
- int pos = m_gridLayout[1][0] + xPos();
- for (int c = 1; c < element()->totalCols(); c++) {
- if (_x >= pos && _x <= pos+element()->border()) {
- if (m_vSplitVar && m_vSplitVar[c - 1])
- m_vSplit = c - 1;
- res = true;
- break;
- }
- pos += m_gridLayout[1][c] + element()->border();
- }
-
- pos = m_gridLayout[0][0] + yPos();
- for (int r = 1; r < element()->totalRows(); r++) {
- if (_y >= pos && _y <= pos+element()->border()) {
- if (m_hSplitVar && m_hSplitVar[r - 1])
- m_hSplit = r - 1;
- res = true;
- break;
- }
- pos += m_gridLayout[0][r] + element()->border();
- }
-
+ if (!m_isResizing) {
if (evt->type() == mousedownEvent) {
- setResizing(true);
- m_vSplitPos = _x;
- m_hSplitPos = _y;
- m_oldpos = -1;
- }
- }
-
- // ### check the resize is not going out of bounds.
- if (m_resizing && evt->type() == mouseupEvent) {
- setResizing(false);
-
- if (m_vSplit != -1) {
- int delta = m_vSplitPos - _x;
- m_gridDelta[1][m_vSplit] -= delta;
- m_gridDelta[1][m_vSplit+1] += delta;
- }
- if (m_hSplit != -1) {
- int delta = m_hSplitPos - _y;
- m_gridDelta[0][m_hSplit] -= delta;
- m_gridDelta[0][m_hSplit+1] += delta;
- }
-
- // this just schedules the relayout
- // important, otherwise the moving indicator is not correctly erased
- setNeedsLayout(true);
- } else if (m_resizing || evt->type() == mouseupEvent) {
- FrameView* v = view()->frameView();
- v->disableFlushDrawing();
- GraphicsContext* context = v->lockDrawingFocus();
-
- IntRect r(xPos(), yPos(), width(), height());
- const int rBord = 3;
- int sw = element()->border();
- int p = m_resizing ? (m_vSplit > -1 ? _x : _y) : -1;
- const RGBA32 greyQuarterOpacity = 0x40A0A0A0;
- if (m_vSplit > -1) {
- if (m_oldpos >= 0)
- v->updateContents(IntRect(m_oldpos + sw/2 - rBord, r.y(), 2 * rBord, r.height()), true);
- if (p >= 0) {
- context->setStrokeStyle(NoStroke);
- context->setFillColor(greyQuarterOpacity);
- context->drawRect(IntRect(p + sw/2 - rBord, r.y(), 2 * rBord, r.height()));
- }
- } else {
- if (m_oldpos >= 0)
- v->updateContents(IntRect(r.x(), m_oldpos + sw/2 - rBord, r.width(), 2 * rBord), true);
- if (p >= 0) {
- context->setStrokeStyle(NoStroke);
- context->setFillColor(greyQuarterOpacity);
- context->drawRect(IntRect(r.x(), p + sw/2 - rBord, r.width(), 2 * rBord));
+ startResizing(m_cols, evt->pageX() - xPos());
+ startResizing(m_rows, evt->pageY() - yPos());
+ if (m_cols.m_splitBeingResized != noSplit || m_rows.m_splitBeingResized != noSplit) {
+ setIsResizing(true);
+ return true;
}
}
- m_oldpos = p;
-
- v->unlockDrawingFocus(context);
- v->enableFlushDrawing();
+ } else {
+ if (evt->type() == mousemoveEvent || evt->type() == mouseupEvent) {
+ continueResizing(m_cols, evt->pageX() - xPos());
+ continueResizing(m_rows, evt->pageY() - yPos());
+ if (evt->type() == mouseupEvent) {
+ setIsResizing(false);
+ return true;
+ }
+ }
}
-
- return res;
-}
-
-void RenderFrameSet::setResizing(bool e)
-{
- m_resizing = e;
- for (RenderObject* p = parent(); p; p = p->parent())
- if (p->isFrameSet())
- static_cast<RenderFrameSet*>(p)->m_clientResizing = m_resizing;
- if (Frame* frame = document()->frame())
- frame->eventHandler()->setResizingFrameSet(e ? element() : 0);
-}
-
-bool RenderFrameSet::canResize(int _x, int _y)
-{
- // if we haven't received a layout, then the gridLayout doesn't contain useful data yet
- if (needsLayout() || !m_gridLayout[0] || !m_gridLayout[1])
- return false;
-
- // check if we're over a horizontal or vertical boundary
- int pos = m_gridLayout[1][0];
- for (int c = 1; c < element()->totalCols(); c++)
- if (_x >= pos && _x <= pos+element()->border())
- return true;
-
- pos = m_gridLayout[0][0];
- for (int r = 1; r < element()->totalRows(); r++)
- if (_y >= pos && _y <= pos+element()->border())
- return true;
return false;
}
+void RenderFrameSet::setIsResizing(bool isResizing)
+{
+ m_isResizing = isResizing;
+ for (RenderObject* p = parent(); p; p = p->parent())
+ if (p->isFrameSet())
+ static_cast<RenderFrameSet*>(p)->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::canResize(const IntPoint& p) const
+{
+ return hitTestSplit(m_cols, p.x()) != noSplit || hitTestSplit(m_rows, p.y()) != noSplit;
+}
+
+bool RenderFrameSet::canResizeRow(const IntPoint& p) const
+{
+ int r = hitTestSplit(m_rows, p.y() - yPos());
+ return r != noSplit && m_rows.m_isSplitResizable[r];
+}
+
+bool RenderFrameSet::canResizeColumn(const IntPoint& p) const
+{
+ int c = hitTestSplit(m_cols, p.x() - xPos());
+ return c != noSplit && m_cols.m_isSplitResizable[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 - 1;
+ splitPosition += borderThickness + axis.m_sizes[i];
+ }
+ return noSplit;
+}
+
#ifndef NDEBUG
void RenderFrameSet::dump(TextStream* stream, DeprecatedString ind) const
{
- *stream << " totalrows=" << element()->totalRows();
- *stream << " totalcols=" << element()->totalCols();
+ *stream << " totalrows=" << frameSet()->totalRows();
+ *stream << " totalcols=" << frameSet()->totalCols();
- unsigned i;
- for (i = 0; i < (unsigned)element()->totalRows(); i++)
- *stream << " hSplitvar(" << i << ")=" << m_hSplitVar[i];
+ for (int i = 0; i < frameSet()->totalRows(); i++)
+ *stream << " hSplitvar(" << i << ")=" << m_rows.m_isSplitResizable[i];
- for (i = 0; i < (unsigned)element()->totalCols(); i++)
- *stream << " vSplitvar(" << i << ")=" << m_vSplitVar[i];
+ for (int i = 0; i < frameSet()->totalCols(); i++)
+ *stream << " vSplitvar(" << i << ")=" << m_cols.m_isSplitResizable[i];
- RenderContainer::dump(stream,ind);
+ RenderContainer::dump(stream,ind);
}
#endif
diff --git a/WebCore/rendering/RenderFrameSet.h b/WebCore/rendering/RenderFrameSet.h
index c44abf1..f24d537 100644
--- a/WebCore/rendering/RenderFrameSet.h
+++ b/WebCore/rendering/RenderFrameSet.h
@@ -25,7 +25,6 @@
#ifndef RenderFrameSet_h
#define RenderFrameSet_h
-#include "HTMLFrameSetElement.h"
#include "RenderContainer.h"
namespace WebCore {
@@ -34,7 +33,6 @@
class MouseEvent;
class RenderFrameSet : public RenderContainer {
- friend class HTMLFrameSetElement;
public:
RenderFrameSet(HTMLFrameSetElement*);
virtual ~RenderFrameSet();
@@ -43,39 +41,54 @@
virtual bool isFrameSet() const { return true; }
virtual void layout();
-
- void positionFrames();
-
- bool resizing() const { return m_resizing; }
-
- bool userResize(MouseEvent*);
- bool canResize(int x, int y);
- void setResizing(bool);
-
virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty, HitTestAction);
- HTMLFrameSetElement* element() const { return static_cast<HTMLFrameSetElement*>(RenderContainer::element()); }
+ bool userResize(MouseEvent*);
+
+ bool isResizingRow() const;
+ bool isResizingColumn() const;
+
+ bool canResizeRow(const IntPoint&) const;
+ bool canResizeColumn(const IntPoint&) const;
#ifndef NDEBUG
- virtual void dump(TextStream* stream, DeprecatedString ind = "") const;
+ virtual void dump(TextStream*, DeprecatedString ind = "") const;
#endif
private:
- int m_oldpos;
- int m_gridLen[2];
- int* m_gridDelta[2];
- int* m_gridLayout[2];
+ static const int noSplit = -1;
- bool* m_hSplitVar; // is this split variable?
- bool* m_vSplitVar;
+ class GridAxis : Noncopyable {
+ public:
+ GridAxis();
+ void resize(int);
+ Vector<int> m_sizes;
+ Vector<int> m_deltas;
+ Vector<bool> m_isSplitResizable;
+ int m_splitBeingResized;
+ int m_splitResizeOffset;
+ };
- int m_hSplit; // the split currently resized
- int m_vSplit;
- int m_hSplitPos;
- int m_vSplitPos;
+ inline HTMLFrameSetElement* frameSet() const;
- bool m_resizing;
- bool m_clientResizing;
+ bool canResize(const IntPoint&) const;
+ void setIsResizing(bool);
+
+ void layOutAxis(GridAxis&, const Length*, int availableSpace);
+ void findNonResizableSplits();
+ void positionFrames();
+
+ int splitPosition(const GridAxis&, int split) const;
+ int hitTestSplit(const GridAxis&, int position) const;
+
+ void startResizing(GridAxis&, int position);
+ void continueResizing(GridAxis&, int position);
+
+ GridAxis m_rows;
+ GridAxis m_cols;
+
+ bool m_isResizing;
+ bool m_isChildResizing;
};
} // namespace WebCore