new
git-svn-id: svn://10.0.0.236/trunk@9558 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
parent
60e776c0b1
commit
429035b95e
141
mozilla/layout/generic/nsBRFrame.cpp
Normal file
141
mozilla/layout/generic/nsBRFrame.cpp
Normal file
@ -0,0 +1,141 @@
|
||||
/* -*- 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 "nsFrame.h"
|
||||
#include "nsHTMLParts.h"
|
||||
#include "nsHTMLIIDs.h"
|
||||
#include "nsIPresContext.h"
|
||||
#include "nsIInlineReflow.h"
|
||||
#include "nsCSSLineLayout.h"
|
||||
#include "nsStyleConsts.h"
|
||||
#include "nsHTMLAtoms.h"
|
||||
#include "nsIStyleContext.h"
|
||||
#include "nsIFontMetrics.h"
|
||||
#include "nsIRenderingContext.h"
|
||||
|
||||
class BRFrame : public nsFrame, public nsIInlineReflow {
|
||||
public:
|
||||
BRFrame(nsIContent* aContent, nsIFrame* aParentFrame);
|
||||
|
||||
// nsISupports
|
||||
NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr);
|
||||
|
||||
// nsIFrame
|
||||
NS_IMETHOD Paint(nsIPresContext& aPresContext,
|
||||
nsIRenderingContext& aRenderingContext,
|
||||
const nsRect& aDirtyRect);
|
||||
|
||||
// nsIInlineReflow
|
||||
NS_IMETHOD FindTextRuns(nsCSSLineLayout& aLineLayout,
|
||||
nsIReflowCommand* aReflowCommand);
|
||||
NS_IMETHOD InlineReflow(nsCSSLineLayout& aLineLayout,
|
||||
nsReflowMetrics& aDesiredSize,
|
||||
const nsReflowState& aReflowState);
|
||||
|
||||
protected:
|
||||
virtual ~BRFrame();
|
||||
};
|
||||
|
||||
nsresult
|
||||
NS_NewBRFrame(nsIContent* aContent, nsIFrame* aParentFrame,
|
||||
nsIFrame*& aResult)
|
||||
{
|
||||
nsIFrame* frame = new BRFrame(aContent, aParentFrame);
|
||||
if (nsnull == frame) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
aResult = frame;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
BRFrame::BRFrame(nsIContent* aContent,
|
||||
nsIFrame* aParentFrame)
|
||||
: nsFrame(aContent, aParentFrame)
|
||||
{
|
||||
}
|
||||
|
||||
BRFrame::~BRFrame()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
BRFrame::QueryInterface(REFNSIID aIID, void** aInstancePtrResult)
|
||||
{
|
||||
NS_PRECONDITION(nsnull != aInstancePtrResult, "null pointer");
|
||||
if (nsnull == aInstancePtrResult) {
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
}
|
||||
if (aIID.Equals(kIInlineReflowIID)) {
|
||||
*aInstancePtrResult = (void*) ((nsIInlineReflow*)this);
|
||||
return NS_OK;
|
||||
}
|
||||
return nsFrame::QueryInterface(aIID, aInstancePtrResult);
|
||||
}
|
||||
|
||||
NS_METHOD
|
||||
BRFrame::Paint(nsIPresContext& aPresContext,
|
||||
nsIRenderingContext& aRenderingContext,
|
||||
const nsRect& aDirtyRect)
|
||||
{
|
||||
if (nsIFrame::GetShowFrameBorders()) {
|
||||
float p2t = aPresContext.GetPixelsToTwips();
|
||||
aRenderingContext.SetColor(NS_RGB(0, 255, 255));
|
||||
aRenderingContext.FillRect(0, 0, NSIntPixelsToTwips(5, p2t), mRect.height);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
BRFrame::FindTextRuns(nsCSSLineLayout& aLineLayout,
|
||||
nsIReflowCommand* aReflowCommand)
|
||||
{
|
||||
aLineLayout.EndTextRun();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
BRFrame::InlineReflow(nsCSSLineLayout& aLineLayout,
|
||||
nsReflowMetrics& aMetrics,
|
||||
const nsReflowState& aReflowState)
|
||||
{
|
||||
if (nsnull != aMetrics.maxElementSize) {
|
||||
aMetrics.maxElementSize->width = 0;
|
||||
aMetrics.maxElementSize->height = 0;
|
||||
}
|
||||
|
||||
// We have no width, but we're the height of the default font
|
||||
const nsStyleFont* font = (const nsStyleFont*)
|
||||
mStyleContext->GetStyleData(eStyleStruct_Font);
|
||||
nsIFontMetrics* fm = aLineLayout.mPresContext->GetMetricsFor(font->mFont);
|
||||
|
||||
fm->GetMaxAscent(aMetrics.ascent);
|
||||
fm->GetMaxDescent(aMetrics.descent);
|
||||
aMetrics.height = aMetrics.ascent + aMetrics.descent;
|
||||
aMetrics.width = 0;
|
||||
NS_RELEASE(fm);
|
||||
|
||||
// Return our inline reflow status
|
||||
const nsStyleDisplay* display = (const nsStyleDisplay*)
|
||||
mStyleContext->GetStyleData(eStyleStruct_Display);
|
||||
PRUint32 breakType = display->mBreakType;
|
||||
if (NS_STYLE_CLEAR_NONE == breakType) {
|
||||
breakType = NS_STYLE_CLEAR_LINE;
|
||||
}
|
||||
|
||||
return NS_INLINE_BREAK | NS_INLINE_BREAK_AFTER |
|
||||
NS_INLINE_MAKE_BREAK_TYPE(breakType);
|
||||
}
|
||||
626
mozilla/layout/generic/nsHTMLFrame.cpp
Normal file
626
mozilla/layout/generic/nsHTMLFrame.cpp
Normal file
@ -0,0 +1,626 @@
|
||||
/* -*- 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 "nsHTMLContainer.h"
|
||||
#include "nsContainerFrame.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsIReflowCommand.h"
|
||||
#include "nsIPresContext.h"
|
||||
#include "nsIStyleContext.h"
|
||||
#include "nsViewsCID.h"
|
||||
#include "nsIView.h"
|
||||
#include "nsIViewManager.h"
|
||||
#include "nsIContentDelegate.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 Reflow(nsIPresContext& aPresContext,
|
||||
nsReflowMetrics& aDesiredSize,
|
||||
const nsReflowState& aReflowState,
|
||||
nsReflowStatus& aStatus);
|
||||
|
||||
NS_IMETHOD HandleEvent(nsIPresContext& aPresContext,
|
||||
nsGUIEvent* aEvent,
|
||||
nsEventStatus& aEventStatus);
|
||||
};
|
||||
|
||||
// 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);
|
||||
|
||||
protected:
|
||||
void CreateFirstChild(nsIPresContext* aPresContext);
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
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::Reflow(nsIPresContext& aPresContext,
|
||||
nsReflowMetrics& aDesiredSize,
|
||||
const nsReflowState& aReflowState,
|
||||
nsReflowStatus& aStatus)
|
||||
{
|
||||
NS_FRAME_TRACE_REFLOW_IN("RootFrame::Reflow");
|
||||
|
||||
#ifdef NS_DEBUG
|
||||
PreReflowCheck();
|
||||
#endif
|
||||
|
||||
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");
|
||||
|
||||
} else {
|
||||
// Do we have any children?
|
||||
if (nsnull == mFirstChild) {
|
||||
// No. Create a pseudo frame
|
||||
NS_ASSERTION(eReflowReason_Initial == aReflowState.reason, "unexpected reflow reason");
|
||||
mFirstChild = new RootContentFrame(mContent, this);
|
||||
mChildCount = 1;
|
||||
nsIStyleContext* style = aPresContext.ResolvePseudoStyleContextFor(nsHTMLAtoms::rootContentPseudo, this);
|
||||
mFirstChild->SetStyleContext(&aPresContext,style);
|
||||
NS_RELEASE(style);
|
||||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
||||
mLastContentOffset = ((RootContentFrame*)mFirstChild)->GetLastContentOffset();
|
||||
}
|
||||
|
||||
// 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;
|
||||
|
||||
#ifdef NS_DEBUG
|
||||
PostReflowCheck(aStatus);
|
||||
#endif
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
RootContentFrame::CreateFirstChild(nsIPresContext* aPresContext)
|
||||
{
|
||||
// Are we paginated?
|
||||
if (aPresContext->IsPaginated()) {
|
||||
// Yes. Create the first page frame
|
||||
mFirstChild = new nsPageFrame(mContent, this);
|
||||
mChildCount = 1;
|
||||
mLastContentOffset = mFirstContentOffset;
|
||||
|
||||
} else {
|
||||
// Create a frame for the body/frameset child
|
||||
PRInt32 i, n;
|
||||
mContent->ChildCount(n);
|
||||
for (i = 0; i < n; i++) {
|
||||
nsIContent* child;
|
||||
mContent->ChildAt(i, child);
|
||||
if (nsnull != child) {
|
||||
nsIAtom* tag;
|
||||
child->GetTag(tag);
|
||||
if ((nsHTMLAtoms::body == tag) || (nsHTMLAtoms::frameset == tag)) {
|
||||
// Create a frame
|
||||
nsIContentDelegate* cd = child->GetDelegate(aPresContext);
|
||||
if (nsnull != cd) {
|
||||
nsIStyleContext* kidStyleContext =
|
||||
aPresContext->ResolveStyleContextFor(child, this);
|
||||
nsresult rv = cd->CreateFrame(aPresContext, child, this,
|
||||
kidStyleContext, mFirstChild);
|
||||
NS_RELEASE(kidStyleContext);
|
||||
if (NS_OK == rv) {
|
||||
mChildCount = 1;
|
||||
mFirstContentOffset = i;
|
||||
mLastContentOffset = i;
|
||||
}
|
||||
NS_RELEASE(cd);
|
||||
}
|
||||
}
|
||||
NS_IF_RELEASE(tag);
|
||||
NS_RELEASE(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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");
|
||||
#ifdef NS_DEBUG
|
||||
PreReflowCheck();
|
||||
#endif
|
||||
|
||||
aStatus = NS_FRAME_COMPLETE;
|
||||
|
||||
// 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(aReflowState.maxSize.width, 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. 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);
|
||||
|
||||
} else {
|
||||
nsReflowReason reflowReason = aReflowState.reason;
|
||||
|
||||
// Do we have any children?
|
||||
if (nsnull == mFirstChild) {
|
||||
// No, create the first child frame
|
||||
reflowReason = eReflowReason_Initial;
|
||||
CreateFirstChild(&aPresContext);
|
||||
}
|
||||
|
||||
// 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);
|
||||
mChildCount++;
|
||||
}
|
||||
|
||||
// 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 {
|
||||
// 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);
|
||||
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. 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;
|
||||
}
|
||||
|
||||
// Place and size the child
|
||||
nsRect rect(0, 0, aDesiredSize.width, aDesiredSize.height);
|
||||
mFirstChild->SetRect(rect);
|
||||
|
||||
// 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;
|
||||
parent->PropagateContentOffsets(this, mFirstContentOffset,
|
||||
mLastContentOffset, mLastContentIsComplete);
|
||||
|
||||
#ifdef NS_DEBUG
|
||||
PostReflowCheck(aStatus);
|
||||
#endif
|
||||
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);
|
||||
}
|
||||
|
||||
nsContainerFrame::Paint(aPresContext, aRenderingContext, aDirtyRect);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
928
mozilla/layout/generic/nsImageFrame.cpp
Normal file
928
mozilla/layout/generic/nsImageFrame.cpp
Normal file
@ -0,0 +1,928 @@
|
||||
/* -*- 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 "nsHTMLImage.h"
|
||||
#include "nsHTMLTagContent.h"
|
||||
#include "nsString.h"
|
||||
#include "nsLeafFrame.h"
|
||||
#include "nsIPresContext.h"
|
||||
#include "nsIRenderingContext.h"
|
||||
#include "nsIFrameImageLoader.h"
|
||||
#include "nsIPresShell.h"
|
||||
#include "nsHTMLIIDs.h"
|
||||
#include "nsIImage.h"
|
||||
#include "nsIWidget.h"
|
||||
#include "nsHTMLAtoms.h"
|
||||
#include "nsIHTMLAttributes.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsIHTMLDocument.h"
|
||||
#include "nsIStyleContext.h"
|
||||
#include "nsStyleConsts.h"
|
||||
#include "nsIImageMap.h"
|
||||
#include "nsILinkHandler.h"
|
||||
#include "nsIURL.h"
|
||||
#include "nsIView.h"
|
||||
#include "nsIViewManager.h"
|
||||
#include "nsCSSLayout.h"
|
||||
#include "nsHTMLBase.h"
|
||||
#include "prprf.h"
|
||||
#include "nsISizeOfHandler.h"
|
||||
#include "nsIFontMetrics.h"
|
||||
#include "nsCSSRendering.h"
|
||||
#include "nsIDOMHTMLImageElement.h"
|
||||
|
||||
#define BROKEN_IMAGE_URL "resource:/res/html/broken-image.gif"
|
||||
|
||||
#define XP_IS_SPACE(_ch) \
|
||||
(((_ch) == ' ') || ((_ch) == '\t') || ((_ch) == '\n'))
|
||||
|
||||
// XXX image frame layout can be 100% decoupled from the content
|
||||
// object; all it needs are attributes to work properly
|
||||
|
||||
static NS_DEFINE_IID(kIHTMLDocumentIID, NS_IHTMLDOCUMENT_IID);
|
||||
|
||||
#if 0
|
||||
#define nsHTMLImageSuper nsHTMLTagContent
|
||||
class nsHTMLImage : public nsHTMLImageSuper, public nsIDOMHTMLImageElement {
|
||||
public:
|
||||
nsHTMLImage(nsIAtom* aTag);
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
NS_IMETHOD SizeOf(nsISizeOfHandler* aHandler) const;
|
||||
NS_IMETHOD CreateFrame(nsIPresContext* aPresContext,
|
||||
nsIFrame* aParentFrame,
|
||||
nsIStyleContext* aStyleContext,
|
||||
nsIFrame*& aResult);
|
||||
|
||||
NS_IMETHOD SetAttribute(nsIAtom* aAttribute, const nsString& aValue,
|
||||
PRBool aNotify);
|
||||
NS_IMETHOD MapAttributesInto(nsIStyleContext* aContext,
|
||||
nsIPresContext* aPresContext);
|
||||
NS_IMETHOD AttributeToString(nsIAtom* aAttribute,
|
||||
nsHTMLValue& aValue,
|
||||
nsString& aResult) const;
|
||||
|
||||
NS_FORWARD_IDOMNODE(nsHTMLImageSuper::)
|
||||
NS_FORWARD_IDOMELEMENT(nsHTMLImageSuper::)
|
||||
NS_FORWARD_IDOMHTMLELEMENT(nsHTMLImageSuper::)
|
||||
|
||||
NS_DECL_IDOMHTMLIMAGEELEMENT
|
||||
|
||||
NS_IMETHOD GetScriptObject(nsIScriptContext *aContext, void** aScriptObject);
|
||||
|
||||
protected:
|
||||
virtual ~nsHTMLImage();
|
||||
void SizeOfWithoutThis(nsISizeOfHandler* aHandler) const;
|
||||
|
||||
void TriggerReflow();
|
||||
};
|
||||
#endif
|
||||
|
||||
#define ImageFrameSuper nsLeafFrame
|
||||
class ImageFrame : public ImageFrameSuper {
|
||||
public:
|
||||
ImageFrame(nsIContent* aContent, nsIFrame* aParentFrame);
|
||||
|
||||
NS_IMETHOD DeleteFrame(nsIPresContext& aPresContext);
|
||||
NS_IMETHOD SizeOf(nsISizeOfHandler* aHandler) const;
|
||||
NS_IMETHOD Paint(nsIPresContext& aPresContext,
|
||||
nsIRenderingContext& aRenderingContext,
|
||||
const nsRect& aDirtyRect);
|
||||
NS_METHOD HandleEvent(nsIPresContext& aPresContext,
|
||||
nsGUIEvent* aEvent,
|
||||
nsEventStatus& aEventStatus);
|
||||
NS_IMETHOD GetCursorAndContentAt(nsIPresContext& aPresContext,
|
||||
const nsPoint& aPoint,
|
||||
nsIFrame** aFrame,
|
||||
nsIContent** aContent,
|
||||
PRInt32& aCursor);
|
||||
NS_IMETHOD ContentChanged(nsIPresShell* aShell,
|
||||
nsIPresContext* aPresContext,
|
||||
nsIContent* aChild,
|
||||
nsISupports* aSubContent);
|
||||
|
||||
protected:
|
||||
virtual ~ImageFrame();
|
||||
void SizeOfWithoutThis(nsISizeOfHandler* aHandler) const;
|
||||
|
||||
virtual void GetDesiredSize(nsIPresContext* aPresContext,
|
||||
const nsReflowState& aReflowState,
|
||||
nsReflowMetrics& aDesiredSize);
|
||||
|
||||
nsIImageMap* GetImageMap();
|
||||
|
||||
nsHTMLImageLoader mImageLoader;
|
||||
nsIImageMap* mImageMap;
|
||||
PRBool mSizeFrozen;
|
||||
|
||||
void TriggerLink(nsIPresContext& aPresContext,
|
||||
const nsString& aURLSpec,
|
||||
const nsString& aTargetSpec,
|
||||
PRBool aClick);
|
||||
|
||||
PRBool IsServerImageMap();
|
||||
PRIntn GetSuppress();
|
||||
|
||||
nscoord MeasureString(nsIFontMetrics* aFontMetrics,
|
||||
const PRUnichar* aString,
|
||||
PRInt32 aLength,
|
||||
nscoord aMaxWidth,
|
||||
PRUint32& aMaxFit);
|
||||
|
||||
void DisplayAltText(nsIPresContext& aPresContext,
|
||||
nsIRenderingContext& aRenderingContext,
|
||||
const nsString& aAltText,
|
||||
const nsRect& aRect);
|
||||
};
|
||||
|
||||
// Value's for mSuppress
|
||||
#define SUPPRESS_UNSET 0
|
||||
#define DONT_SUPPRESS 1
|
||||
#define SUPPRESS 2
|
||||
#define DEFAULT_SUPPRESS 3
|
||||
|
||||
// Default alignment value (so we can tell an unset value from a set value)
|
||||
#define ALIGN_UNSET PRUint8(-1)
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
nsHTMLImageLoader::nsHTMLImageLoader()
|
||||
{
|
||||
mImageLoader = nsnull;
|
||||
mLoadImageFailed = PR_FALSE;
|
||||
mLoadBrokenImageFailed = PR_FALSE;
|
||||
mURLSpec = nsnull;
|
||||
mBaseHREF = nsnull;
|
||||
}
|
||||
|
||||
nsHTMLImageLoader::~nsHTMLImageLoader()
|
||||
{
|
||||
NS_IF_RELEASE(mImageLoader);
|
||||
if (nsnull != mURLSpec) {
|
||||
delete mURLSpec;
|
||||
}
|
||||
if (nsnull != mBaseHREF) {
|
||||
delete mBaseHREF;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsHTMLImageLoader::SizeOf(nsISizeOfHandler* aHandler) const
|
||||
{
|
||||
aHandler->Add(sizeof(*this));
|
||||
if (!aHandler->HaveSeen(mURLSpec)) {
|
||||
mURLSpec->SizeOf(aHandler);
|
||||
}
|
||||
if (!aHandler->HaveSeen(mImageLoader)) {
|
||||
mImageLoader->SizeOf(aHandler);
|
||||
}
|
||||
}
|
||||
|
||||
nsIImage*
|
||||
nsHTMLImageLoader::GetImage()
|
||||
{
|
||||
nsIImage* image = nsnull;
|
||||
if (nsnull != mImageLoader) {
|
||||
mImageLoader->GetImage(image);
|
||||
}
|
||||
return image;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHTMLImageLoader::SetURL(const nsString& aURLSpec)
|
||||
{
|
||||
if (nsnull != mURLSpec) {
|
||||
delete mURLSpec;
|
||||
}
|
||||
mURLSpec = new nsString(aURLSpec);
|
||||
if (nsnull == mURLSpec) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHTMLImageLoader::SetBaseHREF(const nsString& aBaseHREF)
|
||||
{
|
||||
if (nsnull != mBaseHREF) {
|
||||
delete mBaseHREF;
|
||||
}
|
||||
mBaseHREF = new nsString(aBaseHREF);
|
||||
if (nsnull == mBaseHREF) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHTMLImageLoader::StartLoadImage(nsIPresContext* aPresContext,
|
||||
nsIFrame* aForFrame,
|
||||
PRBool aNeedSizeUpdate,
|
||||
PRIntn& aLoadStatus)
|
||||
{
|
||||
aLoadStatus = NS_IMAGE_LOAD_STATUS_NONE;
|
||||
|
||||
// Get absolute url the first time through
|
||||
nsresult rv;
|
||||
nsAutoString src;
|
||||
if (mLoadImageFailed || (nsnull == mURLSpec)) {
|
||||
src.Append(BROKEN_IMAGE_URL);
|
||||
} else {
|
||||
nsAutoString baseURL;
|
||||
if (nsnull != mBaseHREF) {
|
||||
baseURL = *mBaseHREF;
|
||||
}
|
||||
|
||||
// Get documentURL
|
||||
nsIPresShell* shell;
|
||||
shell = aPresContext->GetShell();
|
||||
nsIDocument* doc = shell->GetDocument();
|
||||
nsIURL* docURL = doc->GetDocumentURL();
|
||||
|
||||
// Create an absolute URL
|
||||
nsresult rv = NS_MakeAbsoluteURL(docURL, baseURL, *mURLSpec, src);
|
||||
|
||||
// Release references
|
||||
NS_RELEASE(shell);
|
||||
NS_RELEASE(docURL);
|
||||
NS_RELEASE(doc);
|
||||
if (NS_OK != rv) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
if (nsnull == mImageLoader) {
|
||||
// Start image loading. Note that we don't specify a background color
|
||||
// so transparent images are always rendered using a transparency mask
|
||||
rv = aPresContext->StartLoadImage(src, nsnull, aForFrame, aNeedSizeUpdate,
|
||||
mImageLoader);
|
||||
if (NS_OK != rv) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
// Examine current image load status
|
||||
mImageLoader->GetImageLoadStatus(aLoadStatus);
|
||||
if (0 != (aLoadStatus & NS_IMAGE_LOAD_STATUS_ERROR)) {
|
||||
NS_RELEASE(mImageLoader);
|
||||
if (mLoadImageFailed) {
|
||||
// We are doomed. Loading the broken image has just failed.
|
||||
mLoadBrokenImageFailed = PR_TRUE;
|
||||
}
|
||||
else {
|
||||
// Try again, this time using the broke-image url
|
||||
mLoadImageFailed = PR_TRUE;
|
||||
return StartLoadImage(aPresContext, aForFrame, aNeedSizeUpdate, aLoadStatus);
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsHTMLImageLoader::GetDesiredSize(nsIPresContext* aPresContext,
|
||||
const nsReflowState& aReflowState,
|
||||
nsReflowMetrics& aDesiredSize)
|
||||
{
|
||||
nsSize styleSize;
|
||||
PRIntn ss = nsCSSLayout::GetStyleSize(aPresContext, aReflowState, styleSize);
|
||||
PRIntn loadStatus;
|
||||
if (0 != ss) {
|
||||
if (NS_SIZE_HAS_BOTH == ss) {
|
||||
StartLoadImage(aPresContext, aReflowState.frame, PR_FALSE, loadStatus);
|
||||
aDesiredSize.width = styleSize.width;
|
||||
aDesiredSize.height = styleSize.height;
|
||||
}
|
||||
else {
|
||||
// Preserve aspect ratio of image with unbound dimension.
|
||||
StartLoadImage(aPresContext, aReflowState.frame, PR_TRUE, loadStatus);
|
||||
if ((0 == (loadStatus & NS_IMAGE_LOAD_STATUS_SIZE_AVAILABLE)) ||
|
||||
(nsnull == mImageLoader)) {
|
||||
// Provide a dummy size for now; later on when the image size
|
||||
// shows up we will reflow to the new size.
|
||||
aDesiredSize.width = 1;
|
||||
aDesiredSize.height = 1;
|
||||
}
|
||||
else {
|
||||
float p2t = aPresContext->GetPixelsToTwips();
|
||||
nsSize imageSize;
|
||||
mImageLoader->GetSize(imageSize);
|
||||
float imageWidth = imageSize.width * p2t;
|
||||
float imageHeight = imageSize.height * p2t;
|
||||
if (0.0f != imageHeight) {
|
||||
if (0 != (ss & NS_SIZE_HAS_WIDTH)) {
|
||||
// We have a width, and an auto height. Compute height
|
||||
// from width.
|
||||
aDesiredSize.width = styleSize.width;
|
||||
aDesiredSize.height =
|
||||
(nscoord)NSToIntRound(styleSize.width * imageHeight / imageWidth);
|
||||
}
|
||||
else {
|
||||
// We have a height and an auto width. Compute width from
|
||||
// height.
|
||||
aDesiredSize.height = styleSize.height;
|
||||
aDesiredSize.width =
|
||||
(nscoord)NSToIntRound(styleSize.height * imageWidth / imageHeight);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Screwy image
|
||||
aDesiredSize.width = 1;
|
||||
aDesiredSize.height = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
StartLoadImage(aPresContext, aReflowState.frame, PR_TRUE, loadStatus);
|
||||
if ((0 == (loadStatus & NS_IMAGE_LOAD_STATUS_SIZE_AVAILABLE)) ||
|
||||
(nsnull == mImageLoader)) {
|
||||
// Provide a dummy size for now; later on when the image size
|
||||
// shows up we will reflow to the new size.
|
||||
aDesiredSize.width = 1;
|
||||
aDesiredSize.height = 1;
|
||||
printf ("in image loader, dummy size of 1 returned\n");
|
||||
} else {
|
||||
float p2t = aPresContext->GetPixelsToTwips();
|
||||
nsSize imageSize;
|
||||
mImageLoader->GetSize(imageSize);
|
||||
aDesiredSize.width = NSIntPixelsToTwips(imageSize.width, p2t);
|
||||
aDesiredSize.height = NSIntPixelsToTwips(imageSize.height, p2t);
|
||||
printf ("in image loader, real size of %d returned\n", aDesiredSize.width);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
nsresult
|
||||
NS_NewImageFrame(nsIContent* aContent,
|
||||
nsIFrame* aParentFrame,
|
||||
nsIFrame*& aResult)
|
||||
{
|
||||
ImageFrame* frame = new ImageFrame(aContent, aParentFrame);
|
||||
if (nsnull == frame) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
aResult = frame;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
ImageFrame::ImageFrame(nsIContent* aContent, nsIFrame* aParentFrame)
|
||||
: nsLeafFrame(aContent, aParentFrame)
|
||||
{
|
||||
}
|
||||
|
||||
ImageFrame::~ImageFrame()
|
||||
{
|
||||
}
|
||||
|
||||
NS_METHOD
|
||||
ImageFrame::DeleteFrame(nsIPresContext& aPresContext)
|
||||
{
|
||||
NS_IF_RELEASE(mImageMap);
|
||||
|
||||
// Release image loader first so that it's refcnt can go to zero
|
||||
mImageLoader.DestroyLoader();
|
||||
|
||||
return nsLeafFrame::DeleteFrame(aPresContext);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ImageFrame::SizeOf(nsISizeOfHandler* aHandler) const
|
||||
{
|
||||
aHandler->Add(sizeof(*this));
|
||||
ImageFrame::SizeOfWithoutThis(aHandler);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
ImageFrame::SizeOfWithoutThis(nsISizeOfHandler* aHandler) const
|
||||
{
|
||||
ImageFrameSuper::SizeOfWithoutThis(aHandler);
|
||||
mImageLoader.SizeOf(aHandler);
|
||||
if (!aHandler->HaveSeen(mImageMap)) {
|
||||
mImageMap->SizeOf(aHandler);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ImageFrame::GetDesiredSize(nsIPresContext* aPresContext,
|
||||
const nsReflowState& aReflowState,
|
||||
nsReflowMetrics& aDesiredSize)
|
||||
{
|
||||
if (mSizeFrozen) {
|
||||
aDesiredSize.width = mRect.width;
|
||||
aDesiredSize.height = mRect.height;
|
||||
}
|
||||
else {
|
||||
// XXX Don't create a view, because we want whatever is below the image
|
||||
// to show through while the image is loading; Likewise for transparent
|
||||
// images and broken images
|
||||
//
|
||||
// What we really want to do is to create a view, and indicate that the
|
||||
// view has a transparent content area. Do this while it's loading,
|
||||
// and then when it's fully loaded mark the view as opaque if the
|
||||
// image is opaque.
|
||||
//
|
||||
// We can't use that approach yet, because currently the compositor doesn't
|
||||
// support transparent views...
|
||||
#if 0
|
||||
nsHTMLBase::CreateViewForFrame(aPresContext, this, mStyleContext, PR_TRUE);
|
||||
#endif
|
||||
|
||||
// Setup url before starting the image load
|
||||
nsAutoString src, base;
|
||||
if (NS_CONTENT_ATTR_HAS_VALUE == mContent->GetAttribute("SRC", src)) {
|
||||
mImageLoader.SetURL(src);
|
||||
if (NS_CONTENT_ATTR_HAS_VALUE ==
|
||||
mContent->GetAttribute(NS_HTML_BASE_HREF, base)) {
|
||||
mImageLoader.SetBaseHREF(base);
|
||||
}
|
||||
}
|
||||
mImageLoader.GetDesiredSize(aPresContext, aReflowState, aDesiredSize);
|
||||
}
|
||||
}
|
||||
|
||||
// Computes the width of the specified string. aMaxWidth specifies the maximum
|
||||
// width available. Once this limit is reached no more characters are measured.
|
||||
// The number of characters that fit within the maximum width are returned in
|
||||
// aMaxFit
|
||||
nscoord
|
||||
ImageFrame::MeasureString(nsIFontMetrics* aFontMetrics,
|
||||
const PRUnichar* aString,
|
||||
PRInt32 aLength,
|
||||
nscoord aMaxWidth,
|
||||
PRUint32& aMaxFit)
|
||||
{
|
||||
nscoord totalWidth = 0;
|
||||
nscoord spaceWidth;
|
||||
aFontMetrics->GetWidth(' ', spaceWidth);
|
||||
|
||||
aMaxFit = 0;
|
||||
while (aLength > 0) {
|
||||
// Find the next place we can line break
|
||||
PRUint32 len = aLength;
|
||||
PRBool trailingSpace = PR_FALSE;
|
||||
for (PRInt32 i = 0; i < aLength; i++) {
|
||||
if (XP_IS_SPACE(aString[i]) && (i > 0)) {
|
||||
len = i; // don't include the space when measuring
|
||||
trailingSpace = PR_TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Measure this chunk of text, and see if it fits
|
||||
nscoord width;
|
||||
aFontMetrics->GetWidth(aString, len, width);
|
||||
PRBool fits = (totalWidth + width) <= aMaxWidth;
|
||||
|
||||
// If it fits on the line, or it's the first word we've processed then
|
||||
// include it
|
||||
if (fits || (0 == totalWidth)) {
|
||||
// New piece fits
|
||||
totalWidth += width;
|
||||
|
||||
// If there's a trailing space then see if it fits as well
|
||||
if (trailingSpace) {
|
||||
if ((totalWidth + spaceWidth) <= aMaxWidth) {
|
||||
totalWidth += spaceWidth;
|
||||
} else {
|
||||
// Space won't fit. Leave it at the end but don't include it in
|
||||
// the width
|
||||
fits = PR_FALSE;
|
||||
}
|
||||
|
||||
len++;
|
||||
}
|
||||
|
||||
aMaxFit += len;
|
||||
aString += len;
|
||||
aLength -= len;
|
||||
}
|
||||
|
||||
if (!fits) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return totalWidth;
|
||||
}
|
||||
|
||||
// Formats the alt-text to fit within the specified rectangle. Breaks lines
|
||||
// between words if a word would extend past the edge of the rectangle
|
||||
void
|
||||
ImageFrame::DisplayAltText(nsIPresContext& aPresContext,
|
||||
nsIRenderingContext& aRenderingContext,
|
||||
const nsString& aAltText,
|
||||
const nsRect& aRect)
|
||||
{
|
||||
// Clip so we don't render outside of the rect.
|
||||
aRenderingContext.PushState();
|
||||
aRenderingContext.SetClipRect(aRect, nsClipCombine_kIntersect);
|
||||
|
||||
const nsStyleColor* color =
|
||||
(const nsStyleColor*)mStyleContext->GetStyleData(eStyleStruct_Color);
|
||||
const nsStyleFont* font =
|
||||
(const nsStyleFont*)mStyleContext->GetStyleData(eStyleStruct_Font);
|
||||
|
||||
// Set font and color
|
||||
aRenderingContext.SetColor(color->mColor);
|
||||
aRenderingContext.SetFont(font->mFont);
|
||||
|
||||
// Format the text to display within the formatting rect
|
||||
nsIFontMetrics* fm = aRenderingContext.GetFontMetrics();
|
||||
|
||||
nscoord maxDescent, height;
|
||||
fm->GetMaxDescent(maxDescent);
|
||||
fm->GetHeight(height);
|
||||
|
||||
// XXX It would be nice if there was a way to have the font metrics tell
|
||||
// use where to break the text given a maximum width. At a minimum we need
|
||||
// to be able to get the break character...
|
||||
const PRUnichar* str = aAltText.GetUnicode();
|
||||
PRInt32 strLen = aAltText.Length();
|
||||
nscoord y = aRect.y;
|
||||
while ((strLen > 0) && ((y + maxDescent) < aRect.YMost())) {
|
||||
// Determine how much of the text to display on this line
|
||||
PRUint32 maxFit; // number of characters that fit
|
||||
nscoord width = MeasureString(fm, str, strLen, aRect.width, maxFit);
|
||||
|
||||
// Display the text
|
||||
aRenderingContext.DrawString(str, maxFit, aRect.x, y, 0);
|
||||
|
||||
// Move to the next line
|
||||
str += maxFit;
|
||||
strLen -= maxFit;
|
||||
y += height;
|
||||
}
|
||||
|
||||
NS_RELEASE(fm);
|
||||
aRenderingContext.PopState();
|
||||
}
|
||||
|
||||
struct nsRecessedBorder : public nsStyleSpacing {
|
||||
nsRecessedBorder(nscoord aBorderWidth)
|
||||
: nsStyleSpacing()
|
||||
{
|
||||
nsStyleCoord styleCoord(aBorderWidth);
|
||||
|
||||
mBorder.SetLeft(styleCoord);
|
||||
mBorder.SetTop(styleCoord);
|
||||
mBorder.SetRight(styleCoord);
|
||||
mBorder.SetBottom(styleCoord);
|
||||
mBorderStyle[0] = NS_STYLE_BORDER_STYLE_INSET;
|
||||
mBorderStyle[1] = NS_STYLE_BORDER_STYLE_INSET;
|
||||
mBorderStyle[2] = NS_STYLE_BORDER_STYLE_INSET;
|
||||
mBorderStyle[3] = NS_STYLE_BORDER_STYLE_INSET;
|
||||
mBorderColor[0] = 0;
|
||||
mBorderColor[1] = 0;
|
||||
mBorderColor[2] = 0;
|
||||
mBorderColor[3] = 0;
|
||||
mHasCachedMargin = mHasCachedPadding = mHasCachedBorder = PR_FALSE;
|
||||
}
|
||||
};
|
||||
|
||||
NS_METHOD
|
||||
ImageFrame::Paint(nsIPresContext& aPresContext,
|
||||
nsIRenderingContext& aRenderingContext,
|
||||
const nsRect& aDirtyRect)
|
||||
{
|
||||
if ((0 == mRect.width) || (0 == mRect.height)) {
|
||||
// Do not render when given a zero area. This avoids some useless
|
||||
// scaling work while we wait for our image dimensions to arrive
|
||||
// asynchronously.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
const nsStyleDisplay* disp =
|
||||
(const nsStyleDisplay*)mStyleContext->GetStyleData(eStyleStruct_Display);
|
||||
|
||||
if (disp->mVisible) {
|
||||
// First paint background and borders
|
||||
nsLeafFrame::Paint(aPresContext, aRenderingContext, aDirtyRect);
|
||||
|
||||
nsIImage* image = mImageLoader.GetImage();
|
||||
if (nsnull == image) {
|
||||
// No image yet. Draw the icon that indicates we're loading, and display
|
||||
// the alt-text
|
||||
nsAutoString altText;
|
||||
if (NS_CONTENT_ATTR_HAS_VALUE == mContent->GetAttribute("ALT", altText)) {
|
||||
// Display a recessed one-pixel border in the inner area
|
||||
nsRect inner;
|
||||
GetInnerArea(&aPresContext, inner);
|
||||
|
||||
float p2t = aPresContext.GetPixelsToTwips();
|
||||
nsRecessedBorder recessedBorder(NSIntPixelsToTwips(1, p2t));
|
||||
nsCSSRendering::PaintBorder(aPresContext, aRenderingContext, this, inner,
|
||||
inner, recessedBorder, 0);
|
||||
inner.Deflate(NSIntPixelsToTwips(1, p2t), NSIntPixelsToTwips(1, p2t));
|
||||
|
||||
// Leave a 8 pixel left/right padding, and a 5 pixel top/bottom padding
|
||||
inner.Deflate(NSIntPixelsToTwips(8, p2t), NSIntPixelsToTwips(5, p2t));
|
||||
|
||||
// If there's room, then display the alt-text
|
||||
if (!inner.IsEmpty()) {
|
||||
DisplayAltText(aPresContext, aRenderingContext, altText, inner);
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Now render the image into our inner area (the area without the
|
||||
// borders and padding)
|
||||
nsRect inner;
|
||||
GetInnerArea(&aPresContext, inner);
|
||||
if (mImageLoader.GetLoadImageFailed()) {
|
||||
float p2t = aPresContext.GetPixelsToTwips();
|
||||
inner.width = NSIntPixelsToTwips(image->GetWidth(), p2t);
|
||||
inner.height = NSIntPixelsToTwips(image->GetHeight(), p2t);
|
||||
}
|
||||
aRenderingContext.DrawImage(image, inner);
|
||||
|
||||
if (GetShowFrameBorders()) {
|
||||
nsIImageMap* map = GetImageMap();
|
||||
if (nsnull != map) {
|
||||
aRenderingContext.SetColor(NS_RGB(0, 0, 0));
|
||||
aRenderingContext.PushState();
|
||||
aRenderingContext.Translate(inner.x, inner.y);
|
||||
map->Draw(aPresContext, aRenderingContext);
|
||||
aRenderingContext.PopState();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsIImageMap*
|
||||
ImageFrame::GetImageMap()
|
||||
{
|
||||
if (nsnull == mImageMap) {
|
||||
nsAutoString usemap;
|
||||
mContent->GetAttribute("usemap", usemap);
|
||||
if (0 == usemap.Length()) {
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
nsIDocument* doc = nsnull;
|
||||
mContent->GetDocument(doc);
|
||||
if (nsnull == doc) {
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
if (usemap.First() == '#') {
|
||||
usemap.Cut(0, 1);
|
||||
}
|
||||
nsIHTMLDocument* hdoc;
|
||||
nsresult rv = doc->QueryInterface(kIHTMLDocumentIID, (void**)&hdoc);
|
||||
NS_RELEASE(doc);
|
||||
if (NS_OK == rv) {
|
||||
nsIImageMap* map;
|
||||
rv = hdoc->GetImageMap(usemap, &map);
|
||||
NS_RELEASE(hdoc);
|
||||
if (NS_OK == rv) {
|
||||
mImageMap = map;
|
||||
}
|
||||
}
|
||||
}
|
||||
NS_IF_ADDREF(mImageMap);
|
||||
return mImageMap;
|
||||
}
|
||||
|
||||
void
|
||||
ImageFrame::TriggerLink(nsIPresContext& aPresContext,
|
||||
const nsString& aURLSpec,
|
||||
const nsString& aTargetSpec,
|
||||
PRBool aClick)
|
||||
{
|
||||
nsILinkHandler* handler = nsnull;
|
||||
aPresContext.GetLinkHandler(&handler);
|
||||
if (nsnull != handler) {
|
||||
if (aClick) {
|
||||
handler->OnLinkClick(this, aURLSpec, aTargetSpec);
|
||||
}
|
||||
else {
|
||||
handler->OnOverLink(this, aURLSpec, aTargetSpec);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PRBool
|
||||
ImageFrame::IsServerImageMap()
|
||||
{
|
||||
nsAutoString ismap;
|
||||
return NS_CONTENT_ATTR_HAS_VALUE == mContent->GetAttribute("ismap", ismap);
|
||||
}
|
||||
|
||||
PRIntn
|
||||
ImageFrame::GetSuppress()
|
||||
{
|
||||
nsAutoString s;
|
||||
if (NS_CONTENT_ATTR_HAS_VALUE == mContent->GetAttribute("suppress", s)) {
|
||||
if (s.EqualsIgnoreCase("true")) {
|
||||
return SUPPRESS;
|
||||
} else if (s.EqualsIgnoreCase("false")) {
|
||||
return DONT_SUPPRESS;
|
||||
}
|
||||
}
|
||||
return DEFAULT_SUPPRESS;
|
||||
}
|
||||
|
||||
// XXX what should clicks on transparent pixels do?
|
||||
NS_METHOD
|
||||
ImageFrame::HandleEvent(nsIPresContext& aPresContext,
|
||||
nsGUIEvent* aEvent,
|
||||
nsEventStatus& aEventStatus)
|
||||
{
|
||||
nsIImageMap* map;
|
||||
aEventStatus = nsEventStatus_eIgnore;
|
||||
|
||||
switch (aEvent->message) {
|
||||
case NS_MOUSE_LEFT_BUTTON_UP:
|
||||
case NS_MOUSE_MOVE:
|
||||
map = GetImageMap();
|
||||
if ((nsnull != map) || IsServerImageMap()) {
|
||||
nsIURL* docURL = nsnull;
|
||||
nsIDocument* doc = nsnull;
|
||||
mContent->GetDocument(doc);
|
||||
if (nsnull != doc) {
|
||||
docURL = doc->GetDocumentURL();
|
||||
NS_RELEASE(doc);
|
||||
}
|
||||
|
||||
// Ask map if the x,y coordinates are in a clickable area
|
||||
float t2p = aPresContext.GetTwipsToPixels();
|
||||
nsAutoString absURL, target, altText;
|
||||
PRBool suppress;
|
||||
if (nsnull != map) {
|
||||
// Subtract out border and padding here so that we are looking
|
||||
// at the right coordinates. Hit detection against area tags
|
||||
// is done after the mouse wanders over the image, not over
|
||||
// the image's borders.
|
||||
nsRect inner;
|
||||
GetInnerArea(&aPresContext, inner);
|
||||
PRInt32 x = NSTwipsToIntPixels((aEvent->point.x - inner.x), t2p);
|
||||
PRInt32 y = NSTwipsToIntPixels((aEvent->point.y - inner.y), t2p);
|
||||
nsresult r = map->IsInside(x, y, docURL, absURL, target, altText,
|
||||
&suppress);
|
||||
NS_IF_RELEASE(docURL);
|
||||
NS_RELEASE(map);
|
||||
if (NS_OK == r) {
|
||||
// We hit a clickable area. Time to go somewhere...
|
||||
PRBool clicked = PR_FALSE;
|
||||
if (aEvent->message == NS_MOUSE_LEFT_BUTTON_UP) {
|
||||
aEventStatus = nsEventStatus_eConsumeNoDefault;
|
||||
clicked = PR_TRUE;
|
||||
}
|
||||
TriggerLink(aPresContext, absURL, target, clicked);
|
||||
}
|
||||
}
|
||||
else {
|
||||
suppress = GetSuppress();
|
||||
nsAutoString baseURL;
|
||||
mContent->GetAttribute(NS_HTML_BASE_HREF, baseURL);
|
||||
nsAutoString src;
|
||||
mContent->GetAttribute("src", src);
|
||||
NS_MakeAbsoluteURL(docURL, baseURL, src, absURL);
|
||||
|
||||
// Note: We don't subtract out the border/padding here to remain
|
||||
// compatible with navigator. [ick]
|
||||
PRInt32 x = NSTwipsToIntPixels(aEvent->point.x, t2p);
|
||||
PRInt32 y = NSTwipsToIntPixels(aEvent->point.y, t2p);
|
||||
char cbuf[50];
|
||||
PR_snprintf(cbuf, sizeof(cbuf), "?%d,%d", x, y);
|
||||
absURL.Append(cbuf);
|
||||
PRBool clicked = PR_FALSE;
|
||||
if (aEvent->message == NS_MOUSE_LEFT_BUTTON_UP) {
|
||||
aEventStatus = nsEventStatus_eConsumeNoDefault;
|
||||
clicked = PR_TRUE;
|
||||
}
|
||||
TriggerLink(aPresContext, absURL, target, clicked);
|
||||
}
|
||||
break;
|
||||
}
|
||||
// FALL THROUGH
|
||||
|
||||
default:
|
||||
// Let default event handler deal with it
|
||||
return nsLeafFrame::HandleEvent(aPresContext, aEvent, aEventStatus);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_METHOD
|
||||
ImageFrame::GetCursorAndContentAt(nsIPresContext& aPresContext,
|
||||
const nsPoint& aPoint,
|
||||
nsIFrame** aFrame,
|
||||
nsIContent** aContent,
|
||||
PRInt32& aCursor)
|
||||
{
|
||||
// The default cursor is to have no cursor
|
||||
aCursor = NS_STYLE_CURSOR_INHERIT;
|
||||
*aContent = mContent;
|
||||
|
||||
const nsStyleColor* styleColor = (const nsStyleColor*)
|
||||
mStyleContext->GetStyleData(eStyleStruct_Color);
|
||||
if (styleColor->mCursor != NS_STYLE_CURSOR_INHERIT) {
|
||||
// If we have a particular cursor, use it
|
||||
*aFrame = this;
|
||||
aCursor = (PRInt32) styleColor->mCursor;
|
||||
}
|
||||
|
||||
nsIImageMap* map = GetImageMap();
|
||||
if (nsnull != map) {
|
||||
nsRect inner;
|
||||
GetInnerArea(&aPresContext, inner);
|
||||
aCursor = NS_STYLE_CURSOR_DEFAULT;
|
||||
float t2p = aPresContext.GetTwipsToPixels();
|
||||
PRInt32 x = NSTwipsToIntPixels((aPoint.x - inner.x), t2p);
|
||||
PRInt32 y = NSTwipsToIntPixels((aPoint.y - inner.y), t2p);
|
||||
if (NS_OK == map->IsInside(x, y)) {
|
||||
aCursor = NS_STYLE_CURSOR_HAND;
|
||||
}
|
||||
NS_RELEASE(map);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ImageFrame::ContentChanged(nsIPresShell* aShell,
|
||||
nsIPresContext* aPresContext,
|
||||
nsIContent* aChild,
|
||||
nsISupports* aSubContent)
|
||||
{
|
||||
// See if the src attribute changed; if it did then trigger a redraw
|
||||
// by firing up a new image load request. Otherwise let our base
|
||||
// class handle the content-changed request.
|
||||
nsAutoString oldSRC;
|
||||
mImageLoader.GetURL(oldSRC);
|
||||
|
||||
// Get src attribute's value and construct a new absolute url from it
|
||||
nsAutoString newSRC;
|
||||
if (NS_CONTENT_ATTR_HAS_VALUE == mContent->GetAttribute("SRC", newSRC)) {
|
||||
if (!oldSRC.Equals(newSRC)) {
|
||||
mSizeFrozen = PR_TRUE;
|
||||
|
||||
#ifdef NS_DEBUG
|
||||
char oldcbuf[100], newcbuf[100];
|
||||
oldSRC.ToCString(oldcbuf, sizeof(oldcbuf));
|
||||
newSRC.ToCString(newcbuf, sizeof(newcbuf));
|
||||
NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,
|
||||
("ImageFrame::ContentChanged: new image source; old='%s' new='%s'",
|
||||
oldcbuf, newcbuf));
|
||||
#endif
|
||||
|
||||
// Get rid of old image loader and start a new image load going
|
||||
mImageLoader.DestroyLoader();
|
||||
|
||||
// Fire up a new image load request
|
||||
PRIntn loadStatus;
|
||||
mImageLoader.SetURL(newSRC);
|
||||
mImageLoader.StartLoadImage(aPresContext, this, PR_FALSE, loadStatus);
|
||||
|
||||
NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,
|
||||
("ImageFrame::ContentChanged: loadImage status=%x",
|
||||
loadStatus));
|
||||
|
||||
// If the image is already ready then we need to trigger a
|
||||
// redraw because the image loader won't.
|
||||
if (loadStatus & NS_IMAGE_LOAD_STATUS_IMAGE_READY) {
|
||||
// XXX Stuff this into a method on nsIPresShell/Context
|
||||
nsRect bounds;
|
||||
nsPoint offset;
|
||||
nsIView* view;
|
||||
GetOffsetFromView(offset, view);
|
||||
nsIViewManager* vm;
|
||||
view->GetViewManager(vm);
|
||||
bounds.x = offset.x;
|
||||
bounds.y = offset.y;
|
||||
bounds.width = mRect.width;
|
||||
bounds.height = mRect.height;
|
||||
vm->UpdateView(view, bounds, 0);
|
||||
NS_RELEASE(vm);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
return ImageFrameSuper::ContentChanged(aShell, aPresContext, aChild,
|
||||
aSubContent);
|
||||
}
|
||||
191
mozilla/layout/generic/nsSpacerFrame.cpp
Normal file
191
mozilla/layout/generic/nsSpacerFrame.cpp
Normal file
@ -0,0 +1,191 @@
|
||||
/* -*- 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 "nsIHTMLContent.h"
|
||||
#include "nsFrame.h"
|
||||
#include "nsIInlineReflow.h"
|
||||
#include "nsCSSLineLayout.h"
|
||||
#include "nsHTMLIIDs.h"
|
||||
#include "nsIPresContext.h"
|
||||
#include "nsIPresShell.h"
|
||||
#include "nsHTMLAtoms.h"
|
||||
#include "nsUnitConversion.h"
|
||||
#include "nsIStyleContext.h"
|
||||
#include "nsStyleConsts.h"
|
||||
|
||||
// Spacer type's
|
||||
#define TYPE_WORD 0 // horizontal space
|
||||
#define TYPE_LINE 1 // line-break + vertical space
|
||||
#define TYPE_IMAGE 2 // acts like a sized image with nothing to see
|
||||
|
||||
class SpacerFrame : public nsFrame, private nsIInlineReflow {
|
||||
public:
|
||||
SpacerFrame(nsIContent* aContent, nsIFrame* aParentFrame);
|
||||
|
||||
// nsISupports
|
||||
NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr);
|
||||
|
||||
// nsIInlineReflow
|
||||
NS_IMETHOD FindTextRuns(nsCSSLineLayout& aLineLayout,
|
||||
nsIReflowCommand* aReflowCommand);
|
||||
NS_IMETHOD InlineReflow(nsCSSLineLayout& aLineLayout,
|
||||
nsReflowMetrics& aDesiredSize,
|
||||
const nsReflowState& aReflowState);
|
||||
|
||||
PRUint8 GetType();
|
||||
|
||||
protected:
|
||||
virtual ~SpacerFrame();
|
||||
};
|
||||
|
||||
nsresult
|
||||
NS_NewSpacerFrame(nsIContent* aContent,
|
||||
nsIFrame* aParentFrame,
|
||||
nsIFrame*& aResult)
|
||||
{
|
||||
nsIFrame* frame = new SpacerFrame(aContent, aParentFrame);
|
||||
if (nsnull == frame) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
aResult = frame;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
SpacerFrame::SpacerFrame(nsIContent* aContent, nsIFrame* aParentFrame)
|
||||
: nsFrame(aContent, aParentFrame)
|
||||
{
|
||||
}
|
||||
|
||||
SpacerFrame::~SpacerFrame()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
SpacerFrame::QueryInterface(REFNSIID aIID, void** aInstancePtrResult)
|
||||
{
|
||||
NS_PRECONDITION(nsnull != aInstancePtrResult, "null pointer");
|
||||
if (nsnull == aInstancePtrResult) {
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
}
|
||||
if (aIID.Equals(kIInlineReflowIID)) {
|
||||
*aInstancePtrResult = (void*) ((nsIInlineReflow*)this);
|
||||
return NS_OK;
|
||||
}
|
||||
return nsFrame::QueryInterface(aIID, aInstancePtrResult);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
SpacerFrame::InlineReflow(nsCSSLineLayout& aLineLayout,
|
||||
nsReflowMetrics& aMetrics,
|
||||
const nsReflowState& aReflowState)
|
||||
{
|
||||
nsresult rv = NS_FRAME_COMPLETE;
|
||||
|
||||
// By default, we have no area
|
||||
aMetrics.width = 0;
|
||||
aMetrics.height = 0;
|
||||
aMetrics.ascent = 0;
|
||||
aMetrics.descent = 0;
|
||||
|
||||
nscoord width = 0;
|
||||
nscoord height = 0;
|
||||
PRUint8 type = GetType();
|
||||
nsresult ca;
|
||||
nsIHTMLContent* hc = nsnull;
|
||||
mContent->QueryInterface(kIHTMLContentIID, (void**) &hc);
|
||||
if (nsnull != hc) {
|
||||
if (type != TYPE_IMAGE) {
|
||||
nsHTMLValue val;
|
||||
ca = hc->GetAttribute(nsHTMLAtoms::size, val);
|
||||
if (NS_CONTENT_ATTR_HAS_VALUE == ca) {
|
||||
width = val.GetPixelValue();
|
||||
}
|
||||
} else {
|
||||
nsHTMLValue val;
|
||||
ca = hc->GetAttribute(nsHTMLAtoms::width, val);
|
||||
if (NS_CONTENT_ATTR_HAS_VALUE == ca) {
|
||||
if (eHTMLUnit_Pixel == val.GetUnit()) {
|
||||
width = val.GetPixelValue();
|
||||
}
|
||||
}
|
||||
ca = hc->GetAttribute(nsHTMLAtoms::height, val);
|
||||
if (NS_CONTENT_ATTR_HAS_VALUE == ca) {
|
||||
if (eHTMLUnit_Pixel == val.GetUnit()) {
|
||||
height = val.GetPixelValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
NS_RELEASE(hc);
|
||||
}
|
||||
|
||||
float p2t = aLineLayout.mPresContext->GetPixelsToTwips();
|
||||
switch (type) {
|
||||
case TYPE_WORD:
|
||||
if (0 != width) {
|
||||
aMetrics.width = NSIntPixelsToTwips(width, p2t);
|
||||
}
|
||||
break;
|
||||
|
||||
case TYPE_LINE:
|
||||
if (0 != width) {
|
||||
rv = NS_INLINE_LINE_BREAK_AFTER(0);
|
||||
aMetrics.height = NSIntPixelsToTwips(width, p2t);
|
||||
aMetrics.ascent = aMetrics.height;
|
||||
}
|
||||
break;
|
||||
|
||||
case TYPE_IMAGE:
|
||||
aMetrics.width = NSIntPixelsToTwips(width, p2t);
|
||||
aMetrics.height = NSIntPixelsToTwips(height, p2t);
|
||||
aMetrics.ascent = aMetrics.height;
|
||||
break;
|
||||
}
|
||||
|
||||
if (nsnull != aMetrics.maxElementSize) {
|
||||
aMetrics.maxElementSize->width = aMetrics.width;
|
||||
aMetrics.maxElementSize->height = aMetrics.height;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
SpacerFrame::FindTextRuns(nsCSSLineLayout& aLineLayout,
|
||||
nsIReflowCommand* aReflowCommand)
|
||||
{
|
||||
aLineLayout.EndTextRun();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
PRUint8
|
||||
SpacerFrame::GetType()
|
||||
{
|
||||
PRUint8 type = TYPE_WORD;
|
||||
nsAutoString value;
|
||||
if (NS_CONTENT_ATTR_HAS_VALUE == mContent->GetAttribute("type", value)) {
|
||||
if (value.EqualsIgnoreCase("line") ||
|
||||
value.EqualsIgnoreCase("vert") ||
|
||||
value.EqualsIgnoreCase("vertical")) {
|
||||
return TYPE_LINE;
|
||||
}
|
||||
if (value.EqualsIgnoreCase("block")) {
|
||||
return TYPE_IMAGE;
|
||||
}
|
||||
}
|
||||
return type;
|
||||
}
|
||||
1558
mozilla/layout/generic/nsTextFrame.cpp
Normal file
1558
mozilla/layout/generic/nsTextFrame.cpp
Normal file
File diff suppressed because it is too large
Load Diff
141
mozilla/layout/html/base/src/nsBRFrame.cpp
Normal file
141
mozilla/layout/html/base/src/nsBRFrame.cpp
Normal file
@ -0,0 +1,141 @@
|
||||
/* -*- 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 "nsFrame.h"
|
||||
#include "nsHTMLParts.h"
|
||||
#include "nsHTMLIIDs.h"
|
||||
#include "nsIPresContext.h"
|
||||
#include "nsIInlineReflow.h"
|
||||
#include "nsCSSLineLayout.h"
|
||||
#include "nsStyleConsts.h"
|
||||
#include "nsHTMLAtoms.h"
|
||||
#include "nsIStyleContext.h"
|
||||
#include "nsIFontMetrics.h"
|
||||
#include "nsIRenderingContext.h"
|
||||
|
||||
class BRFrame : public nsFrame, public nsIInlineReflow {
|
||||
public:
|
||||
BRFrame(nsIContent* aContent, nsIFrame* aParentFrame);
|
||||
|
||||
// nsISupports
|
||||
NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr);
|
||||
|
||||
// nsIFrame
|
||||
NS_IMETHOD Paint(nsIPresContext& aPresContext,
|
||||
nsIRenderingContext& aRenderingContext,
|
||||
const nsRect& aDirtyRect);
|
||||
|
||||
// nsIInlineReflow
|
||||
NS_IMETHOD FindTextRuns(nsCSSLineLayout& aLineLayout,
|
||||
nsIReflowCommand* aReflowCommand);
|
||||
NS_IMETHOD InlineReflow(nsCSSLineLayout& aLineLayout,
|
||||
nsReflowMetrics& aDesiredSize,
|
||||
const nsReflowState& aReflowState);
|
||||
|
||||
protected:
|
||||
virtual ~BRFrame();
|
||||
};
|
||||
|
||||
nsresult
|
||||
NS_NewBRFrame(nsIContent* aContent, nsIFrame* aParentFrame,
|
||||
nsIFrame*& aResult)
|
||||
{
|
||||
nsIFrame* frame = new BRFrame(aContent, aParentFrame);
|
||||
if (nsnull == frame) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
aResult = frame;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
BRFrame::BRFrame(nsIContent* aContent,
|
||||
nsIFrame* aParentFrame)
|
||||
: nsFrame(aContent, aParentFrame)
|
||||
{
|
||||
}
|
||||
|
||||
BRFrame::~BRFrame()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
BRFrame::QueryInterface(REFNSIID aIID, void** aInstancePtrResult)
|
||||
{
|
||||
NS_PRECONDITION(nsnull != aInstancePtrResult, "null pointer");
|
||||
if (nsnull == aInstancePtrResult) {
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
}
|
||||
if (aIID.Equals(kIInlineReflowIID)) {
|
||||
*aInstancePtrResult = (void*) ((nsIInlineReflow*)this);
|
||||
return NS_OK;
|
||||
}
|
||||
return nsFrame::QueryInterface(aIID, aInstancePtrResult);
|
||||
}
|
||||
|
||||
NS_METHOD
|
||||
BRFrame::Paint(nsIPresContext& aPresContext,
|
||||
nsIRenderingContext& aRenderingContext,
|
||||
const nsRect& aDirtyRect)
|
||||
{
|
||||
if (nsIFrame::GetShowFrameBorders()) {
|
||||
float p2t = aPresContext.GetPixelsToTwips();
|
||||
aRenderingContext.SetColor(NS_RGB(0, 255, 255));
|
||||
aRenderingContext.FillRect(0, 0, NSIntPixelsToTwips(5, p2t), mRect.height);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
BRFrame::FindTextRuns(nsCSSLineLayout& aLineLayout,
|
||||
nsIReflowCommand* aReflowCommand)
|
||||
{
|
||||
aLineLayout.EndTextRun();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
BRFrame::InlineReflow(nsCSSLineLayout& aLineLayout,
|
||||
nsReflowMetrics& aMetrics,
|
||||
const nsReflowState& aReflowState)
|
||||
{
|
||||
if (nsnull != aMetrics.maxElementSize) {
|
||||
aMetrics.maxElementSize->width = 0;
|
||||
aMetrics.maxElementSize->height = 0;
|
||||
}
|
||||
|
||||
// We have no width, but we're the height of the default font
|
||||
const nsStyleFont* font = (const nsStyleFont*)
|
||||
mStyleContext->GetStyleData(eStyleStruct_Font);
|
||||
nsIFontMetrics* fm = aLineLayout.mPresContext->GetMetricsFor(font->mFont);
|
||||
|
||||
fm->GetMaxAscent(aMetrics.ascent);
|
||||
fm->GetMaxDescent(aMetrics.descent);
|
||||
aMetrics.height = aMetrics.ascent + aMetrics.descent;
|
||||
aMetrics.width = 0;
|
||||
NS_RELEASE(fm);
|
||||
|
||||
// Return our inline reflow status
|
||||
const nsStyleDisplay* display = (const nsStyleDisplay*)
|
||||
mStyleContext->GetStyleData(eStyleStruct_Display);
|
||||
PRUint32 breakType = display->mBreakType;
|
||||
if (NS_STYLE_CLEAR_NONE == breakType) {
|
||||
breakType = NS_STYLE_CLEAR_LINE;
|
||||
}
|
||||
|
||||
return NS_INLINE_BREAK | NS_INLINE_BREAK_AFTER |
|
||||
NS_INLINE_MAKE_BREAK_TYPE(breakType);
|
||||
}
|
||||
342
mozilla/layout/html/base/src/nsHRFrame.cpp
Normal file
342
mozilla/layout/html/base/src/nsHRFrame.cpp
Normal file
@ -0,0 +1,342 @@
|
||||
/* -*- 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 "nsIHTMLContent.h"
|
||||
#include "nsLeafFrame.h"
|
||||
#include "nsIRenderingContext.h"
|
||||
#include "nsGlobalVariables.h"
|
||||
#include "nsIStyleContext.h"
|
||||
#include "nsColor.h"
|
||||
#include "nsIPresContext.h"
|
||||
#include "nsIStyleContext.h"
|
||||
#include "nsHTMLIIDs.h"
|
||||
#include "nsHTMLAtoms.h"
|
||||
#include "nsIFontMetrics.h"
|
||||
#include "nsIHTMLAttributes.h"
|
||||
#include "nsStyleConsts.h"
|
||||
#include "nsCSSRendering.h"
|
||||
#include "nsCSSLayout.h"
|
||||
#include "nsIDOMHTMLHRElement.h"
|
||||
|
||||
static NS_DEFINE_IID(kIDOMHTMLHRElementIID, NS_IDOMHTMLHRELEMENT_IID);
|
||||
|
||||
// default hr thickness in pixels
|
||||
#define DEFAULT_THICKNESS 3
|
||||
|
||||
class HRuleFrame : public nsLeafFrame {
|
||||
public:
|
||||
HRuleFrame(nsIContent* aContent,
|
||||
nsIFrame* aParentFrame);
|
||||
|
||||
NS_IMETHOD Reflow(nsIPresContext& aPresContext,
|
||||
nsReflowMetrics& aDesiredSize,
|
||||
const nsReflowState& aReflowState,
|
||||
nsReflowStatus& aStatus);
|
||||
NS_IMETHOD Paint(nsIPresContext& aPresContext,
|
||||
nsIRenderingContext& aRenderingContext,
|
||||
const nsRect& aDirtyRect);
|
||||
|
||||
protected:
|
||||
virtual ~HRuleFrame();
|
||||
|
||||
virtual void GetDesiredSize(nsIPresContext* aPresContext,
|
||||
const nsReflowState& aReflowState,
|
||||
nsReflowMetrics& aDesiredSize);
|
||||
|
||||
PRBool GetNoShade();
|
||||
PRInt32 GetThickness();
|
||||
|
||||
nscoord mComputedWidth;
|
||||
};
|
||||
|
||||
nsresult
|
||||
NS_NewHRFrame(nsIContent* aContent, nsIFrame* aParentFrame,
|
||||
nsIFrame*& aResult)
|
||||
{
|
||||
nsIFrame* frame = new HRuleFrame(aContent, aParentFrame);
|
||||
if (nsnull == frame) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
aResult = frame;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
HRuleFrame::HRuleFrame(nsIContent* aContent,
|
||||
nsIFrame* aParentFrame)
|
||||
: nsLeafFrame(aContent, aParentFrame)
|
||||
{
|
||||
}
|
||||
|
||||
HRuleFrame::~HRuleFrame()
|
||||
{
|
||||
}
|
||||
|
||||
NS_METHOD
|
||||
HRuleFrame::Paint(nsIPresContext& aPresContext,
|
||||
nsIRenderingContext& aRenderingContext,
|
||||
const nsRect& aDirtyRect)
|
||||
{
|
||||
const nsStyleDisplay* disp =
|
||||
(const nsStyleDisplay*)mStyleContext->GetStyleData(eStyleStruct_Display);
|
||||
if (PR_FALSE == disp->mVisible) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
float p2t = aPresContext.GetPixelsToTwips();
|
||||
nscoord thickness = NSIntPixelsToTwips(GetThickness(), p2t);
|
||||
|
||||
// Get style data
|
||||
const nsStyleSpacing* spacing = (const nsStyleSpacing*)
|
||||
mStyleContext->GetStyleData(eStyleStruct_Spacing);
|
||||
const nsStyleColor* color = (const nsStyleColor*)
|
||||
mStyleContext->GetStyleData(eStyleStruct_Color);
|
||||
nsMargin borderPadding;
|
||||
spacing->CalcBorderPaddingFor(this, borderPadding);
|
||||
nscoord x0 = borderPadding.left;
|
||||
nscoord y0 = borderPadding.top;
|
||||
nscoord width = mRect.width -
|
||||
(borderPadding.left + borderPadding.right);
|
||||
nscoord height = mRect.height -
|
||||
(borderPadding.top + borderPadding.bottom);
|
||||
|
||||
nscoord newWidth = mComputedWidth;
|
||||
if (newWidth < width) {
|
||||
// center or right align rule within the extra space
|
||||
const nsStyleText* text =
|
||||
(const nsStyleText*) mStyleContext->GetStyleData(eStyleStruct_Text);
|
||||
switch (text->mTextAlign) {
|
||||
case NS_STYLE_TEXT_ALIGN_RIGHT:
|
||||
x0 += width - newWidth;
|
||||
break;
|
||||
|
||||
case NS_STYLE_TEXT_ALIGN_LEFT:
|
||||
break;
|
||||
|
||||
default:
|
||||
case NS_STYLE_TEXT_ALIGN_CENTER:
|
||||
x0 += (width - newWidth) / 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
width = newWidth;
|
||||
|
||||
// Center hrule vertically within the available space
|
||||
y0 += (height - thickness) / 2;
|
||||
height = thickness;
|
||||
|
||||
// To shade or not to shade, that is the question. Begin by collecting the
|
||||
// three decision criteria: rendering to the printer or the display, is the
|
||||
// "Beveled Lines" checkbox set in the page setup dialog, and does the tag
|
||||
// have the NOSHADE attribute set.
|
||||
PRBool printing = nsGlobalVariables::Instance()->GetPrinting(&aPresContext);
|
||||
|
||||
PRBool bevel = nsGlobalVariables::Instance()->GetBeveledLines();
|
||||
|
||||
PRBool noShadeAttribute = GetNoShade();
|
||||
|
||||
// Now that we have the data to make the shading criteria, we next
|
||||
// collect the decision criteria for rending in solid black:
|
||||
// printing (which we already have) and the "Black Lines" setting in
|
||||
// the page setup dialog
|
||||
|
||||
PRBool blackLines = nsGlobalVariables::Instance()->GetBlackLines();
|
||||
nscolor colors[2];
|
||||
// Get the background color that applies to this HR
|
||||
if (printing && blackLines)
|
||||
{
|
||||
colors[0] = NS_RGB(0,0,0);
|
||||
colors[1] = colors[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
// XXX Get correct color by finding the first parent that actually
|
||||
// specifies a color.
|
||||
NS_Get3DColors(colors, color->mBackgroundColor);
|
||||
}
|
||||
|
||||
// Draw a "shadowed" box around the rule area
|
||||
if (!noShadeAttribute && ((printing && bevel) || !printing)) {
|
||||
// Lines render inclusively on the both the starting and ending
|
||||
// coordinate, so reduce the end coordinates by one pixel.
|
||||
nscoord x1 = nscoord(x0 + width - NSIntPixelsToTwips(1, p2t));
|
||||
nscoord y1 = nscoord(y0 + height - NSIntPixelsToTwips(1, p2t));
|
||||
|
||||
// Draw bottom and right lines
|
||||
aRenderingContext.SetColor (colors[1]);
|
||||
aRenderingContext.DrawLine (x1, y0, x1, y1);
|
||||
aRenderingContext.DrawLine (x1, y1, x0, y1);
|
||||
|
||||
// Draw top and left lines
|
||||
aRenderingContext.SetColor (colors[0]);
|
||||
aRenderingContext.DrawLine (x0, y1, x0, y0);
|
||||
aRenderingContext.DrawLine (x0, y0, x1, y0);
|
||||
} else {
|
||||
// When a rule is not shaded, then we use a uniform color and
|
||||
// draw half-circles on the end points.
|
||||
aRenderingContext.SetColor (colors[0]);
|
||||
nscoord diameter = height;
|
||||
if ((diameter > width) || (diameter < NSIntPixelsToTwips(3, p2t))) {
|
||||
// The half-circles on the ends of the rule aren't going to
|
||||
// look right so don't bother drawing them.
|
||||
aRenderingContext.FillRect(x0, y0, width, height);
|
||||
} else {
|
||||
aRenderingContext.FillArc(x0, y0, diameter, diameter, 90.0f, 270.0f);
|
||||
aRenderingContext.FillArc(x0 + width - diameter, y0,
|
||||
diameter, diameter, 270.0f, 180.0f);
|
||||
aRenderingContext.FillRect(x0 + diameter/2, y0,
|
||||
width - diameter, height);
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HRuleFrame::Reflow(nsIPresContext& aPresContext,
|
||||
nsReflowMetrics& aDesiredSize,
|
||||
const nsReflowState& aReflowState,
|
||||
nsReflowStatus& aStatus)
|
||||
{
|
||||
NS_PRECONDITION(mState & NS_FRAME_IN_REFLOW, "frame is not in reflow");
|
||||
|
||||
// XXX add in code to check for width/height being set via css
|
||||
// and if set use them instead of calling GetDesiredSize.
|
||||
|
||||
|
||||
GetDesiredSize(&aPresContext, aReflowState, aDesiredSize);
|
||||
AddBordersAndPadding(&aPresContext, aDesiredSize);
|
||||
|
||||
// HR's do not impact the max-element-size, unless a width is specified
|
||||
// otherwise tables behave badly. This makes sense they are springy.
|
||||
if (nsnull != aDesiredSize.maxElementSize) {
|
||||
nscoord onePixel = NSIntPixelsToTwips(1, aPresContext.GetPixelsToTwips());
|
||||
nsSize size;
|
||||
PRIntn ss = nsCSSLayout::GetStyleSize(&aPresContext, aReflowState, size);
|
||||
if (NS_SIZE_HAS_WIDTH & ss) {
|
||||
aDesiredSize.maxElementSize->width = size.width;
|
||||
aDesiredSize.maxElementSize->height = onePixel;
|
||||
}
|
||||
else {
|
||||
aDesiredSize.maxElementSize->width = onePixel;
|
||||
aDesiredSize.maxElementSize->height = onePixel;
|
||||
}
|
||||
}
|
||||
|
||||
aStatus = NS_FRAME_COMPLETE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
HRuleFrame::GetDesiredSize(nsIPresContext* aPresContext,
|
||||
const nsReflowState& aReflowState,
|
||||
nsReflowMetrics& aDesiredSize)
|
||||
{
|
||||
nsSize size;
|
||||
PRIntn ss = nsCSSLayout::GetStyleSize(aPresContext, aReflowState, size);
|
||||
if (NS_SIZE_HAS_WIDTH & ss) {
|
||||
aDesiredSize.width = size.width;
|
||||
}
|
||||
else {
|
||||
if (NS_UNCONSTRAINEDSIZE == aReflowState.maxSize.width) {
|
||||
aDesiredSize.width = nscoord(aPresContext->GetPixelsToTwips());
|
||||
}
|
||||
else {
|
||||
aDesiredSize.width = aReflowState.maxSize.width;
|
||||
}
|
||||
}
|
||||
mComputedWidth = aDesiredSize.width;
|
||||
if (aReflowState.maxSize.width != NS_UNCONSTRAINEDSIZE) {
|
||||
if (aDesiredSize.width < aReflowState.maxSize.width) {
|
||||
aDesiredSize.width = aReflowState.maxSize.width;
|
||||
}
|
||||
}
|
||||
|
||||
// XXX should we interpret css's height property as thickness? or as
|
||||
// line-height? In the meantime, ignore it...
|
||||
nscoord lineHeight;
|
||||
|
||||
// Get the thickness of the rule (this is not css's height property)
|
||||
float p2t = aPresContext->GetPixelsToTwips();
|
||||
nscoord thickness = NSIntPixelsToTwips(GetThickness(), p2t);
|
||||
|
||||
// Compute height of "line" that hrule will layout within. Use the
|
||||
// default font to do this.
|
||||
lineHeight = thickness + NSIntPixelsToTwips(2, p2t);
|
||||
const nsFont& defaultFont = aPresContext->GetDefaultFont();
|
||||
nsIFontMetrics* fm = aPresContext->GetMetricsFor(defaultFont);
|
||||
nscoord defaultLineHeight;
|
||||
fm->GetHeight(defaultLineHeight);
|
||||
NS_RELEASE(fm);
|
||||
if (lineHeight < defaultLineHeight) {
|
||||
lineHeight = defaultLineHeight;
|
||||
}
|
||||
|
||||
aDesiredSize.height = lineHeight;
|
||||
aDesiredSize.ascent = lineHeight;
|
||||
aDesiredSize.descent = 0;
|
||||
}
|
||||
|
||||
PRInt32
|
||||
HRuleFrame::GetThickness()
|
||||
{
|
||||
PRInt32 result = DEFAULT_THICKNESS;
|
||||
|
||||
// See if the underlying content is an HR that also implements the
|
||||
// nsIHTMLContent API.
|
||||
// XXX the dependency on nsIHTMLContent is done to avoid reparsing
|
||||
// the size value.
|
||||
nsIDOMHTMLHRElement* hr = nsnull;
|
||||
nsIHTMLContent* hc = nsnull;
|
||||
mContent->QueryInterface(kIDOMHTMLHRElementIID, (void**) &hr);
|
||||
mContent->QueryInterface(kIHTMLContentIID, (void**) &hc);
|
||||
if ((nsnull != hr) && (nsnull != hc)) {
|
||||
// Winner. Get the size attribute to determine how thick the HR
|
||||
// should be.
|
||||
nsHTMLValue value;
|
||||
if (NS_CONTENT_ATTR_HAS_VALUE ==
|
||||
hc->GetAttribute(nsHTMLAtoms::size, value)) {
|
||||
if (value.GetUnit() == eHTMLUnit_Pixel) {
|
||||
PRInt32 pixels = value.GetPixelValue();
|
||||
switch (pixels) {
|
||||
case 0:
|
||||
case 1:
|
||||
result = 1;
|
||||
break;
|
||||
default:
|
||||
result = pixels + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
NS_IF_RELEASE(hc);
|
||||
NS_IF_RELEASE(hr);
|
||||
return result;
|
||||
}
|
||||
|
||||
PRBool
|
||||
HRuleFrame::GetNoShade()
|
||||
{
|
||||
PRBool result = PR_FALSE;
|
||||
nsIDOMHTMLHRElement* hr = nsnull;
|
||||
mContent->QueryInterface(kIDOMHTMLHRElementIID, (void**) &hr);
|
||||
if (nsnull != hr) {
|
||||
hr->GetNoShade(&result);
|
||||
NS_RELEASE(hr);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
626
mozilla/layout/html/base/src/nsHTMLFrame.cpp
Normal file
626
mozilla/layout/html/base/src/nsHTMLFrame.cpp
Normal file
@ -0,0 +1,626 @@
|
||||
/* -*- 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 "nsHTMLContainer.h"
|
||||
#include "nsContainerFrame.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsIReflowCommand.h"
|
||||
#include "nsIPresContext.h"
|
||||
#include "nsIStyleContext.h"
|
||||
#include "nsViewsCID.h"
|
||||
#include "nsIView.h"
|
||||
#include "nsIViewManager.h"
|
||||
#include "nsIContentDelegate.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 Reflow(nsIPresContext& aPresContext,
|
||||
nsReflowMetrics& aDesiredSize,
|
||||
const nsReflowState& aReflowState,
|
||||
nsReflowStatus& aStatus);
|
||||
|
||||
NS_IMETHOD HandleEvent(nsIPresContext& aPresContext,
|
||||
nsGUIEvent* aEvent,
|
||||
nsEventStatus& aEventStatus);
|
||||
};
|
||||
|
||||
// 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);
|
||||
|
||||
protected:
|
||||
void CreateFirstChild(nsIPresContext* aPresContext);
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
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::Reflow(nsIPresContext& aPresContext,
|
||||
nsReflowMetrics& aDesiredSize,
|
||||
const nsReflowState& aReflowState,
|
||||
nsReflowStatus& aStatus)
|
||||
{
|
||||
NS_FRAME_TRACE_REFLOW_IN("RootFrame::Reflow");
|
||||
|
||||
#ifdef NS_DEBUG
|
||||
PreReflowCheck();
|
||||
#endif
|
||||
|
||||
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");
|
||||
|
||||
} else {
|
||||
// Do we have any children?
|
||||
if (nsnull == mFirstChild) {
|
||||
// No. Create a pseudo frame
|
||||
NS_ASSERTION(eReflowReason_Initial == aReflowState.reason, "unexpected reflow reason");
|
||||
mFirstChild = new RootContentFrame(mContent, this);
|
||||
mChildCount = 1;
|
||||
nsIStyleContext* style = aPresContext.ResolvePseudoStyleContextFor(nsHTMLAtoms::rootContentPseudo, this);
|
||||
mFirstChild->SetStyleContext(&aPresContext,style);
|
||||
NS_RELEASE(style);
|
||||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
||||
mLastContentOffset = ((RootContentFrame*)mFirstChild)->GetLastContentOffset();
|
||||
}
|
||||
|
||||
// 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;
|
||||
|
||||
#ifdef NS_DEBUG
|
||||
PostReflowCheck(aStatus);
|
||||
#endif
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
RootContentFrame::CreateFirstChild(nsIPresContext* aPresContext)
|
||||
{
|
||||
// Are we paginated?
|
||||
if (aPresContext->IsPaginated()) {
|
||||
// Yes. Create the first page frame
|
||||
mFirstChild = new nsPageFrame(mContent, this);
|
||||
mChildCount = 1;
|
||||
mLastContentOffset = mFirstContentOffset;
|
||||
|
||||
} else {
|
||||
// Create a frame for the body/frameset child
|
||||
PRInt32 i, n;
|
||||
mContent->ChildCount(n);
|
||||
for (i = 0; i < n; i++) {
|
||||
nsIContent* child;
|
||||
mContent->ChildAt(i, child);
|
||||
if (nsnull != child) {
|
||||
nsIAtom* tag;
|
||||
child->GetTag(tag);
|
||||
if ((nsHTMLAtoms::body == tag) || (nsHTMLAtoms::frameset == tag)) {
|
||||
// Create a frame
|
||||
nsIContentDelegate* cd = child->GetDelegate(aPresContext);
|
||||
if (nsnull != cd) {
|
||||
nsIStyleContext* kidStyleContext =
|
||||
aPresContext->ResolveStyleContextFor(child, this);
|
||||
nsresult rv = cd->CreateFrame(aPresContext, child, this,
|
||||
kidStyleContext, mFirstChild);
|
||||
NS_RELEASE(kidStyleContext);
|
||||
if (NS_OK == rv) {
|
||||
mChildCount = 1;
|
||||
mFirstContentOffset = i;
|
||||
mLastContentOffset = i;
|
||||
}
|
||||
NS_RELEASE(cd);
|
||||
}
|
||||
}
|
||||
NS_IF_RELEASE(tag);
|
||||
NS_RELEASE(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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");
|
||||
#ifdef NS_DEBUG
|
||||
PreReflowCheck();
|
||||
#endif
|
||||
|
||||
aStatus = NS_FRAME_COMPLETE;
|
||||
|
||||
// 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(aReflowState.maxSize.width, 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. 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);
|
||||
|
||||
} else {
|
||||
nsReflowReason reflowReason = aReflowState.reason;
|
||||
|
||||
// Do we have any children?
|
||||
if (nsnull == mFirstChild) {
|
||||
// No, create the first child frame
|
||||
reflowReason = eReflowReason_Initial;
|
||||
CreateFirstChild(&aPresContext);
|
||||
}
|
||||
|
||||
// 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);
|
||||
mChildCount++;
|
||||
}
|
||||
|
||||
// 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 {
|
||||
// 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);
|
||||
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. 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;
|
||||
}
|
||||
|
||||
// Place and size the child
|
||||
nsRect rect(0, 0, aDesiredSize.width, aDesiredSize.height);
|
||||
mFirstChild->SetRect(rect);
|
||||
|
||||
// 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;
|
||||
parent->PropagateContentOffsets(this, mFirstContentOffset,
|
||||
mLastContentOffset, mLastContentIsComplete);
|
||||
|
||||
#ifdef NS_DEBUG
|
||||
PostReflowCheck(aStatus);
|
||||
#endif
|
||||
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);
|
||||
}
|
||||
|
||||
nsContainerFrame::Paint(aPresContext, aRenderingContext, aDirtyRect);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
928
mozilla/layout/html/base/src/nsImageFrame.cpp
Normal file
928
mozilla/layout/html/base/src/nsImageFrame.cpp
Normal file
@ -0,0 +1,928 @@
|
||||
/* -*- 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 "nsHTMLImage.h"
|
||||
#include "nsHTMLTagContent.h"
|
||||
#include "nsString.h"
|
||||
#include "nsLeafFrame.h"
|
||||
#include "nsIPresContext.h"
|
||||
#include "nsIRenderingContext.h"
|
||||
#include "nsIFrameImageLoader.h"
|
||||
#include "nsIPresShell.h"
|
||||
#include "nsHTMLIIDs.h"
|
||||
#include "nsIImage.h"
|
||||
#include "nsIWidget.h"
|
||||
#include "nsHTMLAtoms.h"
|
||||
#include "nsIHTMLAttributes.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsIHTMLDocument.h"
|
||||
#include "nsIStyleContext.h"
|
||||
#include "nsStyleConsts.h"
|
||||
#include "nsIImageMap.h"
|
||||
#include "nsILinkHandler.h"
|
||||
#include "nsIURL.h"
|
||||
#include "nsIView.h"
|
||||
#include "nsIViewManager.h"
|
||||
#include "nsCSSLayout.h"
|
||||
#include "nsHTMLBase.h"
|
||||
#include "prprf.h"
|
||||
#include "nsISizeOfHandler.h"
|
||||
#include "nsIFontMetrics.h"
|
||||
#include "nsCSSRendering.h"
|
||||
#include "nsIDOMHTMLImageElement.h"
|
||||
|
||||
#define BROKEN_IMAGE_URL "resource:/res/html/broken-image.gif"
|
||||
|
||||
#define XP_IS_SPACE(_ch) \
|
||||
(((_ch) == ' ') || ((_ch) == '\t') || ((_ch) == '\n'))
|
||||
|
||||
// XXX image frame layout can be 100% decoupled from the content
|
||||
// object; all it needs are attributes to work properly
|
||||
|
||||
static NS_DEFINE_IID(kIHTMLDocumentIID, NS_IHTMLDOCUMENT_IID);
|
||||
|
||||
#if 0
|
||||
#define nsHTMLImageSuper nsHTMLTagContent
|
||||
class nsHTMLImage : public nsHTMLImageSuper, public nsIDOMHTMLImageElement {
|
||||
public:
|
||||
nsHTMLImage(nsIAtom* aTag);
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
NS_IMETHOD SizeOf(nsISizeOfHandler* aHandler) const;
|
||||
NS_IMETHOD CreateFrame(nsIPresContext* aPresContext,
|
||||
nsIFrame* aParentFrame,
|
||||
nsIStyleContext* aStyleContext,
|
||||
nsIFrame*& aResult);
|
||||
|
||||
NS_IMETHOD SetAttribute(nsIAtom* aAttribute, const nsString& aValue,
|
||||
PRBool aNotify);
|
||||
NS_IMETHOD MapAttributesInto(nsIStyleContext* aContext,
|
||||
nsIPresContext* aPresContext);
|
||||
NS_IMETHOD AttributeToString(nsIAtom* aAttribute,
|
||||
nsHTMLValue& aValue,
|
||||
nsString& aResult) const;
|
||||
|
||||
NS_FORWARD_IDOMNODE(nsHTMLImageSuper::)
|
||||
NS_FORWARD_IDOMELEMENT(nsHTMLImageSuper::)
|
||||
NS_FORWARD_IDOMHTMLELEMENT(nsHTMLImageSuper::)
|
||||
|
||||
NS_DECL_IDOMHTMLIMAGEELEMENT
|
||||
|
||||
NS_IMETHOD GetScriptObject(nsIScriptContext *aContext, void** aScriptObject);
|
||||
|
||||
protected:
|
||||
virtual ~nsHTMLImage();
|
||||
void SizeOfWithoutThis(nsISizeOfHandler* aHandler) const;
|
||||
|
||||
void TriggerReflow();
|
||||
};
|
||||
#endif
|
||||
|
||||
#define ImageFrameSuper nsLeafFrame
|
||||
class ImageFrame : public ImageFrameSuper {
|
||||
public:
|
||||
ImageFrame(nsIContent* aContent, nsIFrame* aParentFrame);
|
||||
|
||||
NS_IMETHOD DeleteFrame(nsIPresContext& aPresContext);
|
||||
NS_IMETHOD SizeOf(nsISizeOfHandler* aHandler) const;
|
||||
NS_IMETHOD Paint(nsIPresContext& aPresContext,
|
||||
nsIRenderingContext& aRenderingContext,
|
||||
const nsRect& aDirtyRect);
|
||||
NS_METHOD HandleEvent(nsIPresContext& aPresContext,
|
||||
nsGUIEvent* aEvent,
|
||||
nsEventStatus& aEventStatus);
|
||||
NS_IMETHOD GetCursorAndContentAt(nsIPresContext& aPresContext,
|
||||
const nsPoint& aPoint,
|
||||
nsIFrame** aFrame,
|
||||
nsIContent** aContent,
|
||||
PRInt32& aCursor);
|
||||
NS_IMETHOD ContentChanged(nsIPresShell* aShell,
|
||||
nsIPresContext* aPresContext,
|
||||
nsIContent* aChild,
|
||||
nsISupports* aSubContent);
|
||||
|
||||
protected:
|
||||
virtual ~ImageFrame();
|
||||
void SizeOfWithoutThis(nsISizeOfHandler* aHandler) const;
|
||||
|
||||
virtual void GetDesiredSize(nsIPresContext* aPresContext,
|
||||
const nsReflowState& aReflowState,
|
||||
nsReflowMetrics& aDesiredSize);
|
||||
|
||||
nsIImageMap* GetImageMap();
|
||||
|
||||
nsHTMLImageLoader mImageLoader;
|
||||
nsIImageMap* mImageMap;
|
||||
PRBool mSizeFrozen;
|
||||
|
||||
void TriggerLink(nsIPresContext& aPresContext,
|
||||
const nsString& aURLSpec,
|
||||
const nsString& aTargetSpec,
|
||||
PRBool aClick);
|
||||
|
||||
PRBool IsServerImageMap();
|
||||
PRIntn GetSuppress();
|
||||
|
||||
nscoord MeasureString(nsIFontMetrics* aFontMetrics,
|
||||
const PRUnichar* aString,
|
||||
PRInt32 aLength,
|
||||
nscoord aMaxWidth,
|
||||
PRUint32& aMaxFit);
|
||||
|
||||
void DisplayAltText(nsIPresContext& aPresContext,
|
||||
nsIRenderingContext& aRenderingContext,
|
||||
const nsString& aAltText,
|
||||
const nsRect& aRect);
|
||||
};
|
||||
|
||||
// Value's for mSuppress
|
||||
#define SUPPRESS_UNSET 0
|
||||
#define DONT_SUPPRESS 1
|
||||
#define SUPPRESS 2
|
||||
#define DEFAULT_SUPPRESS 3
|
||||
|
||||
// Default alignment value (so we can tell an unset value from a set value)
|
||||
#define ALIGN_UNSET PRUint8(-1)
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
nsHTMLImageLoader::nsHTMLImageLoader()
|
||||
{
|
||||
mImageLoader = nsnull;
|
||||
mLoadImageFailed = PR_FALSE;
|
||||
mLoadBrokenImageFailed = PR_FALSE;
|
||||
mURLSpec = nsnull;
|
||||
mBaseHREF = nsnull;
|
||||
}
|
||||
|
||||
nsHTMLImageLoader::~nsHTMLImageLoader()
|
||||
{
|
||||
NS_IF_RELEASE(mImageLoader);
|
||||
if (nsnull != mURLSpec) {
|
||||
delete mURLSpec;
|
||||
}
|
||||
if (nsnull != mBaseHREF) {
|
||||
delete mBaseHREF;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsHTMLImageLoader::SizeOf(nsISizeOfHandler* aHandler) const
|
||||
{
|
||||
aHandler->Add(sizeof(*this));
|
||||
if (!aHandler->HaveSeen(mURLSpec)) {
|
||||
mURLSpec->SizeOf(aHandler);
|
||||
}
|
||||
if (!aHandler->HaveSeen(mImageLoader)) {
|
||||
mImageLoader->SizeOf(aHandler);
|
||||
}
|
||||
}
|
||||
|
||||
nsIImage*
|
||||
nsHTMLImageLoader::GetImage()
|
||||
{
|
||||
nsIImage* image = nsnull;
|
||||
if (nsnull != mImageLoader) {
|
||||
mImageLoader->GetImage(image);
|
||||
}
|
||||
return image;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHTMLImageLoader::SetURL(const nsString& aURLSpec)
|
||||
{
|
||||
if (nsnull != mURLSpec) {
|
||||
delete mURLSpec;
|
||||
}
|
||||
mURLSpec = new nsString(aURLSpec);
|
||||
if (nsnull == mURLSpec) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHTMLImageLoader::SetBaseHREF(const nsString& aBaseHREF)
|
||||
{
|
||||
if (nsnull != mBaseHREF) {
|
||||
delete mBaseHREF;
|
||||
}
|
||||
mBaseHREF = new nsString(aBaseHREF);
|
||||
if (nsnull == mBaseHREF) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHTMLImageLoader::StartLoadImage(nsIPresContext* aPresContext,
|
||||
nsIFrame* aForFrame,
|
||||
PRBool aNeedSizeUpdate,
|
||||
PRIntn& aLoadStatus)
|
||||
{
|
||||
aLoadStatus = NS_IMAGE_LOAD_STATUS_NONE;
|
||||
|
||||
// Get absolute url the first time through
|
||||
nsresult rv;
|
||||
nsAutoString src;
|
||||
if (mLoadImageFailed || (nsnull == mURLSpec)) {
|
||||
src.Append(BROKEN_IMAGE_URL);
|
||||
} else {
|
||||
nsAutoString baseURL;
|
||||
if (nsnull != mBaseHREF) {
|
||||
baseURL = *mBaseHREF;
|
||||
}
|
||||
|
||||
// Get documentURL
|
||||
nsIPresShell* shell;
|
||||
shell = aPresContext->GetShell();
|
||||
nsIDocument* doc = shell->GetDocument();
|
||||
nsIURL* docURL = doc->GetDocumentURL();
|
||||
|
||||
// Create an absolute URL
|
||||
nsresult rv = NS_MakeAbsoluteURL(docURL, baseURL, *mURLSpec, src);
|
||||
|
||||
// Release references
|
||||
NS_RELEASE(shell);
|
||||
NS_RELEASE(docURL);
|
||||
NS_RELEASE(doc);
|
||||
if (NS_OK != rv) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
if (nsnull == mImageLoader) {
|
||||
// Start image loading. Note that we don't specify a background color
|
||||
// so transparent images are always rendered using a transparency mask
|
||||
rv = aPresContext->StartLoadImage(src, nsnull, aForFrame, aNeedSizeUpdate,
|
||||
mImageLoader);
|
||||
if (NS_OK != rv) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
// Examine current image load status
|
||||
mImageLoader->GetImageLoadStatus(aLoadStatus);
|
||||
if (0 != (aLoadStatus & NS_IMAGE_LOAD_STATUS_ERROR)) {
|
||||
NS_RELEASE(mImageLoader);
|
||||
if (mLoadImageFailed) {
|
||||
// We are doomed. Loading the broken image has just failed.
|
||||
mLoadBrokenImageFailed = PR_TRUE;
|
||||
}
|
||||
else {
|
||||
// Try again, this time using the broke-image url
|
||||
mLoadImageFailed = PR_TRUE;
|
||||
return StartLoadImage(aPresContext, aForFrame, aNeedSizeUpdate, aLoadStatus);
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsHTMLImageLoader::GetDesiredSize(nsIPresContext* aPresContext,
|
||||
const nsReflowState& aReflowState,
|
||||
nsReflowMetrics& aDesiredSize)
|
||||
{
|
||||
nsSize styleSize;
|
||||
PRIntn ss = nsCSSLayout::GetStyleSize(aPresContext, aReflowState, styleSize);
|
||||
PRIntn loadStatus;
|
||||
if (0 != ss) {
|
||||
if (NS_SIZE_HAS_BOTH == ss) {
|
||||
StartLoadImage(aPresContext, aReflowState.frame, PR_FALSE, loadStatus);
|
||||
aDesiredSize.width = styleSize.width;
|
||||
aDesiredSize.height = styleSize.height;
|
||||
}
|
||||
else {
|
||||
// Preserve aspect ratio of image with unbound dimension.
|
||||
StartLoadImage(aPresContext, aReflowState.frame, PR_TRUE, loadStatus);
|
||||
if ((0 == (loadStatus & NS_IMAGE_LOAD_STATUS_SIZE_AVAILABLE)) ||
|
||||
(nsnull == mImageLoader)) {
|
||||
// Provide a dummy size for now; later on when the image size
|
||||
// shows up we will reflow to the new size.
|
||||
aDesiredSize.width = 1;
|
||||
aDesiredSize.height = 1;
|
||||
}
|
||||
else {
|
||||
float p2t = aPresContext->GetPixelsToTwips();
|
||||
nsSize imageSize;
|
||||
mImageLoader->GetSize(imageSize);
|
||||
float imageWidth = imageSize.width * p2t;
|
||||
float imageHeight = imageSize.height * p2t;
|
||||
if (0.0f != imageHeight) {
|
||||
if (0 != (ss & NS_SIZE_HAS_WIDTH)) {
|
||||
// We have a width, and an auto height. Compute height
|
||||
// from width.
|
||||
aDesiredSize.width = styleSize.width;
|
||||
aDesiredSize.height =
|
||||
(nscoord)NSToIntRound(styleSize.width * imageHeight / imageWidth);
|
||||
}
|
||||
else {
|
||||
// We have a height and an auto width. Compute width from
|
||||
// height.
|
||||
aDesiredSize.height = styleSize.height;
|
||||
aDesiredSize.width =
|
||||
(nscoord)NSToIntRound(styleSize.height * imageWidth / imageHeight);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Screwy image
|
||||
aDesiredSize.width = 1;
|
||||
aDesiredSize.height = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
StartLoadImage(aPresContext, aReflowState.frame, PR_TRUE, loadStatus);
|
||||
if ((0 == (loadStatus & NS_IMAGE_LOAD_STATUS_SIZE_AVAILABLE)) ||
|
||||
(nsnull == mImageLoader)) {
|
||||
// Provide a dummy size for now; later on when the image size
|
||||
// shows up we will reflow to the new size.
|
||||
aDesiredSize.width = 1;
|
||||
aDesiredSize.height = 1;
|
||||
printf ("in image loader, dummy size of 1 returned\n");
|
||||
} else {
|
||||
float p2t = aPresContext->GetPixelsToTwips();
|
||||
nsSize imageSize;
|
||||
mImageLoader->GetSize(imageSize);
|
||||
aDesiredSize.width = NSIntPixelsToTwips(imageSize.width, p2t);
|
||||
aDesiredSize.height = NSIntPixelsToTwips(imageSize.height, p2t);
|
||||
printf ("in image loader, real size of %d returned\n", aDesiredSize.width);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
nsresult
|
||||
NS_NewImageFrame(nsIContent* aContent,
|
||||
nsIFrame* aParentFrame,
|
||||
nsIFrame*& aResult)
|
||||
{
|
||||
ImageFrame* frame = new ImageFrame(aContent, aParentFrame);
|
||||
if (nsnull == frame) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
aResult = frame;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
ImageFrame::ImageFrame(nsIContent* aContent, nsIFrame* aParentFrame)
|
||||
: nsLeafFrame(aContent, aParentFrame)
|
||||
{
|
||||
}
|
||||
|
||||
ImageFrame::~ImageFrame()
|
||||
{
|
||||
}
|
||||
|
||||
NS_METHOD
|
||||
ImageFrame::DeleteFrame(nsIPresContext& aPresContext)
|
||||
{
|
||||
NS_IF_RELEASE(mImageMap);
|
||||
|
||||
// Release image loader first so that it's refcnt can go to zero
|
||||
mImageLoader.DestroyLoader();
|
||||
|
||||
return nsLeafFrame::DeleteFrame(aPresContext);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ImageFrame::SizeOf(nsISizeOfHandler* aHandler) const
|
||||
{
|
||||
aHandler->Add(sizeof(*this));
|
||||
ImageFrame::SizeOfWithoutThis(aHandler);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
ImageFrame::SizeOfWithoutThis(nsISizeOfHandler* aHandler) const
|
||||
{
|
||||
ImageFrameSuper::SizeOfWithoutThis(aHandler);
|
||||
mImageLoader.SizeOf(aHandler);
|
||||
if (!aHandler->HaveSeen(mImageMap)) {
|
||||
mImageMap->SizeOf(aHandler);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ImageFrame::GetDesiredSize(nsIPresContext* aPresContext,
|
||||
const nsReflowState& aReflowState,
|
||||
nsReflowMetrics& aDesiredSize)
|
||||
{
|
||||
if (mSizeFrozen) {
|
||||
aDesiredSize.width = mRect.width;
|
||||
aDesiredSize.height = mRect.height;
|
||||
}
|
||||
else {
|
||||
// XXX Don't create a view, because we want whatever is below the image
|
||||
// to show through while the image is loading; Likewise for transparent
|
||||
// images and broken images
|
||||
//
|
||||
// What we really want to do is to create a view, and indicate that the
|
||||
// view has a transparent content area. Do this while it's loading,
|
||||
// and then when it's fully loaded mark the view as opaque if the
|
||||
// image is opaque.
|
||||
//
|
||||
// We can't use that approach yet, because currently the compositor doesn't
|
||||
// support transparent views...
|
||||
#if 0
|
||||
nsHTMLBase::CreateViewForFrame(aPresContext, this, mStyleContext, PR_TRUE);
|
||||
#endif
|
||||
|
||||
// Setup url before starting the image load
|
||||
nsAutoString src, base;
|
||||
if (NS_CONTENT_ATTR_HAS_VALUE == mContent->GetAttribute("SRC", src)) {
|
||||
mImageLoader.SetURL(src);
|
||||
if (NS_CONTENT_ATTR_HAS_VALUE ==
|
||||
mContent->GetAttribute(NS_HTML_BASE_HREF, base)) {
|
||||
mImageLoader.SetBaseHREF(base);
|
||||
}
|
||||
}
|
||||
mImageLoader.GetDesiredSize(aPresContext, aReflowState, aDesiredSize);
|
||||
}
|
||||
}
|
||||
|
||||
// Computes the width of the specified string. aMaxWidth specifies the maximum
|
||||
// width available. Once this limit is reached no more characters are measured.
|
||||
// The number of characters that fit within the maximum width are returned in
|
||||
// aMaxFit
|
||||
nscoord
|
||||
ImageFrame::MeasureString(nsIFontMetrics* aFontMetrics,
|
||||
const PRUnichar* aString,
|
||||
PRInt32 aLength,
|
||||
nscoord aMaxWidth,
|
||||
PRUint32& aMaxFit)
|
||||
{
|
||||
nscoord totalWidth = 0;
|
||||
nscoord spaceWidth;
|
||||
aFontMetrics->GetWidth(' ', spaceWidth);
|
||||
|
||||
aMaxFit = 0;
|
||||
while (aLength > 0) {
|
||||
// Find the next place we can line break
|
||||
PRUint32 len = aLength;
|
||||
PRBool trailingSpace = PR_FALSE;
|
||||
for (PRInt32 i = 0; i < aLength; i++) {
|
||||
if (XP_IS_SPACE(aString[i]) && (i > 0)) {
|
||||
len = i; // don't include the space when measuring
|
||||
trailingSpace = PR_TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Measure this chunk of text, and see if it fits
|
||||
nscoord width;
|
||||
aFontMetrics->GetWidth(aString, len, width);
|
||||
PRBool fits = (totalWidth + width) <= aMaxWidth;
|
||||
|
||||
// If it fits on the line, or it's the first word we've processed then
|
||||
// include it
|
||||
if (fits || (0 == totalWidth)) {
|
||||
// New piece fits
|
||||
totalWidth += width;
|
||||
|
||||
// If there's a trailing space then see if it fits as well
|
||||
if (trailingSpace) {
|
||||
if ((totalWidth + spaceWidth) <= aMaxWidth) {
|
||||
totalWidth += spaceWidth;
|
||||
} else {
|
||||
// Space won't fit. Leave it at the end but don't include it in
|
||||
// the width
|
||||
fits = PR_FALSE;
|
||||
}
|
||||
|
||||
len++;
|
||||
}
|
||||
|
||||
aMaxFit += len;
|
||||
aString += len;
|
||||
aLength -= len;
|
||||
}
|
||||
|
||||
if (!fits) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return totalWidth;
|
||||
}
|
||||
|
||||
// Formats the alt-text to fit within the specified rectangle. Breaks lines
|
||||
// between words if a word would extend past the edge of the rectangle
|
||||
void
|
||||
ImageFrame::DisplayAltText(nsIPresContext& aPresContext,
|
||||
nsIRenderingContext& aRenderingContext,
|
||||
const nsString& aAltText,
|
||||
const nsRect& aRect)
|
||||
{
|
||||
// Clip so we don't render outside of the rect.
|
||||
aRenderingContext.PushState();
|
||||
aRenderingContext.SetClipRect(aRect, nsClipCombine_kIntersect);
|
||||
|
||||
const nsStyleColor* color =
|
||||
(const nsStyleColor*)mStyleContext->GetStyleData(eStyleStruct_Color);
|
||||
const nsStyleFont* font =
|
||||
(const nsStyleFont*)mStyleContext->GetStyleData(eStyleStruct_Font);
|
||||
|
||||
// Set font and color
|
||||
aRenderingContext.SetColor(color->mColor);
|
||||
aRenderingContext.SetFont(font->mFont);
|
||||
|
||||
// Format the text to display within the formatting rect
|
||||
nsIFontMetrics* fm = aRenderingContext.GetFontMetrics();
|
||||
|
||||
nscoord maxDescent, height;
|
||||
fm->GetMaxDescent(maxDescent);
|
||||
fm->GetHeight(height);
|
||||
|
||||
// XXX It would be nice if there was a way to have the font metrics tell
|
||||
// use where to break the text given a maximum width. At a minimum we need
|
||||
// to be able to get the break character...
|
||||
const PRUnichar* str = aAltText.GetUnicode();
|
||||
PRInt32 strLen = aAltText.Length();
|
||||
nscoord y = aRect.y;
|
||||
while ((strLen > 0) && ((y + maxDescent) < aRect.YMost())) {
|
||||
// Determine how much of the text to display on this line
|
||||
PRUint32 maxFit; // number of characters that fit
|
||||
nscoord width = MeasureString(fm, str, strLen, aRect.width, maxFit);
|
||||
|
||||
// Display the text
|
||||
aRenderingContext.DrawString(str, maxFit, aRect.x, y, 0);
|
||||
|
||||
// Move to the next line
|
||||
str += maxFit;
|
||||
strLen -= maxFit;
|
||||
y += height;
|
||||
}
|
||||
|
||||
NS_RELEASE(fm);
|
||||
aRenderingContext.PopState();
|
||||
}
|
||||
|
||||
struct nsRecessedBorder : public nsStyleSpacing {
|
||||
nsRecessedBorder(nscoord aBorderWidth)
|
||||
: nsStyleSpacing()
|
||||
{
|
||||
nsStyleCoord styleCoord(aBorderWidth);
|
||||
|
||||
mBorder.SetLeft(styleCoord);
|
||||
mBorder.SetTop(styleCoord);
|
||||
mBorder.SetRight(styleCoord);
|
||||
mBorder.SetBottom(styleCoord);
|
||||
mBorderStyle[0] = NS_STYLE_BORDER_STYLE_INSET;
|
||||
mBorderStyle[1] = NS_STYLE_BORDER_STYLE_INSET;
|
||||
mBorderStyle[2] = NS_STYLE_BORDER_STYLE_INSET;
|
||||
mBorderStyle[3] = NS_STYLE_BORDER_STYLE_INSET;
|
||||
mBorderColor[0] = 0;
|
||||
mBorderColor[1] = 0;
|
||||
mBorderColor[2] = 0;
|
||||
mBorderColor[3] = 0;
|
||||
mHasCachedMargin = mHasCachedPadding = mHasCachedBorder = PR_FALSE;
|
||||
}
|
||||
};
|
||||
|
||||
NS_METHOD
|
||||
ImageFrame::Paint(nsIPresContext& aPresContext,
|
||||
nsIRenderingContext& aRenderingContext,
|
||||
const nsRect& aDirtyRect)
|
||||
{
|
||||
if ((0 == mRect.width) || (0 == mRect.height)) {
|
||||
// Do not render when given a zero area. This avoids some useless
|
||||
// scaling work while we wait for our image dimensions to arrive
|
||||
// asynchronously.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
const nsStyleDisplay* disp =
|
||||
(const nsStyleDisplay*)mStyleContext->GetStyleData(eStyleStruct_Display);
|
||||
|
||||
if (disp->mVisible) {
|
||||
// First paint background and borders
|
||||
nsLeafFrame::Paint(aPresContext, aRenderingContext, aDirtyRect);
|
||||
|
||||
nsIImage* image = mImageLoader.GetImage();
|
||||
if (nsnull == image) {
|
||||
// No image yet. Draw the icon that indicates we're loading, and display
|
||||
// the alt-text
|
||||
nsAutoString altText;
|
||||
if (NS_CONTENT_ATTR_HAS_VALUE == mContent->GetAttribute("ALT", altText)) {
|
||||
// Display a recessed one-pixel border in the inner area
|
||||
nsRect inner;
|
||||
GetInnerArea(&aPresContext, inner);
|
||||
|
||||
float p2t = aPresContext.GetPixelsToTwips();
|
||||
nsRecessedBorder recessedBorder(NSIntPixelsToTwips(1, p2t));
|
||||
nsCSSRendering::PaintBorder(aPresContext, aRenderingContext, this, inner,
|
||||
inner, recessedBorder, 0);
|
||||
inner.Deflate(NSIntPixelsToTwips(1, p2t), NSIntPixelsToTwips(1, p2t));
|
||||
|
||||
// Leave a 8 pixel left/right padding, and a 5 pixel top/bottom padding
|
||||
inner.Deflate(NSIntPixelsToTwips(8, p2t), NSIntPixelsToTwips(5, p2t));
|
||||
|
||||
// If there's room, then display the alt-text
|
||||
if (!inner.IsEmpty()) {
|
||||
DisplayAltText(aPresContext, aRenderingContext, altText, inner);
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Now render the image into our inner area (the area without the
|
||||
// borders and padding)
|
||||
nsRect inner;
|
||||
GetInnerArea(&aPresContext, inner);
|
||||
if (mImageLoader.GetLoadImageFailed()) {
|
||||
float p2t = aPresContext.GetPixelsToTwips();
|
||||
inner.width = NSIntPixelsToTwips(image->GetWidth(), p2t);
|
||||
inner.height = NSIntPixelsToTwips(image->GetHeight(), p2t);
|
||||
}
|
||||
aRenderingContext.DrawImage(image, inner);
|
||||
|
||||
if (GetShowFrameBorders()) {
|
||||
nsIImageMap* map = GetImageMap();
|
||||
if (nsnull != map) {
|
||||
aRenderingContext.SetColor(NS_RGB(0, 0, 0));
|
||||
aRenderingContext.PushState();
|
||||
aRenderingContext.Translate(inner.x, inner.y);
|
||||
map->Draw(aPresContext, aRenderingContext);
|
||||
aRenderingContext.PopState();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsIImageMap*
|
||||
ImageFrame::GetImageMap()
|
||||
{
|
||||
if (nsnull == mImageMap) {
|
||||
nsAutoString usemap;
|
||||
mContent->GetAttribute("usemap", usemap);
|
||||
if (0 == usemap.Length()) {
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
nsIDocument* doc = nsnull;
|
||||
mContent->GetDocument(doc);
|
||||
if (nsnull == doc) {
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
if (usemap.First() == '#') {
|
||||
usemap.Cut(0, 1);
|
||||
}
|
||||
nsIHTMLDocument* hdoc;
|
||||
nsresult rv = doc->QueryInterface(kIHTMLDocumentIID, (void**)&hdoc);
|
||||
NS_RELEASE(doc);
|
||||
if (NS_OK == rv) {
|
||||
nsIImageMap* map;
|
||||
rv = hdoc->GetImageMap(usemap, &map);
|
||||
NS_RELEASE(hdoc);
|
||||
if (NS_OK == rv) {
|
||||
mImageMap = map;
|
||||
}
|
||||
}
|
||||
}
|
||||
NS_IF_ADDREF(mImageMap);
|
||||
return mImageMap;
|
||||
}
|
||||
|
||||
void
|
||||
ImageFrame::TriggerLink(nsIPresContext& aPresContext,
|
||||
const nsString& aURLSpec,
|
||||
const nsString& aTargetSpec,
|
||||
PRBool aClick)
|
||||
{
|
||||
nsILinkHandler* handler = nsnull;
|
||||
aPresContext.GetLinkHandler(&handler);
|
||||
if (nsnull != handler) {
|
||||
if (aClick) {
|
||||
handler->OnLinkClick(this, aURLSpec, aTargetSpec);
|
||||
}
|
||||
else {
|
||||
handler->OnOverLink(this, aURLSpec, aTargetSpec);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PRBool
|
||||
ImageFrame::IsServerImageMap()
|
||||
{
|
||||
nsAutoString ismap;
|
||||
return NS_CONTENT_ATTR_HAS_VALUE == mContent->GetAttribute("ismap", ismap);
|
||||
}
|
||||
|
||||
PRIntn
|
||||
ImageFrame::GetSuppress()
|
||||
{
|
||||
nsAutoString s;
|
||||
if (NS_CONTENT_ATTR_HAS_VALUE == mContent->GetAttribute("suppress", s)) {
|
||||
if (s.EqualsIgnoreCase("true")) {
|
||||
return SUPPRESS;
|
||||
} else if (s.EqualsIgnoreCase("false")) {
|
||||
return DONT_SUPPRESS;
|
||||
}
|
||||
}
|
||||
return DEFAULT_SUPPRESS;
|
||||
}
|
||||
|
||||
// XXX what should clicks on transparent pixels do?
|
||||
NS_METHOD
|
||||
ImageFrame::HandleEvent(nsIPresContext& aPresContext,
|
||||
nsGUIEvent* aEvent,
|
||||
nsEventStatus& aEventStatus)
|
||||
{
|
||||
nsIImageMap* map;
|
||||
aEventStatus = nsEventStatus_eIgnore;
|
||||
|
||||
switch (aEvent->message) {
|
||||
case NS_MOUSE_LEFT_BUTTON_UP:
|
||||
case NS_MOUSE_MOVE:
|
||||
map = GetImageMap();
|
||||
if ((nsnull != map) || IsServerImageMap()) {
|
||||
nsIURL* docURL = nsnull;
|
||||
nsIDocument* doc = nsnull;
|
||||
mContent->GetDocument(doc);
|
||||
if (nsnull != doc) {
|
||||
docURL = doc->GetDocumentURL();
|
||||
NS_RELEASE(doc);
|
||||
}
|
||||
|
||||
// Ask map if the x,y coordinates are in a clickable area
|
||||
float t2p = aPresContext.GetTwipsToPixels();
|
||||
nsAutoString absURL, target, altText;
|
||||
PRBool suppress;
|
||||
if (nsnull != map) {
|
||||
// Subtract out border and padding here so that we are looking
|
||||
// at the right coordinates. Hit detection against area tags
|
||||
// is done after the mouse wanders over the image, not over
|
||||
// the image's borders.
|
||||
nsRect inner;
|
||||
GetInnerArea(&aPresContext, inner);
|
||||
PRInt32 x = NSTwipsToIntPixels((aEvent->point.x - inner.x), t2p);
|
||||
PRInt32 y = NSTwipsToIntPixels((aEvent->point.y - inner.y), t2p);
|
||||
nsresult r = map->IsInside(x, y, docURL, absURL, target, altText,
|
||||
&suppress);
|
||||
NS_IF_RELEASE(docURL);
|
||||
NS_RELEASE(map);
|
||||
if (NS_OK == r) {
|
||||
// We hit a clickable area. Time to go somewhere...
|
||||
PRBool clicked = PR_FALSE;
|
||||
if (aEvent->message == NS_MOUSE_LEFT_BUTTON_UP) {
|
||||
aEventStatus = nsEventStatus_eConsumeNoDefault;
|
||||
clicked = PR_TRUE;
|
||||
}
|
||||
TriggerLink(aPresContext, absURL, target, clicked);
|
||||
}
|
||||
}
|
||||
else {
|
||||
suppress = GetSuppress();
|
||||
nsAutoString baseURL;
|
||||
mContent->GetAttribute(NS_HTML_BASE_HREF, baseURL);
|
||||
nsAutoString src;
|
||||
mContent->GetAttribute("src", src);
|
||||
NS_MakeAbsoluteURL(docURL, baseURL, src, absURL);
|
||||
|
||||
// Note: We don't subtract out the border/padding here to remain
|
||||
// compatible with navigator. [ick]
|
||||
PRInt32 x = NSTwipsToIntPixels(aEvent->point.x, t2p);
|
||||
PRInt32 y = NSTwipsToIntPixels(aEvent->point.y, t2p);
|
||||
char cbuf[50];
|
||||
PR_snprintf(cbuf, sizeof(cbuf), "?%d,%d", x, y);
|
||||
absURL.Append(cbuf);
|
||||
PRBool clicked = PR_FALSE;
|
||||
if (aEvent->message == NS_MOUSE_LEFT_BUTTON_UP) {
|
||||
aEventStatus = nsEventStatus_eConsumeNoDefault;
|
||||
clicked = PR_TRUE;
|
||||
}
|
||||
TriggerLink(aPresContext, absURL, target, clicked);
|
||||
}
|
||||
break;
|
||||
}
|
||||
// FALL THROUGH
|
||||
|
||||
default:
|
||||
// Let default event handler deal with it
|
||||
return nsLeafFrame::HandleEvent(aPresContext, aEvent, aEventStatus);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_METHOD
|
||||
ImageFrame::GetCursorAndContentAt(nsIPresContext& aPresContext,
|
||||
const nsPoint& aPoint,
|
||||
nsIFrame** aFrame,
|
||||
nsIContent** aContent,
|
||||
PRInt32& aCursor)
|
||||
{
|
||||
// The default cursor is to have no cursor
|
||||
aCursor = NS_STYLE_CURSOR_INHERIT;
|
||||
*aContent = mContent;
|
||||
|
||||
const nsStyleColor* styleColor = (const nsStyleColor*)
|
||||
mStyleContext->GetStyleData(eStyleStruct_Color);
|
||||
if (styleColor->mCursor != NS_STYLE_CURSOR_INHERIT) {
|
||||
// If we have a particular cursor, use it
|
||||
*aFrame = this;
|
||||
aCursor = (PRInt32) styleColor->mCursor;
|
||||
}
|
||||
|
||||
nsIImageMap* map = GetImageMap();
|
||||
if (nsnull != map) {
|
||||
nsRect inner;
|
||||
GetInnerArea(&aPresContext, inner);
|
||||
aCursor = NS_STYLE_CURSOR_DEFAULT;
|
||||
float t2p = aPresContext.GetTwipsToPixels();
|
||||
PRInt32 x = NSTwipsToIntPixels((aPoint.x - inner.x), t2p);
|
||||
PRInt32 y = NSTwipsToIntPixels((aPoint.y - inner.y), t2p);
|
||||
if (NS_OK == map->IsInside(x, y)) {
|
||||
aCursor = NS_STYLE_CURSOR_HAND;
|
||||
}
|
||||
NS_RELEASE(map);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ImageFrame::ContentChanged(nsIPresShell* aShell,
|
||||
nsIPresContext* aPresContext,
|
||||
nsIContent* aChild,
|
||||
nsISupports* aSubContent)
|
||||
{
|
||||
// See if the src attribute changed; if it did then trigger a redraw
|
||||
// by firing up a new image load request. Otherwise let our base
|
||||
// class handle the content-changed request.
|
||||
nsAutoString oldSRC;
|
||||
mImageLoader.GetURL(oldSRC);
|
||||
|
||||
// Get src attribute's value and construct a new absolute url from it
|
||||
nsAutoString newSRC;
|
||||
if (NS_CONTENT_ATTR_HAS_VALUE == mContent->GetAttribute("SRC", newSRC)) {
|
||||
if (!oldSRC.Equals(newSRC)) {
|
||||
mSizeFrozen = PR_TRUE;
|
||||
|
||||
#ifdef NS_DEBUG
|
||||
char oldcbuf[100], newcbuf[100];
|
||||
oldSRC.ToCString(oldcbuf, sizeof(oldcbuf));
|
||||
newSRC.ToCString(newcbuf, sizeof(newcbuf));
|
||||
NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,
|
||||
("ImageFrame::ContentChanged: new image source; old='%s' new='%s'",
|
||||
oldcbuf, newcbuf));
|
||||
#endif
|
||||
|
||||
// Get rid of old image loader and start a new image load going
|
||||
mImageLoader.DestroyLoader();
|
||||
|
||||
// Fire up a new image load request
|
||||
PRIntn loadStatus;
|
||||
mImageLoader.SetURL(newSRC);
|
||||
mImageLoader.StartLoadImage(aPresContext, this, PR_FALSE, loadStatus);
|
||||
|
||||
NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,
|
||||
("ImageFrame::ContentChanged: loadImage status=%x",
|
||||
loadStatus));
|
||||
|
||||
// If the image is already ready then we need to trigger a
|
||||
// redraw because the image loader won't.
|
||||
if (loadStatus & NS_IMAGE_LOAD_STATUS_IMAGE_READY) {
|
||||
// XXX Stuff this into a method on nsIPresShell/Context
|
||||
nsRect bounds;
|
||||
nsPoint offset;
|
||||
nsIView* view;
|
||||
GetOffsetFromView(offset, view);
|
||||
nsIViewManager* vm;
|
||||
view->GetViewManager(vm);
|
||||
bounds.x = offset.x;
|
||||
bounds.y = offset.y;
|
||||
bounds.width = mRect.width;
|
||||
bounds.height = mRect.height;
|
||||
vm->UpdateView(view, bounds, 0);
|
||||
NS_RELEASE(vm);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
return ImageFrameSuper::ContentChanged(aShell, aPresContext, aChild,
|
||||
aSubContent);
|
||||
}
|
||||
191
mozilla/layout/html/base/src/nsSpacerFrame.cpp
Normal file
191
mozilla/layout/html/base/src/nsSpacerFrame.cpp
Normal file
@ -0,0 +1,191 @@
|
||||
/* -*- 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 "nsIHTMLContent.h"
|
||||
#include "nsFrame.h"
|
||||
#include "nsIInlineReflow.h"
|
||||
#include "nsCSSLineLayout.h"
|
||||
#include "nsHTMLIIDs.h"
|
||||
#include "nsIPresContext.h"
|
||||
#include "nsIPresShell.h"
|
||||
#include "nsHTMLAtoms.h"
|
||||
#include "nsUnitConversion.h"
|
||||
#include "nsIStyleContext.h"
|
||||
#include "nsStyleConsts.h"
|
||||
|
||||
// Spacer type's
|
||||
#define TYPE_WORD 0 // horizontal space
|
||||
#define TYPE_LINE 1 // line-break + vertical space
|
||||
#define TYPE_IMAGE 2 // acts like a sized image with nothing to see
|
||||
|
||||
class SpacerFrame : public nsFrame, private nsIInlineReflow {
|
||||
public:
|
||||
SpacerFrame(nsIContent* aContent, nsIFrame* aParentFrame);
|
||||
|
||||
// nsISupports
|
||||
NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr);
|
||||
|
||||
// nsIInlineReflow
|
||||
NS_IMETHOD FindTextRuns(nsCSSLineLayout& aLineLayout,
|
||||
nsIReflowCommand* aReflowCommand);
|
||||
NS_IMETHOD InlineReflow(nsCSSLineLayout& aLineLayout,
|
||||
nsReflowMetrics& aDesiredSize,
|
||||
const nsReflowState& aReflowState);
|
||||
|
||||
PRUint8 GetType();
|
||||
|
||||
protected:
|
||||
virtual ~SpacerFrame();
|
||||
};
|
||||
|
||||
nsresult
|
||||
NS_NewSpacerFrame(nsIContent* aContent,
|
||||
nsIFrame* aParentFrame,
|
||||
nsIFrame*& aResult)
|
||||
{
|
||||
nsIFrame* frame = new SpacerFrame(aContent, aParentFrame);
|
||||
if (nsnull == frame) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
aResult = frame;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
SpacerFrame::SpacerFrame(nsIContent* aContent, nsIFrame* aParentFrame)
|
||||
: nsFrame(aContent, aParentFrame)
|
||||
{
|
||||
}
|
||||
|
||||
SpacerFrame::~SpacerFrame()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
SpacerFrame::QueryInterface(REFNSIID aIID, void** aInstancePtrResult)
|
||||
{
|
||||
NS_PRECONDITION(nsnull != aInstancePtrResult, "null pointer");
|
||||
if (nsnull == aInstancePtrResult) {
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
}
|
||||
if (aIID.Equals(kIInlineReflowIID)) {
|
||||
*aInstancePtrResult = (void*) ((nsIInlineReflow*)this);
|
||||
return NS_OK;
|
||||
}
|
||||
return nsFrame::QueryInterface(aIID, aInstancePtrResult);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
SpacerFrame::InlineReflow(nsCSSLineLayout& aLineLayout,
|
||||
nsReflowMetrics& aMetrics,
|
||||
const nsReflowState& aReflowState)
|
||||
{
|
||||
nsresult rv = NS_FRAME_COMPLETE;
|
||||
|
||||
// By default, we have no area
|
||||
aMetrics.width = 0;
|
||||
aMetrics.height = 0;
|
||||
aMetrics.ascent = 0;
|
||||
aMetrics.descent = 0;
|
||||
|
||||
nscoord width = 0;
|
||||
nscoord height = 0;
|
||||
PRUint8 type = GetType();
|
||||
nsresult ca;
|
||||
nsIHTMLContent* hc = nsnull;
|
||||
mContent->QueryInterface(kIHTMLContentIID, (void**) &hc);
|
||||
if (nsnull != hc) {
|
||||
if (type != TYPE_IMAGE) {
|
||||
nsHTMLValue val;
|
||||
ca = hc->GetAttribute(nsHTMLAtoms::size, val);
|
||||
if (NS_CONTENT_ATTR_HAS_VALUE == ca) {
|
||||
width = val.GetPixelValue();
|
||||
}
|
||||
} else {
|
||||
nsHTMLValue val;
|
||||
ca = hc->GetAttribute(nsHTMLAtoms::width, val);
|
||||
if (NS_CONTENT_ATTR_HAS_VALUE == ca) {
|
||||
if (eHTMLUnit_Pixel == val.GetUnit()) {
|
||||
width = val.GetPixelValue();
|
||||
}
|
||||
}
|
||||
ca = hc->GetAttribute(nsHTMLAtoms::height, val);
|
||||
if (NS_CONTENT_ATTR_HAS_VALUE == ca) {
|
||||
if (eHTMLUnit_Pixel == val.GetUnit()) {
|
||||
height = val.GetPixelValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
NS_RELEASE(hc);
|
||||
}
|
||||
|
||||
float p2t = aLineLayout.mPresContext->GetPixelsToTwips();
|
||||
switch (type) {
|
||||
case TYPE_WORD:
|
||||
if (0 != width) {
|
||||
aMetrics.width = NSIntPixelsToTwips(width, p2t);
|
||||
}
|
||||
break;
|
||||
|
||||
case TYPE_LINE:
|
||||
if (0 != width) {
|
||||
rv = NS_INLINE_LINE_BREAK_AFTER(0);
|
||||
aMetrics.height = NSIntPixelsToTwips(width, p2t);
|
||||
aMetrics.ascent = aMetrics.height;
|
||||
}
|
||||
break;
|
||||
|
||||
case TYPE_IMAGE:
|
||||
aMetrics.width = NSIntPixelsToTwips(width, p2t);
|
||||
aMetrics.height = NSIntPixelsToTwips(height, p2t);
|
||||
aMetrics.ascent = aMetrics.height;
|
||||
break;
|
||||
}
|
||||
|
||||
if (nsnull != aMetrics.maxElementSize) {
|
||||
aMetrics.maxElementSize->width = aMetrics.width;
|
||||
aMetrics.maxElementSize->height = aMetrics.height;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
SpacerFrame::FindTextRuns(nsCSSLineLayout& aLineLayout,
|
||||
nsIReflowCommand* aReflowCommand)
|
||||
{
|
||||
aLineLayout.EndTextRun();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
PRUint8
|
||||
SpacerFrame::GetType()
|
||||
{
|
||||
PRUint8 type = TYPE_WORD;
|
||||
nsAutoString value;
|
||||
if (NS_CONTENT_ATTR_HAS_VALUE == mContent->GetAttribute("type", value)) {
|
||||
if (value.EqualsIgnoreCase("line") ||
|
||||
value.EqualsIgnoreCase("vert") ||
|
||||
value.EqualsIgnoreCase("vertical")) {
|
||||
return TYPE_LINE;
|
||||
}
|
||||
if (value.EqualsIgnoreCase("block")) {
|
||||
return TYPE_IMAGE;
|
||||
}
|
||||
}
|
||||
return type;
|
||||
}
|
||||
1558
mozilla/layout/html/base/src/nsTextFrame.cpp
Normal file
1558
mozilla/layout/html/base/src/nsTextFrame.cpp
Normal file
File diff suppressed because it is too large
Load Diff
35
mozilla/layout/html/base/src/nsWBRFrame.cpp
Normal file
35
mozilla/layout/html/base/src/nsWBRFrame.cpp
Normal file
@ -0,0 +1,35 @@
|
||||
/* -*- 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 "nsHTMLTagContent.h"
|
||||
#include "nsFrame.h"
|
||||
#include "nsHTMLIIDs.h"
|
||||
|
||||
nsresult
|
||||
NS_NewWBRFrame(nsIContent* aContent,
|
||||
nsIFrame* aParentFrame,
|
||||
nsIFrame*& aResult)
|
||||
{
|
||||
nsIFrame* frame = nsnull;
|
||||
nsresult rv = nsFrame::NewFrame(&frame, aContent, aParentFrame);
|
||||
if (NS_OK != rv) {
|
||||
return rv;
|
||||
}
|
||||
aResult = frame;
|
||||
return NS_OK;
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user