Bug 416168. Ensure that the overflow rect for a frame always includes (0,0) even if the frame rect is empty. Also ensures that if the frame rect is empty but has non-zero dimension on one axis, the overflow rect includes that size. A scrolled view for such a frame also includes that size to ensure width:0,height:Npx and width:Npx,height:0 frames are scrollable by that amount. r+sr=dbaron
This commit is contained in:
Родитель
82be2b809e
Коммит
5ebd68ca4d
|
@ -100,12 +100,21 @@ struct NS_GFX nsRect {
|
||||||
PRBool IntersectRect(const nsRect& aRect1, const nsRect& aRect2);
|
PRBool IntersectRect(const nsRect& aRect1, const nsRect& aRect2);
|
||||||
|
|
||||||
// Computes the smallest rectangle that contains both aRect1 and aRect2 and
|
// Computes the smallest rectangle that contains both aRect1 and aRect2 and
|
||||||
// fills 'this' with the result. Returns FALSE and sets 'this' rect to be an
|
// fills 'this' with the result, ignoring empty input rectangles.
|
||||||
// empty rect if both aRect1 and aRect2 are empty
|
// Returns FALSE and sets 'this' rect to be an empty rect if both aRect1
|
||||||
|
// and aRect2 are empty.
|
||||||
//
|
//
|
||||||
// 'this' can be the same object as either aRect1 or aRect2
|
// 'this' can be the same object as either aRect1 or aRect2
|
||||||
PRBool UnionRect(const nsRect& aRect1, const nsRect& aRect2);
|
PRBool UnionRect(const nsRect& aRect1, const nsRect& aRect2);
|
||||||
|
|
||||||
|
// Computes the smallest rectangle that contains both aRect1 and aRect2,
|
||||||
|
// where empty input rectangles are allowed to affect the result; the
|
||||||
|
// top-left of an empty input rectangle will be inside or on the edge of
|
||||||
|
// the result.
|
||||||
|
//
|
||||||
|
// 'this' can be the same object as either aRect1 or aRect2
|
||||||
|
void UnionRectIncludeEmpty(const nsRect& aRect1, const nsRect& aRect2);
|
||||||
|
|
||||||
// Accessors
|
// Accessors
|
||||||
void SetRect(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight) {
|
void SetRect(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight) {
|
||||||
x = aX; y = aY; width = aWidth; height = aHeight;
|
x = aX; y = aY; width = aWidth; height = aHeight;
|
||||||
|
@ -143,6 +152,13 @@ struct NS_GFX nsRect {
|
||||||
return (PRBool) !operator==(aRect);
|
return (PRBool) !operator==(aRect);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Useful when we care about the exact x/y/width/height values being
|
||||||
|
// equal (i.e. we care about differences in empty rectangles)
|
||||||
|
PRBool IsExactEqual(const nsRect& aRect) const {
|
||||||
|
return x == aRect.x && y == aRect.y &&
|
||||||
|
width == aRect.width && height == aRect.height;
|
||||||
|
}
|
||||||
|
|
||||||
nsRect operator+(const nsPoint& aPoint) const {
|
nsRect operator+(const nsPoint& aPoint) const {
|
||||||
return nsRect(x + aPoint.x, y + aPoint.y, width, height);
|
return nsRect(x + aPoint.x, y + aPoint.y, width, height);
|
||||||
}
|
}
|
||||||
|
|
|
@ -115,23 +115,28 @@ PRBool nsRect::UnionRect(const nsRect &aRect1, const nsRect &aRect2)
|
||||||
// aRect2 is empty so set the result to aRect1
|
// aRect2 is empty so set the result to aRect1
|
||||||
*this = aRect1;
|
*this = aRect1;
|
||||||
} else {
|
} else {
|
||||||
nscoord xmost1 = aRect1.XMost();
|
UnionRectIncludeEmpty(aRect1, aRect2);
|
||||||
nscoord xmost2 = aRect2.XMost();
|
|
||||||
nscoord ymost1 = aRect1.YMost();
|
|
||||||
nscoord ymost2 = aRect2.YMost();
|
|
||||||
|
|
||||||
// Compute the origin
|
|
||||||
x = PR_MIN(aRect1.x, aRect2.x);
|
|
||||||
y = PR_MIN(aRect1.y, aRect2.y);
|
|
||||||
|
|
||||||
// Compute the size
|
|
||||||
width = PR_MAX(xmost1, xmost2) - x;
|
|
||||||
height = PR_MAX(ymost1, ymost2) - y;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void nsRect::UnionRectIncludeEmpty(const nsRect &aRect1, const nsRect &aRect2)
|
||||||
|
{
|
||||||
|
nscoord xmost1 = aRect1.XMost();
|
||||||
|
nscoord xmost2 = aRect2.XMost();
|
||||||
|
nscoord ymost1 = aRect1.YMost();
|
||||||
|
nscoord ymost2 = aRect2.YMost();
|
||||||
|
|
||||||
|
// Compute the origin
|
||||||
|
x = PR_MIN(aRect1.x, aRect2.x);
|
||||||
|
y = PR_MIN(aRect1.y, aRect2.y);
|
||||||
|
|
||||||
|
// Compute the size
|
||||||
|
width = PR_MAX(xmost1, xmost2) - x;
|
||||||
|
height = PR_MAX(ymost1, ymost2) - y;
|
||||||
|
}
|
||||||
|
|
||||||
// Inflate the rect by the specified width and height
|
// Inflate the rect by the specified width and height
|
||||||
void nsRect::Inflate(nscoord aDx, nscoord aDy)
|
void nsRect::Inflate(nscoord aDx, nscoord aDy)
|
||||||
{
|
{
|
||||||
|
|
|
@ -3803,11 +3803,7 @@ UnionRectForClosestScrolledView(nsIFrame* aFrame,
|
||||||
// We can't use nsRect::UnionRect since it drops empty rects on
|
// We can't use nsRect::UnionRect since it drops empty rects on
|
||||||
// the floor, and we need to include them. (Thus we need
|
// the floor, and we need to include them. (Thus we need
|
||||||
// aHaveRect to know when to drop the initial value on the floor.)
|
// aHaveRect to know when to drop the initial value on the floor.)
|
||||||
nscoord x = PR_MIN(aRect.x, frameBounds.x),
|
aRect.UnionRectIncludeEmpty(aRect, frameBounds);
|
||||||
y = PR_MIN(aRect.y, frameBounds.y),
|
|
||||||
xmost = PR_MAX(aRect.XMost(), frameBounds.XMost()),
|
|
||||||
ymost = PR_MAX(aRect.YMost(), frameBounds.YMost());
|
|
||||||
aRect.SetRect(x, y, xmost - x, ymost - y);
|
|
||||||
} else {
|
} else {
|
||||||
aHaveRect = PR_TRUE;
|
aHaveRect = PR_TRUE;
|
||||||
aRect = frameBounds;
|
aRect = frameBounds;
|
||||||
|
|
|
@ -5293,6 +5293,11 @@ nsIFrame::FinishAndStoreOverflow(nsRect* aOverflowArea, nsSize aNewSize)
|
||||||
aOverflowArea->UnionRect(*aOverflowArea, r);
|
aOverflowArea->UnionRect(*aOverflowArea, r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Overflow area must always include the frame's top-left and bottom-right,
|
||||||
|
// even if the frame rect is empty.
|
||||||
|
aOverflowArea->UnionRectIncludeEmpty(*aOverflowArea,
|
||||||
|
nsRect(nsPoint(0, 0), aNewSize));
|
||||||
|
|
||||||
PRBool geometricOverflow =
|
PRBool geometricOverflow =
|
||||||
aOverflowArea->x < 0 || aOverflowArea->y < 0 ||
|
aOverflowArea->x < 0 || aOverflowArea->y < 0 ||
|
||||||
|
@ -5318,7 +5323,6 @@ nsIFrame::FinishAndStoreOverflow(nsRect* aOverflowArea, nsSize aNewSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (outlineRect != nsRect(nsPoint(0, 0), aNewSize)) {
|
if (outlineRect != nsRect(nsPoint(0, 0), aNewSize)) {
|
||||||
// Throw out any overflow if we're -moz-hidden-unscrollable
|
|
||||||
mState |= NS_FRAME_OUTSIDE_CHILDREN;
|
mState |= NS_FRAME_OUTSIDE_CHILDREN;
|
||||||
nsRect* overflowArea = GetOverflowAreaProperty(PR_TRUE);
|
nsRect* overflowArea = GetOverflowAreaProperty(PR_TRUE);
|
||||||
NS_ASSERTION(overflowArea, "should have created rect");
|
NS_ASSERTION(overflowArea, "should have created rect");
|
||||||
|
|
|
@ -673,8 +673,9 @@ nsHTMLScrollFrame::PlaceScrollArea(const ScrollReflowState& aState)
|
||||||
scrolledFrame->SetPosition(scrolledView->GetOffsetTo(GetView()));
|
scrolledFrame->SetPosition(scrolledView->GetOffsetTo(GetView()));
|
||||||
|
|
||||||
nsRect scrolledArea;
|
nsRect scrolledArea;
|
||||||
scrolledArea.UnionRect(mInner.GetScrolledRect(aState.mScrollPortRect.Size()),
|
// Preserve the width or height of empty rects
|
||||||
nsRect(nsPoint(0,0), aState.mScrollPortRect.Size()));
|
scrolledArea.UnionRectIncludeEmpty(mInner.GetScrolledRect(aState.mScrollPortRect.Size()),
|
||||||
|
nsRect(nsPoint(0,0), aState.mScrollPortRect.Size()));
|
||||||
|
|
||||||
// Store the new overflow area. Note that this changes where an outline
|
// Store the new overflow area. Note that this changes where an outline
|
||||||
// of the scrolled frame would be painted, but scrolled frames can't have
|
// of the scrolled frame would be painted, but scrolled frames can't have
|
||||||
|
|
|
@ -59,6 +59,7 @@ _TEST_FILES = test_bug288789.html \
|
||||||
test_bug402380.html \
|
test_bug402380.html \
|
||||||
test_bug404872.html \
|
test_bug404872.html \
|
||||||
test_bug405178.html \
|
test_bug405178.html \
|
||||||
|
test_bug416168.html \
|
||||||
test_character_movement.html \
|
test_character_movement.html \
|
||||||
test_word_movement.html \
|
test_word_movement.html \
|
||||||
test_backspace_delete.html \
|
test_backspace_delete.html \
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html>
|
||||||
|
<!--
|
||||||
|
https://bugzilla.mozilla.org/show_bug.cgi?id=416168
|
||||||
|
-->
|
||||||
|
<head>
|
||||||
|
<title>Test for Bug 416168</title>
|
||||||
|
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
|
||||||
|
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||||
|
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=416168">Mozilla Bug 416168</a>
|
||||||
|
<p id="display">
|
||||||
|
|
||||||
|
<div id="a" style="overflow: hidden; outline: 1px solid black; height: 0px;">
|
||||||
|
<div style="margin-top: 50px; width:20px; height:20px;"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="b" style="overflow: hidden; outline: 1px solid black; width:0px; height: 100px;">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="c" style="overflow: hidden; outline: 1px solid black; width:100px; height: 0px;">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</p>
|
||||||
|
<div id="content" style="display: none">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<pre id="test">
|
||||||
|
<script class="testbody" type="text/javascript">
|
||||||
|
|
||||||
|
var a = document.getElementById("a");
|
||||||
|
is(a.scrollHeight, 70, "margin-top included");
|
||||||
|
|
||||||
|
var b = document.getElementById("b");
|
||||||
|
is(b.scrollHeight, 100, "zero width");
|
||||||
|
|
||||||
|
var c = document.getElementById("c");
|
||||||
|
is(c.scrollWidth, 100, "zero height");
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</pre>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -1662,7 +1662,7 @@ NS_IMETHODIMP nsViewManager::ResizeView(nsIView *aView, const nsRect &aRect, PRB
|
||||||
nsRect oldDimensions;
|
nsRect oldDimensions;
|
||||||
|
|
||||||
view->GetDimensions(oldDimensions);
|
view->GetDimensions(oldDimensions);
|
||||||
if (oldDimensions != aRect) {
|
if (!oldDimensions.IsExactEqual(aRect)) {
|
||||||
nsView* parentView = view->GetParent();
|
nsView* parentView = view->GetParent();
|
||||||
if (parentView == nsnull)
|
if (parentView == nsnull)
|
||||||
parentView = view;
|
parentView = view;
|
||||||
|
|
Загрузка…
Ссылка в новой задаче