mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-02 07:05:24 +00:00
759 lines
27 KiB
C++
759 lines
27 KiB
C++
/* -*- 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.
|
|
*/
|
|
#include "nsHTMLParts.h"
|
|
#include "nsContainerFrame.h"
|
|
#include "nsCSSRendering.h"
|
|
#include "nsIDocument.h"
|
|
#include "nsIReflowCommand.h"
|
|
#include "nsIPresContext.h"
|
|
#include "nsIStyleContext.h"
|
|
#include "nsViewsCID.h"
|
|
#include "nsIView.h"
|
|
#include "nsIViewManager.h"
|
|
#include "nsIWidget.h"
|
|
#include "nsHTMLIIDs.h"
|
|
#include "nsPageFrame.h"
|
|
#include "nsIRenderingContext.h"
|
|
#include "nsGUIEvent.h"
|
|
#include "nsDOMEvent.h"
|
|
#include "nsStyleConsts.h"
|
|
#include "nsIViewManager.h"
|
|
#include "nsHTMLAtoms.h"
|
|
#include "nsIEventStateManager.h"
|
|
#include "nsIDeviceContext.h"
|
|
|
|
class RootFrame : public nsContainerFrame {
|
|
public:
|
|
RootFrame(nsIContent* aContent);
|
|
|
|
NS_IMETHOD Init(nsIPresContext& aPresContext, nsIFrame* aChildList);
|
|
NS_IMETHOD Reflow(nsIPresContext& aPresContext,
|
|
nsReflowMetrics& aDesiredSize,
|
|
const nsReflowState& aReflowState,
|
|
nsReflowStatus& aStatus);
|
|
NS_IMETHOD HandleEvent(nsIPresContext& aPresContext,
|
|
nsGUIEvent* aEvent,
|
|
nsEventStatus& aEventStatus);
|
|
NS_IMETHOD IsPercentageBase(PRBool& aBase) const {
|
|
aBase = PR_TRUE;
|
|
return NS_OK;
|
|
}
|
|
};
|
|
|
|
// Pseudo frame created by the root frame
|
|
class RootContentFrame : public nsContainerFrame {
|
|
public:
|
|
RootContentFrame(nsIContent* aContent, nsIFrame* aParent);
|
|
|
|
NS_IMETHOD Reflow(nsIPresContext& aPresContext,
|
|
nsReflowMetrics& aDesiredSize,
|
|
const nsReflowState& aReflowState,
|
|
nsReflowStatus& aStatus);
|
|
NS_IMETHOD Paint(nsIPresContext& aPresContext,
|
|
nsIRenderingContext& aRenderingContext,
|
|
const nsRect& aDirtyRect);
|
|
NS_IMETHOD HandleEvent(nsIPresContext& aPresContext,
|
|
nsGUIEvent* aEvent,
|
|
nsEventStatus& aEventStatus);
|
|
NS_IMETHOD IsPercentageBase(PRBool& aBase) const {
|
|
aBase = PR_TRUE;
|
|
return NS_OK;
|
|
}
|
|
|
|
void ComputeChildMargins(nsMargin& aMargin);
|
|
};
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
nsresult
|
|
NS_NewHTMLFrame(nsIContent* aContent, nsIFrame* aParentFrame,
|
|
nsIFrame*& aResult)
|
|
{
|
|
RootFrame* frame = new RootFrame(aContent);
|
|
if (nsnull == frame) {
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
}
|
|
aResult = frame;
|
|
return NS_OK;
|
|
}
|
|
|
|
RootFrame::RootFrame(nsIContent* aContent)
|
|
: nsContainerFrame(aContent, nsnull)
|
|
{
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
RootFrame::Init(nsIPresContext& aPresContext, nsIFrame* aChildList)
|
|
{
|
|
// Construct the root content frame and set its style context
|
|
mFirstChild = new RootContentFrame(mContent, this);
|
|
nsIStyleContext* pseudoStyleContext =
|
|
aPresContext.ResolvePseudoStyleContextFor(nsHTMLAtoms::rootContentPseudo, this);
|
|
mFirstChild->SetStyleContext(&aPresContext, pseudoStyleContext);
|
|
NS_RELEASE(pseudoStyleContext);
|
|
|
|
// Set the geometric and content parent for each of the child frames
|
|
for (nsIFrame* frame = aChildList; nsnull != frame; frame->GetNextSibling(frame)) {
|
|
frame->SetGeometricParent(mFirstChild);
|
|
frame->SetContentParent(mFirstChild);
|
|
}
|
|
|
|
// Queue up the frames for the root content frame
|
|
return mFirstChild->Init(aPresContext, aChildList);
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
RootFrame::Reflow(nsIPresContext& aPresContext,
|
|
nsReflowMetrics& aDesiredSize,
|
|
const nsReflowState& aReflowState,
|
|
nsReflowStatus& aStatus)
|
|
{
|
|
NS_FRAME_TRACE_REFLOW_IN("RootFrame::Reflow");
|
|
|
|
aStatus = NS_FRAME_COMPLETE;
|
|
|
|
if (eReflowReason_Incremental == aReflowState.reason) {
|
|
// We don't expect the target of the reflow command to be the root frame
|
|
#ifdef NS_DEBUG
|
|
NS_ASSERTION(nsnull != aReflowState.reflowCommand, "no reflow command");
|
|
|
|
nsIFrame* target;
|
|
aReflowState.reflowCommand->GetTarget(target);
|
|
NS_ASSERTION(target != this, "root frame is reflow command target");
|
|
#endif
|
|
|
|
// Verify that the next frame in the reflow chain is our pseudo frame
|
|
nsIFrame* next;
|
|
aReflowState.reflowCommand->GetNext(next);
|
|
NS_ASSERTION(next == mFirstChild, "unexpected next reflow command frame");
|
|
}
|
|
|
|
// Reflow our pseudo frame. It will choose whetever height its child frame
|
|
// wants
|
|
if (nsnull != mFirstChild) {
|
|
nsReflowMetrics desiredSize(nsnull);
|
|
nsReflowState kidReflowState(mFirstChild, aReflowState, aReflowState.maxSize);
|
|
|
|
mFirstChild->WillReflow(aPresContext);
|
|
aStatus = ReflowChild(mFirstChild, &aPresContext, desiredSize, kidReflowState);
|
|
|
|
// Place and size the child
|
|
nsRect rect(0, 0, desiredSize.width, desiredSize.height);
|
|
mFirstChild->SetRect(rect);
|
|
mFirstChild->DidReflow(aPresContext, NS_FRAME_REFLOW_FINISHED);
|
|
}
|
|
|
|
// Return the max size as our desired size
|
|
aDesiredSize.width = aReflowState.maxSize.width;
|
|
aDesiredSize.height = aReflowState.maxSize.height;
|
|
aDesiredSize.ascent = aDesiredSize.height;
|
|
aDesiredSize.descent = 0;
|
|
|
|
NS_FRAME_TRACE_REFLOW_OUT("RootFrame::Reflow", aStatus);
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
RootFrame::HandleEvent(nsIPresContext& aPresContext,
|
|
nsGUIEvent* aEvent,
|
|
nsEventStatus& aEventStatus)
|
|
{
|
|
mContent->HandleDOMEvent(aPresContext, (nsEvent*)aEvent, nsnull, DOM_EVENT_INIT, aEventStatus);
|
|
|
|
if (aEvent->message == NS_MOUSE_LEFT_BUTTON_UP ||
|
|
aEvent->message == NS_MOUSE_MIDDLE_BUTTON_UP ||
|
|
aEvent->message == NS_MOUSE_RIGHT_BUTTON_UP) {
|
|
nsFrame::HandleEvent(aPresContext, aEvent, aEventStatus);
|
|
}
|
|
|
|
#if 0
|
|
if (aEventStatus != nsEventStatus_eConsumeNoDefault) {
|
|
switch (aEvent->message) {
|
|
case NS_MOUSE_MOVE:
|
|
case NS_MOUSE_ENTER:
|
|
{
|
|
nsIFrame* target = this;
|
|
PRInt32 cursor;
|
|
|
|
GetCursorAndContentAt(aPresContext, aEvent->point, &target, &mContent, cursor);
|
|
if (cursor == NS_STYLE_CURSOR_INHERIT) {
|
|
cursor = NS_STYLE_CURSOR_DEFAULT;
|
|
}
|
|
nsCursor c;
|
|
switch (cursor) {
|
|
default:
|
|
case NS_STYLE_CURSOR_DEFAULT:
|
|
c = eCursor_standard;
|
|
break;
|
|
case NS_STYLE_CURSOR_HAND:
|
|
c = eCursor_hyperlink;
|
|
break;
|
|
case NS_STYLE_CURSOR_IBEAM:
|
|
c = eCursor_select;
|
|
break;
|
|
}
|
|
nsIWidget* window;
|
|
target->GetWindow(window);
|
|
window->SetCursor(c);
|
|
NS_RELEASE(window);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
#endif
|
|
return NS_OK;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
RootContentFrame::RootContentFrame(nsIContent* aContent, nsIFrame* aParent)
|
|
: nsContainerFrame(aContent, aParent)
|
|
{
|
|
// Create a view
|
|
nsIFrame* parent;
|
|
nsIView* view;
|
|
|
|
GetParentWithView(parent);
|
|
NS_ASSERTION(parent, "GetParentWithView failed");
|
|
nsIView* parView;
|
|
|
|
parent->GetView(parView);
|
|
NS_ASSERTION(parView, "no parent with view");
|
|
|
|
// Create a view
|
|
static NS_DEFINE_IID(kViewCID, NS_VIEW_CID);
|
|
static NS_DEFINE_IID(kIViewIID, NS_IVIEW_IID);
|
|
|
|
nsresult result = nsRepository::CreateInstance(kViewCID,
|
|
nsnull,
|
|
kIViewIID,
|
|
(void **)&view);
|
|
if (NS_OK == result) {
|
|
nsIView* rootView = parView;
|
|
nsIViewManager* viewManager;
|
|
rootView->GetViewManager(viewManager);
|
|
|
|
// Initialize the view
|
|
NS_ASSERTION(nsnull != viewManager, "null view manager");
|
|
|
|
view->Init(viewManager, mRect, rootView);
|
|
viewManager->InsertChild(rootView, view, 0);
|
|
|
|
NS_RELEASE(viewManager);
|
|
|
|
// Remember our view
|
|
SetView(view);
|
|
}
|
|
}
|
|
|
|
// Determine the margins to place around the child frame. Note that
|
|
// this applies to the frame in the page-frame when paginating, not
|
|
// to the page-frame.
|
|
void
|
|
RootContentFrame::ComputeChildMargins(nsMargin& aMargin)
|
|
{
|
|
const nsStyleSpacing* spacing = nsnull;
|
|
mFirstChild->GetStyleData(eStyleStruct_Spacing,
|
|
(const nsStyleStruct*&) spacing);
|
|
if (nsnull != spacing) {
|
|
spacing->CalcMarginFor(mFirstChild, aMargin);
|
|
|
|
// We cannot allow negative margins
|
|
if (aMargin.top < 0) aMargin.top = 0;
|
|
if (aMargin.right < 0) aMargin.right = 0;
|
|
if (aMargin.bottom < 0) aMargin.bottom = 0;
|
|
if (aMargin.left < 0) aMargin.left = 0;
|
|
}
|
|
else {
|
|
aMargin.left = 0;
|
|
aMargin.right = 0;
|
|
aMargin.top = 0;
|
|
aMargin.bottom = 0;
|
|
}
|
|
}
|
|
|
|
// XXX Hack
|
|
#define PAGE_SPACING_TWIPS 100
|
|
|
|
NS_IMETHODIMP
|
|
RootContentFrame::Reflow(nsIPresContext& aPresContext,
|
|
nsReflowMetrics& aDesiredSize,
|
|
const nsReflowState& aReflowState,
|
|
nsReflowStatus& aStatus)
|
|
{
|
|
NS_FRAME_TRACE_REFLOW_IN("RootContentFrame::Reflow");
|
|
|
|
aStatus = NS_FRAME_COMPLETE;
|
|
|
|
// XXX Need a copy of this margin and border handling code in nsPageFrame
|
|
|
|
// Calculate margin around our child
|
|
nsMargin margin;
|
|
ComputeChildMargins(margin);
|
|
|
|
// Calculate our border and padding. Note that we use our parents
|
|
// style context since we have a pseudo-style.
|
|
nsMargin borderPadding(0, 0, 0, 0);
|
|
const nsStyleSpacing* spacing;
|
|
mGeometricParent->GetStyleData(eStyleStruct_Spacing,
|
|
(const nsStyleStruct*&) spacing);
|
|
if (nsnull != spacing) {
|
|
spacing->CalcBorderPaddingFor(this, borderPadding);
|
|
}
|
|
|
|
// Calculate the inner area available for reflowing the child
|
|
nscoord top = margin.top + borderPadding.top;
|
|
nscoord right = margin.right + borderPadding.right;
|
|
nscoord bottom = margin.bottom + borderPadding.bottom;
|
|
nscoord left = margin.left + borderPadding.left;
|
|
nscoord availWidth = aReflowState.maxSize.width - left - right;
|
|
|
|
// If this is not a paginated view then (maybe) subtract out space
|
|
// reserved for the scroll bar. We check our child and see if it
|
|
// wants to be scrolled (overflow: auto/scroll) and if so then we
|
|
// reserve some space for the scrollbar.
|
|
nscoord sbarWidth = 0;
|
|
if (!aPresContext.IsPaginated()) {
|
|
const nsStyleDisplay* display;
|
|
mFirstChild->GetStyleData(eStyleStruct_Display,
|
|
(const nsStyleStruct*&) display);
|
|
if ((NS_STYLE_OVERFLOW_AUTO == display->mOverflow) ||
|
|
(NS_STYLE_OVERFLOW_SCROLL == display->mOverflow)) {
|
|
nsIDeviceContext* dc = aPresContext.GetDeviceContext();
|
|
float sbWidth, sbHeight;
|
|
dc->GetScrollBarDimensions(sbWidth, sbHeight);
|
|
sbarWidth = NSToCoordRound(sbWidth);
|
|
availWidth -= sbarWidth;
|
|
NS_RELEASE(dc);
|
|
}
|
|
}
|
|
|
|
// 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");
|
|
|
|
nsSize maxSize(availWidth, NS_UNCONSTRAINEDSIZE);
|
|
nsReflowState kidReflowState(next, aReflowState, maxSize);
|
|
|
|
// Dispatch the reflow command to our child frame. Allow it to be as high
|
|
// as it wants
|
|
mFirstChild->WillReflow(aPresContext);
|
|
aStatus = ReflowChild(mFirstChild, &aPresContext, aDesiredSize, kidReflowState);
|
|
|
|
// Place and size the child
|
|
nsRect rect(left, top, aDesiredSize.width, aDesiredSize.height);
|
|
mFirstChild->SetRect(rect);
|
|
|
|
// Compute our desired size
|
|
aDesiredSize.width += left + right + sbarWidth;
|
|
aDesiredSize.height += top + bottom;
|
|
if (aDesiredSize.height < aReflowState.maxSize.height) {
|
|
aDesiredSize.height = aReflowState.maxSize.height;
|
|
}
|
|
} else {
|
|
nsReflowReason reflowReason = aReflowState.reason;
|
|
|
|
// Resize our frames
|
|
if (nsnull != mFirstChild) {
|
|
if (aPresContext.IsPaginated()) {
|
|
nscoord y = PAGE_SPACING_TWIPS;
|
|
nsReflowMetrics kidSize(aDesiredSize.maxElementSize);
|
|
|
|
// Compute the size of each page and the x coordinate within
|
|
// ourselves that the pages will be placed at.
|
|
nsSize pageSize(aPresContext.GetPageWidth(),
|
|
aPresContext.GetPageHeight());
|
|
nsIDeviceContext *dx = aPresContext.GetDeviceContext();
|
|
float sbWidth, sbHeight;
|
|
dx->GetScrollBarDimensions(sbWidth, sbHeight);
|
|
PRInt32 extra = aReflowState.maxSize.width - PAGE_SPACING_TWIPS*2 -
|
|
pageSize.width - NSToCoordRound(sbWidth);
|
|
NS_RELEASE(dx);
|
|
|
|
// Note: nscoord is an unsigned type so don't combine these
|
|
// two statements or the extra will be promoted to unsigned
|
|
// and the >0 won't work!
|
|
nscoord x = PAGE_SPACING_TWIPS;
|
|
if (extra > 0) {
|
|
x += extra / 2;
|
|
}
|
|
|
|
// Tile the pages vertically
|
|
for (nsIFrame* kidFrame = mFirstChild; nsnull != kidFrame; ) {
|
|
// Reflow the page
|
|
nsReflowState kidReflowState(kidFrame, aReflowState, pageSize,
|
|
reflowReason);
|
|
nsReflowStatus status;
|
|
|
|
// Place and size the page. If the page is narrower than our
|
|
// max width then center it horizontally
|
|
kidFrame->WillReflow(aPresContext);
|
|
kidFrame->MoveTo(x, y);
|
|
status = ReflowChild(kidFrame, &aPresContext, kidSize,
|
|
kidReflowState);
|
|
kidFrame->SetRect(nsRect(x, y, kidSize.width, kidSize.height));
|
|
y += kidSize.height;
|
|
|
|
// Leave a slight gap between the pages
|
|
y += PAGE_SPACING_TWIPS;
|
|
|
|
// 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);
|
|
reflowReason = eReflowReason_Initial;
|
|
|
|
// 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.height = y;
|
|
if (aDesiredSize.height < aReflowState.maxSize.height) {
|
|
aDesiredSize.height = aReflowState.maxSize.height;
|
|
}
|
|
aDesiredSize.width = PAGE_SPACING_TWIPS*2 + pageSize.width;
|
|
if (aDesiredSize.width < aReflowState.maxSize.width) {
|
|
aDesiredSize.width = aReflowState.maxSize.width;
|
|
}
|
|
|
|
} else {
|
|
nsSize maxSize(availWidth, NS_UNCONSTRAINEDSIZE);
|
|
nsReflowState kidReflowState(mFirstChild, aReflowState, maxSize,
|
|
reflowReason);
|
|
|
|
// Get the child's desired size. Our child's desired height is our
|
|
// desired size
|
|
mFirstChild->WillReflow(aPresContext);
|
|
aStatus = ReflowChild(mFirstChild, &aPresContext, aDesiredSize, kidReflowState);
|
|
NS_ASSERTION(NS_FRAME_IS_COMPLETE(aStatus), "bad status");
|
|
|
|
// Place and size the child
|
|
nsRect rect(left, top, aDesiredSize.width, aDesiredSize.height);
|
|
mFirstChild->SetRect(rect);
|
|
|
|
// Compute our desired size
|
|
aDesiredSize.width += left + right + sbarWidth;
|
|
aDesiredSize.height += top + bottom;
|
|
if (aDesiredSize.height < aReflowState.maxSize.height) {
|
|
aDesiredSize.height = aReflowState.maxSize.height;
|
|
}
|
|
|
|
// Do the necessary repainting
|
|
if (eReflowReason_Initial == reflowReason) {
|
|
// Repaint the visible area
|
|
Invalidate(nsRect(0, 0, aReflowState.maxSize.width, aReflowState.maxSize.height));
|
|
} else if (eReflowReason_Resize == aReflowState.reason) {
|
|
// Repaint the entire frame
|
|
Invalidate(nsRect(0, 0, aReflowState.maxSize.width, aDesiredSize.height));
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
aDesiredSize.width = aReflowState.maxSize.width;
|
|
aDesiredSize.height = aReflowState.maxSize.height;
|
|
aDesiredSize.ascent = aDesiredSize.height;
|
|
aDesiredSize.descent = 0;
|
|
if (nsnull != aDesiredSize.maxElementSize) {
|
|
aDesiredSize.maxElementSize->width = 0;
|
|
aDesiredSize.maxElementSize->height = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
// We are always a pseudo-frame; make sure our content offset is
|
|
// properly pushed upwards
|
|
nsContainerFrame* parent = (nsContainerFrame*) mGeometricParent;
|
|
|
|
NS_FRAME_TRACE_REFLOW_OUT("RootContentFrame::Reflow", aStatus);
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
RootContentFrame::Paint(nsIPresContext& aPresContext,
|
|
nsIRenderingContext& aRenderingContext,
|
|
const nsRect& aDirtyRect)
|
|
{
|
|
// 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);
|
|
}
|
|
else {
|
|
// Get our parents color from the style sheet; our parent can't
|
|
// paint (special hackery because it's the root frame), but we
|
|
// can. If our parent's color is transparent then use our first
|
|
// child's color instead. This is done so that you override the
|
|
// HTML background using css but still allow for the BODY
|
|
// background/bgcolor attribute to affect the HTML element when
|
|
// css is not involved.
|
|
PRBool renderAll = PR_TRUE;
|
|
const nsStyleColor* color = nsnull;
|
|
mGeometricParent->GetStyleData(eStyleStruct_Color,
|
|
(const nsStyleStruct*&) color);
|
|
if (nsnull != color) {
|
|
// If we have no bg color and we have no bg image then...
|
|
if ((NS_STYLE_BG_COLOR_TRANSPARENT|NS_STYLE_BG_IMAGE_NONE) ==
|
|
((NS_STYLE_BG_COLOR_TRANSPARENT|NS_STYLE_BG_IMAGE_NONE) &
|
|
color->mBackgroundFlags)) {
|
|
// Use the color from our child to render just the margins and
|
|
// padding area.
|
|
mFirstChild->GetStyleData(eStyleStruct_Color,
|
|
(const nsStyleStruct*&) color);
|
|
renderAll = PR_FALSE;
|
|
}
|
|
}
|
|
|
|
const nsStyleSpacing* spacing = nsnull;
|
|
mGeometricParent->GetStyleData(eStyleStruct_Spacing,
|
|
(const nsStyleStruct*&) spacing);
|
|
nsMargin borderPadding(0, 0, 0, 0);
|
|
nsMargin border(0, 0, 0, 0);
|
|
if (nsnull != spacing) {
|
|
// Paint border
|
|
nsRect r(0, 0, mRect.width, mRect.height);
|
|
spacing->CalcBorderFor(this, border);
|
|
spacing->CalcBorderPaddingFor(this, borderPadding);
|
|
nsCSSRendering::PaintBorder(aPresContext, aRenderingContext,
|
|
this, aDirtyRect,
|
|
r, *spacing, 0);
|
|
}
|
|
if (nsnull != color) {
|
|
if (renderAll) {
|
|
// Paint the entire background
|
|
nscoord w = mRect.width - border.left - border.right;
|
|
nscoord h = mRect.height - border.top - border.bottom;
|
|
nsRect r(border.left, border.top, w, h);
|
|
if ((w > 0) && (h > 0)) {
|
|
nsCSSRendering::PaintBackground(aPresContext, aRenderingContext,
|
|
this, aDirtyRect, r, *color, 0, 0);
|
|
}
|
|
}
|
|
else {
|
|
// Paint our padding area and our childs margin area
|
|
nsMargin padding(0, 0, 0, 0);
|
|
if (nsnull != spacing) {
|
|
spacing->CalcPaddingFor(this, padding);
|
|
}
|
|
|
|
nsMargin margin;
|
|
ComputeChildMargins(margin);
|
|
|
|
// If this is not a paginated view then (maybe) subtract out space
|
|
// reserved for the scroll bar. We check our child and see if it
|
|
// wants to be scrolled (overflow: auto/scroll) and if so then we
|
|
// reserve some space for the scrollbar.
|
|
nscoord sbarWidth = 0;
|
|
{
|
|
const nsStyleDisplay* display;
|
|
mFirstChild->GetStyleData(eStyleStruct_Display,
|
|
(const nsStyleStruct*&) display);
|
|
if ((NS_STYLE_OVERFLOW_AUTO == display->mOverflow) ||
|
|
(NS_STYLE_OVERFLOW_SCROLL == display->mOverflow)) {
|
|
nsIDeviceContext* dc = aPresContext.GetDeviceContext();
|
|
float sbWidth, sbHeight;
|
|
dc->GetScrollBarDimensions(sbWidth, sbHeight);
|
|
sbarWidth = NSToCoordRound(sbWidth);
|
|
NS_RELEASE(dc);
|
|
}
|
|
}
|
|
|
|
nsRect childBounds;
|
|
mFirstChild->GetRect(childBounds);
|
|
|
|
// Paint the top padding+margin area
|
|
nsRect r(border.left, border.top,
|
|
mRect.width - border.left - border.right,
|
|
padding.top + margin.top);
|
|
nsCSSRendering::PaintBackground(aPresContext, aRenderingContext,
|
|
this, aDirtyRect, r, *color,
|
|
childBounds.x, childBounds.y);
|
|
|
|
// Paint the left padding+margin area
|
|
r.y = childBounds.y;
|
|
r.width = padding.left + margin.left;
|
|
r.height = childBounds.YMost() - padding.top - margin.top;
|
|
nsCSSRendering::PaintBackground(aPresContext, aRenderingContext,
|
|
this, aDirtyRect, r, *color,
|
|
childBounds.x, childBounds.y);
|
|
|
|
// Paint the right padding+margin area
|
|
r.x = mRect.width - border.right - padding.right - margin.right -
|
|
sbarWidth;
|
|
r.width = padding.right + margin.right + sbarWidth;
|
|
nsCSSRendering::PaintBackground(aPresContext, aRenderingContext,
|
|
this, aDirtyRect, r, *color,
|
|
childBounds.x, childBounds.y);
|
|
|
|
// Paint the bottom padding+margin+extra area
|
|
r.x = border.left;
|
|
r.y = childBounds.YMost();
|
|
if (r.y < mRect.height) {
|
|
r.width = mRect.width - border.left - border.right;
|
|
r.height = mRect.height - r.y;
|
|
nsCSSRendering::PaintBackground(aPresContext, aRenderingContext,
|
|
this, aDirtyRect, r, *color,
|
|
childBounds.x, childBounds.y);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Now paint our children
|
|
return nsContainerFrame::Paint(aPresContext, aRenderingContext, aDirtyRect);
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
RootContentFrame::HandleEvent(nsIPresContext& aPresContext,
|
|
nsGUIEvent* aEvent,
|
|
nsEventStatus& aEventStatus)
|
|
{
|
|
#if 0
|
|
mContent->HandleDOMEvent(aPresContext, (nsEvent*)aEvent, nsnull, DOM_EVENT_INIT, aEventStatus);
|
|
#else
|
|
nsContainerFrame::HandleEvent(aPresContext, aEvent, aEventStatus);
|
|
#endif
|
|
|
|
if (aEventStatus != nsEventStatus_eConsumeNoDefault) {
|
|
switch (aEvent->message) {
|
|
case NS_MOUSE_MOVE:
|
|
case NS_MOUSE_ENTER:
|
|
{
|
|
nsIFrame* target = this;
|
|
nsIContent* mTargetContent = mContent;
|
|
PRInt32 cursor;
|
|
|
|
GetCursorAndContentAt(aPresContext, aEvent->point, &target, &mTargetContent, cursor);
|
|
if (cursor == NS_STYLE_CURSOR_INHERIT) {
|
|
cursor = NS_STYLE_CURSOR_DEFAULT;
|
|
}
|
|
nsCursor c;
|
|
switch (cursor) {
|
|
default:
|
|
case NS_STYLE_CURSOR_DEFAULT:
|
|
c = eCursor_standard;
|
|
break;
|
|
case NS_STYLE_CURSOR_HAND:
|
|
c = eCursor_hyperlink;
|
|
break;
|
|
case NS_STYLE_CURSOR_IBEAM:
|
|
c = eCursor_select;
|
|
break;
|
|
}
|
|
nsIWidget* window;
|
|
target->GetWindow(window);
|
|
window->SetCursor(c);
|
|
NS_RELEASE(window);
|
|
|
|
//If the content object under the cursor has changed, fire a mouseover/out
|
|
nsIEventStateManager *mStateManager;
|
|
nsIContent *mLastContent;
|
|
if (NS_OK == aPresContext.GetEventStateManager(&mStateManager)) {
|
|
mStateManager->GetLastMouseOverContent(&mLastContent);
|
|
if (mLastContent != mTargetContent) {
|
|
if (nsnull != mLastContent) {
|
|
//fire mouseout
|
|
nsEventStatus mStatus = nsEventStatus_eIgnore;
|
|
nsMouseEvent mEvent;
|
|
mEvent.eventStructType = NS_MOUSE_EVENT;
|
|
mEvent.message = NS_MOUSE_EXIT;
|
|
mLastContent->HandleDOMEvent(aPresContext, &mEvent, nsnull, DOM_EVENT_INIT, mStatus);
|
|
}
|
|
//fire mouseover
|
|
nsEventStatus mStatus = nsEventStatus_eIgnore;
|
|
nsMouseEvent mEvent;
|
|
mEvent.eventStructType = NS_MOUSE_EVENT;
|
|
mEvent.message = NS_MOUSE_ENTER;
|
|
mTargetContent->HandleDOMEvent(aPresContext, &mEvent, nsnull, DOM_EVENT_INIT, mStatus);
|
|
mStateManager->SetLastMouseOverContent(mTargetContent);
|
|
}
|
|
NS_RELEASE(mStateManager);
|
|
NS_IF_RELEASE(mLastContent);
|
|
}
|
|
}
|
|
break;
|
|
case NS_MOUSE_EXIT:
|
|
//Don't know if this is actually hooked up.
|
|
{
|
|
//Fire of mouseout to the last content object.
|
|
nsIEventStateManager *mStateManager;
|
|
nsIContent *mLastContent;
|
|
if (NS_OK == aPresContext.GetEventStateManager(&mStateManager)) {
|
|
mStateManager->GetLastMouseOverContent(&mLastContent);
|
|
if (nsnull != mLastContent) {
|
|
//fire mouseout
|
|
nsEventStatus mStatus = nsEventStatus_eIgnore;
|
|
nsMouseEvent mEvent;
|
|
mEvent.eventStructType = NS_MOUSE_EVENT;
|
|
mEvent.message = NS_MOUSE_EXIT;
|
|
mLastContent->HandleDOMEvent(aPresContext, &mEvent, nsnull, DOM_EVENT_INIT, mStatus);
|
|
mStateManager->SetLastMouseOverContent(nsnull);
|
|
|
|
NS_RELEASE(mLastContent);
|
|
}
|
|
NS_RELEASE(mStateManager);
|
|
}
|
|
}
|
|
break;
|
|
case NS_MOUSE_LEFT_BUTTON_UP:
|
|
{
|
|
nsIEventStateManager *mStateManager;
|
|
if (NS_OK == aPresContext.GetEventStateManager(&mStateManager)) {
|
|
mStateManager->SetActiveLink(nsnull);
|
|
NS_RELEASE(mStateManager);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|