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:
roc+@cs.cmu.edu 2008-02-27 01:46:22 -08:00
Родитель 82be2b809e
Коммит 5ebd68ca4d
8 изменённых файлов: 91 добавлений и 23 удалений

Просмотреть файл

@ -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;