# HG changeset patch # Parent 98e964205d79eb6527a5bfe2dc8f12e6dacc1e76 # User Boris Zbarsky Bug 129941. Don't create scrollframes for blockframes (except inline blocks) while printing, and make such blockframes clip their contents instead. r=dbaron diff --git a/layout/base/nsCSSFrameConstructor.cpp b/layout/base/nsCSSFrameConstructor.cpp --- a/layout/base/nsCSSFrameConstructor.cpp +++ b/layout/base/nsCSSFrameConstructor.cpp @@ -4385,24 +4385,34 @@ nsCSSFrameConstructor::FindDisplayData(c // make this function static. PRBool propagatedScrollToViewport = PR_FALSE; if (aContent->NodeInfo()->Equals(nsGkAtoms::body) && aContent->IsHTML()) { propagatedScrollToViewport = PropagateScrollToViewport() == aContent; } + NS_ASSERTION(!propagatedScrollToViewport || + !mPresShell->GetPresContext()->IsPaginated(), + "Shouldn't propagate scroll in paginated contexts"); + // If the frame is a block-level frame and is scrollable, then wrap it - // in a scroll frame. + // in a scroll frame. Except we don't want to do that for paginated contexts + // for frames that are block-outside. + // The condition on skipping scrollframe construction in the + // paginated case needs to match code in ConstructNonScrollableBlock + // and in nsFrame::ApplyPaginatedOverflowClipping. // XXX Ignore tables for the time being // XXXbz it would be nice to combine this with the other block // case... Think about how do do this? if (aDisplay->IsBlockInside() && aDisplay->IsScrollableOverflow() && - !propagatedScrollToViewport) { + !propagatedScrollToViewport && + (!mPresShell->GetPresContext()->IsPaginated() || + !aDisplay->IsBlockOutside())) { static const FrameConstructionData sScrollableBlockData = FULL_CTOR_FCDATA(0, &nsCSSFrameConstructor::ConstructScrollableBlock); return &sScrollableBlockData; } // Handle various non-scrollable blocks if (aDisplay->IsBlockInside() || NS_STYLE_DISPLAY_RUN_IN == aDisplay->mDisplay || @@ -4520,17 +4530,28 @@ nsCSSFrameConstructor::ConstructNonScrol const nsStyleDisplay* aDisplay, nsFrameItems& aFrameItems, nsIFrame** aNewFrame) { nsStyleContext* const styleContext = aItem.mStyleContext; if (aDisplay->IsAbsolutelyPositioned() || aDisplay->IsFloating() || - NS_STYLE_DISPLAY_INLINE_BLOCK == aDisplay->mDisplay) { + NS_STYLE_DISPLAY_INLINE_BLOCK == aDisplay->mDisplay || + // This check just needs to be the same as the check for using scrollable + // blocks in FindDisplayData and the check for clipping in + // nsFrame::ApplyPaginatedOverflowClipping; we want a block formatting + // context root in paginated contexts for every block that would be + // scrollable in a non-paginated context. Note that IsPaginated() + // implies that no propagation to viewport has taken place, so we don't + // need to check for propagation here. + (mPresShell->GetPresContext()->IsPaginated() && + aDisplay->IsBlockInside() && + aDisplay->IsScrollableOverflow() && + aDisplay->IsBlockOutside())) { *aNewFrame = NS_NewBlockFormattingContext(mPresShell, styleContext); } else { *aNewFrame = NS_NewBlockFrame(mPresShell, styleContext); } return ConstructBlock(aState, aDisplay, aItem.mContent, aState.GetGeometricParent(aDisplay, aParentFrame), aParentFrame, styleContext, aNewFrame, diff --git a/layout/generic/nsFrame.cpp b/layout/generic/nsFrame.cpp --- a/layout/generic/nsFrame.cpp +++ b/layout/generic/nsFrame.cpp @@ -1052,45 +1052,65 @@ static PRBool ApplyAbsPosClipping(nsDisp *aRect += aBuilder->ToReferenceFrame(aFrame); return PR_TRUE; } /** * Returns PR_TRUE if aFrame is overflow:hidden and we should interpret * that as -moz-hidden-unscrollable. */ -static PRBool ApplyOverflowHiddenClipping(nsIFrame* aFrame, - const nsStyleDisplay* aDisp) +static inline PRBool ApplyOverflowHiddenClipping(nsIFrame* aFrame, + const nsStyleDisplay* aDisp) { if (aDisp->mOverflowX != NS_STYLE_OVERFLOW_HIDDEN) return PR_FALSE; nsIAtom* type = aFrame->GetType(); // REVIEW: these are the frame types that call IsTableClip and set up // clipping. Actually there were also table rows and the inner table frame // doing this, but 'overflow' isn't applicable to them according to // CSS 2.1 so I removed them. Also, we used to clip at tableOuterFrame // but we should actually clip at tableFrame (as per discussion with Hixie and // bz). return type == nsGkAtoms::tableFrame || type == nsGkAtoms::tableCellFrame || type == nsGkAtoms::bcTableCellFrame; } +static inline PRBool ApplyPaginatedOverflowClipping(nsIFrame* aFrame, + const nsStyleDisplay* aDisp) +{ + // These conditions on aDisp need to match the conditions for which in + // non-paginated contexts we'd create a scrollframe for a block but in a + // paginated context we don't. See nsCSSFrameConstructor::FindDisplayData + // for the relevant conditions. These conditions must also match those in + // nsCSSFrameConstructor::ConstructNonScrollableBlock for creating block + // formatting context roots for forced-to-be-no-longer scrollable blocks in + // paginated contexts. + return + aFrame->PresContext()->IsPaginated() && + aDisp->IsBlockInside() && + aDisp->IsScrollableOverflow() && + aDisp->IsBlockOutside() && + aFrame->GetType() == nsGkAtoms::blockFrame; +} + static PRBool ApplyOverflowClipping(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, const nsStyleDisplay* aDisp, nsRect* aRect) { // REVIEW: from nsContainerFrame.cpp SyncFrameViewGeometryDependentProperties, // except that that function used the border-edge for // -moz-hidden-unscrollable which I don't think is correct... Also I've // changed -moz-hidden-unscrollable to apply to any kind of frame. // Only -moz-hidden-unscrollable is handled here (and 'hidden' for table - // frames). Other overflow clipping is applied by nsHTML/XULScrollFrame. - if (!ApplyOverflowHiddenClipping(aFrame, aDisp)) { + // frames, and any non-visible value for blocks in a paginated context). + // Other overflow clipping is applied by nsHTML/XULScrollFrame. + if (!ApplyOverflowHiddenClipping(aFrame, aDisp) && + !ApplyPaginatedOverflowClipping(aFrame, aDisp)) { PRBool clip = aDisp->mOverflowX == NS_STYLE_OVERFLOW_CLIP; if (!clip) return PR_FALSE; // We allow -moz-hidden-unscrollable to apply to any kind of frame. This // is required by comboboxes which make their display text (an inline frame) // have clipping. } diff --git a/layout/reftests/printing/129941-1-ref.html b/layout/reftests/printing/129941-1-ref.html new file mode 100644 --- /dev/null +++ b/layout/reftests/printing/129941-1-ref.html @@ -0,0 +1,8 @@ + + + +
+
+
+ + diff --git a/layout/reftests/printing/129941-1a.html b/layout/reftests/printing/129941-1a.html new file mode 100644 --- /dev/null +++ b/layout/reftests/printing/129941-1a.html @@ -0,0 +1,8 @@ + + + +
+
+
+ + diff --git a/layout/reftests/printing/129941-1b.html b/layout/reftests/printing/129941-1b.html new file mode 100644 --- /dev/null +++ b/layout/reftests/printing/129941-1b.html @@ -0,0 +1,8 @@ + + + +
+
+
+ + diff --git a/layout/reftests/printing/reftest.list b/layout/reftests/printing/reftest.list --- a/layout/reftests/printing/reftest.list +++ b/layout/reftests/printing/reftest.list @@ -2,8 +2,10 @@ == blank.html blank.html # Bugs == 272830-1.html 272830-1-ref.html == 318022-1.html 318022-1-ref.html == 403669-1.html 403669-1-ref.html == 381497-n.html 381497-f.html == test-async-print.html 272830-1-ref.html +== 129941-1a.html 129941-1-ref.html +== 129941-1b.html 129941-1-ref.html