зеркало из https://github.com/mozilla/gecko-dev.git
Bug 699351. Add nsIFrameLoader::clipSubdocument API to allow XUL <iframe> and <browser> to not clip the subdocument. r=tnikkel,sr=bzbarsky
This commit is contained in:
Родитель
5d8f39ecbf
Коммит
f68ef67da3
|
@ -141,7 +141,7 @@ interface nsIContentViewManager : nsISupports
|
|||
readonly attribute nsIContentView rootContentView;
|
||||
};
|
||||
|
||||
[scriptable, uuid(12905a29-4246-475a-81d4-fc389197df02)]
|
||||
[scriptable, uuid(efc0b731-45dc-4189-8ffa-d3eeeb850977)]
|
||||
interface nsIFrameLoader : nsISupports
|
||||
{
|
||||
/**
|
||||
|
@ -258,6 +258,13 @@ interface nsIFrameLoader : nsISupports
|
|||
const unsigned long EVENT_MODE_DONT_FORWARD_TO_CHILD = 0x00000001;
|
||||
|
||||
attribute unsigned long eventMode;
|
||||
|
||||
/**
|
||||
* If false, then the subdocument is not clipped to its CSS viewport, and the
|
||||
* subdocument's viewport scrollbar(s) are not rendered.
|
||||
* Defaults to true.
|
||||
*/
|
||||
attribute boolean clipSubdocument;
|
||||
};
|
||||
|
||||
native alreadyAddRefed_nsFrameLoader(already_AddRefed<nsFrameLoader>);
|
||||
|
|
|
@ -143,14 +143,12 @@ public:
|
|||
nsRefPtr<nsIDocShell> mDocShell;
|
||||
};
|
||||
|
||||
static void InvalidateFrame(nsIFrame* aFrame)
|
||||
static void InvalidateFrame(nsIFrame* aFrame, PRUint32 aFlags)
|
||||
{
|
||||
if (!aFrame)
|
||||
return;
|
||||
nsRect rect = nsRect(nsPoint(0, 0), aFrame->GetRect().Size());
|
||||
// NB: we pass INVALIDATE_NO_THEBES_LAYERS here to keep view
|
||||
// semantics the same for both in-process and out-of-process
|
||||
// <browser>. This is just a transform of the layer subtree in
|
||||
// both.
|
||||
aFrame->InvalidateWithFlags(rect, nsIFrame::INVALIDATE_NO_THEBES_LAYERS);
|
||||
aFrame->InvalidateWithFlags(rect, aFlags);
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS1(nsContentView, nsIContentView)
|
||||
|
@ -189,8 +187,11 @@ nsContentView::Update(const ViewConfig& aConfig)
|
|||
|
||||
// XXX could be clever here and compute a smaller invalidation
|
||||
// rect
|
||||
nsIFrame* frame = mFrameLoader->GetPrimaryFrameOfOwningContent();
|
||||
InvalidateFrame(frame);
|
||||
// NB: we pass INVALIDATE_NO_THEBES_LAYERS here to keep view
|
||||
// semantics the same for both in-process and out-of-process
|
||||
// <browser>. This is just a transform of the layer subtree in
|
||||
// both.
|
||||
InvalidateFrame(mFrameLoader->GetPrimaryFrameOfOwningContent(), nsIFrame::INVALIDATE_NO_THEBES_LAYERS);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -328,6 +329,7 @@ nsFrameLoader::nsFrameLoader(Element* aOwner, bool aNetworkCreated)
|
|||
, mDelayRemoteDialogs(false)
|
||||
, mRemoteBrowserShown(false)
|
||||
, mRemoteFrame(false)
|
||||
, mClipSubdocument(true)
|
||||
, mCurrentRemoteFrame(nsnull)
|
||||
, mRemoteBrowser(nsnull)
|
||||
, mRenderMode(RENDER_MODE_DEFAULT)
|
||||
|
@ -1693,7 +1695,11 @@ nsFrameLoader::SetRenderMode(PRUint32 aRenderMode)
|
|||
}
|
||||
|
||||
mRenderMode = aRenderMode;
|
||||
InvalidateFrame(GetPrimaryFrameOfOwningContent());
|
||||
// NB: we pass INVALIDATE_NO_THEBES_LAYERS here to keep view
|
||||
// semantics the same for both in-process and out-of-process
|
||||
// <browser>. This is just a transform of the layer subtree in
|
||||
// both.
|
||||
InvalidateFrame(GetPrimaryFrameOfOwningContent(), nsIFrame::INVALIDATE_NO_THEBES_LAYERS);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -1711,6 +1717,38 @@ nsFrameLoader::SetEventMode(PRUint32 aEventMode)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFrameLoader::GetClipSubdocument(bool* aResult)
|
||||
{
|
||||
*aResult = mClipSubdocument;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFrameLoader::SetClipSubdocument(bool aClip)
|
||||
{
|
||||
mClipSubdocument = aClip;
|
||||
nsIFrame* frame = GetPrimaryFrameOfOwningContent();
|
||||
if (frame) {
|
||||
InvalidateFrame(frame, 0);
|
||||
frame->PresContext()->PresShell()->
|
||||
FrameNeedsReflow(frame, nsIPresShell::eResize, NS_FRAME_IS_DIRTY);
|
||||
nsSubDocumentFrame* subdocFrame = do_QueryFrame(frame);
|
||||
if (subdocFrame) {
|
||||
nsIFrame* subdocRootFrame = subdocFrame->GetSubdocumentRootFrame();
|
||||
if (subdocRootFrame) {
|
||||
nsIFrame* subdocRootScrollFrame = subdocRootFrame->PresContext()->PresShell()->
|
||||
GetRootScrollFrame();
|
||||
if (subdocRootScrollFrame) {
|
||||
frame->PresContext()->PresShell()->
|
||||
FrameNeedsReflow(frame, nsIPresShell::eResize, NS_FRAME_IS_DIRTY);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsIntSize
|
||||
nsFrameLoader::GetSubDocumentSize(const nsIFrame *aIFrame)
|
||||
{
|
||||
|
|
|
@ -287,6 +287,8 @@ public:
|
|||
mozilla::dom::Element* GetOwnerContent() { return mOwnerContent; }
|
||||
void SetOwnerContent(mozilla::dom::Element* aContent);
|
||||
|
||||
bool ShouldClipSubdocument() { return mClipSubdocument; }
|
||||
|
||||
private:
|
||||
|
||||
bool ShouldUseRemoteProcess();
|
||||
|
@ -338,7 +340,9 @@ private:
|
|||
|
||||
bool mDelayRemoteDialogs : 1;
|
||||
bool mRemoteBrowserShown : 1;
|
||||
bool mRemoteFrame;
|
||||
bool mRemoteFrame : 1;
|
||||
bool mClipSubdocument : 1;
|
||||
|
||||
// XXX leaking
|
||||
nsCOMPtr<nsIObserver> mChildHost;
|
||||
RenderFrameParent* mCurrentRemoteFrame;
|
||||
|
|
|
@ -7295,14 +7295,14 @@ PresShell::DoReflow(nsIFrame* target, bool aInterruptible)
|
|||
desiredSize.height == size.height),
|
||||
"non-root frame's desired size changed during an "
|
||||
"incremental reflow");
|
||||
NS_ASSERTION(desiredSize.VisualOverflow().IsEqualInterior(
|
||||
NS_ASSERTION(target == rootFrame || desiredSize.VisualOverflow().IsEqualInterior(
|
||||
nsRect(nsPoint(0, 0),
|
||||
nsSize(desiredSize.width, desiredSize.height))),
|
||||
"reflow roots must not have visible overflow");
|
||||
NS_ASSERTION(desiredSize.ScrollableOverflow().IsEqualEdges(
|
||||
"non-root reflow roots must not have visible overflow");
|
||||
NS_ASSERTION(target == rootFrame || desiredSize.ScrollableOverflow().IsEqualEdges(
|
||||
nsRect(nsPoint(0, 0),
|
||||
nsSize(desiredSize.width, desiredSize.height))),
|
||||
"reflow roots must not have scrollable overflow");
|
||||
"non-root reflow roots must not have scrollable overflow");
|
||||
NS_ASSERTION(status == NS_FRAME_COMPLETE,
|
||||
"reflow roots should never split");
|
||||
|
||||
|
|
|
@ -62,6 +62,9 @@ _CHROME_FILES = \
|
|||
test_default_background.xul \
|
||||
default_background_window.xul \
|
||||
test_leaf_layers_partition_browser_window.xul \
|
||||
test_no_clip_iframe.xul \
|
||||
no_clip_iframe_window.xul \
|
||||
no_clip_iframe_subdoc.html \
|
||||
test_printpreview.xul \
|
||||
printpreview_helper.xul \
|
||||
test_printpreview_bug396024.xul \
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<body style="margin:0; background:lime;">
|
||||
<div id="d" style="position:relative; top:-50px; width:150px; height:250px; background:yellow;"></div>
|
||||
<div id="p" style="margin-top:-50px; width:150px; height:50px;"></div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,137 @@
|
|||
<?xml version="1.0"?>
|
||||
<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
|
||||
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
|
||||
type="text/css"?>
|
||||
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
onload="runTests()">
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/WindowSnapshot.js"></script>
|
||||
|
||||
<div id="container" xmlns="http://www.w3.org/1999/xhtml" style="height:400px; overflow:auto; background:gray">
|
||||
<div style="height:0">
|
||||
<iframe type="content" id="f" src="no_clip_iframe_subdoc.html"
|
||||
style="margin-top:50px; border:1px solid black; width:100px; height:100px;"/>
|
||||
</div>
|
||||
<div id="ref" style="background:gray;">
|
||||
<div style="border:1px solid black; margin-top:50px; width:100px; height:100px;">
|
||||
<div id="ref-d" style="background:lime; height:250px; width:150px;">
|
||||
<div style="position:relative; top:-50px; width:150px; height:100%; background:yellow;"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<vbox flex="1"/>
|
||||
|
||||
<script type="application/javascript">
|
||||
<![CDATA[
|
||||
var imports = [ "SimpleTest", "is", "isnot", "ok", "onerror" ];
|
||||
for each (var name in imports) {
|
||||
window[name] = window.opener.wrappedJSObject[name];
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
var accumulatedRect = null;
|
||||
var onpaint = function() {};
|
||||
|
||||
function paintListener(event) {
|
||||
if (event.target != window)
|
||||
return;
|
||||
dump("got MozAfterPaint: " + event.boundingClientRect.left + "," + event.boundingClientRect.top + "," +
|
||||
event.boundingClientRect.right + "," + event.boundingClientRect.bottom + "\n");
|
||||
if (accumulatedRect) {
|
||||
accumulatedRect[0] = Math.min(accumulatedRect[0], event.boundingClientRect.left);
|
||||
accumulatedRect[1] = Math.min(accumulatedRect[1], event.boundingClientRect.top);
|
||||
accumulatedRect[2] = Math.max(accumulatedRect[2], event.boundingClientRect.right);
|
||||
accumulatedRect[3] = Math.max(accumulatedRect[3], event.boundingClientRect.bottom);
|
||||
} else {
|
||||
accumulatedRect = [event.boundingClientRect.left, event.boundingClientRect.top,
|
||||
event.boundingClientRect.right, event.boundingClientRect.bottom];
|
||||
}
|
||||
onpaint();
|
||||
}
|
||||
window.addEventListener("MozAfterPaint", paintListener, false);
|
||||
|
||||
function waitForAllPaintsFlushed(callback) {
|
||||
document.documentElement.getBoundingClientRect();
|
||||
var CI = Components.interfaces;
|
||||
var utils = window.QueryInterface(CI.nsIInterfaceRequestor)
|
||||
.getInterface(CI.nsIDOMWindowUtils);
|
||||
if (!utils.isMozAfterPaintPending) {
|
||||
dump("done...\n");
|
||||
var result = accumulatedRect;
|
||||
accumulatedRect = null;
|
||||
onpaint = function() {};
|
||||
if (!result) {
|
||||
result = [0,0,0,0];
|
||||
}
|
||||
callback(result[0], result[1], result[2], result[3]);
|
||||
return;
|
||||
}
|
||||
dump("waiting for paint...\n");
|
||||
onpaint = function() { waitForAllPaintsFlushed(callback); };
|
||||
}
|
||||
|
||||
var Ci = Components.interfaces;
|
||||
var frame = document.getElementById("f");
|
||||
var fl = frame.QueryInterface(Ci.nsIFrameLoaderOwner).frameLoader;
|
||||
is(fl.clipSubdocument, true, "clipSubdocument should default to true");
|
||||
fl.clipSubdocument = false;
|
||||
is(fl.clipSubdocument, false, "clipSubdocument should have been set to false");
|
||||
|
||||
function runTests() {
|
||||
var ref = document.getElementById("ref");
|
||||
frame.contentWindow.scrollTo(0,0);
|
||||
|
||||
ref.style.visibility = "hidden";
|
||||
var testCanvas = snapshotWindow(window);
|
||||
ref.style.visibility = "";
|
||||
var refCanvas = snapshotWindow(window);
|
||||
var comparison = compareSnapshots(testCanvas, refCanvas, true);
|
||||
ok(comparison[0], "Basic overflow drawing; got " + comparison[1] + ", expected " + comparison[2]);
|
||||
|
||||
document.getElementById("container").style.height = "200px";
|
||||
ref.style.visibility = "hidden";
|
||||
testCanvas = snapshotWindow(window);
|
||||
ref.style.visibility = "";
|
||||
refCanvas = snapshotWindow(window);
|
||||
comparison = compareSnapshots(testCanvas, refCanvas, true);
|
||||
ok(comparison[0], "Drawing with vertical scrollbar to show overflow area computation; got " +
|
||||
comparison[1] + ", expected " + comparison[2]);
|
||||
|
||||
frame.contentDocument.getElementById("d").style.height = "350px";
|
||||
document.getElementById("ref-d").style.height = "350px";
|
||||
ref.style.visibility = "hidden";
|
||||
testCanvas = snapshotWindow(window);
|
||||
ref.style.visibility = "";
|
||||
refCanvas = snapshotWindow(window);
|
||||
comparison = compareSnapshots(testCanvas, refCanvas, true);
|
||||
ok(comparison[0], "testing dynamic overflow area change affecting scrollbar; got " +
|
||||
comparison[1] + ", expected " + comparison[2]);
|
||||
|
||||
// Now do invalidation tests
|
||||
ref.style.visibility = "hidden";
|
||||
document.getElementById("container").style.height = "400px";
|
||||
waitForAllPaintsFlushed(function() {
|
||||
dump("Scrolling\n");
|
||||
frame.contentWindow.scrollTo(0,80);
|
||||
waitForAllPaintsFlushed(function(x1, y1, x2, y2) {
|
||||
ok(x1 <= 1 && x2 >= 151 && y1 <= 0 && y2 >= 400,
|
||||
"Entire scrolled region is painted: " + x1 + "," + y1 + "," + x2 + "," + y2);
|
||||
frame.contentDocument.getElementById("p").style.background = "cyan";
|
||||
waitForAllPaintsFlushed(function(x1, y1, x2, y2) {
|
||||
ok(x1 <= 1 && x2 >= 151 && y1 <= 271 && y2 >= 320,
|
||||
"Entire updated region is painted: " + x1 + "," + y1 + "," + x2 + "," + y2);
|
||||
|
||||
var tester = window.SimpleTest;
|
||||
window.close();
|
||||
tester.finish();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
]]>
|
||||
</script>
|
||||
</window>
|
|
@ -0,0 +1,23 @@
|
|||
<?xml version="1.0"?>
|
||||
<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
|
||||
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
|
||||
type="text/css"?>
|
||||
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
|
||||
<!-- test results are displayed in the html:body -->
|
||||
<body xmlns="http://www.w3.org/1999/xhtml">
|
||||
</body>
|
||||
|
||||
<!-- test code goes here -->
|
||||
<script type="application/javascript">
|
||||
<![CDATA[
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
// Run the test in a separate window so that the test runs as a chrome
|
||||
// window
|
||||
window.open("no_clip_iframe_window.xul", "no_clip_iframe",
|
||||
"chrome,width=200,height=400");
|
||||
]]>
|
||||
</script>
|
||||
</window>
|
|
@ -6439,13 +6439,17 @@ nsFrame::CreateAccessible()
|
|||
NS_DECLARE_FRAME_PROPERTY(OverflowAreasProperty,
|
||||
nsIFrame::DestroyOverflowAreas)
|
||||
|
||||
void
|
||||
bool
|
||||
nsIFrame::ClearOverflowRects()
|
||||
{
|
||||
if (mOverflow.mType == NS_FRAME_OVERFLOW_NONE) {
|
||||
return false;
|
||||
}
|
||||
if (mOverflow.mType == NS_FRAME_OVERFLOW_LARGE) {
|
||||
Properties().Delete(OverflowAreasProperty());
|
||||
}
|
||||
mOverflow.mType = NS_FRAME_OVERFLOW_NONE;
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Create or retrieve the previously stored overflow area, if the frame does
|
||||
|
@ -6473,17 +6477,18 @@ nsIFrame::GetOverflowAreasProperty()
|
|||
/** Set the overflowArea rect, storing it as deltas or a separate rect
|
||||
* depending on its size in relation to the primary frame rect.
|
||||
*/
|
||||
void
|
||||
bool
|
||||
nsIFrame::SetOverflowAreas(const nsOverflowAreas& aOverflowAreas)
|
||||
{
|
||||
if (mOverflow.mType == NS_FRAME_OVERFLOW_LARGE) {
|
||||
nsOverflowAreas *overflow =
|
||||
static_cast<nsOverflowAreas*>(Properties().Get(OverflowAreasProperty()));
|
||||
bool changed = *overflow != aOverflowAreas;
|
||||
*overflow = aOverflowAreas;
|
||||
|
||||
// Don't bother with converting to the deltas form if we already
|
||||
// have a property.
|
||||
return;
|
||||
return changed;
|
||||
}
|
||||
|
||||
const nsRect& vis = aOverflowAreas.VisualOverflow();
|
||||
|
@ -6505,6 +6510,7 @@ nsIFrame::SetOverflowAreas(const nsOverflowAreas& aOverflowAreas)
|
|||
// so that our eventual SetRect/SetSize will know that it has to
|
||||
// reset our overflow areas.
|
||||
(l | t | r | b) != 0) {
|
||||
VisualDeltas oldDeltas = mOverflow.mVisualDeltas;
|
||||
// It's a "small" overflow area so we store the deltas for each edge
|
||||
// directly in the frame, rather than allocating a separate rect.
|
||||
// If they're all zero, that's fine; we're setting things to
|
||||
|
@ -6513,12 +6519,18 @@ nsIFrame::SetOverflowAreas(const nsOverflowAreas& aOverflowAreas)
|
|||
mOverflow.mVisualDeltas.mTop = t;
|
||||
mOverflow.mVisualDeltas.mRight = r;
|
||||
mOverflow.mVisualDeltas.mBottom = b;
|
||||
// There was no scrollable overflow before, and there isn't now.
|
||||
return oldDeltas != mOverflow.mVisualDeltas;
|
||||
} else {
|
||||
bool changed = !aOverflowAreas.ScrollableOverflow().IsEqualEdges(nsRect(nsPoint(0, 0), GetSize())) ||
|
||||
!aOverflowAreas.VisualOverflow().IsEqualEdges(GetVisualOverflowFromDeltas());
|
||||
|
||||
// it's a large overflow area that we need to store as a property
|
||||
mOverflow.mType = NS_FRAME_OVERFLOW_LARGE;
|
||||
nsOverflowAreas* overflow = GetOverflowAreasProperty();
|
||||
NS_ASSERTION(overflow, "should have created areas");
|
||||
*overflow = aOverflowAreas;
|
||||
return changed;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6529,7 +6541,7 @@ IsInlineFrame(nsIFrame *aFrame)
|
|||
return type == nsGkAtoms::inlineFrame;
|
||||
}
|
||||
|
||||
void
|
||||
bool
|
||||
nsIFrame::FinishAndStoreOverflow(nsOverflowAreas& aOverflowAreas,
|
||||
nsSize aNewSize)
|
||||
{
|
||||
|
@ -6638,11 +6650,11 @@ nsIFrame::FinishAndStoreOverflow(nsOverflowAreas& aOverflowAreas,
|
|||
|
||||
bool visualOverflowChanged =
|
||||
!GetVisualOverflowRect().IsEqualInterior(aOverflowAreas.VisualOverflow());
|
||||
|
||||
bool anyOverflowChanged;
|
||||
if (aOverflowAreas != nsOverflowAreas(bounds, bounds)) {
|
||||
SetOverflowAreas(aOverflowAreas);
|
||||
anyOverflowChanged = SetOverflowAreas(aOverflowAreas);
|
||||
} else {
|
||||
ClearOverflowRects();
|
||||
anyOverflowChanged = ClearOverflowRects();
|
||||
}
|
||||
|
||||
if (visualOverflowChanged) {
|
||||
|
@ -6687,6 +6699,8 @@ nsIFrame::FinishAndStoreOverflow(nsOverflowAreas& aOverflowAreas,
|
|||
nsDisplayItem::TYPE_TRANSFORM);
|
||||
}
|
||||
}
|
||||
|
||||
return anyOverflowChanged;
|
||||
}
|
||||
|
||||
/* The overflow rects for leaf nodes in a preserve-3d hierarchy depends on
|
||||
|
|
|
@ -82,6 +82,7 @@
|
|||
#include "mozilla/dom/Element.h"
|
||||
#include "FrameLayerBuilder.h"
|
||||
#include "nsSMILKeySpline.h"
|
||||
#include "nsSubDocumentFrame.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
|
@ -196,16 +197,20 @@ nsHTMLScrollFrame::InvalidateInternal(const nsRect& aDamageRect,
|
|||
nsRect damage = aDamageRect + nsPoint(aX, aY);
|
||||
// This is the damage rect that we're going to pass up to our parent.
|
||||
nsRect parentDamage;
|
||||
// If we're using a displayport, we might be displaying an area
|
||||
// different than our scroll port and the damage needs to be
|
||||
// clipped to that instead.
|
||||
nsRect displayport;
|
||||
bool usingDisplayport = nsLayoutUtils::GetDisplayPort(GetContent(),
|
||||
&displayport);
|
||||
if (usingDisplayport) {
|
||||
parentDamage.IntersectRect(damage, displayport);
|
||||
if (mInner.IsIgnoringViewportClipping()) {
|
||||
parentDamage = damage;
|
||||
} else {
|
||||
parentDamage.IntersectRect(damage, mInner.mScrollPort);
|
||||
// If we're using a displayport, we might be displaying an area
|
||||
// different than our scroll port and the damage needs to be
|
||||
// clipped to that instead.
|
||||
nsRect displayport;
|
||||
bool usingDisplayport = nsLayoutUtils::GetDisplayPort(GetContent(),
|
||||
&displayport);
|
||||
if (usingDisplayport) {
|
||||
parentDamage.IntersectRect(damage, displayport);
|
||||
} else {
|
||||
parentDamage.IntersectRect(damage, mInner.mScrollPort);
|
||||
}
|
||||
}
|
||||
|
||||
if (IsScrollingActive()) {
|
||||
|
@ -283,7 +288,7 @@ struct ScrollReflowState {
|
|||
nsMargin mComputedBorder;
|
||||
|
||||
// === Filled in by ReflowScrolledFrame ===
|
||||
nsRect mContentsOverflowArea;
|
||||
nsOverflowAreas mContentsOverflowAreas;
|
||||
bool mReflowedContentsWithHScrollbar;
|
||||
bool mReflowedContentsWithVScrollbar;
|
||||
|
||||
|
@ -427,7 +432,8 @@ nsHTMLScrollFrame::TryLayout(ScrollReflowState* aState,
|
|||
|
||||
if (!aForce) {
|
||||
nsRect scrolledRect =
|
||||
mInner.GetScrolledRectInternal(aState->mContentsOverflowArea, scrollPortSize);
|
||||
mInner.GetScrolledRectInternal(aState->mContentsOverflowAreas.ScrollableOverflow(),
|
||||
scrollPortSize);
|
||||
nscoord oneDevPixel = aState->mBoxState.PresContext()->DevPixelsToAppUnits(1);
|
||||
|
||||
// If the style is HIDDEN then we already know that aAssumeHScroll is false
|
||||
|
@ -566,7 +572,7 @@ nsHTMLScrollFrame::ReflowScrolledFrame(ScrollReflowState* aState,
|
|||
// overflow area doesn't include the frame bounds.
|
||||
aMetrics->UnionOverflowAreasWithDesiredBounds();
|
||||
|
||||
aState->mContentsOverflowArea = aMetrics->ScrollableOverflow();
|
||||
aState->mContentsOverflowAreas = aMetrics->mOverflowAreas;
|
||||
aState->mReflowedContentsWithHScrollbar = aAssumeHScroll;
|
||||
aState->mReflowedContentsWithVScrollbar = aAssumeVScroll;
|
||||
|
||||
|
@ -718,7 +724,9 @@ nsHTMLScrollFrame::PlaceScrollArea(const ScrollReflowState& aState,
|
|||
nsRect scrolledArea;
|
||||
// Preserve the width or height of empty rects
|
||||
nsSize portSize = mInner.mScrollPort.Size();
|
||||
nsRect scrolledRect = mInner.GetScrolledRectInternal(aState.mContentsOverflowArea, portSize);
|
||||
nsRect scrolledRect =
|
||||
mInner.GetScrolledRectInternal(aState.mContentsOverflowAreas.ScrollableOverflow(),
|
||||
portSize);
|
||||
scrolledArea.UnionRectEdges(scrolledRect,
|
||||
nsRect(nsPoint(0,0), portSize));
|
||||
|
||||
|
@ -925,6 +933,10 @@ nsHTMLScrollFrame::Reflow(nsPresContext* aPresContext,
|
|||
state.mComputedBorder.TopBottom();
|
||||
|
||||
aDesiredSize.SetOverflowAreasToDesiredBounds();
|
||||
if (mInner.IsIgnoringViewportClipping()) {
|
||||
aDesiredSize.mOverflowAreas.UnionWith(
|
||||
state.mContentsOverflowAreas + mInner.mScrolledFrame->GetPosition());
|
||||
}
|
||||
|
||||
CheckInvalidateSizeChange(aDesiredSize);
|
||||
|
||||
|
@ -1687,6 +1699,15 @@ InvalidateFixedBackgroundFrames(nsIFrame* aRootFrame,
|
|||
list.DeleteAll();
|
||||
}
|
||||
|
||||
bool nsGfxScrollFrameInner::IsIgnoringViewportClipping() const
|
||||
{
|
||||
if (!mIsRoot)
|
||||
return false;
|
||||
nsSubDocumentFrame* subdocFrame = static_cast<nsSubDocumentFrame*>
|
||||
(nsLayoutUtils::GetCrossDocParentFrame(mOuter->PresContext()->PresShell()->GetRootFrame()));
|
||||
return subdocFrame && !subdocFrame->ShouldClipSubdocument();
|
||||
}
|
||||
|
||||
bool nsGfxScrollFrameInner::IsAlwaysActive() const
|
||||
{
|
||||
// The root scrollframe for a non-chrome document which is the direct
|
||||
|
@ -1721,7 +1742,7 @@ void nsGfxScrollFrameInner::MarkActive()
|
|||
}
|
||||
}
|
||||
|
||||
void nsGfxScrollFrameInner::ScrollVisual()
|
||||
void nsGfxScrollFrameInner::ScrollVisual(nsPoint aOldScrolledFramePos)
|
||||
{
|
||||
nsRootPresContext* rootPresContext = mOuter->PresContext()->GetRootPresContext();
|
||||
if (!rootPresContext) {
|
||||
|
@ -1748,9 +1769,15 @@ void nsGfxScrollFrameInner::ScrollVisual()
|
|||
}
|
||||
|
||||
nsRect invalidateRect, displayport;
|
||||
invalidateRect =
|
||||
(nsLayoutUtils::GetDisplayPort(mOuter->GetContent(), &displayport)) ?
|
||||
displayport : mScrollPort;
|
||||
if (IsIgnoringViewportClipping()) {
|
||||
nsRect visualOverflow = mScrolledFrame->GetVisualOverflowRect();
|
||||
invalidateRect.UnionRect(visualOverflow + mScrolledFrame->GetPosition(),
|
||||
visualOverflow + aOldScrolledFramePos);
|
||||
} else {
|
||||
invalidateRect =
|
||||
(nsLayoutUtils::GetDisplayPort(mOuter->GetContent(), &displayport)) ?
|
||||
displayport : mScrollPort;
|
||||
}
|
||||
|
||||
mOuter->InvalidateWithFlags(invalidateRect, flags);
|
||||
|
||||
|
@ -1820,12 +1847,13 @@ nsGfxScrollFrameInner::ScrollToImpl(nsPoint aPt)
|
|||
for (PRUint32 i = 0; i < mListeners.Length(); i++) {
|
||||
mListeners[i]->ScrollPositionWillChange(pt.x, pt.y);
|
||||
}
|
||||
|
||||
|
||||
nsPoint oldScrollFramePos = mScrolledFrame->GetPosition();
|
||||
// Update frame position for scrolling
|
||||
mScrolledFrame->SetPosition(mScrollPort.TopLeft() - pt);
|
||||
|
||||
// We pass in the amount to move visually
|
||||
ScrollVisual();
|
||||
ScrollVisual(oldScrollFramePos);
|
||||
|
||||
presContext->PresShell()->SynthesizeMouseMove(true);
|
||||
UpdateScrollbarPosition();
|
||||
|
@ -1937,7 +1965,7 @@ nsGfxScrollFrameInner::BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
|||
}
|
||||
}
|
||||
|
||||
if (aBuilder->GetIgnoreScrollFrame() == mOuter) {
|
||||
if (aBuilder->GetIgnoreScrollFrame() == mOuter || IsIgnoringViewportClipping()) {
|
||||
// Don't clip the scrolled child, and don't paint scrollbars/scrollcorner.
|
||||
// The scrolled frame shouldn't have its own background/border, so we
|
||||
// can just pass aLists directly.
|
||||
|
|
|
@ -182,7 +182,7 @@ public:
|
|||
static void AsyncScrollCallback(nsITimer *aTimer, void* anInstance);
|
||||
void ScrollTo(nsPoint aScrollPosition, nsIScrollableFrame::ScrollMode aMode);
|
||||
void ScrollToImpl(nsPoint aScrollPosition);
|
||||
void ScrollVisual();
|
||||
void ScrollVisual(nsPoint aOldScrolledFramePosition);
|
||||
void ScrollBy(nsIntPoint aDelta, nsIScrollableFrame::ScrollUnit aUnit,
|
||||
nsIScrollableFrame::ScrollMode aMode, nsIntPoint* aOverflow);
|
||||
void ScrollToRestoredPosition();
|
||||
|
@ -256,6 +256,8 @@ public:
|
|||
const nsRect& aContentArea,
|
||||
const nsRect& aOldScrollArea);
|
||||
|
||||
bool IsIgnoringViewportClipping() const;
|
||||
|
||||
bool IsAlwaysActive() const;
|
||||
void MarkActive();
|
||||
void MarkInactive();
|
||||
|
|
|
@ -2274,14 +2274,15 @@ public:
|
|||
/**
|
||||
* Store the overflow area in the frame's mOverflow.mVisualDeltas
|
||||
* fields or as a frame property in the frame manager so that it can
|
||||
* be retrieved later without reflowing the frame.
|
||||
* be retrieved later without reflowing the frame. Returns true if either of
|
||||
* the overflow areas changed.
|
||||
*/
|
||||
void FinishAndStoreOverflow(nsOverflowAreas& aOverflowAreas,
|
||||
bool FinishAndStoreOverflow(nsOverflowAreas& aOverflowAreas,
|
||||
nsSize aNewSize);
|
||||
|
||||
void FinishAndStoreOverflow(nsHTMLReflowMetrics* aMetrics) {
|
||||
FinishAndStoreOverflow(aMetrics->mOverflowAreas,
|
||||
nsSize(aMetrics->width, aMetrics->height));
|
||||
bool FinishAndStoreOverflow(nsHTMLReflowMetrics* aMetrics) {
|
||||
return FinishAndStoreOverflow(aMetrics->mOverflowAreas,
|
||||
nsSize(aMetrics->width, aMetrics->height));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2294,8 +2295,9 @@ public:
|
|||
|
||||
/**
|
||||
* Removes any stored overflow rects (visual and scrollable) from the frame.
|
||||
* Returns true if the overflow changed.
|
||||
*/
|
||||
void ClearOverflowRects();
|
||||
bool ClearOverflowRects();
|
||||
|
||||
/**
|
||||
* Determine whether borders should not be painted on certain sides of the
|
||||
|
@ -2822,14 +2824,24 @@ protected:
|
|||
// If mOverflow.mType == NS_FRAME_OVERFLOW_LARGE, then the
|
||||
// delta values are not meaningful and the overflow area is stored
|
||||
// as a separate rect property.
|
||||
struct VisualDeltas {
|
||||
PRUint8 mLeft;
|
||||
PRUint8 mTop;
|
||||
PRUint8 mRight;
|
||||
PRUint8 mBottom;
|
||||
bool operator==(const VisualDeltas& aOther) const
|
||||
{
|
||||
return mLeft == aOther.mLeft && mTop == aOther.mTop &&
|
||||
mRight == aOther.mRight && mBottom == aOther.mBottom;
|
||||
}
|
||||
bool operator!=(const VisualDeltas& aOther) const
|
||||
{
|
||||
return !(*this == aOther);
|
||||
}
|
||||
};
|
||||
union {
|
||||
PRUint32 mType;
|
||||
struct {
|
||||
PRUint8 mLeft;
|
||||
PRUint8 mTop;
|
||||
PRUint8 mRight;
|
||||
PRUint8 mBottom;
|
||||
} mVisualDeltas;
|
||||
PRUint32 mType;
|
||||
VisualDeltas mVisualDeltas;
|
||||
} mOverflow;
|
||||
|
||||
// Helpers
|
||||
|
@ -2944,7 +2956,10 @@ private:
|
|||
mRect.height + mOverflow.mVisualDeltas.mBottom +
|
||||
mOverflow.mVisualDeltas.mTop);
|
||||
}
|
||||
void SetOverflowAreas(const nsOverflowAreas& aOverflowAreas);
|
||||
/**
|
||||
* Returns true if any overflow changed.
|
||||
*/
|
||||
bool SetOverflowAreas(const nsOverflowAreas& aOverflowAreas);
|
||||
nsPoint GetOffsetToCrossDoc(const nsIFrame* aOther, const PRInt32 aAPD) const;
|
||||
|
||||
#ifdef NS_DEBUG
|
||||
|
|
|
@ -411,18 +411,21 @@ nsSubDocumentFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
|||
childItems.AppendToTop(layerItem);
|
||||
}
|
||||
|
||||
nsDisplayList list;
|
||||
// Clip children to the child root frame's rectangle
|
||||
rv = list.AppendNewToTop(
|
||||
if (ShouldClipSubdocument()) {
|
||||
nsDisplayClip* item =
|
||||
new (aBuilder) nsDisplayClip(aBuilder, this, &childItems,
|
||||
subdocBoundsInParentUnits));
|
||||
subdocBoundsInParentUnits);
|
||||
// Clip children to the child root frame's rectangle
|
||||
childItems.AppendToTop(item);
|
||||
}
|
||||
|
||||
if (mIsInline) {
|
||||
WrapReplacedContentForBorderRadius(aBuilder, &list, aLists);
|
||||
WrapReplacedContentForBorderRadius(aBuilder, &childItems, aLists);
|
||||
} else {
|
||||
aLists.Content()->AppendToTop(&list);
|
||||
aLists.Content()->AppendToTop(&childItems);
|
||||
}
|
||||
}
|
||||
|
||||
// delete childItems in case of OOM
|
||||
childItems.DeleteAll();
|
||||
|
||||
|
@ -617,6 +620,14 @@ nsSubDocumentFrame::Reflow(nsPresContext* aPresContext,
|
|||
vm->ResizeView(mInnerView, nsRect(nsPoint(0, 0), innerSize), true);
|
||||
}
|
||||
|
||||
aDesiredSize.SetOverflowAreasToDesiredBounds();
|
||||
if (!ShouldClipSubdocument()) {
|
||||
nsIFrame* subdocRootFrame = GetSubdocumentRootFrame();
|
||||
if (subdocRootFrame) {
|
||||
aDesiredSize.mOverflowAreas.UnionWith(subdocRootFrame->GetOverflowAreas() + offset);
|
||||
}
|
||||
}
|
||||
|
||||
// Determine if we need to repaint our border, background or outline
|
||||
CheckInvalidateSizeChange(aDesiredSize);
|
||||
|
||||
|
|
|
@ -124,6 +124,12 @@ public:
|
|||
virtual bool ReflowFinished();
|
||||
virtual void ReflowCallbackCanceled();
|
||||
|
||||
bool ShouldClipSubdocument()
|
||||
{
|
||||
nsFrameLoader* frameLoader = FrameLoader();
|
||||
return !frameLoader || frameLoader->ShouldClipSubdocument();
|
||||
}
|
||||
|
||||
protected:
|
||||
friend class AsyncFrameInit;
|
||||
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
#include "nsIScrollableFrame.h"
|
||||
#include "nsDisplayList.h"
|
||||
#include "FrameLayerBuilder.h"
|
||||
#include "nsSubDocumentFrame.h"
|
||||
#include "nsAbsoluteContainingBlock.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
@ -210,6 +211,8 @@ ViewportFrame::Reflow(nsPresContext* aPresContext,
|
|||
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
aDesiredSize.SetOverflowAreasToDesiredBounds();
|
||||
|
||||
if (mFrames.NotEmpty()) {
|
||||
// Deal with a non-incremental reflow or an incremental reflow
|
||||
// targeted at our one-and-only principal child frame.
|
||||
|
@ -234,6 +237,7 @@ ViewportFrame::Reflow(nsPresContext* aPresContext,
|
|||
} else {
|
||||
kidHeight = mFrames.FirstChild()->GetSize().height;
|
||||
}
|
||||
ConsiderChildOverflow(aDesiredSize.mOverflowAreas, mFrames.FirstChild());
|
||||
}
|
||||
|
||||
NS_ASSERTION(aReflowState.availableWidth != NS_UNCONSTRAINEDSIZE,
|
||||
|
@ -252,22 +256,18 @@ ViewportFrame::Reflow(nsPresContext* aPresContext,
|
|||
nsHTMLReflowState reflowState(aReflowState);
|
||||
nsPoint offset = AdjustReflowStateForScrollbars(&reflowState);
|
||||
|
||||
#ifdef DEBUG
|
||||
if (IsAbsoluteContainer()) {
|
||||
NS_ASSERTION(GetAbsoluteContainingBlock()->GetChildList().IsEmpty() ||
|
||||
(offset.x == 0 && offset.y == 0),
|
||||
"We don't handle correct positioning of fixed frames with "
|
||||
"scrollbars in odd positions");
|
||||
}
|
||||
#endif
|
||||
|
||||
if (IsAbsoluteContainer()) {
|
||||
// Just reflow all the fixed-pos frames.
|
||||
rv = GetAbsoluteContainingBlock()->Reflow(this, aPresContext, reflowState, aStatus,
|
||||
reflowState.ComputedWidth(),
|
||||
reflowState.ComputedHeight(),
|
||||
false, true, true, // XXX could be optimized
|
||||
nsnull /* ignore overflow */);
|
||||
&aDesiredSize.mOverflowAreas);
|
||||
}
|
||||
|
||||
// If we were dirty then do a repaint
|
||||
|
@ -276,8 +276,19 @@ ViewportFrame::Reflow(nsPresContext* aPresContext,
|
|||
Invalidate(damageRect);
|
||||
}
|
||||
|
||||
// XXX Should we do something to clip our children to this?
|
||||
aDesiredSize.SetOverflowAreasToDesiredBounds();
|
||||
// Clipping is handled by the document container (e.g., nsSubDocumentFrame),
|
||||
// so we don't need to change our overflow areas.
|
||||
bool overflowChanged = FinishAndStoreOverflow(&aDesiredSize);
|
||||
if (overflowChanged) {
|
||||
// We may need to alert our container to get it to pick up the
|
||||
// overflow change.
|
||||
nsSubDocumentFrame* container = static_cast<nsSubDocumentFrame*>
|
||||
(nsLayoutUtils::GetCrossDocParentFrame(this));
|
||||
if (container && !container->ShouldClipSubdocument()) {
|
||||
container->PresContext()->PresShell()->
|
||||
FrameNeedsReflow(container, nsIPresShell::eResize, NS_FRAME_IS_DIRTY);
|
||||
}
|
||||
}
|
||||
|
||||
NS_FRAME_TRACE_REFLOW_OUT("ViewportFrame::Reflow", aStatus);
|
||||
NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
|
||||
|
|
Загрузка…
Ссылка в новой задаче