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);
|
||||
|
||||
// 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
|
||||
// empty rect if both aRect1 and aRect2 are empty
|
||||
// fills 'this' with the result, ignoring empty input rectangles.
|
||||
// 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
|
||||
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
|
||||
void SetRect(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight) {
|
||||
x = aX; y = aY; width = aWidth; height = aHeight;
|
||||
|
@ -143,6 +152,13 @@ struct NS_GFX nsRect {
|
|||
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 {
|
||||
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
|
||||
*this = aRect1;
|
||||
} else {
|
||||
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;
|
||||
UnionRectIncludeEmpty(aRect1, aRect2);
|
||||
}
|
||||
|
||||
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
|
||||
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
|
||||
// the floor, and we need to include them. (Thus we need
|
||||
// aHaveRect to know when to drop the initial value on the floor.)
|
||||
nscoord x = PR_MIN(aRect.x, frameBounds.x),
|
||||
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);
|
||||
aRect.UnionRectIncludeEmpty(aRect, frameBounds);
|
||||
} else {
|
||||
aHaveRect = PR_TRUE;
|
||||
aRect = frameBounds;
|
||||
|
|
|
@ -5293,6 +5293,11 @@ nsIFrame::FinishAndStoreOverflow(nsRect* aOverflowArea, nsSize aNewSize)
|
|||
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 =
|
||||
aOverflowArea->x < 0 || aOverflowArea->y < 0 ||
|
||||
|
@ -5318,7 +5323,6 @@ nsIFrame::FinishAndStoreOverflow(nsRect* aOverflowArea, nsSize aNewSize)
|
|||
}
|
||||
|
||||
if (outlineRect != nsRect(nsPoint(0, 0), aNewSize)) {
|
||||
// Throw out any overflow if we're -moz-hidden-unscrollable
|
||||
mState |= NS_FRAME_OUTSIDE_CHILDREN;
|
||||
nsRect* overflowArea = GetOverflowAreaProperty(PR_TRUE);
|
||||
NS_ASSERTION(overflowArea, "should have created rect");
|
||||
|
|
|
@ -673,8 +673,9 @@ nsHTMLScrollFrame::PlaceScrollArea(const ScrollReflowState& aState)
|
|||
scrolledFrame->SetPosition(scrolledView->GetOffsetTo(GetView()));
|
||||
|
||||
nsRect scrolledArea;
|
||||
scrolledArea.UnionRect(mInner.GetScrolledRect(aState.mScrollPortRect.Size()),
|
||||
nsRect(nsPoint(0,0), aState.mScrollPortRect.Size()));
|
||||
// Preserve the width or height of empty rects
|
||||
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
|
||||
// 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_bug404872.html \
|
||||
test_bug405178.html \
|
||||
test_bug416168.html \
|
||||
test_character_movement.html \
|
||||
test_word_movement.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;
|
||||
|
||||
view->GetDimensions(oldDimensions);
|
||||
if (oldDimensions != aRect) {
|
||||
if (!oldDimensions.IsExactEqual(aRect)) {
|
||||
nsView* parentView = view->GetParent();
|
||||
if (parentView == nsnull)
|
||||
parentView = view;
|
||||
|
|
Загрузка…
Ссылка в новой задаче