diff --git a/content/html/style/src/nsHTMLStyleSheet.cpp b/content/html/style/src/nsHTMLStyleSheet.cpp
index 897aa7d071a4..4b7623917aa7 100644
--- a/content/html/style/src/nsHTMLStyleSheet.cpp
+++ b/content/html/style/src/nsHTMLStyleSheet.cpp
@@ -325,6 +325,8 @@ protected:
nsIFrame* aParentFrame,
nsIFrame*& aFrame);
+ PRBool IsScrollable(nsIFrame* aFrame, const nsStyleDisplay* aDisplay);
+
protected:
PRUint32 mInHeap : 1;
PRUint32 mRefCnt : 31;
@@ -1351,6 +1353,28 @@ HTMLStyleSheetImpl::ConstructFrameByDisplayType(nsIPresContext* aPresContext,
return rv;
}
+PRBool
+HTMLStyleSheetImpl::IsScrollable(nsIFrame* aFrame,
+ const nsStyleDisplay* aDisplay)
+{
+ // If the overflow property is scroll then it's scrollable regardless
+ // of whether the content overflows the block.
+ // XXX This isn't correct. Only do this if the height is not allowed to
+ // grow to accomodate its child frames...
+ if (NS_STYLE_OVERFLOW_SCROLL == aDisplay->mOverflow) {
+ return PR_TRUE;
+ }
+
+#if 0
+ if ((NS_STYLE_OVERFLOW_SCROLL == aDisplay->mOverflow) ||
+ // If the element has a fixed height (it isn't auto) and an overflow
+ // property of scroll or auto, then it's potentially scrollable.
+ // XXX Deal with width considerations, too
+ (NS_STYLE_OVERFLOW_AUTO == aDisplay->mOverflow)) {
+#endif
+ return PR_FALSE;
+}
+
NS_IMETHODIMP
HTMLStyleSheetImpl::ConstructFrame(nsIPresContext* aPresContext,
nsIContent* aContent,
@@ -1406,20 +1430,32 @@ HTMLStyleSheetImpl::ConstructFrame(nsIPresContext* aPresContext,
}
-#if 0
- // If the frame is a block-level frame and it has a fixed height and overflow
- // property of scroll, then wrap it in a scroll frame.
- // XXX Deal with replaced elements and overflow of auto and width, too
- nsIFrame* kidFrame = nsnull;
- nsresult rv;
- if ((NS_STYLE_OVERFLOW_SCROLL == kidDisplay->mOverflow) ||
- (NS_STYLE_OVERFLOW_AUTO == kidDisplay->mOverflow)) {
- rv = NS_NewScrollFrame(&kidFrame, aKid, aParentFrame);
- if (NS_OK == rv) {
- kidFrame->SetStyleContext(aPresContext, kidSC);
+ // If the frame is a block-level frame and is scrollable then wrap it
+ // in a scroll frame.
+ // XXX Applies to replaced elements, too, but how to tell if the element
+ // is replaced?
+ if (nsnull != aFrameSubTree) {
+ if (display->IsBlockLevel() && IsScrollable(aFrameSubTree, display)) {
+ nsIFrame* scrollFrame;
+
+ if NS_SUCCEEDED(NS_NewScrollFrame(aContent, aParentFrame, scrollFrame)) {
+ // The scroll frame gets the original style context, and the scrolled
+ // frame gets a pseudo style context.
+ // XXX Is this the best way to do this?
+ scrollFrame->SetStyleContext(aPresContext, styleContext);
+
+ nsIStyleContext* pseudoStyle;
+ pseudoStyle = aPresContext->ResolvePseudoStyleContextFor(nsHTMLAtoms::columnPseudo,
+ scrollFrame);
+ aFrameSubTree->SetStyleContext(aPresContext, pseudoStyle);
+ NS_RELEASE(pseudoStyle);
+
+ // Initialize the scroll frame
+ scrollFrame->Init(*aPresContext, aFrameSubTree);
+ aFrameSubTree = scrollFrame;
+ }
}
}
-#endif
}
}
NS_RELEASE(styleContext);
diff --git a/layout/generic/nsHTMLContainerFrame.cpp b/layout/generic/nsHTMLContainerFrame.cpp
index a6e5c441a73e..f42c5ba15b9b 100644
--- a/layout/generic/nsHTMLContainerFrame.cpp
+++ b/layout/generic/nsHTMLContainerFrame.cpp
@@ -35,7 +35,6 @@
#include "nsPlaceholderFrame.h"
#include "nsIHTMLContent.h"
#include "nsHTMLParts.h"
-#include "nsScrollFrame.h"
#include "nsIView.h"
#include "nsIViewManager.h"
#include "nsViewsCID.h"
diff --git a/layout/generic/nsHTMLParts.h b/layout/generic/nsHTMLParts.h
index fdcbde9af902..c41b9f00bc8c 100644
--- a/layout/generic/nsHTMLParts.h
+++ b/layout/generic/nsHTMLParts.h
@@ -303,6 +303,10 @@ nsresult
NS_NewWBRFrame(nsIContent* aContent, nsIFrame* aParentFrame,
nsIFrame*& aResult);
+extern nsresult
+NS_NewScrollFrame(nsIContent* aContent, nsIFrame* aParentFrame,
+ nsIFrame*& aResult);
+
// forms
extern nsresult
NS_NewFormFrame(nsIContent* aContent, nsIFrame* aParentFrame,
diff --git a/layout/html/base/src/nsHTMLContainerFrame.cpp b/layout/html/base/src/nsHTMLContainerFrame.cpp
index a6e5c441a73e..f42c5ba15b9b 100644
--- a/layout/html/base/src/nsHTMLContainerFrame.cpp
+++ b/layout/html/base/src/nsHTMLContainerFrame.cpp
@@ -35,7 +35,6 @@
#include "nsPlaceholderFrame.h"
#include "nsIHTMLContent.h"
#include "nsHTMLParts.h"
-#include "nsScrollFrame.h"
#include "nsIView.h"
#include "nsIViewManager.h"
#include "nsViewsCID.h"
diff --git a/layout/html/base/src/nsHTMLParts.h b/layout/html/base/src/nsHTMLParts.h
index fdcbde9af902..c41b9f00bc8c 100644
--- a/layout/html/base/src/nsHTMLParts.h
+++ b/layout/html/base/src/nsHTMLParts.h
@@ -303,6 +303,10 @@ nsresult
NS_NewWBRFrame(nsIContent* aContent, nsIFrame* aParentFrame,
nsIFrame*& aResult);
+extern nsresult
+NS_NewScrollFrame(nsIContent* aContent, nsIFrame* aParentFrame,
+ nsIFrame*& aResult);
+
// forms
extern nsresult
NS_NewFormFrame(nsIContent* aContent, nsIFrame* aParentFrame,
diff --git a/layout/html/base/src/nsScrollFrame.cpp b/layout/html/base/src/nsScrollFrame.cpp
index 85d13189e97f..3012faa1a14a 100644
--- a/layout/html/base/src/nsScrollFrame.cpp
+++ b/layout/html/base/src/nsScrollFrame.cpp
@@ -15,7 +15,6 @@
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
-#include "nsScrollFrame.h"
#include "nsIPresContext.h"
#include "nsIStyleContext.h"
#include "nsIReflowCommand.h"
@@ -27,264 +26,123 @@
#include "nsBodyFrame.h"
#include "nsHTMLContainerFrame.h"
#include "nsHTMLIIDs.h"
+#include "nsCSSRendering.h"
+#include "nsIScrollableView.h"
+#include "nsWidgetsCID.h"
-#include "nsBodyFrame.h"
+static NS_DEFINE_IID(kScrollViewIID, NS_ISCROLLABLEVIEW_IID);
+static NS_DEFINE_IID(kWidgetCID, NS_CHILD_CID);
-class nsScrollBodyFrame : public nsContainerFrame {
+//----------------------------------------------------------------------
+
+class nsScrollViewFrame : public nsHTMLContainerFrame {
public:
- nsScrollBodyFrame(nsIContent* aContent, nsIFrame* aParent);
+ nsScrollViewFrame(nsIContent* aContent, nsIFrame* aParent);
+ NS_IMETHOD Init(nsIPresContext& aPresContext, nsIFrame* aChildList);
+
NS_IMETHOD Reflow(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
const nsHTMLReflowState& aReflowState,
nsReflowStatus& aStatus);
- NS_IMETHOD Paint(nsIPresContext& aPresContext,
- nsIRenderingContext& aRenderingContext,
- const nsRect& aDirtyRect);
-
NS_IMETHOD ListTag(FILE* out = stdout) const;
protected:
- void CreateFirstChild(nsIPresContext* aPresContext);
+ virtual PRIntn GetSkipSides() const;
};
-nsScrollBodyFrame::nsScrollBodyFrame(nsIContent* aContent, nsIFrame* aParent)
- : nsContainerFrame(aContent, aParent)
+nsScrollViewFrame::nsScrollViewFrame(nsIContent* aContent, nsIFrame* aParent)
+ : nsHTMLContainerFrame(aContent, aParent)
{
}
-void
-nsScrollBodyFrame::CreateFirstChild(nsIPresContext* aPresContext)
-{
- // Are we paginated?
- if (aPresContext->IsPaginated()) {
- // Yes. Create the first page frame
- mFirstChild = new nsPageFrame(mContent, this);/* XXX mContent won't work here */
- } else {
- if (nsnull != mContent) {
-#if 0
- // Create a frame for the child we are wrapping up
- nsIContentDelegate* cd = mContent->GetDelegate(aPresContext);
- if (nsnull != cd) {
- nsIStyleContext* kidStyleContext =
- aPresContext->ResolveStyleContextFor(mContent, this);
- nsresult rv = cd->CreateFrame(aPresContext, mContent, this,
- kidStyleContext, mFirstChild);
- NS_RELEASE(kidStyleContext);
- if (NS_OK == rv) {
- mChildCount = 1;
- mLastContentOffset = mFirstContentOffset;
- }
- NS_RELEASE(cd);
- }
-#else
- nsBodyFrame::NewFrame(&mFirstChild, mContent, this);
-#endif
- }
- }
-}
-
-// XXX Hack
-#define PAGE_SPACING 100
-
NS_IMETHODIMP
-nsScrollBodyFrame::Reflow(nsIPresContext& aPresContext,
+nsScrollViewFrame::Init(nsIPresContext& aPresContext, nsIFrame* aChildList)
+{
+ mFirstChild = aChildList;
+
+ // XXX Unless it's already a body frame, child frames that are containers
+ // need to be wrapped in a body frame
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsScrollViewFrame::Reflow(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
const nsHTMLReflowState& aReflowState,
nsReflowStatus& aStatus)
{
- nsHTMLContainerFrame::CreateViewForFrame(aPresContext, this,
- nsnull, PR_TRUE);
-
NS_FRAME_TRACE_MSG(NS_FRAME_TRACE_CALLS,
- ("enter nsScrollBodyFrame::Reflow: maxSize=%d,%d",
+ ("enter nsScrollViewFrame::Reflow: maxSize=%d,%d",
aReflowState.maxSize.width,
aReflowState.maxSize.height));
- aStatus = NS_FRAME_COMPLETE;
+ // Create a view
+ if (eReflowReason_Initial == aReflowState.reason) {
+ // XXX It would be nice if we could do this sort of thing in our Init()
+ // member function instead of here...
+ nsHTMLContainerFrame::CreateViewForFrame(aPresContext, this,
+ nsnull, PR_TRUE);
+ }
- // XXX Incremental reflow code doesn't handle page mode at all...
- if (eReflowReason_Incremental == aReflowState.reason) {
- // We don't expect the target of the reflow command to be the root
- // content frame
-#ifdef NS_DEBUG
- nsIFrame* target;
- aReflowState.reflowCommand->GetTarget(target);
- NS_ASSERTION(target != this, "root content frame is reflow command target");
-#endif
-
- // Verify the next frame in the reflow chain is our child frame
- nsIFrame* next;
- aReflowState.reflowCommand->GetNext(next);
- NS_ASSERTION(next == mFirstChild, "unexpected next reflow command frame");
+ // Scroll frame handles the border, and we handle the padding and background
+ const nsStyleSpacing* spacing = (const nsStyleSpacing*)
+ mStyleContext->GetStyleData(eStyleStruct_Spacing);
+ nsMargin padding;
+ spacing->CalcPaddingFor(this, padding);
- nsSize maxSize(aReflowState.maxSize.width, NS_UNCONSTRAINEDSIZE);
- nsHTMLReflowState kidReflowState(aPresContext, next, aReflowState, maxSize);
- nsIHTMLReflow* htmlReflow;
-
- if (NS_OK == mFirstChild->QueryInterface(kIHTMLReflowIID, (void**)&htmlReflow)) {
- // Dispatch the reflow command to our child frame. Allow it to be as high
- // as it wants
- ReflowChild(mFirstChild, aPresContext, aDesiredSize, kidReflowState, aStatus);
-
- // Place and size the child. Make sure the child is at least as
- // tall as our max size (the containing window)
- if (aDesiredSize.height < aReflowState.maxSize.height) {
- aDesiredSize.height = aReflowState.maxSize.height;
- }
-
- nsRect rect(0, 0, aDesiredSize.width, aDesiredSize.height);
- mFirstChild->SetRect(rect);
- // XXX Why are we sending a DidReflow() notification here?
- htmlReflow->DidReflow(aPresContext, NS_FRAME_REFLOW_FINISHED);
- }
+ // Allow the child frame to be as wide as our max width (minus scrollbar
+ // width and padding), and as high as it wants to be.
+ nsSize maxSize;
+ nsIDeviceContext* dc = aPresContext.GetDeviceContext();
+ float sbWidth, sbHeight;
- } else {
- // Do we have any children?
- if (nsnull == mFirstChild) {
- // No, create the first child frame
- CreateFirstChild(&aPresContext);
- }
+ dc->GetScrollBarDimensions(sbWidth, sbHeight);
+ maxSize.width = aReflowState.maxSize.width - NSToCoordRound(sbWidth) -
+ (padding.left + padding.right);
+ NS_RELEASE(dc);
+ maxSize.height = NS_UNCONSTRAINEDSIZE;
- // Resize our frames
- if (nsnull != mFirstChild) {
- if (aPresContext.IsPaginated()) {
- nscoord y = PAGE_SPACING;
- nsHTMLReflowMetrics kidSize(aDesiredSize.maxElementSize);
- nsSize pageSize(aPresContext.GetPageWidth(),
- aPresContext.GetPageHeight());
-
- // Tile the pages vertically
- for (nsIFrame* kidFrame = mFirstChild; nsnull != kidFrame; ) {
- // Reflow the page
- nsHTMLReflowState kidReflowState(aPresContext, kidFrame, aReflowState, pageSize);
- nsReflowStatus status;
+ // Reflow the child
+ nsHTMLReflowMetrics kidMetrics(aDesiredSize.maxElementSize);
+ nsHTMLReflowState kidReflowState(aPresContext, mFirstChild, aReflowState, maxSize);
- // Place and size the page. If the page is narrower than our
- // max width then center it horizontally
- nsIDeviceContext *dx = aPresContext.GetDeviceContext();
- float sbWidth, sbHeight;
- dx->GetScrollBarDimensions(sbWidth, sbHeight);
- nscoord extra = aReflowState.maxSize.width - kidSize.width -
- NSToCoordRound(sbWidth);
- NS_RELEASE(dx);
- nscoord x = extra > 0 ? extra / 2 : 0;
- nsIHTMLReflow* htmlReflow;
+ ReflowChild(mFirstChild, aPresContext, kidMetrics, kidReflowState, aStatus);
+ NS_ASSERTION(NS_FRAME_IS_COMPLETE(aStatus), "bad status");
+
+ // Place and size the child
+ nsRect rect(padding.left, padding.top, kidMetrics.width, kidMetrics.height);
+ mFirstChild->SetRect(rect);
- if (NS_OK == kidFrame->QueryInterface(kIHTMLReflowIID, (void**)&htmlReflow)) {
- htmlReflow->WillReflow(aPresContext);
- ReflowChild(kidFrame, aPresContext, kidSize, kidReflowState, status);
-
- kidFrame->SetRect(nsRect(x, y, kidSize.width, kidSize.height));
- htmlReflow->DidReflow(aPresContext, NS_FRAME_REFLOW_FINISHED);
- y += kidSize.height;
-
- // Leave a slight gap between the pages
- y += PAGE_SPACING;
-
- // Is the page complete?
- nsIFrame* kidNextInFlow;
-
- kidFrame->GetNextInFlow(kidNextInFlow);
- if (NS_FRAME_IS_COMPLETE(status)) {
- NS_ASSERTION(nsnull == kidNextInFlow, "bad child flow list");
- } else if (nsnull == kidNextInFlow) {
- // The page isn't complete and it doesn't have a next-in-flow so
- // create a continuing page
- nsIStyleContext* kidSC;
- kidFrame->GetStyleContext(&aPresContext, kidSC);
- nsIFrame* continuingPage;
- nsresult rv = kidFrame->CreateContinuingFrame(aPresContext, this,
- kidSC, continuingPage);
- NS_RELEASE(kidSC);
-
- // Add it to our child list
- #ifdef NS_DEBUG
- nsIFrame* kidNextSibling;
-
- kidFrame->GetNextSibling(kidNextSibling);
- NS_ASSERTION(nsnull == kidNextSibling, "unexpected sibling");
- #endif
- kidFrame->SetNextSibling(continuingPage);
- }
- }
-
- // Get the next page
- kidFrame->GetNextSibling(kidFrame);
- }
-
- // Return our desired size
- aDesiredSize.width = aReflowState.maxSize.width;
- aDesiredSize.height = y;
-
- } else {
- // Allow the frame to be as wide as our max width, and as high
- // as it wants to be.
- nsSize maxSize(aReflowState.maxSize.width, NS_UNCONSTRAINEDSIZE);
- nsHTMLReflowState kidReflowState(aPresContext, mFirstChild, aReflowState, maxSize);
- nsIHTMLReflow* htmlReflow;
-
- if (NS_OK == mFirstChild->QueryInterface(kIHTMLReflowIID, (void**)&htmlReflow)) {
- // Get the child's desired size. Our child's desired height is our
- // desired size
- htmlReflow->WillReflow(aPresContext);
- ReflowChild(mFirstChild, aPresContext, aDesiredSize, kidReflowState, aStatus);
- NS_ASSERTION(NS_FRAME_IS_COMPLETE(aStatus), "bad status");
-
-#if 0
- // Place and size the child. Make sure the child is at least as
- // tall as our max size (the containing window)
- if (aDesiredSize.height < aReflowState.maxSize.height) {
- aDesiredSize.height = aReflowState.maxSize.height;
- }
-#endif
-
- // Place and size the child
- nsRect rect(0, 0, aDesiredSize.width, aDesiredSize.height);
- mFirstChild->SetRect(rect);
- htmlReflow->DidReflow(aPresContext, NS_FRAME_REFLOW_FINISHED);
- }
- }
- }
- else {
- aDesiredSize.width = aReflowState.maxSize.width;
- aDesiredSize.height = 1;
- aDesiredSize.ascent = aDesiredSize.height;
- aDesiredSize.descent = 0;
- if (nsnull != aDesiredSize.maxElementSize) {
- aDesiredSize.maxElementSize->width = 0;
- aDesiredSize.maxElementSize->height = 0;
- }
- }
+ // Determine our size. Our width is our maxWidth and our height is the max
+ // of our child's height plus padding and our maxHeight (if our maxHeight is
+ // constrained).
+ aDesiredSize.width = aReflowState.maxSize.width;
+ if (NS_UNCONSTRAINEDSIZE == aReflowState.maxSize.height) {
+ aDesiredSize.height = kidMetrics.height + padding.top + padding.bottom;
+ }
+ else {
+ aDesiredSize.height = aReflowState.maxSize.height;
}
NS_FRAME_TRACE_MSG(NS_FRAME_TRACE_CALLS,
- ("exit nsScrollBodyFrame::Reflow: status=%d width=%d height=%d",
- aStatus, aDesiredSize.width, aDesiredSize.height));
+ ("exit nsScrollViewFrame::Reflow: status=%d width=%d height=%d",
+ aStatus, aDesiredSize.width, aDesiredSize.height));
return NS_OK;
}
-NS_IMETHODIMP
-nsScrollBodyFrame::Paint(nsIPresContext& aPresContext,
- nsIRenderingContext& aRenderingContext,
- const nsRect& aDirtyRect)
+PRIntn
+nsScrollViewFrame::GetSkipSides() const
{
- // If we're paginated then fill the dirty rect with white
- if (aPresContext.IsPaginated()) {
- // Cross hatching would be nicer...
- aRenderingContext.SetColor(NS_RGB(255,255,255));
- aRenderingContext.FillRect(aDirtyRect);
- }
-
- nsContainerFrame::Paint(aPresContext, aRenderingContext, aDirtyRect);
- return NS_OK;
+ // Scroll frame handles the border...
+ return 0xF;
}
NS_IMETHODIMP
-nsScrollBodyFrame::ListTag(FILE* out) const
+nsScrollViewFrame::ListTag(FILE* out) const
{
- fputs("*scrollbodyframe<", out);
+ fputs("*scrollviewframe<", out);
nsIAtom* atom;
mContent->GetTag(atom);
if (nsnull != atom) {
@@ -299,36 +157,70 @@ nsScrollBodyFrame::ListTag(FILE* out) const
//----------------------------------------------------------------------
-class nsScrollInnerFrame : public nsContainerFrame {
+/**
+ * The scrolling view frame creates and manages the scrolling view.
+ * It creates a nsScrollViewFrame which handles padding and rendering
+ * of the background.
+ */
+class nsScrollingViewFrame : public nsHTMLContainerFrame {
public:
- nsScrollInnerFrame(nsIContent* aContent, nsIFrame* aParent);
+ nsScrollingViewFrame(nsIContent* aContent, nsIFrame* aParent);
+
+ NS_IMETHOD Init(nsIPresContext& aPresContext, nsIFrame* aChildList);
NS_IMETHOD Reflow(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
const nsHTMLReflowState& aReflowState,
nsReflowStatus& aStatus);
+ NS_IMETHOD Paint(nsIPresContext& aPresContext,
+ nsIRenderingContext& aRenderingContext,
+ const nsRect& aDirtyRect);
+
NS_IMETHOD ListTag(FILE* out = stdout) const;
protected:
+ virtual PRIntn GetSkipSides() const;
};
-nsScrollInnerFrame::nsScrollInnerFrame(nsIContent* aContent, nsIFrame* aParent)
- : nsContainerFrame(aContent, aParent)
+nsScrollingViewFrame::nsScrollingViewFrame(nsIContent* aContent, nsIFrame* aParent)
+ : nsHTMLContainerFrame(aContent, aParent)
{
}
NS_IMETHODIMP
-nsScrollInnerFrame::Reflow(nsIPresContext& aPresContext,
- nsHTMLReflowMetrics& aDesiredSize,
- const nsHTMLReflowState& aReflowState,
- nsReflowStatus& aStatus)
+nsScrollingViewFrame::Init(nsIPresContext& aPresContext, nsIFrame* aChildList)
+{
+ // Create a scroll view frame
+ mFirstChild = new nsScrollViewFrame(mContent, this);
+ if (nsnull == mFirstChild) {
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+ // Have it use our style context
+ mFirstChild->SetStyleContext(&aPresContext, mStyleContext);
+
+ // Reset the child frame's geometric and content parent to be
+ // the scroll view frame
+ aChildList->SetGeometricParent(mFirstChild);
+ aChildList->SetContentParent(mFirstChild);
+
+ // Init the scroll view frame passing it the child list
+ return mFirstChild->Init(aPresContext, aChildList);
+}
+
+//XXX incremental reflow pass through
+NS_IMETHODIMP
+nsScrollingViewFrame::Reflow(nsIPresContext& aPresContext,
+ nsHTMLReflowMetrics& aDesiredSize,
+ const nsHTMLReflowState& aReflowState,
+ nsReflowStatus& aStatus)
{
NS_FRAME_TRACE_MSG(NS_FRAME_TRACE_CALLS,
- ("enter nsScrollInnerFrame::Reflow: maxSize=%d,%d",
+ ("enter nsScrollingViewFrame::Reflow: maxSize=%d,%d",
aReflowState.maxSize.width,
aReflowState.maxSize.height));
+ // Make sure we have a scrolling view
nsIView* view;
GetView(view);
if (nsnull == view) {
@@ -350,77 +242,75 @@ nsScrollInnerFrame::Reflow(nsIPresContext& aPresContext,
nsnull,
kIViewIID,
(void **)&view);
+ // XXX We want the scrolling view to have a widget to clip any child
+ // widgets that aren't visible, e.g. form elements, but there's currently
+ // a bug which is why it's commented out
if ((NS_OK != rv) || (NS_OK != view->Init(viewManager,
mRect,
- parentView))) {
+ parentView,
+ nsnull))) {
+ // &kWidgetCID))) {
NS_RELEASE(viewManager);
return rv;
}
// Insert new view as a child of the parent view
viewManager->InsertChild(parentView, view, 0);
- NS_RELEASE(viewManager);
-
- // NS_RELEASE(parentView);
SetView(view);
+ NS_RELEASE(viewManager);
}
if (nsnull == view) {
return NS_OK;
}
- // NS_RELEASE(view);
- if (nsnull == mFirstChild) {
- mFirstChild = new nsScrollBodyFrame(mContent, this);
- }
+ // Reflow the child and get its desired size. Let the child's height be
+ // whatever it wants
+ nsHTMLReflowState kidReflowState(aPresContext, mFirstChild, aReflowState,
+ nsSize(aReflowState.maxSize.width, NS_UNCONSTRAINEDSIZE));
- // Allow the child frame to be as wide as our max width (minus a
- // scroll bar width), and as high as it wants to be.
- nsSize maxSize;
- nsIDeviceContext* dc = aPresContext.GetDeviceContext();
- float sbWidth, sbHeight;
- dc->GetScrollBarDimensions(sbWidth, sbHeight);
- maxSize.width = aReflowState.maxSize.width - NSToCoordRound(sbWidth);
- NS_RELEASE(dc);
- maxSize.height = NS_UNCONSTRAINEDSIZE;
+ ReflowChild(mFirstChild, aPresContext, aDesiredSize, kidReflowState, aStatus);
+ NS_ASSERTION(NS_FRAME_IS_COMPLETE(aStatus), "bad status");
- // Reflow the child
- nsHTMLReflowMetrics kidMetrics(aDesiredSize.maxElementSize);
+ // Place and size the child
+ nsRect rect(0, 0, aDesiredSize.width, aDesiredSize.height);
+ mFirstChild->SetRect(rect);
- nsHTMLReflowState kidReflowState(aPresContext, mFirstChild, aReflowState, maxSize);
- nsIHTMLReflow* htmlReflow;
-
- if (NS_OK == mFirstChild->QueryInterface(kIHTMLReflowIID, (void**)&htmlReflow)) {
- htmlReflow->WillReflow(aPresContext);
- ReflowChild(mFirstChild, aPresContext, kidMetrics, kidReflowState, aStatus);
- NS_ASSERTION(NS_FRAME_IS_COMPLETE(aStatus), "bad status");
-
- // Place and size the child
- nsRect rect(0, 0, kidMetrics.width, kidMetrics.height);
- mFirstChild->SetRect(rect);
- htmlReflow->DidReflow(aPresContext, NS_FRAME_REFLOW_FINISHED);
+ // The scroll view frame either shrink wraps around it's single
+ // child OR uses the style width/height.
+ if (aReflowState.HaveConstrainedWidth()) {
+ aDesiredSize.width = aReflowState.minWidth;
}
-
- // Determine our size. Our width is our maxWidth and our height is
- // either our child's height or our maxHeight if our maxHeight is
- // constrained.
- aDesiredSize.width = aReflowState.maxSize.width;
- if (NS_UNCONSTRAINEDSIZE == aReflowState.maxSize.height) {
- aDesiredSize.height = kidMetrics.height;
- }
- else {
- aDesiredSize.height = aReflowState.maxSize.height;
+ if (aReflowState.HaveConstrainedHeight()) {
+ aDesiredSize.height = aReflowState.minHeight;
}
+ aDesiredSize.ascent = aDesiredSize.height;
+ aDesiredSize.descent = 0;
NS_FRAME_TRACE_MSG(NS_FRAME_TRACE_CALLS,
- ("exit nsScrollInnerFrame::Reflow: status=%d width=%d height=%d",
+ ("exit nsScrollingViewFrame::Reflow: status=%d width=%d height=%d",
aStatus, aDesiredSize.width, aDesiredSize.height));
return NS_OK;
}
NS_IMETHODIMP
-nsScrollInnerFrame::ListTag(FILE* out) const
+nsScrollingViewFrame::Paint(nsIPresContext& aPresContext,
+ nsIRenderingContext& aRenderingContext,
+ const nsRect& aDirtyRect)
{
- fputs("*scrollinnerframe<", out);
+ // Paint our children
+ return nsContainerFrame::Paint(aPresContext, aRenderingContext, aDirtyRect);
+}
+
+PRIntn
+nsScrollingViewFrame::GetSkipSides() const
+{
+ return 0;
+}
+
+NS_IMETHODIMP
+nsScrollingViewFrame::ListTag(FILE* out) const
+{
+ fputs("*scrollingviewframe<", out);
nsIAtom* atom;
mContent->GetTag(atom);
if (nsnull != atom) {
@@ -435,108 +325,160 @@ nsScrollInnerFrame::ListTag(FILE* out) const
//----------------------------------------------------------------------
-class nsScrollOuterFrame : public nsHTMLContainerFrame {
+/**
+ * The scroll frame basically acts as a border frame. It leaves room for and
+ * renders the border. It creates a nsScrollingViewFrame which creates and
+ * manages the scrollable view.
+ */
+class nsScrollFrame : public nsHTMLContainerFrame {
public:
- nsScrollOuterFrame(nsIContent* aContent, nsIFrame* aParent);
+ nsScrollFrame(nsIContent* aContent, nsIFrame* aParent);
+
+ NS_IMETHOD Init(nsIPresContext& aPresContext, nsIFrame* aChildList);
NS_IMETHOD Reflow(nsIPresContext& aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
const nsHTMLReflowState& aReflowState,
nsReflowStatus& aStatus);
+ NS_IMETHOD Paint(nsIPresContext& aPresContext,
+ nsIRenderingContext& aRenderingContext,
+ const nsRect& aDirtyRect);
+
NS_IMETHOD ListTag(FILE* out = stdout) const;
protected:
virtual PRIntn GetSkipSides() const;
};
-nsScrollOuterFrame::nsScrollOuterFrame(nsIContent* aContent, nsIFrame* aParent)
+nsScrollFrame::nsScrollFrame(nsIContent* aContent, nsIFrame* aParent)
: nsHTMLContainerFrame(aContent, aParent)
{
}
+NS_IMETHODIMP
+nsScrollFrame::Init(nsIPresContext& aPresContext, nsIFrame* aChildList)
+{
+ NS_PRECONDITION(nsnull != aChildList, "no child frame");
+
+ // Create a scrolling view frame
+ mFirstChild = new nsScrollingViewFrame(mContent, this);
+ if (nsnull == mFirstChild) {
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+ // Have it use our style context
+ mFirstChild->SetStyleContext(&aPresContext, mStyleContext);
+
+ // Reset the child frame's geometric and content parent to be
+ // the scrolling view frame
+#ifdef NS_DEBUG
+ // Verify that there's only one child frame
+ nsIFrame* nextSibling;
+ aChildList->GetNextSibling(nextSibling);
+ NS_ASSERTION(nsnull == nextSibling, "expected only one child");
+#endif
+ aChildList->SetGeometricParent(mFirstChild);
+ aChildList->SetContentParent(mFirstChild);
+
+ // Init the scrollable view frame passing it the child list
+ return mFirstChild->Init(aPresContext, aChildList);
+}
+
//XXX incremental reflow pass through
NS_IMETHODIMP
-nsScrollOuterFrame::Reflow(nsIPresContext& aPresContext,
- nsHTMLReflowMetrics& aDesiredSize,
- const nsHTMLReflowState& aReflowState,
- nsReflowStatus& aStatus)
+nsScrollFrame::Reflow(nsIPresContext& aPresContext,
+ nsHTMLReflowMetrics& aDesiredSize,
+ const nsHTMLReflowState& aReflowState,
+ nsReflowStatus& aStatus)
{
NS_FRAME_TRACE_MSG(NS_FRAME_TRACE_CALLS,
- ("enter nsScrollOuterFrame::Reflow: maxSize=%d,%d",
+ ("enter nsScrollFrame::Reflow: maxSize=%d,%d",
aReflowState.maxSize.width,
aReflowState.maxSize.height));
- if (nsnull == mFirstChild) {
- mFirstChild = new nsScrollInnerFrame(mContent, this);
- }
-
+ // We handle the border only
const nsStyleSpacing* spacing = (const nsStyleSpacing*)
mStyleContext->GetStyleData(eStyleStruct_Spacing);
- nsMargin borderPadding;
- spacing->CalcBorderPaddingFor(this, borderPadding);
- nscoord lr = borderPadding.left + borderPadding.right;
- nscoord tb = borderPadding.top + borderPadding.bottom;
+ nsMargin border;
+ spacing->CalcBorderFor(this, border);
+ nscoord lr = border.left + border.right;
+ nscoord tb = border.top + border.bottom;
- // Get style size and determine how much area is available for the
- // child (the scroll inner frame) to layout into.
- nsSize maxSize;
+ // Compute the scrolling view frame's max size taking into account our
+ // borders
+ nsSize kidMaxSize;
if (aReflowState.HaveConstrainedWidth()) {
- maxSize.width = aReflowState.minWidth - lr;
+ // This value reflects space for the content area only, so don't
+ // subtract for borders...
+ kidMaxSize.width = aReflowState.minWidth;
}
else {
- maxSize.width = aReflowState.maxSize.width;
+ kidMaxSize.width = aReflowState.maxSize.width;
+ if (NS_UNCONSTRAINEDSIZE != kidMaxSize.width) {
+ kidMaxSize.width -= lr;
+ }
}
if (aReflowState.HaveConstrainedHeight()) {
- maxSize.height = aReflowState.minHeight - tb;
+ // This value reflects space for the content area only, so don't
+ // subtract for borders...
+ kidMaxSize.height = aReflowState.minHeight;
}
else {
- maxSize.height = NS_UNCONSTRAINEDSIZE;
+ kidMaxSize.height = NS_UNCONSTRAINEDSIZE;
+ if (NS_UNCONSTRAINEDSIZE != kidMaxSize.height) {
+ kidMaxSize.height -= tb;
+ }
}
-
+
// Reflow the child and get its desired size
- nsHTMLReflowState kidReflowState(aPresContext, mFirstChild, aReflowState, maxSize);
- nsIHTMLReflow* htmlReflow;
+ nsHTMLReflowState kidReflowState(aPresContext, mFirstChild, aReflowState, kidMaxSize);
- if (NS_OK == mFirstChild->QueryInterface(kIHTMLReflowIID, (void**)&htmlReflow)) {
- htmlReflow->WillReflow(aPresContext);
- ReflowChild(mFirstChild, aPresContext, aDesiredSize, kidReflowState, aStatus);
- NS_ASSERTION(NS_FRAME_IS_COMPLETE(aStatus), "bad status");
+ ReflowChild(mFirstChild, aPresContext, aDesiredSize, kidReflowState, aStatus);
+ NS_ASSERTION(NS_FRAME_IS_COMPLETE(aStatus), "bad status");
- // Place and size the child
- nsRect rect(borderPadding.left, borderPadding.top,
- aDesiredSize.width, aDesiredSize.height);
- mFirstChild->SetRect(rect);
- htmlReflow->DidReflow(aPresContext, NS_FRAME_REFLOW_FINISHED);
- }
+ // Place and size the child
+ nsRect rect(border.left, border.top, aDesiredSize.width, aDesiredSize.height);
+ mFirstChild->SetRect(rect);
- // The scroll outer frame either shrink wraps around it's single
- // child OR uses the style width/height.
- if (aReflowState.HaveConstrainedWidth()) {
- aDesiredSize.width = aReflowState.minWidth;
- }
- else {
- aDesiredSize.width += lr;
- }
- if (aReflowState.HaveConstrainedHeight()) {
- aDesiredSize.height = aReflowState.minHeight;
- }
- else {
- aDesiredSize.height += tb;
- }
+ // Compute our desired size by adding in space for the borders
+ aDesiredSize.width += lr;
+ aDesiredSize.height += tb;
aDesiredSize.ascent = aDesiredSize.height;
aDesiredSize.descent = 0;
NS_FRAME_TRACE_MSG(NS_FRAME_TRACE_CALLS,
- ("exit nsScrollOuterFrame::Reflow: status=%d width=%d height=%d",
+ ("exit nsScrollFrame::Reflow: status=%d width=%d height=%d",
aStatus, aDesiredSize.width, aDesiredSize.height));
return NS_OK;
}
NS_IMETHODIMP
-nsScrollOuterFrame::ListTag(FILE* out) const
+nsScrollFrame::Paint(nsIPresContext& aPresContext,
+ nsIRenderingContext& aRenderingContext,
+ const nsRect& aDirtyRect)
{
- fputs("*scrollouterframe<", out);
+ // Paint our border only (no background)
+ const nsStyleSpacing* spacing =
+ (const nsStyleSpacing*)mStyleContext->GetStyleData(eStyleStruct_Spacing);
+
+ nsRect rect(0, 0, mRect.width, mRect.height);
+ nsCSSRendering::PaintBorder(aPresContext, aRenderingContext, this,
+ aDirtyRect, rect, *spacing, 0);
+
+ // Paint our children
+ return nsContainerFrame::Paint(aPresContext, aRenderingContext, aDirtyRect);
+}
+
+PRIntn
+nsScrollFrame::GetSkipSides() const
+{
+ return 0;
+}
+
+NS_IMETHODIMP
+nsScrollFrame::ListTag(FILE* out) const
+{
+ fputs("*scrollframe<", out);
nsIAtom* atom;
mContent->GetTag(atom);
if (nsnull != atom) {
@@ -549,27 +491,16 @@ nsScrollOuterFrame::ListTag(FILE* out) const
return NS_OK;
}
-PRIntn
-nsScrollOuterFrame::GetSkipSides() const
-{
- return 0;
-}
-
//----------------------------------------------------------------------
nsresult
-NS_NewScrollFrame(nsIFrame** aInstancePtrResult,
- nsIContent* aContent,
- nsIFrame* aParent)
+NS_NewScrollFrame(nsIContent* aContent,
+ nsIFrame* aParentFrame,
+ nsIFrame*& aResult)
{
- NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr");
- if (nsnull == aInstancePtrResult) {
- return NS_ERROR_NULL_POINTER;
- }
- nsIFrame* it = new nsScrollOuterFrame(aContent, aParent);
- if (nsnull == it) {
+ aResult = new nsScrollFrame(aContent, aParentFrame);
+ if (nsnull == aResult) {
return NS_ERROR_OUT_OF_MEMORY;
}
- *aInstancePtrResult = it;
return NS_OK;
}
diff --git a/layout/html/base/src/nsScrollFrame.h b/layout/html/base/src/nsScrollFrame.h
deleted file mode 100644
index b866f4a85df3..000000000000
--- a/layout/html/base/src/nsScrollFrame.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- *
- * The contents of this file are subject to the Netscape Public License
- * Version 1.0 (the "NPL"); you may not use this file except in
- * compliance with the NPL. You may obtain a copy of the NPL at
- * http://www.mozilla.org/NPL/
- *
- * Software distributed under the NPL is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
- * for the specific language governing rights and limitations under the
- * NPL.
- *
- * The Initial Developer of this code under the NPL is Netscape
- * Communications Corporation. Portions created by Netscape are
- * Copyright (C) 1998 Netscape Communications Corporation. All Rights
- * Reserved.
- */
-#ifndef nsScrollFrame_h___
-#define nsScrollFrame_h___
-
-#include "nsHTMLContainerFrame.h"
-
-extern nsresult NS_NewScrollFrame(nsIFrame** aInstancePtrResult,
- nsIContent* aContent,
- nsIFrame* aParent);
-
-#endif /* nsScrollFrame_h___ */
diff --git a/layout/html/style/src/nsHTMLStyleSheet.cpp b/layout/html/style/src/nsHTMLStyleSheet.cpp
index 897aa7d071a4..4b7623917aa7 100644
--- a/layout/html/style/src/nsHTMLStyleSheet.cpp
+++ b/layout/html/style/src/nsHTMLStyleSheet.cpp
@@ -325,6 +325,8 @@ protected:
nsIFrame* aParentFrame,
nsIFrame*& aFrame);
+ PRBool IsScrollable(nsIFrame* aFrame, const nsStyleDisplay* aDisplay);
+
protected:
PRUint32 mInHeap : 1;
PRUint32 mRefCnt : 31;
@@ -1351,6 +1353,28 @@ HTMLStyleSheetImpl::ConstructFrameByDisplayType(nsIPresContext* aPresContext,
return rv;
}
+PRBool
+HTMLStyleSheetImpl::IsScrollable(nsIFrame* aFrame,
+ const nsStyleDisplay* aDisplay)
+{
+ // If the overflow property is scroll then it's scrollable regardless
+ // of whether the content overflows the block.
+ // XXX This isn't correct. Only do this if the height is not allowed to
+ // grow to accomodate its child frames...
+ if (NS_STYLE_OVERFLOW_SCROLL == aDisplay->mOverflow) {
+ return PR_TRUE;
+ }
+
+#if 0
+ if ((NS_STYLE_OVERFLOW_SCROLL == aDisplay->mOverflow) ||
+ // If the element has a fixed height (it isn't auto) and an overflow
+ // property of scroll or auto, then it's potentially scrollable.
+ // XXX Deal with width considerations, too
+ (NS_STYLE_OVERFLOW_AUTO == aDisplay->mOverflow)) {
+#endif
+ return PR_FALSE;
+}
+
NS_IMETHODIMP
HTMLStyleSheetImpl::ConstructFrame(nsIPresContext* aPresContext,
nsIContent* aContent,
@@ -1406,20 +1430,32 @@ HTMLStyleSheetImpl::ConstructFrame(nsIPresContext* aPresContext,
}
-#if 0
- // If the frame is a block-level frame and it has a fixed height and overflow
- // property of scroll, then wrap it in a scroll frame.
- // XXX Deal with replaced elements and overflow of auto and width, too
- nsIFrame* kidFrame = nsnull;
- nsresult rv;
- if ((NS_STYLE_OVERFLOW_SCROLL == kidDisplay->mOverflow) ||
- (NS_STYLE_OVERFLOW_AUTO == kidDisplay->mOverflow)) {
- rv = NS_NewScrollFrame(&kidFrame, aKid, aParentFrame);
- if (NS_OK == rv) {
- kidFrame->SetStyleContext(aPresContext, kidSC);
+ // If the frame is a block-level frame and is scrollable then wrap it
+ // in a scroll frame.
+ // XXX Applies to replaced elements, too, but how to tell if the element
+ // is replaced?
+ if (nsnull != aFrameSubTree) {
+ if (display->IsBlockLevel() && IsScrollable(aFrameSubTree, display)) {
+ nsIFrame* scrollFrame;
+
+ if NS_SUCCEEDED(NS_NewScrollFrame(aContent, aParentFrame, scrollFrame)) {
+ // The scroll frame gets the original style context, and the scrolled
+ // frame gets a pseudo style context.
+ // XXX Is this the best way to do this?
+ scrollFrame->SetStyleContext(aPresContext, styleContext);
+
+ nsIStyleContext* pseudoStyle;
+ pseudoStyle = aPresContext->ResolvePseudoStyleContextFor(nsHTMLAtoms::columnPseudo,
+ scrollFrame);
+ aFrameSubTree->SetStyleContext(aPresContext, pseudoStyle);
+ NS_RELEASE(pseudoStyle);
+
+ // Initialize the scroll frame
+ scrollFrame->Init(*aPresContext, aFrameSubTree);
+ aFrameSubTree = scrollFrame;
+ }
}
}
-#endif
}
}
NS_RELEASE(styleContext);
diff --git a/layout/style/nsHTMLStyleSheet.cpp b/layout/style/nsHTMLStyleSheet.cpp
index 897aa7d071a4..4b7623917aa7 100644
--- a/layout/style/nsHTMLStyleSheet.cpp
+++ b/layout/style/nsHTMLStyleSheet.cpp
@@ -325,6 +325,8 @@ protected:
nsIFrame* aParentFrame,
nsIFrame*& aFrame);
+ PRBool IsScrollable(nsIFrame* aFrame, const nsStyleDisplay* aDisplay);
+
protected:
PRUint32 mInHeap : 1;
PRUint32 mRefCnt : 31;
@@ -1351,6 +1353,28 @@ HTMLStyleSheetImpl::ConstructFrameByDisplayType(nsIPresContext* aPresContext,
return rv;
}
+PRBool
+HTMLStyleSheetImpl::IsScrollable(nsIFrame* aFrame,
+ const nsStyleDisplay* aDisplay)
+{
+ // If the overflow property is scroll then it's scrollable regardless
+ // of whether the content overflows the block.
+ // XXX This isn't correct. Only do this if the height is not allowed to
+ // grow to accomodate its child frames...
+ if (NS_STYLE_OVERFLOW_SCROLL == aDisplay->mOverflow) {
+ return PR_TRUE;
+ }
+
+#if 0
+ if ((NS_STYLE_OVERFLOW_SCROLL == aDisplay->mOverflow) ||
+ // If the element has a fixed height (it isn't auto) and an overflow
+ // property of scroll or auto, then it's potentially scrollable.
+ // XXX Deal with width considerations, too
+ (NS_STYLE_OVERFLOW_AUTO == aDisplay->mOverflow)) {
+#endif
+ return PR_FALSE;
+}
+
NS_IMETHODIMP
HTMLStyleSheetImpl::ConstructFrame(nsIPresContext* aPresContext,
nsIContent* aContent,
@@ -1406,20 +1430,32 @@ HTMLStyleSheetImpl::ConstructFrame(nsIPresContext* aPresContext,
}
-#if 0
- // If the frame is a block-level frame and it has a fixed height and overflow
- // property of scroll, then wrap it in a scroll frame.
- // XXX Deal with replaced elements and overflow of auto and width, too
- nsIFrame* kidFrame = nsnull;
- nsresult rv;
- if ((NS_STYLE_OVERFLOW_SCROLL == kidDisplay->mOverflow) ||
- (NS_STYLE_OVERFLOW_AUTO == kidDisplay->mOverflow)) {
- rv = NS_NewScrollFrame(&kidFrame, aKid, aParentFrame);
- if (NS_OK == rv) {
- kidFrame->SetStyleContext(aPresContext, kidSC);
+ // If the frame is a block-level frame and is scrollable then wrap it
+ // in a scroll frame.
+ // XXX Applies to replaced elements, too, but how to tell if the element
+ // is replaced?
+ if (nsnull != aFrameSubTree) {
+ if (display->IsBlockLevel() && IsScrollable(aFrameSubTree, display)) {
+ nsIFrame* scrollFrame;
+
+ if NS_SUCCEEDED(NS_NewScrollFrame(aContent, aParentFrame, scrollFrame)) {
+ // The scroll frame gets the original style context, and the scrolled
+ // frame gets a pseudo style context.
+ // XXX Is this the best way to do this?
+ scrollFrame->SetStyleContext(aPresContext, styleContext);
+
+ nsIStyleContext* pseudoStyle;
+ pseudoStyle = aPresContext->ResolvePseudoStyleContextFor(nsHTMLAtoms::columnPseudo,
+ scrollFrame);
+ aFrameSubTree->SetStyleContext(aPresContext, pseudoStyle);
+ NS_RELEASE(pseudoStyle);
+
+ // Initialize the scroll frame
+ scrollFrame->Init(*aPresContext, aFrameSubTree);
+ aFrameSubTree = scrollFrame;
+ }
}
}
-#endif
}
}
NS_RELEASE(styleContext);