diff --git a/mozilla/layout/base/nsIPresShell.h b/mozilla/layout/base/nsIPresShell.h index ffdd8ea8a77..5a9f186f464 100644 --- a/mozilla/layout/base/nsIPresShell.h +++ b/mozilla/layout/base/nsIPresShell.h @@ -30,6 +30,7 @@ class nsIStyleSet; class nsIViewManager; class nsIReflowCommand; class nsIDeviceContext; +class nsIRenderingContext; #define NS_IPRESSHELL_IID \ { 0x76e79c60, 0x944e, 0x11d1, \ @@ -94,6 +95,12 @@ public: virtual void ProcessReflowCommands() = 0; + /** + * Given a frame, cough up a rendering context suitable for use with + * the frame. + */ + NS_IMETHOD CreateRenderingContext(nsIFrame *aFrame, nsIRenderingContext *&aContext) = 0; + // XXX events // XXX selection diff --git a/mozilla/layout/base/nsPresShell.cpp b/mozilla/layout/base/nsPresShell.cpp index 02ffcf56ab5..7f9f50a60b8 100644 --- a/mozilla/layout/base/nsPresShell.cpp +++ b/mozilla/layout/base/nsPresShell.cpp @@ -33,6 +33,7 @@ #include "nsIViewObserver.h" #include "nsContainerFrame.h" #include "nsHTMLIIDs.h" +#include "nsIDeviceContext.h" static PRBool gsNoisyRefs = PR_FALSE; #undef NOISY @@ -207,8 +208,7 @@ public: virtual nsIFrame* FindFrameWithContent(nsIContent* aContent); virtual void AppendReflowCommand(nsIReflowCommand* aReflowCommand); virtual void ProcessReflowCommands(); - - //nsIViewObserver + NS_IMETHOD CreateRenderingContext(nsIFrame *aFrame, nsIRenderingContext *&aContext); //nsIViewObserver interface @@ -496,13 +496,17 @@ PresShell::InitialReflow(nscoord aWidth, nscoord aHeight) mRootFrame->VerifyTree(); } #endif - nsRect bounds; + nsRect bounds; mPresContext->GetVisibleArea(bounds); - nsSize maxSize(bounds.width, bounds.height); - nsHTMLReflowMetrics desiredSize(nsnull); - nsReflowStatus status; - nsReflowState reflowState(mRootFrame, eReflowReason_Initial, maxSize); - nsIHTMLReflow* htmlReflow; + nsSize maxSize(bounds.width, bounds.height); + nsHTMLReflowMetrics desiredSize(nsnull); + nsReflowStatus status; + nsIHTMLReflow* htmlReflow; + nsIRenderingContext* rcx = nsnull; + + CreateRenderingContext(mRootFrame, rcx); + + nsReflowState reflowState(mRootFrame, eReflowReason_Initial, maxSize, rcx); if (NS_OK == mRootFrame->QueryInterface(kIHTMLReflowIID, (void**)&htmlReflow)) { htmlReflow->Reflow(*mPresContext, desiredSize, reflowState, status); @@ -513,6 +517,7 @@ PresShell::InitialReflow(nscoord aWidth, nscoord aHeight) } #endif } + NS_IF_RELEASE(rcx); NS_FRAME_LOG(NS_FRAME_TRACE_CALLS, ("exit nsPresShell::InitialReflow")); } @@ -542,13 +547,17 @@ PresShell::ResizeReflow(nscoord aWidth, nscoord aHeight) mRootFrame->VerifyTree(); } #endif - nsRect bounds; + nsRect bounds; mPresContext->GetVisibleArea(bounds); - nsSize maxSize(bounds.width, bounds.height); - nsHTMLReflowMetrics desiredSize(nsnull); - nsReflowStatus status; - nsReflowState reflowState(mRootFrame, eReflowReason_Resize, maxSize); - nsIHTMLReflow* htmlReflow; + nsSize maxSize(bounds.width, bounds.height); + nsHTMLReflowMetrics desiredSize(nsnull); + nsReflowStatus status; + nsIHTMLReflow* htmlReflow; + nsIRenderingContext* rcx = nsnull; + + CreateRenderingContext(mRootFrame, rcx); + + nsReflowState reflowState(mRootFrame, eReflowReason_Resize, maxSize, rcx); if (NS_OK == mRootFrame->QueryInterface(kIHTMLReflowIID, (void**)&htmlReflow)) { htmlReflow->Reflow(*mPresContext, desiredSize, reflowState, status); @@ -559,6 +568,7 @@ PresShell::ResizeReflow(nscoord aWidth, nscoord aHeight) } #endif } + NS_IF_RELEASE(rcx); NS_FRAME_LOG(NS_FRAME_TRACE_CALLS, ("exit nsPresShell::ResizeReflow")); // XXX if debugging then we should assert that the cache is empty @@ -631,7 +641,10 @@ void PresShell::ProcessReflowCommands() { if (0 != mReflowCommands.Count()) { - nsHTMLReflowMetrics desiredSize(nsnull); + nsHTMLReflowMetrics desiredSize(nsnull); + nsIRenderingContext* rcx; + + CreateRenderingContext(mRootFrame, rcx); while (0 != mReflowCommands.Count()) { nsIReflowCommand* rc = (nsIReflowCommand*) mReflowCommands.ElementAt(0); @@ -647,7 +660,7 @@ PresShell::ProcessReflowCommands() ("PresShell::ProcessReflowCommands: begin reflow command type=%d", type)); #endif - rc->Dispatch(*mPresContext, desiredSize, maxSize); + rc->Dispatch(*mPresContext, desiredSize, maxSize, *rcx); NS_RELEASE(rc); NS_FRAME_LOG(NS_FRAME_TRACE_CALLS, ("PresShell::ProcessReflowCommands: end reflow command")); @@ -663,9 +676,53 @@ PresShell::ProcessReflowCommands() VerifyIncrementalReflow(); } #endif + NS_IF_RELEASE(rcx); } } +NS_IMETHODIMP PresShell :: CreateRenderingContext(nsIFrame *aFrame, + nsIRenderingContext *&aContext) +{ + nsIWidget *widget = nsnull; + nsIView *view = nsnull; + nsPoint pt; + nsresult rv; + + aFrame->GetView(view); + + if (nsnull == view) + aFrame->GetOffsetFromView(pt, view); + + while (nsnull != view) + { + view->GetWidget(widget); + + if (nsnull != widget) + { + NS_RELEASE(widget); + break; + } + + view->GetParent(view); + } + + if (nsnull != view) + { + nsIDeviceContext *dx; + + dx = mPresContext->GetDeviceContext(); + rv = dx->CreateRenderingContext(view, aContext); + NS_RELEASE(dx); + } + else + { + rv = NS_ERROR_FAILURE; + aContext = nsnull; + } + + return rv; +} + #ifdef NS_DEBUG static char* ContentTag(nsIContent* aContent, PRIntn aSlot) diff --git a/mozilla/layout/base/public/nsIFrame.h b/mozilla/layout/base/public/nsIFrame.h index d01e66e3b8a..c0cb3d05839 100644 --- a/mozilla/layout/base/public/nsIFrame.h +++ b/mozilla/layout/base/public/nsIFrame.h @@ -214,10 +214,12 @@ public: nsGUIEvent * aEvent, nsEventStatus& aEventStatus) = 0; - virtual PRInt32 GetPosition(nsIPresContext& aPresContext, - nsGUIEvent* aEvent, - nsIFrame * aNewFrame, - PRUint32& aAcutalContentOffset) = 0; + NS_IMETHOD GetPosition(nsIPresContext& aPresContext, + nsIRenderingContext * aRendContext, + nsGUIEvent* aEvent, + nsIFrame * aNewFrame, + PRUint32& aAcutalContentOffset, + PRInt32& aOffset) = 0; /** diff --git a/mozilla/layout/base/public/nsIFrameReflow.h b/mozilla/layout/base/public/nsIFrameReflow.h index 723454c236f..63707f6657b 100644 --- a/mozilla/layout/base/public/nsIFrameReflow.h +++ b/mozilla/layout/base/public/nsIFrameReflow.h @@ -21,6 +21,7 @@ #include "nslayout.h" #include "nsISupports.h" #include "nsSize.h" +#include "nsIRenderingContext.h" class nsIFrame; class nsIPresContext; @@ -88,21 +89,24 @@ struct nsReflowState { nsReflowReason reason; // the reason for the reflow nsIReflowCommand* reflowCommand; // only used for incremental changes nsSize maxSize; // the max available space in which to reflow + nsIRenderingContext* rendContext; // rendering context to use for measurement // Note: there is no copy constructor so that the compiler can // generate an optimal one. // Constructs an initial reflow state (no parent reflow state) for a // non-incremental reflow command - nsReflowState(nsIFrame* aFrame, - nsReflowReason aReason, - const nsSize& aMaxSize); + nsReflowState(nsIFrame* aFrame, + nsReflowReason aReason, + const nsSize& aMaxSize, + nsIRenderingContext* aContext); // Constructs an initial reflow state (no parent reflow state) for an // incremental reflow command - nsReflowState(nsIFrame* aFrame, - nsIReflowCommand& aReflowCommand, - const nsSize& aMaxSize); + nsReflowState(nsIFrame* aFrame, + nsIReflowCommand& aReflowCommand, + const nsSize& aMaxSize, + nsIRenderingContext* aContext); // Construct a reflow state for the given frame, parent reflow state, and // max size. Uses the reflow reason and reflow command from the parent's @@ -252,29 +256,35 @@ private: // Constructs an initial reflow state (no parent reflow state) for a // non-incremental reflow command -inline nsReflowState::nsReflowState(nsIFrame* aFrame, - nsReflowReason aReason, - const nsSize& aMaxSize) +inline nsReflowState::nsReflowState(nsIFrame* aFrame, + nsReflowReason aReason, + const nsSize& aMaxSize, + nsIRenderingContext* aContext) { NS_PRECONDITION(aReason != eReflowReason_Incremental, "unexpected reflow reason"); + NS_PRECONDITION(!(aContext == nsnull), "no rendering context"); reason = aReason; reflowCommand = nsnull; maxSize = aMaxSize; parentReflowState = nsnull; frame = aFrame; + rendContext = aContext; } // Constructs an initial reflow state (no parent reflow state) for an // incremental reflow command -inline nsReflowState::nsReflowState(nsIFrame* aFrame, - nsIReflowCommand& aReflowCommand, - const nsSize& aMaxSize) +inline nsReflowState::nsReflowState(nsIFrame* aFrame, + nsIReflowCommand& aReflowCommand, + const nsSize& aMaxSize, + nsIRenderingContext* aContext) { + NS_PRECONDITION(!(aContext == nsnull), "no rendering context"); reason = eReflowReason_Incremental; reflowCommand = &aReflowCommand; maxSize = aMaxSize; parentReflowState = nsnull; frame = aFrame; + rendContext = aContext; } // Construct a reflow state for the given frame, parent reflow state, and @@ -289,6 +299,7 @@ inline nsReflowState::nsReflowState(nsIFrame* aFrame, maxSize = aMaxSize; parentReflowState = &aParentReflowState; frame = aFrame; + rendContext = aParentReflowState.rendContext; } // Constructs a reflow state that overrides the reflow reason of the parent @@ -303,6 +314,7 @@ inline nsReflowState::nsReflowState(nsIFrame* aFrame, maxSize = aMaxSize; parentReflowState = &aParentReflowState; frame = aFrame; + rendContext = aParentReflowState.rendContext; } #endif /* nsIFrameReflow_h___ */ diff --git a/mozilla/layout/base/public/nsIPresShell.h b/mozilla/layout/base/public/nsIPresShell.h index ffdd8ea8a77..5a9f186f464 100644 --- a/mozilla/layout/base/public/nsIPresShell.h +++ b/mozilla/layout/base/public/nsIPresShell.h @@ -30,6 +30,7 @@ class nsIStyleSet; class nsIViewManager; class nsIReflowCommand; class nsIDeviceContext; +class nsIRenderingContext; #define NS_IPRESSHELL_IID \ { 0x76e79c60, 0x944e, 0x11d1, \ @@ -94,6 +95,12 @@ public: virtual void ProcessReflowCommands() = 0; + /** + * Given a frame, cough up a rendering context suitable for use with + * the frame. + */ + NS_IMETHOD CreateRenderingContext(nsIFrame *aFrame, nsIRenderingContext *&aContext) = 0; + // XXX events // XXX selection diff --git a/mozilla/layout/base/public/nsIReflowCommand.h b/mozilla/layout/base/public/nsIReflowCommand.h index 5818b52f0a5..925442a09e2 100644 --- a/mozilla/layout/base/public/nsIReflowCommand.h +++ b/mozilla/layout/base/public/nsIReflowCommand.h @@ -22,6 +22,7 @@ class nsIFrame; class nsIPresContext; +class nsIRenderingContext; struct nsHTMLReflowMetrics; struct nsSize; @@ -93,7 +94,8 @@ public: */ NS_IMETHOD Dispatch(nsIPresContext& aPresContext, nsHTMLReflowMetrics& aDesiredSize, - const nsSize& aMaxSize) = 0; + const nsSize& aMaxSize, + nsIRenderingContext& aRendContext) = 0; /** * Get the next frame in the command processing path. Note that this removes diff --git a/mozilla/layout/forms/nsFormControlFrame.cpp b/mozilla/layout/forms/nsFormControlFrame.cpp index 93bb61c3668..b9e3e346a60 100644 --- a/mozilla/layout/forms/nsFormControlFrame.cpp +++ b/mozilla/layout/forms/nsFormControlFrame.cpp @@ -580,7 +580,8 @@ GetRepChars(nsIPresContext& aPresContext, char& char1, char& char2) nscoord nsFormControlFrame::GetTextSize(nsIPresContext& aPresContext, nsFormControlFrame* aFrame, - const nsString& aString, nsSize& aSize) + const nsString& aString, nsSize& aSize, + nsIRenderingContext *aRendContext) { nsFont font(aPresContext.GetDefaultFixedFont()); aFrame->GetFont(&aPresContext, font); @@ -589,14 +590,15 @@ nsFormControlFrame::GetTextSize(nsIPresContext& aPresContext, nsFormControlFrame nsIFontMetrics* fontMet; deviceContext->GetMetricsFor(font, fontMet); - fontMet->GetWidth(aString, aSize.width); + aRendContext->SetFont(fontMet); + aRendContext->GetWidth(aString, aSize.width); fontMet->GetHeight(aSize.height); char char1, char2; GetRepChars(aPresContext, char1, char2); nscoord char1Width, char2Width; - fontMet->GetWidth(char1, char1Width); - fontMet->GetWidth(char2, char2Width); + aRendContext->GetWidth(char1, char1Width); + aRendContext->GetWidth(char2, char2Width); NS_RELEASE(fontMet); NS_RELEASE(deviceContext); @@ -606,7 +608,8 @@ nsFormControlFrame::GetTextSize(nsIPresContext& aPresContext, nsFormControlFrame nscoord nsFormControlFrame::GetTextSize(nsIPresContext& aPresContext, nsFormControlFrame* aFrame, - PRInt32 aNumChars, nsSize& aSize) + PRInt32 aNumChars, nsSize& aSize, + nsIRenderingContext *aRendContext) { nsAutoString val; char char1, char2; @@ -618,14 +621,15 @@ nsFormControlFrame::GetTextSize(nsIPresContext& aPresContext, nsFormControlFrame for (i = 1; i < aNumChars; i+=2) { val += char2; } - return GetTextSize(aPresContext, aFrame, val, aSize); + return GetTextSize(aPresContext, aFrame, val, aSize, aRendContext); } PRInt32 nsFormControlFrame::CalculateSize (nsIPresContext* aPresContext, nsFormControlFrame* aFrame, const nsSize& aCSSSize, nsInputDimensionSpec& aSpec, nsSize& aBounds, PRBool& aWidthExplicit, - PRBool& aHeightExplicit, nscoord& aRowHeight) + PRBool& aHeightExplicit, nscoord& aRowHeight, + nsIRenderingContext *aRendContext) { nscoord charWidth = 0; PRInt32 numRows = ATTR_NOTSET; @@ -669,7 +673,7 @@ nsFormControlFrame::CalculateSize (nsIPresContext* aPresContext, nsFormControlFr } else { col = (col <= 0) ? 1 : col; - charWidth = GetTextSize(*aPresContext, aFrame, col, aBounds); + charWidth = GetTextSize(*aPresContext, aFrame, col, aBounds, aRendContext); aRowHeight = aBounds.height; // XXX aBounds.height has CSS_NOTSET } if (aSpec.mColSizeAttrInPixels) { @@ -683,17 +687,17 @@ nsFormControlFrame::CalculateSize (nsIPresContext* aPresContext, nsFormControlFr } else { if (NS_CONTENT_ATTR_HAS_VALUE == valStatus) { // use width of initial value - charWidth = GetTextSize(*aPresContext, aFrame, valAttr, aBounds); + charWidth = GetTextSize(*aPresContext, aFrame, valAttr, aBounds, aRendContext); } else if (aSpec.mColDefaultValue) { // use default value - charWidth = GetTextSize(*aPresContext, aFrame, *aSpec.mColDefaultValue, aBounds); + charWidth = GetTextSize(*aPresContext, aFrame, *aSpec.mColDefaultValue, aBounds, aRendContext); } else if (aSpec.mColDefaultSizeInPixels) { // use default width in pixels - charWidth = GetTextSize(*aPresContext, aFrame, 1, aBounds); + charWidth = GetTextSize(*aPresContext, aFrame, 1, aBounds, aRendContext); aBounds.width = aSpec.mColDefaultSize; } else { // use default width in num characters - charWidth = GetTextSize(*aPresContext, aFrame, aSpec.mColDefaultSize, aBounds); + charWidth = GetTextSize(*aPresContext, aFrame, aSpec.mColDefaultSize, aBounds, aRendContext); } aRowHeight = aBounds.height; // XXX aBounds.height has CSS_NOTSET } @@ -709,7 +713,7 @@ nsFormControlFrame::CalculateSize (nsIPresContext* aPresContext, nsFormControlFr PRInt32 rowAttrInt = ((rowAttr.GetUnit() == eHTMLUnit_Pixel) ? rowAttr.GetPixelValue() : rowAttr.GetIntValue()); adjSize = (rowAttrInt > 0) ? rowAttrInt : 1; if (0 == charWidth) { - charWidth = GetTextSize(*aPresContext, aFrame, 1, textSize); + charWidth = GetTextSize(*aPresContext, aFrame, 1, textSize, aRendContext); aBounds.height = textSize.height * adjSize; aRowHeight = textSize.height; numRows = adjSize; @@ -724,7 +728,7 @@ nsFormControlFrame::CalculateSize (nsIPresContext* aPresContext, nsFormControlFr } else { // use default height in num lines if (0 == charWidth) { - charWidth = GetTextSize(*aPresContext, aFrame, 1, textSize); + charWidth = GetTextSize(*aPresContext, aFrame, 1, textSize, aRendContext); aBounds.height = textSize.height * aSpec.mRowDefaultSize; aRowHeight = textSize.height; } @@ -734,7 +738,7 @@ nsFormControlFrame::CalculateSize (nsIPresContext* aPresContext, nsFormControlFr } if ((0 == charWidth) || (0 == textSize.width)) { - charWidth = GetTextSize(*aPresContext, aFrame, 1, textSize); + charWidth = GetTextSize(*aPresContext, aFrame, 1, textSize, aRendContext); aRowHeight = textSize.height; } diff --git a/mozilla/layout/forms/nsFormControlFrame.h b/mozilla/layout/forms/nsFormControlFrame.h index 708044cf24f..cb588f55ccc 100644 --- a/mozilla/layout/forms/nsFormControlFrame.h +++ b/mozilla/layout/forms/nsFormControlFrame.h @@ -92,7 +92,8 @@ public: static nscoord CalculateSize (nsIPresContext* aPresContext, nsFormControlFrame* aFrame, const nsSize& aCSSSize, nsInputDimensionSpec& aDimensionSpec, nsSize& aBounds, PRBool& aWidthExplicit, - PRBool& aHeightExplicit, nscoord& aRowSize); + PRBool& aHeightExplicit, nscoord& aRowSize, + nsIRenderingContext *aRendContext); /** * Respond to a gui event @@ -179,9 +180,11 @@ public: virtual nsWidgetInitData* GetWidgetInitData(nsIPresContext& aPresContext); static nscoord GetTextSize(nsIPresContext& aContext, nsFormControlFrame* aFrame, - const nsString& aString, nsSize& aSize); + const nsString& aString, nsSize& aSize, + nsIRenderingContext *aRendContext); static nscoord GetTextSize(nsIPresContext& aContext, nsFormControlFrame* aFrame, - PRInt32 aNumChars, nsSize& aSize); + PRInt32 aNumChars, nsSize& aSize, + nsIRenderingContext *aRendContext); void GetWidgetSize(nsSize& aSize) const { aSize.width = mWidgetSize.width; aSize.height = mWidgetSize.height; } diff --git a/mozilla/layout/forms/nsTextControlFrame.cpp b/mozilla/layout/forms/nsTextControlFrame.cpp index 0054efd54aa..277fe047690 100644 --- a/mozilla/layout/forms/nsTextControlFrame.cpp +++ b/mozilla/layout/forms/nsTextControlFrame.cpp @@ -197,12 +197,14 @@ nsTextControlFrame::GetDesiredSize(nsIPresContext* aPresContext, nsInputDimensionSpec textSpec(nsnull, PR_FALSE, nsnull, nsnull, width, PR_FALSE, nsnull, 1); CalculateSize(aPresContext, this, styleSize, textSpec, size, - widthExplicit, heightExplicit, ignore); + widthExplicit, heightExplicit, ignore, + aReflowState.rendContext); } else { nsInputDimensionSpec areaSpec(nsHTMLAtoms::cols, PR_FALSE, nsnull, nsnull, 20, PR_FALSE, nsHTMLAtoms::rows, 1); CalculateSize(aPresContext, this, styleSize, areaSpec, size, - widthExplicit, heightExplicit, ignore); + widthExplicit, heightExplicit, ignore, + aReflowState.rendContext); } if (NS_FORM_TEXTAREA == type) { diff --git a/mozilla/layout/generic/nsBlockFrame.cpp b/mozilla/layout/generic/nsBlockFrame.cpp index 5929f72bb5c..ed689d6d838 100644 --- a/mozilla/layout/generic/nsBlockFrame.cpp +++ b/mozilla/layout/generic/nsBlockFrame.cpp @@ -562,8 +562,8 @@ BulletFrame::Paint(nsIPresContext& aCX, case NS_STYLE_LIST_STYLE_UPPER_ALPHA: fm = aCX.GetMetricsFor(myFont->mFont); GetListItemText(aCX, *myList, text); - aRenderingContext.SetFont(myFont->mFont); - fm->GetWidth(text, width); + aRenderingContext.SetFont(fm); + aRenderingContext.GetWidth(text, width); aRenderingContext.DrawString(text, mPadding.left, mPadding.top, width); NS_RELEASE(fm); break; @@ -819,8 +819,9 @@ BulletFrame::GetDesiredSize(nsIPresContext* aCX, // between the list item and the content that follows. mPadding.right = aMetrics.height / 2; // From old layout engine } - - fm->GetWidth(text, aMetrics.width); + + aReflowState.rendContext->SetFont(fm); + aReflowState.rendContext->GetWidth(text, aMetrics.width); aMetrics.width += mPadding.right; fm->GetMaxAscent(aMetrics.ascent); fm->GetMaxDescent(aMetrics.descent); diff --git a/mozilla/layout/generic/nsBlockReflowState.cpp b/mozilla/layout/generic/nsBlockReflowState.cpp index 5929f72bb5c..ed689d6d838 100644 --- a/mozilla/layout/generic/nsBlockReflowState.cpp +++ b/mozilla/layout/generic/nsBlockReflowState.cpp @@ -562,8 +562,8 @@ BulletFrame::Paint(nsIPresContext& aCX, case NS_STYLE_LIST_STYLE_UPPER_ALPHA: fm = aCX.GetMetricsFor(myFont->mFont); GetListItemText(aCX, *myList, text); - aRenderingContext.SetFont(myFont->mFont); - fm->GetWidth(text, width); + aRenderingContext.SetFont(fm); + aRenderingContext.GetWidth(text, width); aRenderingContext.DrawString(text, mPadding.left, mPadding.top, width); NS_RELEASE(fm); break; @@ -819,8 +819,9 @@ BulletFrame::GetDesiredSize(nsIPresContext* aCX, // between the list item and the content that follows. mPadding.right = aMetrics.height / 2; // From old layout engine } - - fm->GetWidth(text, aMetrics.width); + + aReflowState.rendContext->SetFont(fm); + aReflowState.rendContext->GetWidth(text, aMetrics.width); aMetrics.width += mPadding.right; fm->GetMaxAscent(aMetrics.ascent); fm->GetMaxDescent(aMetrics.descent); diff --git a/mozilla/layout/generic/nsBlockReflowState.h b/mozilla/layout/generic/nsBlockReflowState.h index 5929f72bb5c..ed689d6d838 100644 --- a/mozilla/layout/generic/nsBlockReflowState.h +++ b/mozilla/layout/generic/nsBlockReflowState.h @@ -562,8 +562,8 @@ BulletFrame::Paint(nsIPresContext& aCX, case NS_STYLE_LIST_STYLE_UPPER_ALPHA: fm = aCX.GetMetricsFor(myFont->mFont); GetListItemText(aCX, *myList, text); - aRenderingContext.SetFont(myFont->mFont); - fm->GetWidth(text, width); + aRenderingContext.SetFont(fm); + aRenderingContext.GetWidth(text, width); aRenderingContext.DrawString(text, mPadding.left, mPadding.top, width); NS_RELEASE(fm); break; @@ -819,8 +819,9 @@ BulletFrame::GetDesiredSize(nsIPresContext* aCX, // between the list item and the content that follows. mPadding.right = aMetrics.height / 2; // From old layout engine } - - fm->GetWidth(text, aMetrics.width); + + aReflowState.rendContext->SetFont(fm); + aReflowState.rendContext->GetWidth(text, aMetrics.width); aMetrics.width += mPadding.right; fm->GetMaxAscent(aMetrics.ascent); fm->GetMaxDescent(aMetrics.descent); diff --git a/mozilla/layout/generic/nsFrame.cpp b/mozilla/layout/generic/nsFrame.cpp index 1473415f81e..2df82255ed4 100644 --- a/mozilla/layout/generic/nsFrame.cpp +++ b/mozilla/layout/generic/nsFrame.cpp @@ -642,15 +642,17 @@ NS_METHOD nsFrame::HandlePress(nsIPresContext& aPresContext, return NS_OK; } - nsFrame * currentFrame = this; - nsIPresShell * shell = aPresContext.GetShell(); - nsMouseEvent * mouseEvent = (nsMouseEvent *)aEvent; + nsFrame * currentFrame = this; + nsIPresShell * shell = aPresContext.GetShell(); + nsMouseEvent * mouseEvent = (nsMouseEvent *)aEvent; + nsIRenderingContext * acx; gDoc = shell->GetDocument(); nsISelection * selection; gDoc->GetSelection(selection); + shell->CreateRenderingContext(this, acx); mSelectionRange = selection->GetRange(); @@ -660,7 +662,7 @@ NS_METHOD nsFrame::HandlePress(nsIPresContext& aPresContext, mDidDrag = PR_FALSE; mCurrentFrame = currentFrame; - mStartPos = GetPosition(aPresContext, aEvent, currentFrame, actualOffset); + GetPosition(aPresContext, acx, aEvent, currentFrame, actualOffset, mStartPos); // Click count is 1 nsIContent * newContent; @@ -803,6 +805,8 @@ NS_METHOD nsFrame::HandlePress(nsIPresContext& aPresContext, if (SELECTION_DEBUG) printf("HandleEvent::mSelectionRange %s\n", mSelectionRange->ToString()); + NS_IF_RELEASE(acx); + // Force Update ForceDrawFrame(this); @@ -830,6 +834,12 @@ NS_METHOD nsFrame::HandleDrag(nsIPresContext& aPresContext, mDidDrag = PR_TRUE; + nsIPresShell *ps = aPresContext.GetShell(); + nsIRenderingContext *acx; + + ps->CreateRenderingContext(this, acx); + NS_RELEASE(ps); + //if (aFrame != nsnull) { //printf("nsFrame::HandleDrag\n"); @@ -850,20 +860,20 @@ NS_METHOD nsFrame::HandleDrag(nsIPresContext& aPresContext, if (currentContent == newContent) { if (SELECTION_DEBUG) printf("HandleDrag::New Frame, same content.\n"); - AdjustPointsInSameContent(aPresContext, aEvent); + AdjustPointsInSameContent(aPresContext, acx, aEvent); addRangeToSelectionTrackers(currentContent, currentContent, kInsertInAddList); } else if (gDoc->IsBefore(newContent, currentContent)) { if (SELECTION_DEBUG) printf("HandleDrag::New Frame, is Before.\n"); resetContentTrackers(); - NewContentIsBefore(aPresContext, aEvent, newContent, currentContent, this); + NewContentIsBefore(aPresContext, acx, aEvent, newContent, currentContent, this); } else { // Content is AFTER if (SELECTION_DEBUG) printf("HandleDrag::New Frame, is After.\n"); resetContentTrackers(); - NewContentIsAfter(aPresContext, aEvent, newContent, currentContent, this); + NewContentIsAfter(aPresContext, acx, aEvent, newContent, currentContent, this); } mCurrentFrame = this; @@ -882,7 +892,7 @@ NS_METHOD nsFrame::HandleDrag(nsIPresContext& aPresContext, if (selStartContent == selEndContent) { if (SELECTION_DEBUG) printf("Start & End Frame are the same: \n"); - AdjustPointsInSameContent(aPresContext, aEvent); + AdjustPointsInSameContent(aPresContext, acx, aEvent); } else { if (SELECTION_DEBUG) printf("Start & End Frame are different: \n"); @@ -892,7 +902,7 @@ NS_METHOD nsFrame::HandleDrag(nsIPresContext& aPresContext, PRInt32 newPos = -1; PRUint32 actualOffset = 0; - newPos = GetPosition(aPresContext, aEvent, this, actualOffset); + GetPosition(aPresContext, acx, aEvent, this, actualOffset, newPos); if (newContent == selStartContent) { if (SELECTION_DEBUG) printf("New Content equals Start Content\n"); @@ -921,6 +931,8 @@ NS_METHOD nsFrame::HandleDrag(nsIPresContext& aPresContext, NS_IF_RELEASE(startContent); NS_IF_RELEASE(endContent); + NS_IF_RELEASE(acx); + // Force Update ForceDrawFrame(this); //RefreshContentFrames(aPresContext, startContent, endContent); @@ -943,10 +955,13 @@ NS_METHOD nsFrame::HandleRelease(nsIPresContext& aPresContext, //-------------------------------------------------------------------------- //-- GetPosition //-------------------------------------------------------------------------- -PRInt32 nsFrame::GetPosition(nsIPresContext& aPresContext, - nsGUIEvent * aEvent, - nsIFrame * aNewFrame, - PRUint32& aAcutalContentOffset) { +NS_IMETHODIMP nsFrame::GetPosition(nsIPresContext& aPresContext, + nsIRenderingContext * aRendContext, + nsGUIEvent * aEvent, + nsIFrame * aNewFrame, + PRUint32& aAcutalContentOffset, + PRInt32& aOffset) +{ //PRInt32 offset; //PRInt32 width; @@ -955,19 +970,24 @@ PRInt32 nsFrame::GetPosition(nsIPresContext& aPresContext, //return offset; aAcutalContentOffset = 0; - return -1; + aOffset = -1; + + return NS_OK; } /******************************************************** * Adjusts the Starting and Ending TextPoint for a Range *********************************************************/ void nsFrame::AdjustPointsInNewContent(nsIPresContext& aPresContext, + nsIRenderingContext * aRendContext, nsGUIEvent * aEvent, nsIFrame * aNewFrame) { PRUint32 actualOffset = 0; // Get new Cursor Poition in the new content - PRInt32 newPos = GetPosition(aPresContext, aEvent, aNewFrame, actualOffset); + PRInt32 newPos; + + GetPosition(aPresContext, aRendContext, aEvent, aNewFrame, actualOffset, newPos); if (mStartSelectionPoint->IsAnchor()) { if (newPos == mStartSelectionPoint->GetOffset()) { @@ -1012,11 +1032,13 @@ void nsFrame::AdjustPointsInNewContent(nsIPresContext& aPresContext, * Adjusts the Starting and Ending TextPoint for a Range *********************************************************/ void nsFrame::AdjustPointsInSameContent(nsIPresContext& aPresContext, + nsIRenderingContext * aRendContext, nsGUIEvent * aEvent) { PRUint32 actualOffset = 0; // Get new Cursor Poition in the same content - PRInt32 newPos = GetPosition(aPresContext, aEvent, mCurrentFrame, actualOffset); + PRInt32 newPos; + GetPosition(aPresContext, aRendContext, aEvent, mCurrentFrame, actualOffset, newPos); //newPos += actualOffset; if (SELECTION_DEBUG) printf("AdjustTextPointsInSameContent newPos: %d\n", newPos); @@ -1469,6 +1491,7 @@ NS_METHOD nsFrame::VerifyTree() const * the content that the cursor is currently in *********************************************************/ void nsFrame::NewContentIsBefore(nsIPresContext& aPresContext, + nsIRenderingContext * aRendContext, nsGUIEvent * aEvent, nsIContent * aNewContent, nsIContent * aCurrentContent, @@ -1509,11 +1532,12 @@ void nsFrame::NewContentIsBefore(nsIPresContext& aPresContext, // Returns the new End Point, if Start and End are on the // same content then End Point's Cursor is set to Start's mEndSelectionPoint->SetContent(selStartContent); - AdjustPointsInNewContent(aPresContext, aEvent, aNewFrame); + AdjustPointsInNewContent(aPresContext, aRendContext, aEvent, aNewFrame); } else { PRUint32 actualOffset = 0; - PRInt32 newPos = GetPosition(aPresContext, aEvent, aNewFrame, actualOffset); + PRInt32 newPos; + GetPosition(aPresContext, aRendContext, aEvent, aNewFrame, actualOffset, newPos); mEndSelectionPoint->SetPoint(aNewContent, newPos, PR_FALSE); mSelectionRange->SetEndPoint(mEndSelectionPoint); } @@ -1525,7 +1549,9 @@ void nsFrame::NewContentIsBefore(nsIPresContext& aPresContext, if (SELECTION_DEBUG) printf("Case #2 - (Before) New Content is NOT in selected Range. Moving Start Backward.\n"); PRUint32 actualOffset = 0; - PRInt32 newPos = GetPosition(aPresContext, aEvent, aNewFrame, actualOffset); + PRInt32 newPos; + + GetPosition(aPresContext, aRendContext, aEvent, aNewFrame, actualOffset, newPos); // Create new TextPoint and move Start Point backward mStartSelectionPoint->SetPoint(aNewContent, newPos, PR_FALSE); // position is set correctly in adjustTextPoints @@ -1601,6 +1627,7 @@ void RefreshContentFrames(nsIPresContext& aPresContext, * the content that the cursor is currently in *********************************************************/ void nsFrame::NewContentIsAfter(nsIPresContext& aPresContext, + nsIRenderingContext * aRendContext, nsGUIEvent * aEvent, nsIContent * aNewContent, nsIContent * aCurrentContent, @@ -1638,14 +1665,15 @@ void nsFrame::NewContentIsAfter(nsIPresContext& aPresContext, PRUint32 actualOffset = 0; // [TODO] Always get nearest Text content - PRInt32 newPos = GetPosition(aPresContext, aEvent, aNewFrame, actualOffset); + PRInt32 newPos; + GetPosition(aPresContext, aRendContext, aEvent, aNewFrame, actualOffset, newPos); // Check to see if the new Content is the same as the End Point's if (aNewContent == selEndContent) { if (SELECTION_DEBUG) printf("New Content matches End Point\n"); mStartSelectionPoint->SetContent(aNewContent); - AdjustPointsInNewContent(aPresContext, aEvent, aNewFrame); + AdjustPointsInNewContent(aPresContext, aRendContext, aEvent, aNewFrame); } else { if (SELECTION_DEBUG) printf("New Content does NOT matches End Point\n"); @@ -1660,7 +1688,8 @@ void nsFrame::NewContentIsAfter(nsIPresContext& aPresContext, // Case #2 - Adding Content (at End) PRUint32 actualOffset = 0; // The new content is not in the selection - PRInt32 newPos = GetPosition(aPresContext, aEvent, aNewFrame, actualOffset); + PRInt32 newPos; + GetPosition(aPresContext, aRendContext, aEvent, aNewFrame, actualOffset, newPos); // Check to see if we need to create a new SelectionPoint and add it // or do we simply move the existing start or end point diff --git a/mozilla/layout/generic/nsFrame.h b/mozilla/layout/generic/nsFrame.h index 3dd3028853e..a0574c7aaf3 100644 --- a/mozilla/layout/generic/nsFrame.h +++ b/mozilla/layout/generic/nsFrame.h @@ -202,10 +202,12 @@ public: nsGUIEvent * aEvent, nsEventStatus& aEventStatus); - virtual PRInt32 GetPosition(nsIPresContext& aPresContext, - nsGUIEvent* aEvent, - nsIFrame * aNewFrame, - PRUint32& aAcutalContentOffset); + NS_IMETHOD GetPosition(nsIPresContext& aPresContext, + nsIRenderingContext * aRendContext, + nsGUIEvent* aEvent, + nsIFrame * aNewFrame, + PRUint32& aAcutalContentOffset, + PRInt32& aOffset); //-------------------------------------------------- // Additional methods @@ -229,22 +231,26 @@ public: protected: virtual void NewContentIsBefore(nsIPresContext& aPresContext, + nsIRenderingContext * aRendContext, nsGUIEvent * aEvent, nsIContent * aNewContent, nsIContent * aCurrentContent, nsIFrame * aNewFrame); virtual void NewContentIsAfter(nsIPresContext& aPresContext, + nsIRenderingContext * aRendContext, nsGUIEvent * aEvent, nsIContent * aNewContent, nsIContent * aCurrentContent, nsIFrame * aNewFrame); virtual void AdjustPointsInNewContent(nsIPresContext& aPresContext, + nsIRenderingContext * aRendContext, nsGUIEvent * aEvent, nsIFrame * aNewFrame); virtual void AdjustPointsInSameContent(nsIPresContext& aPresContext, + nsIRenderingContext * aRendContext, nsGUIEvent * aEvent); PRBool DisplaySelection(nsIPresContext& aPresContext, PRBool isOkToTurnOn = PR_FALSE); diff --git a/mozilla/layout/generic/nsFrameSetFrame.cpp b/mozilla/layout/generic/nsFrameSetFrame.cpp index f927419f0d9..c58a353227e 100644 --- a/mozilla/layout/generic/nsFrameSetFrame.cpp +++ b/mozilla/layout/generic/nsFrameSetFrame.cpp @@ -1396,7 +1396,12 @@ nsHTMLFramesetFrame::MouseDrag(nsIPresContext& aPresContext, nsGUIEvent* aEvent) nsHTMLReflowMetrics metrics(nsnull); nsSize size; GetSize(size); - nsReflowState state(this, eReflowReason_Initial, size); + nsIPresShell *shell; + nsIRenderingContext *acx; + shell = aPresContext.GetShell(); + shell->CreateRenderingContext(this, acx); + NS_RELEASE(shell); + nsReflowState state(this, eReflowReason_Initial, size, acx); state.reason = eReflowReason_Incremental; nsReflowStatus status; nsDidReflowStatus didStatus; @@ -1404,6 +1409,7 @@ nsHTMLFramesetFrame::MouseDrag(nsIPresContext& aPresContext, nsGUIEvent* aEvent) nsFramesetDrag drag(mDragger->mVertical, mDragger->mPrevNeighbor, change, this); Reflow(aPresContext, &drag, metrics, state, status); DidReflow(aPresContext, didStatus); + NS_IF_RELEASE(acx); } mLastDragPoint.x = aEvent->point.x; diff --git a/mozilla/layout/generic/nsHTMLReflowCommand.cpp b/mozilla/layout/generic/nsHTMLReflowCommand.cpp index 203135c3b81..d0377845ab6 100644 --- a/mozilla/layout/generic/nsHTMLReflowCommand.cpp +++ b/mozilla/layout/generic/nsHTMLReflowCommand.cpp @@ -136,7 +136,8 @@ void nsHTMLReflowCommand::BuildPath() NS_IMETHODIMP nsHTMLReflowCommand::Dispatch(nsIPresContext& aPresContext, nsHTMLReflowMetrics& aDesiredSize, - const nsSize& aMaxSize) + const nsSize& aMaxSize, + nsIRenderingContext& aRendContext) { // Build the path from the target frame (index 0) to the root frame BuildPath(); @@ -155,7 +156,7 @@ NS_IMETHODIMP nsHTMLReflowCommand::Dispatch(nsIPresContext& aPresContext, if (nsnull != root) { mPath.RemoveElementAt(mPath.Count() - 1); - nsReflowState reflowState(root, *this, aMaxSize); + nsReflowState reflowState(root, *this, aMaxSize, &aRendContext); nsIHTMLReflow* htmlReflow; nsReflowStatus status; diff --git a/mozilla/layout/generic/nsHTMLReflowCommand.h b/mozilla/layout/generic/nsHTMLReflowCommand.h index e7227057461..f5faf1cf076 100644 --- a/mozilla/layout/generic/nsHTMLReflowCommand.h +++ b/mozilla/layout/generic/nsHTMLReflowCommand.h @@ -52,7 +52,8 @@ public: // nsIReflowCommand NS_IMETHOD Dispatch(nsIPresContext& aPresContext, nsHTMLReflowMetrics& aDesiredSize, - const nsSize& aMaxSize); + const nsSize& aMaxSize, + nsIRenderingContext& aRendContext); NS_IMETHOD GetNext(nsIFrame*& aNextFrame); NS_IMETHOD GetTarget(nsIFrame*& aTargetFrame) const; NS_IMETHOD SetTarget(nsIFrame* aTargetFrame); diff --git a/mozilla/layout/generic/nsIFrame.h b/mozilla/layout/generic/nsIFrame.h index d01e66e3b8a..c0cb3d05839 100644 --- a/mozilla/layout/generic/nsIFrame.h +++ b/mozilla/layout/generic/nsIFrame.h @@ -214,10 +214,12 @@ public: nsGUIEvent * aEvent, nsEventStatus& aEventStatus) = 0; - virtual PRInt32 GetPosition(nsIPresContext& aPresContext, - nsGUIEvent* aEvent, - nsIFrame * aNewFrame, - PRUint32& aAcutalContentOffset) = 0; + NS_IMETHOD GetPosition(nsIPresContext& aPresContext, + nsIRenderingContext * aRendContext, + nsGUIEvent* aEvent, + nsIFrame * aNewFrame, + PRUint32& aAcutalContentOffset, + PRInt32& aOffset) = 0; /** diff --git a/mozilla/layout/generic/nsImageFrame.cpp b/mozilla/layout/generic/nsImageFrame.cpp index ec48079c016..321781ef357 100644 --- a/mozilla/layout/generic/nsImageFrame.cpp +++ b/mozilla/layout/generic/nsImageFrame.cpp @@ -98,11 +98,11 @@ protected: PRBool IsServerImageMap(); PRIntn GetSuppress(); - nscoord MeasureString(nsIFontMetrics* aFontMetrics, - const PRUnichar* aString, - PRInt32 aLength, - nscoord aMaxWidth, - PRUint32& aMaxFit); + nscoord MeasureString(const PRUnichar* aString, + PRInt32 aLength, + nscoord aMaxWidth, + PRUint32& aMaxFit, + nsIRenderingContext& aContext); void DisplayAltText(nsIPresContext& aPresContext, nsIRenderingContext& aRenderingContext, @@ -459,17 +459,18 @@ ImageFrame::GetDesiredSize(nsIPresContext* aPresContext, // 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 +// aMaxFit. NOTE: it is assumed that the fontmetrics have already been selected +// into the rendering context before this is called (for performance). MMP nscoord -ImageFrame::MeasureString(nsIFontMetrics* aFontMetrics, - const PRUnichar* aString, - PRInt32 aLength, - nscoord aMaxWidth, - PRUint32& aMaxFit) +ImageFrame::MeasureString(const PRUnichar* aString, + PRInt32 aLength, + nscoord aMaxWidth, + PRUint32& aMaxFit, + nsIRenderingContext& aContext) { nscoord totalWidth = 0; nscoord spaceWidth; - aFontMetrics->GetWidth(' ', spaceWidth); + aContext.GetWidth(' ', spaceWidth); aMaxFit = 0; while (aLength > 0) { @@ -486,7 +487,7 @@ ImageFrame::MeasureString(nsIFontMetrics* aFontMetrics, // Measure this chunk of text, and see if it fits nscoord width; - aFontMetrics->GetWidth(aString, len, width); + aContext.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 @@ -554,7 +555,7 @@ ImageFrame::DisplayAltText(nsIPresContext& aPresContext, 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); + nscoord width = MeasureString(str, strLen, aRect.width, maxFit, aRenderingContext); // Display the text aRenderingContext.DrawString(str, maxFit, aRect.x, y, 0); diff --git a/mozilla/layout/generic/nsTextFrame.cpp b/mozilla/layout/generic/nsTextFrame.cpp index da6a46443fb..933f783dd6e 100644 --- a/mozilla/layout/generic/nsTextFrame.cpp +++ b/mozilla/layout/generic/nsTextFrame.cpp @@ -78,7 +78,7 @@ static NS_DEFINE_IID(kIDOMTextIID, NS_IDOMTEXT_IID); #define XP_IS_SPACE(_ch) \ (((_ch) == ' ') || ((_ch) == '\t') || ((_ch) == '\n')) -// XXX need more of this in nsIFontMetrics.GetWidth +// XXX need more of this in nsIRenderingContext.GetWidth #define CH_NBSP 160 // XXX use a PreTextFrame for pre-formatted text? @@ -141,10 +141,12 @@ public: NS_IMETHOD ListTag(FILE* out) const; - virtual PRInt32 GetPosition(nsIPresContext& aCX, - nsGUIEvent* aEvent, - nsIFrame * aNewFrame, - PRUint32& aAcutalContentOffset); + NS_IMETHOD GetPosition(nsIPresContext& aCX, + nsIRenderingContext * aRendContext, + nsGUIEvent* aEvent, + nsIFrame * aNewFrame, + PRUint32& aAcutalContentOffset, + PRInt32& aOffset); // nsIInlineReflow NS_IMETHOD FindTextRuns(nsLineLayout& aLineLayout, @@ -1009,7 +1011,7 @@ TextFrame::PaintUnicodeText(nsIPresContext& aPresContext, if (si.mEmptySelection) { aRenderingContext.DrawString(text, textLength, dx, dy, mRect.width); PaintTextDecorations(aRenderingContext, aDecorations, dx, dy, mRect.width); - fm->GetWidth(text, PRUint32(si.mStartOffset), textWidth); + aRenderingContext.GetWidth(text, PRUint32(si.mStartOffset), textWidth); RenderSelectionCursor(aRenderingContext, dx + textWidth, dy, mRect.height, CURSOR_COLOR); @@ -1019,7 +1021,7 @@ TextFrame::PaintUnicodeText(nsIPresContext& aPresContext, if (0 != si.mStartOffset) { // Render first (unselected) section - fm->GetWidth(text, PRUint32(si.mStartOffset), textWidth); + aRenderingContext.GetWidth(text, PRUint32(si.mStartOffset), textWidth); aRenderingContext.DrawString(text, si.mStartOffset, x, dy, textWidth); PaintTextDecorations(aRenderingContext, aDecorations, x, dy, textWidth); @@ -1028,7 +1030,7 @@ TextFrame::PaintUnicodeText(nsIPresContext& aPresContext, PRInt32 secondLen = si.mEndOffset - si.mStartOffset; if (0 != secondLen) { // Get the width of the second (selected) section - fm->GetWidth(text + si.mStartOffset, PRUint32(secondLen), textWidth); + aRenderingContext.GetWidth(text + si.mStartOffset, PRUint32(secondLen), textWidth); // Render second (selected) section aRenderingContext.SetColor(aSelectionBGColor); @@ -1044,7 +1046,7 @@ TextFrame::PaintUnicodeText(nsIPresContext& aPresContext, PRInt32 thirdLen = textLength - si.mEndOffset; // Render third (unselected) section - fm->GetWidth(text + si.mEndOffset, PRUint32(thirdLen), textWidth); + aRenderingContext.GetWidth(text + si.mEndOffset, PRUint32(thirdLen), textWidth); aRenderingContext.DrawString(text + si.mEndOffset, thirdLen, x, dy, textWidth); PaintTextDecorations(aRenderingContext, aDecorations, x, dy, textWidth); @@ -1104,7 +1106,7 @@ TextFrame::PaintAsciiText(nsIPresContext& aPresContext, if (si.mEmptySelection) { aRenderingContext.DrawString(text, textLength, dx, dy, mRect.width); PaintTextDecorations(aRenderingContext, aDecorations, dx, dy, mRect.width); - fm->GetWidth(text, PRUint32(si.mStartOffset), textWidth); + aRenderingContext.GetWidth(text, PRUint32(si.mStartOffset), textWidth); RenderSelectionCursor(aRenderingContext, dx + textWidth, dy, mRect.height, CURSOR_COLOR); @@ -1114,7 +1116,7 @@ TextFrame::PaintAsciiText(nsIPresContext& aPresContext, if (0 != si.mStartOffset) { // Render first (unselected) section - fm->GetWidth(text, PRUint32(si.mStartOffset), textWidth); + aRenderingContext.GetWidth(text, PRUint32(si.mStartOffset), textWidth); aRenderingContext.DrawString(text, si.mStartOffset, x, dy, textWidth); PaintTextDecorations(aRenderingContext, aDecorations, x, dy, textWidth); @@ -1123,7 +1125,7 @@ TextFrame::PaintAsciiText(nsIPresContext& aPresContext, PRInt32 secondLen = si.mEndOffset - si.mStartOffset; if (0 != secondLen) { // Get the width of the second (selected) section - fm->GetWidth(text + si.mStartOffset, PRUint32(secondLen), textWidth); + aRenderingContext.GetWidth(text + si.mStartOffset, PRUint32(secondLen), textWidth); // Render second (selected) section aRenderingContext.SetColor(aSelectionBGColor); @@ -1139,7 +1141,7 @@ TextFrame::PaintAsciiText(nsIPresContext& aPresContext, PRInt32 thirdLen = textLength - si.mEndOffset; // Render third (unselected) section - fm->GetWidth(text + si.mEndOffset, PRUint32(thirdLen), textWidth); + aRenderingContext.GetWidth(text + si.mEndOffset, PRUint32(thirdLen), textWidth); aRenderingContext.DrawString(text + si.mEndOffset, thirdLen, x, dy, textWidth); PaintTextDecorations(aRenderingContext, aDecorations, x, dy, textWidth); @@ -1182,7 +1184,7 @@ TextFrame::FindTextRuns(nsLineLayout& aLineLayout, // aTextWidth returns the (in twips) the length of the text that falls before the cursor // aIndex contains the index of the text where the cursor falls static PRBool -BinarySearchForPosition(nsIFontMetrics* aFM, +BinarySearchForPosition(nsIRenderingContext* acx, PRUnichar* aText, PRInt32 aBaseWidth, PRInt32 aBaseInx, @@ -1200,7 +1202,7 @@ BinarySearchForPosition(nsIFontMetrics* aFM, PRInt32 inx = aStartInx + (range / 2); PRInt32 textWidth; - aFM->GetWidth(aText, inx, textWidth); + acx->GetWidth(aText, inx, textWidth); PRInt32 fullWidth = aBaseWidth + textWidth; if (fullWidth == aCursorPos) { @@ -1208,13 +1210,13 @@ BinarySearchForPosition(nsIFontMetrics* aFM, return PR_TRUE; } else if (aCursorPos < fullWidth) { aTextWidth = aBaseWidth; - if (BinarySearchForPosition(aFM, aText, aBaseWidth, aBaseInx, aStartInx, inx, aCursorPos, aIndex, aTextWidth)) { + if (BinarySearchForPosition(acx, aText, aBaseWidth, aBaseInx, aStartInx, inx, aCursorPos, aIndex, aTextWidth)) { return PR_TRUE; } } else { aTextWidth = fullWidth; PRInt32 end = aEndInx - inx; - if (BinarySearchForPosition(aFM, aText+inx, fullWidth, aBaseInx+inx, 0, end, aCursorPos, aIndex, aTextWidth)) { + if (BinarySearchForPosition(acx, aText+inx, fullWidth, aBaseInx+inx, 0, end, aCursorPos, aIndex, aTextWidth)) { return PR_TRUE; } } @@ -1227,11 +1229,13 @@ BinarySearchForPosition(nsIFontMetrics* aFM, // un-compressed text, selection is based on the un-compressed text, the visual // display of selection is based on the compressed text. //--------------------------------------------------------------------------- -PRInt32 +NS_IMETHODIMP TextFrame::GetPosition(nsIPresContext& aCX, + nsIRenderingContext * aRendContext, nsGUIEvent* aEvent, nsIFrame* aNewFrame, - PRUint32& aAcutalContentOffset) + PRUint32& aAcutalContentOffset, + PRInt32& aOffset) { const PRInt16 kNumIndices = 512; @@ -1259,10 +1263,12 @@ TextFrame::GetPosition(nsIPresContext& aCX, PRInt32 index; PRInt32 textWidth; - PRBool found = BinarySearchForPosition(fm, text, 0, 0, 0, PRInt32(textLength), PRInt32(aEvent->point.x), index, textWidth); + aRendContext->SetFont(fm); + + PRBool found = BinarySearchForPosition(aRendContext, text, 0, 0, 0, PRInt32(textLength), PRInt32(aEvent->point.x), index, textWidth); if (found) { PRInt32 charWidth; - fm->GetWidth(text[index], charWidth); + aRendContext->GetWidth(text[index], charWidth); charWidth /= 2; if (PRInt32(aEvent->point.x) > textWidth+charWidth) { @@ -1290,7 +1296,9 @@ TextFrame::GetPosition(nsIPresContext& aCX, } aAcutalContentOffset = ((TextFrame *)aNewFrame)->mContentOffset; - return offset; + aOffset = offset; + + return NS_OK; } NS_IMETHODIMP @@ -1363,7 +1371,8 @@ TextFrame::ReflowNormal(nsLineLayout& aLineLayout, nsIFontMetrics* fm = aLineLayout.mPresContext.GetMetricsFor(aFont.mFont); PRInt32 spaceWidth; - fm->GetWidth(' ', spaceWidth); + aReflowState.rendContext->SetFont(fm); + aReflowState.rendContext->GetWidth(' ', spaceWidth); PRBool wrapping = PR_TRUE; if (NS_STYLE_WHITESPACE_NORMAL != aTextStyle.mWhiteSpace) { wrapping = PR_FALSE; @@ -1435,7 +1444,7 @@ TextFrame::ReflowNormal(nsLineLayout& aLineLayout, } break; } - fm->GetWidth(wordStart, PRUint32(cp - wordStart), width); + aReflowState.rendContext->GetWidth(wordStart, PRUint32(cp - wordStart), width); skipWhitespace = PR_FALSE; isWhitespace = PR_FALSE; } @@ -1543,7 +1552,8 @@ TextFrame::ReflowPre(nsLineLayout& aLineLayout, PRUint16 col = aLineLayout.GetColumn(); mColumn = col; nscoord spaceWidth; - fm->GetWidth(' ', spaceWidth); + aReflowState.rendContext->SetFont(fm); + aReflowState.rendContext->GetWidth(' ', spaceWidth); // XXX change this to measure a line at a time while (cp < end) { @@ -1569,11 +1579,11 @@ TextFrame::ReflowPre(nsLineLayout& aLineLayout, } if (ch < 256) { nscoord charWidth; - fm->GetWidth(ch, charWidth); + aReflowState.rendContext->GetWidth(ch, charWidth); width += charWidth; } else { nscoord charWidth; - fm->GetWidth(ch, charWidth); + aReflowState.rendContext->GetWidth(ch, charWidth); width += charWidth; hasMultibyte = PR_TRUE; } diff --git a/mozilla/layout/html/base/src/nsBlockFrame.cpp b/mozilla/layout/html/base/src/nsBlockFrame.cpp index 5929f72bb5c..ed689d6d838 100644 --- a/mozilla/layout/html/base/src/nsBlockFrame.cpp +++ b/mozilla/layout/html/base/src/nsBlockFrame.cpp @@ -562,8 +562,8 @@ BulletFrame::Paint(nsIPresContext& aCX, case NS_STYLE_LIST_STYLE_UPPER_ALPHA: fm = aCX.GetMetricsFor(myFont->mFont); GetListItemText(aCX, *myList, text); - aRenderingContext.SetFont(myFont->mFont); - fm->GetWidth(text, width); + aRenderingContext.SetFont(fm); + aRenderingContext.GetWidth(text, width); aRenderingContext.DrawString(text, mPadding.left, mPadding.top, width); NS_RELEASE(fm); break; @@ -819,8 +819,9 @@ BulletFrame::GetDesiredSize(nsIPresContext* aCX, // between the list item and the content that follows. mPadding.right = aMetrics.height / 2; // From old layout engine } - - fm->GetWidth(text, aMetrics.width); + + aReflowState.rendContext->SetFont(fm); + aReflowState.rendContext->GetWidth(text, aMetrics.width); aMetrics.width += mPadding.right; fm->GetMaxAscent(aMetrics.ascent); fm->GetMaxDescent(aMetrics.descent); diff --git a/mozilla/layout/html/base/src/nsBlockReflowState.cpp b/mozilla/layout/html/base/src/nsBlockReflowState.cpp index 5929f72bb5c..ed689d6d838 100644 --- a/mozilla/layout/html/base/src/nsBlockReflowState.cpp +++ b/mozilla/layout/html/base/src/nsBlockReflowState.cpp @@ -562,8 +562,8 @@ BulletFrame::Paint(nsIPresContext& aCX, case NS_STYLE_LIST_STYLE_UPPER_ALPHA: fm = aCX.GetMetricsFor(myFont->mFont); GetListItemText(aCX, *myList, text); - aRenderingContext.SetFont(myFont->mFont); - fm->GetWidth(text, width); + aRenderingContext.SetFont(fm); + aRenderingContext.GetWidth(text, width); aRenderingContext.DrawString(text, mPadding.left, mPadding.top, width); NS_RELEASE(fm); break; @@ -819,8 +819,9 @@ BulletFrame::GetDesiredSize(nsIPresContext* aCX, // between the list item and the content that follows. mPadding.right = aMetrics.height / 2; // From old layout engine } - - fm->GetWidth(text, aMetrics.width); + + aReflowState.rendContext->SetFont(fm); + aReflowState.rendContext->GetWidth(text, aMetrics.width); aMetrics.width += mPadding.right; fm->GetMaxAscent(aMetrics.ascent); fm->GetMaxDescent(aMetrics.descent); diff --git a/mozilla/layout/html/base/src/nsBlockReflowState.h b/mozilla/layout/html/base/src/nsBlockReflowState.h index 5929f72bb5c..ed689d6d838 100644 --- a/mozilla/layout/html/base/src/nsBlockReflowState.h +++ b/mozilla/layout/html/base/src/nsBlockReflowState.h @@ -562,8 +562,8 @@ BulletFrame::Paint(nsIPresContext& aCX, case NS_STYLE_LIST_STYLE_UPPER_ALPHA: fm = aCX.GetMetricsFor(myFont->mFont); GetListItemText(aCX, *myList, text); - aRenderingContext.SetFont(myFont->mFont); - fm->GetWidth(text, width); + aRenderingContext.SetFont(fm); + aRenderingContext.GetWidth(text, width); aRenderingContext.DrawString(text, mPadding.left, mPadding.top, width); NS_RELEASE(fm); break; @@ -819,8 +819,9 @@ BulletFrame::GetDesiredSize(nsIPresContext* aCX, // between the list item and the content that follows. mPadding.right = aMetrics.height / 2; // From old layout engine } - - fm->GetWidth(text, aMetrics.width); + + aReflowState.rendContext->SetFont(fm); + aReflowState.rendContext->GetWidth(text, aMetrics.width); aMetrics.width += mPadding.right; fm->GetMaxAscent(aMetrics.ascent); fm->GetMaxDescent(aMetrics.descent); diff --git a/mozilla/layout/html/base/src/nsFrame.cpp b/mozilla/layout/html/base/src/nsFrame.cpp index 1473415f81e..2df82255ed4 100644 --- a/mozilla/layout/html/base/src/nsFrame.cpp +++ b/mozilla/layout/html/base/src/nsFrame.cpp @@ -642,15 +642,17 @@ NS_METHOD nsFrame::HandlePress(nsIPresContext& aPresContext, return NS_OK; } - nsFrame * currentFrame = this; - nsIPresShell * shell = aPresContext.GetShell(); - nsMouseEvent * mouseEvent = (nsMouseEvent *)aEvent; + nsFrame * currentFrame = this; + nsIPresShell * shell = aPresContext.GetShell(); + nsMouseEvent * mouseEvent = (nsMouseEvent *)aEvent; + nsIRenderingContext * acx; gDoc = shell->GetDocument(); nsISelection * selection; gDoc->GetSelection(selection); + shell->CreateRenderingContext(this, acx); mSelectionRange = selection->GetRange(); @@ -660,7 +662,7 @@ NS_METHOD nsFrame::HandlePress(nsIPresContext& aPresContext, mDidDrag = PR_FALSE; mCurrentFrame = currentFrame; - mStartPos = GetPosition(aPresContext, aEvent, currentFrame, actualOffset); + GetPosition(aPresContext, acx, aEvent, currentFrame, actualOffset, mStartPos); // Click count is 1 nsIContent * newContent; @@ -803,6 +805,8 @@ NS_METHOD nsFrame::HandlePress(nsIPresContext& aPresContext, if (SELECTION_DEBUG) printf("HandleEvent::mSelectionRange %s\n", mSelectionRange->ToString()); + NS_IF_RELEASE(acx); + // Force Update ForceDrawFrame(this); @@ -830,6 +834,12 @@ NS_METHOD nsFrame::HandleDrag(nsIPresContext& aPresContext, mDidDrag = PR_TRUE; + nsIPresShell *ps = aPresContext.GetShell(); + nsIRenderingContext *acx; + + ps->CreateRenderingContext(this, acx); + NS_RELEASE(ps); + //if (aFrame != nsnull) { //printf("nsFrame::HandleDrag\n"); @@ -850,20 +860,20 @@ NS_METHOD nsFrame::HandleDrag(nsIPresContext& aPresContext, if (currentContent == newContent) { if (SELECTION_DEBUG) printf("HandleDrag::New Frame, same content.\n"); - AdjustPointsInSameContent(aPresContext, aEvent); + AdjustPointsInSameContent(aPresContext, acx, aEvent); addRangeToSelectionTrackers(currentContent, currentContent, kInsertInAddList); } else if (gDoc->IsBefore(newContent, currentContent)) { if (SELECTION_DEBUG) printf("HandleDrag::New Frame, is Before.\n"); resetContentTrackers(); - NewContentIsBefore(aPresContext, aEvent, newContent, currentContent, this); + NewContentIsBefore(aPresContext, acx, aEvent, newContent, currentContent, this); } else { // Content is AFTER if (SELECTION_DEBUG) printf("HandleDrag::New Frame, is After.\n"); resetContentTrackers(); - NewContentIsAfter(aPresContext, aEvent, newContent, currentContent, this); + NewContentIsAfter(aPresContext, acx, aEvent, newContent, currentContent, this); } mCurrentFrame = this; @@ -882,7 +892,7 @@ NS_METHOD nsFrame::HandleDrag(nsIPresContext& aPresContext, if (selStartContent == selEndContent) { if (SELECTION_DEBUG) printf("Start & End Frame are the same: \n"); - AdjustPointsInSameContent(aPresContext, aEvent); + AdjustPointsInSameContent(aPresContext, acx, aEvent); } else { if (SELECTION_DEBUG) printf("Start & End Frame are different: \n"); @@ -892,7 +902,7 @@ NS_METHOD nsFrame::HandleDrag(nsIPresContext& aPresContext, PRInt32 newPos = -1; PRUint32 actualOffset = 0; - newPos = GetPosition(aPresContext, aEvent, this, actualOffset); + GetPosition(aPresContext, acx, aEvent, this, actualOffset, newPos); if (newContent == selStartContent) { if (SELECTION_DEBUG) printf("New Content equals Start Content\n"); @@ -921,6 +931,8 @@ NS_METHOD nsFrame::HandleDrag(nsIPresContext& aPresContext, NS_IF_RELEASE(startContent); NS_IF_RELEASE(endContent); + NS_IF_RELEASE(acx); + // Force Update ForceDrawFrame(this); //RefreshContentFrames(aPresContext, startContent, endContent); @@ -943,10 +955,13 @@ NS_METHOD nsFrame::HandleRelease(nsIPresContext& aPresContext, //-------------------------------------------------------------------------- //-- GetPosition //-------------------------------------------------------------------------- -PRInt32 nsFrame::GetPosition(nsIPresContext& aPresContext, - nsGUIEvent * aEvent, - nsIFrame * aNewFrame, - PRUint32& aAcutalContentOffset) { +NS_IMETHODIMP nsFrame::GetPosition(nsIPresContext& aPresContext, + nsIRenderingContext * aRendContext, + nsGUIEvent * aEvent, + nsIFrame * aNewFrame, + PRUint32& aAcutalContentOffset, + PRInt32& aOffset) +{ //PRInt32 offset; //PRInt32 width; @@ -955,19 +970,24 @@ PRInt32 nsFrame::GetPosition(nsIPresContext& aPresContext, //return offset; aAcutalContentOffset = 0; - return -1; + aOffset = -1; + + return NS_OK; } /******************************************************** * Adjusts the Starting and Ending TextPoint for a Range *********************************************************/ void nsFrame::AdjustPointsInNewContent(nsIPresContext& aPresContext, + nsIRenderingContext * aRendContext, nsGUIEvent * aEvent, nsIFrame * aNewFrame) { PRUint32 actualOffset = 0; // Get new Cursor Poition in the new content - PRInt32 newPos = GetPosition(aPresContext, aEvent, aNewFrame, actualOffset); + PRInt32 newPos; + + GetPosition(aPresContext, aRendContext, aEvent, aNewFrame, actualOffset, newPos); if (mStartSelectionPoint->IsAnchor()) { if (newPos == mStartSelectionPoint->GetOffset()) { @@ -1012,11 +1032,13 @@ void nsFrame::AdjustPointsInNewContent(nsIPresContext& aPresContext, * Adjusts the Starting and Ending TextPoint for a Range *********************************************************/ void nsFrame::AdjustPointsInSameContent(nsIPresContext& aPresContext, + nsIRenderingContext * aRendContext, nsGUIEvent * aEvent) { PRUint32 actualOffset = 0; // Get new Cursor Poition in the same content - PRInt32 newPos = GetPosition(aPresContext, aEvent, mCurrentFrame, actualOffset); + PRInt32 newPos; + GetPosition(aPresContext, aRendContext, aEvent, mCurrentFrame, actualOffset, newPos); //newPos += actualOffset; if (SELECTION_DEBUG) printf("AdjustTextPointsInSameContent newPos: %d\n", newPos); @@ -1469,6 +1491,7 @@ NS_METHOD nsFrame::VerifyTree() const * the content that the cursor is currently in *********************************************************/ void nsFrame::NewContentIsBefore(nsIPresContext& aPresContext, + nsIRenderingContext * aRendContext, nsGUIEvent * aEvent, nsIContent * aNewContent, nsIContent * aCurrentContent, @@ -1509,11 +1532,12 @@ void nsFrame::NewContentIsBefore(nsIPresContext& aPresContext, // Returns the new End Point, if Start and End are on the // same content then End Point's Cursor is set to Start's mEndSelectionPoint->SetContent(selStartContent); - AdjustPointsInNewContent(aPresContext, aEvent, aNewFrame); + AdjustPointsInNewContent(aPresContext, aRendContext, aEvent, aNewFrame); } else { PRUint32 actualOffset = 0; - PRInt32 newPos = GetPosition(aPresContext, aEvent, aNewFrame, actualOffset); + PRInt32 newPos; + GetPosition(aPresContext, aRendContext, aEvent, aNewFrame, actualOffset, newPos); mEndSelectionPoint->SetPoint(aNewContent, newPos, PR_FALSE); mSelectionRange->SetEndPoint(mEndSelectionPoint); } @@ -1525,7 +1549,9 @@ void nsFrame::NewContentIsBefore(nsIPresContext& aPresContext, if (SELECTION_DEBUG) printf("Case #2 - (Before) New Content is NOT in selected Range. Moving Start Backward.\n"); PRUint32 actualOffset = 0; - PRInt32 newPos = GetPosition(aPresContext, aEvent, aNewFrame, actualOffset); + PRInt32 newPos; + + GetPosition(aPresContext, aRendContext, aEvent, aNewFrame, actualOffset, newPos); // Create new TextPoint and move Start Point backward mStartSelectionPoint->SetPoint(aNewContent, newPos, PR_FALSE); // position is set correctly in adjustTextPoints @@ -1601,6 +1627,7 @@ void RefreshContentFrames(nsIPresContext& aPresContext, * the content that the cursor is currently in *********************************************************/ void nsFrame::NewContentIsAfter(nsIPresContext& aPresContext, + nsIRenderingContext * aRendContext, nsGUIEvent * aEvent, nsIContent * aNewContent, nsIContent * aCurrentContent, @@ -1638,14 +1665,15 @@ void nsFrame::NewContentIsAfter(nsIPresContext& aPresContext, PRUint32 actualOffset = 0; // [TODO] Always get nearest Text content - PRInt32 newPos = GetPosition(aPresContext, aEvent, aNewFrame, actualOffset); + PRInt32 newPos; + GetPosition(aPresContext, aRendContext, aEvent, aNewFrame, actualOffset, newPos); // Check to see if the new Content is the same as the End Point's if (aNewContent == selEndContent) { if (SELECTION_DEBUG) printf("New Content matches End Point\n"); mStartSelectionPoint->SetContent(aNewContent); - AdjustPointsInNewContent(aPresContext, aEvent, aNewFrame); + AdjustPointsInNewContent(aPresContext, aRendContext, aEvent, aNewFrame); } else { if (SELECTION_DEBUG) printf("New Content does NOT matches End Point\n"); @@ -1660,7 +1688,8 @@ void nsFrame::NewContentIsAfter(nsIPresContext& aPresContext, // Case #2 - Adding Content (at End) PRUint32 actualOffset = 0; // The new content is not in the selection - PRInt32 newPos = GetPosition(aPresContext, aEvent, aNewFrame, actualOffset); + PRInt32 newPos; + GetPosition(aPresContext, aRendContext, aEvent, aNewFrame, actualOffset, newPos); // Check to see if we need to create a new SelectionPoint and add it // or do we simply move the existing start or end point diff --git a/mozilla/layout/html/base/src/nsFrame.h b/mozilla/layout/html/base/src/nsFrame.h index 3dd3028853e..a0574c7aaf3 100644 --- a/mozilla/layout/html/base/src/nsFrame.h +++ b/mozilla/layout/html/base/src/nsFrame.h @@ -202,10 +202,12 @@ public: nsGUIEvent * aEvent, nsEventStatus& aEventStatus); - virtual PRInt32 GetPosition(nsIPresContext& aPresContext, - nsGUIEvent* aEvent, - nsIFrame * aNewFrame, - PRUint32& aAcutalContentOffset); + NS_IMETHOD GetPosition(nsIPresContext& aPresContext, + nsIRenderingContext * aRendContext, + nsGUIEvent* aEvent, + nsIFrame * aNewFrame, + PRUint32& aAcutalContentOffset, + PRInt32& aOffset); //-------------------------------------------------- // Additional methods @@ -229,22 +231,26 @@ public: protected: virtual void NewContentIsBefore(nsIPresContext& aPresContext, + nsIRenderingContext * aRendContext, nsGUIEvent * aEvent, nsIContent * aNewContent, nsIContent * aCurrentContent, nsIFrame * aNewFrame); virtual void NewContentIsAfter(nsIPresContext& aPresContext, + nsIRenderingContext * aRendContext, nsGUIEvent * aEvent, nsIContent * aNewContent, nsIContent * aCurrentContent, nsIFrame * aNewFrame); virtual void AdjustPointsInNewContent(nsIPresContext& aPresContext, + nsIRenderingContext * aRendContext, nsGUIEvent * aEvent, nsIFrame * aNewFrame); virtual void AdjustPointsInSameContent(nsIPresContext& aPresContext, + nsIRenderingContext * aRendContext, nsGUIEvent * aEvent); PRBool DisplaySelection(nsIPresContext& aPresContext, PRBool isOkToTurnOn = PR_FALSE); diff --git a/mozilla/layout/html/base/src/nsHTMLImage.cpp b/mozilla/layout/html/base/src/nsHTMLImage.cpp new file mode 100644 index 00000000000..c820c8971ee --- /dev/null +++ b/mozilla/layout/html/base/src/nsHTMLImage.cpp @@ -0,0 +1,935 @@ +/* -*- 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 + nsIViewManager* vm; + nsIView* view; + GetView(view); + if (nsnull != view) { + view->GetViewManager(vm); + vm->UpdateView(view, nsnull, 0); + } + else { + nsRect bounds; + nsPoint offset; + GetOffsetFromView(offset, view); + bounds.x = offset.x; + bounds.y = offset.y; + bounds.width = mRect.width; + bounds.height = mRect.height; + view->GetViewManager(vm); + vm->UpdateView(view, bounds, 0); + } + NS_RELEASE(vm); + } + + return NS_OK; + } + } + + return ImageFrameSuper::ContentChanged(aShell, aPresContext, aChild, + aSubContent); +} diff --git a/mozilla/layout/html/base/src/nsHTMLReflowCommand.cpp b/mozilla/layout/html/base/src/nsHTMLReflowCommand.cpp index 203135c3b81..d0377845ab6 100644 --- a/mozilla/layout/html/base/src/nsHTMLReflowCommand.cpp +++ b/mozilla/layout/html/base/src/nsHTMLReflowCommand.cpp @@ -136,7 +136,8 @@ void nsHTMLReflowCommand::BuildPath() NS_IMETHODIMP nsHTMLReflowCommand::Dispatch(nsIPresContext& aPresContext, nsHTMLReflowMetrics& aDesiredSize, - const nsSize& aMaxSize) + const nsSize& aMaxSize, + nsIRenderingContext& aRendContext) { // Build the path from the target frame (index 0) to the root frame BuildPath(); @@ -155,7 +156,7 @@ NS_IMETHODIMP nsHTMLReflowCommand::Dispatch(nsIPresContext& aPresContext, if (nsnull != root) { mPath.RemoveElementAt(mPath.Count() - 1); - nsReflowState reflowState(root, *this, aMaxSize); + nsReflowState reflowState(root, *this, aMaxSize, &aRendContext); nsIHTMLReflow* htmlReflow; nsReflowStatus status; diff --git a/mozilla/layout/html/base/src/nsHTMLReflowCommand.h b/mozilla/layout/html/base/src/nsHTMLReflowCommand.h index e7227057461..f5faf1cf076 100644 --- a/mozilla/layout/html/base/src/nsHTMLReflowCommand.h +++ b/mozilla/layout/html/base/src/nsHTMLReflowCommand.h @@ -52,7 +52,8 @@ public: // nsIReflowCommand NS_IMETHOD Dispatch(nsIPresContext& aPresContext, nsHTMLReflowMetrics& aDesiredSize, - const nsSize& aMaxSize); + const nsSize& aMaxSize, + nsIRenderingContext& aRendContext); NS_IMETHOD GetNext(nsIFrame*& aNextFrame); NS_IMETHOD GetTarget(nsIFrame*& aTargetFrame) const; NS_IMETHOD SetTarget(nsIFrame* aTargetFrame); diff --git a/mozilla/layout/html/base/src/nsImageFrame.cpp b/mozilla/layout/html/base/src/nsImageFrame.cpp index ec48079c016..321781ef357 100644 --- a/mozilla/layout/html/base/src/nsImageFrame.cpp +++ b/mozilla/layout/html/base/src/nsImageFrame.cpp @@ -98,11 +98,11 @@ protected: PRBool IsServerImageMap(); PRIntn GetSuppress(); - nscoord MeasureString(nsIFontMetrics* aFontMetrics, - const PRUnichar* aString, - PRInt32 aLength, - nscoord aMaxWidth, - PRUint32& aMaxFit); + nscoord MeasureString(const PRUnichar* aString, + PRInt32 aLength, + nscoord aMaxWidth, + PRUint32& aMaxFit, + nsIRenderingContext& aContext); void DisplayAltText(nsIPresContext& aPresContext, nsIRenderingContext& aRenderingContext, @@ -459,17 +459,18 @@ ImageFrame::GetDesiredSize(nsIPresContext* aPresContext, // 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 +// aMaxFit. NOTE: it is assumed that the fontmetrics have already been selected +// into the rendering context before this is called (for performance). MMP nscoord -ImageFrame::MeasureString(nsIFontMetrics* aFontMetrics, - const PRUnichar* aString, - PRInt32 aLength, - nscoord aMaxWidth, - PRUint32& aMaxFit) +ImageFrame::MeasureString(const PRUnichar* aString, + PRInt32 aLength, + nscoord aMaxWidth, + PRUint32& aMaxFit, + nsIRenderingContext& aContext) { nscoord totalWidth = 0; nscoord spaceWidth; - aFontMetrics->GetWidth(' ', spaceWidth); + aContext.GetWidth(' ', spaceWidth); aMaxFit = 0; while (aLength > 0) { @@ -486,7 +487,7 @@ ImageFrame::MeasureString(nsIFontMetrics* aFontMetrics, // Measure this chunk of text, and see if it fits nscoord width; - aFontMetrics->GetWidth(aString, len, width); + aContext.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 @@ -554,7 +555,7 @@ ImageFrame::DisplayAltText(nsIPresContext& aPresContext, 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); + nscoord width = MeasureString(str, strLen, aRect.width, maxFit, aRenderingContext); // Display the text aRenderingContext.DrawString(str, maxFit, aRect.x, y, 0); diff --git a/mozilla/layout/html/base/src/nsPresShell.cpp b/mozilla/layout/html/base/src/nsPresShell.cpp index 02ffcf56ab5..7f9f50a60b8 100644 --- a/mozilla/layout/html/base/src/nsPresShell.cpp +++ b/mozilla/layout/html/base/src/nsPresShell.cpp @@ -33,6 +33,7 @@ #include "nsIViewObserver.h" #include "nsContainerFrame.h" #include "nsHTMLIIDs.h" +#include "nsIDeviceContext.h" static PRBool gsNoisyRefs = PR_FALSE; #undef NOISY @@ -207,8 +208,7 @@ public: virtual nsIFrame* FindFrameWithContent(nsIContent* aContent); virtual void AppendReflowCommand(nsIReflowCommand* aReflowCommand); virtual void ProcessReflowCommands(); - - //nsIViewObserver + NS_IMETHOD CreateRenderingContext(nsIFrame *aFrame, nsIRenderingContext *&aContext); //nsIViewObserver interface @@ -496,13 +496,17 @@ PresShell::InitialReflow(nscoord aWidth, nscoord aHeight) mRootFrame->VerifyTree(); } #endif - nsRect bounds; + nsRect bounds; mPresContext->GetVisibleArea(bounds); - nsSize maxSize(bounds.width, bounds.height); - nsHTMLReflowMetrics desiredSize(nsnull); - nsReflowStatus status; - nsReflowState reflowState(mRootFrame, eReflowReason_Initial, maxSize); - nsIHTMLReflow* htmlReflow; + nsSize maxSize(bounds.width, bounds.height); + nsHTMLReflowMetrics desiredSize(nsnull); + nsReflowStatus status; + nsIHTMLReflow* htmlReflow; + nsIRenderingContext* rcx = nsnull; + + CreateRenderingContext(mRootFrame, rcx); + + nsReflowState reflowState(mRootFrame, eReflowReason_Initial, maxSize, rcx); if (NS_OK == mRootFrame->QueryInterface(kIHTMLReflowIID, (void**)&htmlReflow)) { htmlReflow->Reflow(*mPresContext, desiredSize, reflowState, status); @@ -513,6 +517,7 @@ PresShell::InitialReflow(nscoord aWidth, nscoord aHeight) } #endif } + NS_IF_RELEASE(rcx); NS_FRAME_LOG(NS_FRAME_TRACE_CALLS, ("exit nsPresShell::InitialReflow")); } @@ -542,13 +547,17 @@ PresShell::ResizeReflow(nscoord aWidth, nscoord aHeight) mRootFrame->VerifyTree(); } #endif - nsRect bounds; + nsRect bounds; mPresContext->GetVisibleArea(bounds); - nsSize maxSize(bounds.width, bounds.height); - nsHTMLReflowMetrics desiredSize(nsnull); - nsReflowStatus status; - nsReflowState reflowState(mRootFrame, eReflowReason_Resize, maxSize); - nsIHTMLReflow* htmlReflow; + nsSize maxSize(bounds.width, bounds.height); + nsHTMLReflowMetrics desiredSize(nsnull); + nsReflowStatus status; + nsIHTMLReflow* htmlReflow; + nsIRenderingContext* rcx = nsnull; + + CreateRenderingContext(mRootFrame, rcx); + + nsReflowState reflowState(mRootFrame, eReflowReason_Resize, maxSize, rcx); if (NS_OK == mRootFrame->QueryInterface(kIHTMLReflowIID, (void**)&htmlReflow)) { htmlReflow->Reflow(*mPresContext, desiredSize, reflowState, status); @@ -559,6 +568,7 @@ PresShell::ResizeReflow(nscoord aWidth, nscoord aHeight) } #endif } + NS_IF_RELEASE(rcx); NS_FRAME_LOG(NS_FRAME_TRACE_CALLS, ("exit nsPresShell::ResizeReflow")); // XXX if debugging then we should assert that the cache is empty @@ -631,7 +641,10 @@ void PresShell::ProcessReflowCommands() { if (0 != mReflowCommands.Count()) { - nsHTMLReflowMetrics desiredSize(nsnull); + nsHTMLReflowMetrics desiredSize(nsnull); + nsIRenderingContext* rcx; + + CreateRenderingContext(mRootFrame, rcx); while (0 != mReflowCommands.Count()) { nsIReflowCommand* rc = (nsIReflowCommand*) mReflowCommands.ElementAt(0); @@ -647,7 +660,7 @@ PresShell::ProcessReflowCommands() ("PresShell::ProcessReflowCommands: begin reflow command type=%d", type)); #endif - rc->Dispatch(*mPresContext, desiredSize, maxSize); + rc->Dispatch(*mPresContext, desiredSize, maxSize, *rcx); NS_RELEASE(rc); NS_FRAME_LOG(NS_FRAME_TRACE_CALLS, ("PresShell::ProcessReflowCommands: end reflow command")); @@ -663,9 +676,53 @@ PresShell::ProcessReflowCommands() VerifyIncrementalReflow(); } #endif + NS_IF_RELEASE(rcx); } } +NS_IMETHODIMP PresShell :: CreateRenderingContext(nsIFrame *aFrame, + nsIRenderingContext *&aContext) +{ + nsIWidget *widget = nsnull; + nsIView *view = nsnull; + nsPoint pt; + nsresult rv; + + aFrame->GetView(view); + + if (nsnull == view) + aFrame->GetOffsetFromView(pt, view); + + while (nsnull != view) + { + view->GetWidget(widget); + + if (nsnull != widget) + { + NS_RELEASE(widget); + break; + } + + view->GetParent(view); + } + + if (nsnull != view) + { + nsIDeviceContext *dx; + + dx = mPresContext->GetDeviceContext(); + rv = dx->CreateRenderingContext(view, aContext); + NS_RELEASE(dx); + } + else + { + rv = NS_ERROR_FAILURE; + aContext = nsnull; + } + + return rv; +} + #ifdef NS_DEBUG static char* ContentTag(nsIContent* aContent, PRIntn aSlot) diff --git a/mozilla/layout/html/base/src/nsTextFrame.cpp b/mozilla/layout/html/base/src/nsTextFrame.cpp index da6a46443fb..933f783dd6e 100644 --- a/mozilla/layout/html/base/src/nsTextFrame.cpp +++ b/mozilla/layout/html/base/src/nsTextFrame.cpp @@ -78,7 +78,7 @@ static NS_DEFINE_IID(kIDOMTextIID, NS_IDOMTEXT_IID); #define XP_IS_SPACE(_ch) \ (((_ch) == ' ') || ((_ch) == '\t') || ((_ch) == '\n')) -// XXX need more of this in nsIFontMetrics.GetWidth +// XXX need more of this in nsIRenderingContext.GetWidth #define CH_NBSP 160 // XXX use a PreTextFrame for pre-formatted text? @@ -141,10 +141,12 @@ public: NS_IMETHOD ListTag(FILE* out) const; - virtual PRInt32 GetPosition(nsIPresContext& aCX, - nsGUIEvent* aEvent, - nsIFrame * aNewFrame, - PRUint32& aAcutalContentOffset); + NS_IMETHOD GetPosition(nsIPresContext& aCX, + nsIRenderingContext * aRendContext, + nsGUIEvent* aEvent, + nsIFrame * aNewFrame, + PRUint32& aAcutalContentOffset, + PRInt32& aOffset); // nsIInlineReflow NS_IMETHOD FindTextRuns(nsLineLayout& aLineLayout, @@ -1009,7 +1011,7 @@ TextFrame::PaintUnicodeText(nsIPresContext& aPresContext, if (si.mEmptySelection) { aRenderingContext.DrawString(text, textLength, dx, dy, mRect.width); PaintTextDecorations(aRenderingContext, aDecorations, dx, dy, mRect.width); - fm->GetWidth(text, PRUint32(si.mStartOffset), textWidth); + aRenderingContext.GetWidth(text, PRUint32(si.mStartOffset), textWidth); RenderSelectionCursor(aRenderingContext, dx + textWidth, dy, mRect.height, CURSOR_COLOR); @@ -1019,7 +1021,7 @@ TextFrame::PaintUnicodeText(nsIPresContext& aPresContext, if (0 != si.mStartOffset) { // Render first (unselected) section - fm->GetWidth(text, PRUint32(si.mStartOffset), textWidth); + aRenderingContext.GetWidth(text, PRUint32(si.mStartOffset), textWidth); aRenderingContext.DrawString(text, si.mStartOffset, x, dy, textWidth); PaintTextDecorations(aRenderingContext, aDecorations, x, dy, textWidth); @@ -1028,7 +1030,7 @@ TextFrame::PaintUnicodeText(nsIPresContext& aPresContext, PRInt32 secondLen = si.mEndOffset - si.mStartOffset; if (0 != secondLen) { // Get the width of the second (selected) section - fm->GetWidth(text + si.mStartOffset, PRUint32(secondLen), textWidth); + aRenderingContext.GetWidth(text + si.mStartOffset, PRUint32(secondLen), textWidth); // Render second (selected) section aRenderingContext.SetColor(aSelectionBGColor); @@ -1044,7 +1046,7 @@ TextFrame::PaintUnicodeText(nsIPresContext& aPresContext, PRInt32 thirdLen = textLength - si.mEndOffset; // Render third (unselected) section - fm->GetWidth(text + si.mEndOffset, PRUint32(thirdLen), textWidth); + aRenderingContext.GetWidth(text + si.mEndOffset, PRUint32(thirdLen), textWidth); aRenderingContext.DrawString(text + si.mEndOffset, thirdLen, x, dy, textWidth); PaintTextDecorations(aRenderingContext, aDecorations, x, dy, textWidth); @@ -1104,7 +1106,7 @@ TextFrame::PaintAsciiText(nsIPresContext& aPresContext, if (si.mEmptySelection) { aRenderingContext.DrawString(text, textLength, dx, dy, mRect.width); PaintTextDecorations(aRenderingContext, aDecorations, dx, dy, mRect.width); - fm->GetWidth(text, PRUint32(si.mStartOffset), textWidth); + aRenderingContext.GetWidth(text, PRUint32(si.mStartOffset), textWidth); RenderSelectionCursor(aRenderingContext, dx + textWidth, dy, mRect.height, CURSOR_COLOR); @@ -1114,7 +1116,7 @@ TextFrame::PaintAsciiText(nsIPresContext& aPresContext, if (0 != si.mStartOffset) { // Render first (unselected) section - fm->GetWidth(text, PRUint32(si.mStartOffset), textWidth); + aRenderingContext.GetWidth(text, PRUint32(si.mStartOffset), textWidth); aRenderingContext.DrawString(text, si.mStartOffset, x, dy, textWidth); PaintTextDecorations(aRenderingContext, aDecorations, x, dy, textWidth); @@ -1123,7 +1125,7 @@ TextFrame::PaintAsciiText(nsIPresContext& aPresContext, PRInt32 secondLen = si.mEndOffset - si.mStartOffset; if (0 != secondLen) { // Get the width of the second (selected) section - fm->GetWidth(text + si.mStartOffset, PRUint32(secondLen), textWidth); + aRenderingContext.GetWidth(text + si.mStartOffset, PRUint32(secondLen), textWidth); // Render second (selected) section aRenderingContext.SetColor(aSelectionBGColor); @@ -1139,7 +1141,7 @@ TextFrame::PaintAsciiText(nsIPresContext& aPresContext, PRInt32 thirdLen = textLength - si.mEndOffset; // Render third (unselected) section - fm->GetWidth(text + si.mEndOffset, PRUint32(thirdLen), textWidth); + aRenderingContext.GetWidth(text + si.mEndOffset, PRUint32(thirdLen), textWidth); aRenderingContext.DrawString(text + si.mEndOffset, thirdLen, x, dy, textWidth); PaintTextDecorations(aRenderingContext, aDecorations, x, dy, textWidth); @@ -1182,7 +1184,7 @@ TextFrame::FindTextRuns(nsLineLayout& aLineLayout, // aTextWidth returns the (in twips) the length of the text that falls before the cursor // aIndex contains the index of the text where the cursor falls static PRBool -BinarySearchForPosition(nsIFontMetrics* aFM, +BinarySearchForPosition(nsIRenderingContext* acx, PRUnichar* aText, PRInt32 aBaseWidth, PRInt32 aBaseInx, @@ -1200,7 +1202,7 @@ BinarySearchForPosition(nsIFontMetrics* aFM, PRInt32 inx = aStartInx + (range / 2); PRInt32 textWidth; - aFM->GetWidth(aText, inx, textWidth); + acx->GetWidth(aText, inx, textWidth); PRInt32 fullWidth = aBaseWidth + textWidth; if (fullWidth == aCursorPos) { @@ -1208,13 +1210,13 @@ BinarySearchForPosition(nsIFontMetrics* aFM, return PR_TRUE; } else if (aCursorPos < fullWidth) { aTextWidth = aBaseWidth; - if (BinarySearchForPosition(aFM, aText, aBaseWidth, aBaseInx, aStartInx, inx, aCursorPos, aIndex, aTextWidth)) { + if (BinarySearchForPosition(acx, aText, aBaseWidth, aBaseInx, aStartInx, inx, aCursorPos, aIndex, aTextWidth)) { return PR_TRUE; } } else { aTextWidth = fullWidth; PRInt32 end = aEndInx - inx; - if (BinarySearchForPosition(aFM, aText+inx, fullWidth, aBaseInx+inx, 0, end, aCursorPos, aIndex, aTextWidth)) { + if (BinarySearchForPosition(acx, aText+inx, fullWidth, aBaseInx+inx, 0, end, aCursorPos, aIndex, aTextWidth)) { return PR_TRUE; } } @@ -1227,11 +1229,13 @@ BinarySearchForPosition(nsIFontMetrics* aFM, // un-compressed text, selection is based on the un-compressed text, the visual // display of selection is based on the compressed text. //--------------------------------------------------------------------------- -PRInt32 +NS_IMETHODIMP TextFrame::GetPosition(nsIPresContext& aCX, + nsIRenderingContext * aRendContext, nsGUIEvent* aEvent, nsIFrame* aNewFrame, - PRUint32& aAcutalContentOffset) + PRUint32& aAcutalContentOffset, + PRInt32& aOffset) { const PRInt16 kNumIndices = 512; @@ -1259,10 +1263,12 @@ TextFrame::GetPosition(nsIPresContext& aCX, PRInt32 index; PRInt32 textWidth; - PRBool found = BinarySearchForPosition(fm, text, 0, 0, 0, PRInt32(textLength), PRInt32(aEvent->point.x), index, textWidth); + aRendContext->SetFont(fm); + + PRBool found = BinarySearchForPosition(aRendContext, text, 0, 0, 0, PRInt32(textLength), PRInt32(aEvent->point.x), index, textWidth); if (found) { PRInt32 charWidth; - fm->GetWidth(text[index], charWidth); + aRendContext->GetWidth(text[index], charWidth); charWidth /= 2; if (PRInt32(aEvent->point.x) > textWidth+charWidth) { @@ -1290,7 +1296,9 @@ TextFrame::GetPosition(nsIPresContext& aCX, } aAcutalContentOffset = ((TextFrame *)aNewFrame)->mContentOffset; - return offset; + aOffset = offset; + + return NS_OK; } NS_IMETHODIMP @@ -1363,7 +1371,8 @@ TextFrame::ReflowNormal(nsLineLayout& aLineLayout, nsIFontMetrics* fm = aLineLayout.mPresContext.GetMetricsFor(aFont.mFont); PRInt32 spaceWidth; - fm->GetWidth(' ', spaceWidth); + aReflowState.rendContext->SetFont(fm); + aReflowState.rendContext->GetWidth(' ', spaceWidth); PRBool wrapping = PR_TRUE; if (NS_STYLE_WHITESPACE_NORMAL != aTextStyle.mWhiteSpace) { wrapping = PR_FALSE; @@ -1435,7 +1444,7 @@ TextFrame::ReflowNormal(nsLineLayout& aLineLayout, } break; } - fm->GetWidth(wordStart, PRUint32(cp - wordStart), width); + aReflowState.rendContext->GetWidth(wordStart, PRUint32(cp - wordStart), width); skipWhitespace = PR_FALSE; isWhitespace = PR_FALSE; } @@ -1543,7 +1552,8 @@ TextFrame::ReflowPre(nsLineLayout& aLineLayout, PRUint16 col = aLineLayout.GetColumn(); mColumn = col; nscoord spaceWidth; - fm->GetWidth(' ', spaceWidth); + aReflowState.rendContext->SetFont(fm); + aReflowState.rendContext->GetWidth(' ', spaceWidth); // XXX change this to measure a line at a time while (cp < end) { @@ -1569,11 +1579,11 @@ TextFrame::ReflowPre(nsLineLayout& aLineLayout, } if (ch < 256) { nscoord charWidth; - fm->GetWidth(ch, charWidth); + aReflowState.rendContext->GetWidth(ch, charWidth); width += charWidth; } else { nscoord charWidth; - fm->GetWidth(ch, charWidth); + aReflowState.rendContext->GetWidth(ch, charWidth); width += charWidth; hasMultibyte = PR_TRUE; } diff --git a/mozilla/layout/html/document/src/nsFrameSetFrame.cpp b/mozilla/layout/html/document/src/nsFrameSetFrame.cpp index f927419f0d9..c58a353227e 100644 --- a/mozilla/layout/html/document/src/nsFrameSetFrame.cpp +++ b/mozilla/layout/html/document/src/nsFrameSetFrame.cpp @@ -1396,7 +1396,12 @@ nsHTMLFramesetFrame::MouseDrag(nsIPresContext& aPresContext, nsGUIEvent* aEvent) nsHTMLReflowMetrics metrics(nsnull); nsSize size; GetSize(size); - nsReflowState state(this, eReflowReason_Initial, size); + nsIPresShell *shell; + nsIRenderingContext *acx; + shell = aPresContext.GetShell(); + shell->CreateRenderingContext(this, acx); + NS_RELEASE(shell); + nsReflowState state(this, eReflowReason_Initial, size, acx); state.reason = eReflowReason_Incremental; nsReflowStatus status; nsDidReflowStatus didStatus; @@ -1404,6 +1409,7 @@ nsHTMLFramesetFrame::MouseDrag(nsIPresContext& aPresContext, nsGUIEvent* aEvent) nsFramesetDrag drag(mDragger->mVertical, mDragger->mPrevNeighbor, change, this); Reflow(aPresContext, &drag, metrics, state, status); DidReflow(aPresContext, didStatus); + NS_IF_RELEASE(acx); } mLastDragPoint.x = aEvent->point.x; diff --git a/mozilla/layout/html/forms/src/nsButtonControlFrame.cpp b/mozilla/layout/html/forms/src/nsButtonControlFrame.cpp index 3afa485fb11..4f082fdd1ee 100644 --- a/mozilla/layout/html/forms/src/nsButtonControlFrame.cpp +++ b/mozilla/layout/html/forms/src/nsButtonControlFrame.cpp @@ -334,7 +334,8 @@ nsButtonControlFrame::GetDesiredSize(nsIPresContext* aPresContext, nsInputDimensionSpec spec(nsHTMLAtoms::size, PR_TRUE, nsHTMLAtoms::value, &defaultLabel, 1, PR_FALSE, nsnull, 1); CalculateSize(aPresContext, this, styleSize, spec, size, - widthExplicit, heightExplicit, ignore); + widthExplicit, heightExplicit, ignore, + aReflowState.rendContext); aDesiredLayoutSize.width = size.width; aDesiredLayoutSize.height= size.height; } diff --git a/mozilla/layout/html/forms/src/nsFormControlFrame.cpp b/mozilla/layout/html/forms/src/nsFormControlFrame.cpp index 93bb61c3668..b9e3e346a60 100644 --- a/mozilla/layout/html/forms/src/nsFormControlFrame.cpp +++ b/mozilla/layout/html/forms/src/nsFormControlFrame.cpp @@ -580,7 +580,8 @@ GetRepChars(nsIPresContext& aPresContext, char& char1, char& char2) nscoord nsFormControlFrame::GetTextSize(nsIPresContext& aPresContext, nsFormControlFrame* aFrame, - const nsString& aString, nsSize& aSize) + const nsString& aString, nsSize& aSize, + nsIRenderingContext *aRendContext) { nsFont font(aPresContext.GetDefaultFixedFont()); aFrame->GetFont(&aPresContext, font); @@ -589,14 +590,15 @@ nsFormControlFrame::GetTextSize(nsIPresContext& aPresContext, nsFormControlFrame nsIFontMetrics* fontMet; deviceContext->GetMetricsFor(font, fontMet); - fontMet->GetWidth(aString, aSize.width); + aRendContext->SetFont(fontMet); + aRendContext->GetWidth(aString, aSize.width); fontMet->GetHeight(aSize.height); char char1, char2; GetRepChars(aPresContext, char1, char2); nscoord char1Width, char2Width; - fontMet->GetWidth(char1, char1Width); - fontMet->GetWidth(char2, char2Width); + aRendContext->GetWidth(char1, char1Width); + aRendContext->GetWidth(char2, char2Width); NS_RELEASE(fontMet); NS_RELEASE(deviceContext); @@ -606,7 +608,8 @@ nsFormControlFrame::GetTextSize(nsIPresContext& aPresContext, nsFormControlFrame nscoord nsFormControlFrame::GetTextSize(nsIPresContext& aPresContext, nsFormControlFrame* aFrame, - PRInt32 aNumChars, nsSize& aSize) + PRInt32 aNumChars, nsSize& aSize, + nsIRenderingContext *aRendContext) { nsAutoString val; char char1, char2; @@ -618,14 +621,15 @@ nsFormControlFrame::GetTextSize(nsIPresContext& aPresContext, nsFormControlFrame for (i = 1; i < aNumChars; i+=2) { val += char2; } - return GetTextSize(aPresContext, aFrame, val, aSize); + return GetTextSize(aPresContext, aFrame, val, aSize, aRendContext); } PRInt32 nsFormControlFrame::CalculateSize (nsIPresContext* aPresContext, nsFormControlFrame* aFrame, const nsSize& aCSSSize, nsInputDimensionSpec& aSpec, nsSize& aBounds, PRBool& aWidthExplicit, - PRBool& aHeightExplicit, nscoord& aRowHeight) + PRBool& aHeightExplicit, nscoord& aRowHeight, + nsIRenderingContext *aRendContext) { nscoord charWidth = 0; PRInt32 numRows = ATTR_NOTSET; @@ -669,7 +673,7 @@ nsFormControlFrame::CalculateSize (nsIPresContext* aPresContext, nsFormControlFr } else { col = (col <= 0) ? 1 : col; - charWidth = GetTextSize(*aPresContext, aFrame, col, aBounds); + charWidth = GetTextSize(*aPresContext, aFrame, col, aBounds, aRendContext); aRowHeight = aBounds.height; // XXX aBounds.height has CSS_NOTSET } if (aSpec.mColSizeAttrInPixels) { @@ -683,17 +687,17 @@ nsFormControlFrame::CalculateSize (nsIPresContext* aPresContext, nsFormControlFr } else { if (NS_CONTENT_ATTR_HAS_VALUE == valStatus) { // use width of initial value - charWidth = GetTextSize(*aPresContext, aFrame, valAttr, aBounds); + charWidth = GetTextSize(*aPresContext, aFrame, valAttr, aBounds, aRendContext); } else if (aSpec.mColDefaultValue) { // use default value - charWidth = GetTextSize(*aPresContext, aFrame, *aSpec.mColDefaultValue, aBounds); + charWidth = GetTextSize(*aPresContext, aFrame, *aSpec.mColDefaultValue, aBounds, aRendContext); } else if (aSpec.mColDefaultSizeInPixels) { // use default width in pixels - charWidth = GetTextSize(*aPresContext, aFrame, 1, aBounds); + charWidth = GetTextSize(*aPresContext, aFrame, 1, aBounds, aRendContext); aBounds.width = aSpec.mColDefaultSize; } else { // use default width in num characters - charWidth = GetTextSize(*aPresContext, aFrame, aSpec.mColDefaultSize, aBounds); + charWidth = GetTextSize(*aPresContext, aFrame, aSpec.mColDefaultSize, aBounds, aRendContext); } aRowHeight = aBounds.height; // XXX aBounds.height has CSS_NOTSET } @@ -709,7 +713,7 @@ nsFormControlFrame::CalculateSize (nsIPresContext* aPresContext, nsFormControlFr PRInt32 rowAttrInt = ((rowAttr.GetUnit() == eHTMLUnit_Pixel) ? rowAttr.GetPixelValue() : rowAttr.GetIntValue()); adjSize = (rowAttrInt > 0) ? rowAttrInt : 1; if (0 == charWidth) { - charWidth = GetTextSize(*aPresContext, aFrame, 1, textSize); + charWidth = GetTextSize(*aPresContext, aFrame, 1, textSize, aRendContext); aBounds.height = textSize.height * adjSize; aRowHeight = textSize.height; numRows = adjSize; @@ -724,7 +728,7 @@ nsFormControlFrame::CalculateSize (nsIPresContext* aPresContext, nsFormControlFr } else { // use default height in num lines if (0 == charWidth) { - charWidth = GetTextSize(*aPresContext, aFrame, 1, textSize); + charWidth = GetTextSize(*aPresContext, aFrame, 1, textSize, aRendContext); aBounds.height = textSize.height * aSpec.mRowDefaultSize; aRowHeight = textSize.height; } @@ -734,7 +738,7 @@ nsFormControlFrame::CalculateSize (nsIPresContext* aPresContext, nsFormControlFr } if ((0 == charWidth) || (0 == textSize.width)) { - charWidth = GetTextSize(*aPresContext, aFrame, 1, textSize); + charWidth = GetTextSize(*aPresContext, aFrame, 1, textSize, aRendContext); aRowHeight = textSize.height; } diff --git a/mozilla/layout/html/forms/src/nsFormControlFrame.h b/mozilla/layout/html/forms/src/nsFormControlFrame.h index 708044cf24f..cb588f55ccc 100644 --- a/mozilla/layout/html/forms/src/nsFormControlFrame.h +++ b/mozilla/layout/html/forms/src/nsFormControlFrame.h @@ -92,7 +92,8 @@ public: static nscoord CalculateSize (nsIPresContext* aPresContext, nsFormControlFrame* aFrame, const nsSize& aCSSSize, nsInputDimensionSpec& aDimensionSpec, nsSize& aBounds, PRBool& aWidthExplicit, - PRBool& aHeightExplicit, nscoord& aRowSize); + PRBool& aHeightExplicit, nscoord& aRowSize, + nsIRenderingContext *aRendContext); /** * Respond to a gui event @@ -179,9 +180,11 @@ public: virtual nsWidgetInitData* GetWidgetInitData(nsIPresContext& aPresContext); static nscoord GetTextSize(nsIPresContext& aContext, nsFormControlFrame* aFrame, - const nsString& aString, nsSize& aSize); + const nsString& aString, nsSize& aSize, + nsIRenderingContext *aRendContext); static nscoord GetTextSize(nsIPresContext& aContext, nsFormControlFrame* aFrame, - PRInt32 aNumChars, nsSize& aSize); + PRInt32 aNumChars, nsSize& aSize, + nsIRenderingContext *aRendContext); void GetWidgetSize(nsSize& aSize) const { aSize.width = mWidgetSize.width; aSize.height = mWidgetSize.height; } diff --git a/mozilla/layout/html/forms/src/nsSelectControlFrame.cpp b/mozilla/layout/html/forms/src/nsSelectControlFrame.cpp index 14cc33faf34..0e63d78a814 100644 --- a/mozilla/layout/html/forms/src/nsSelectControlFrame.cpp +++ b/mozilla/layout/html/forms/src/nsSelectControlFrame.cpp @@ -223,7 +223,7 @@ nsSelectControlFrame::GetDesiredSize(nsIPresContext* aPresContext, } nsSize textSize; // use the style for the select rather that the option, since widgets don't support it - nsFormControlFrame::GetTextSize(*aPresContext, this, text, textSize); + nsFormControlFrame::GetTextSize(*aPresContext, this, text, textSize, aReflowState.rendContext); if (textSize.width > maxWidth) { maxWidth = textSize.width; } @@ -238,7 +238,8 @@ nsSelectControlFrame::GetDesiredSize(nsIPresContext* aPresContext, maxWidth, PR_TRUE, nsHTMLAtoms::size, 1); // XXX fix CalculateSize to return PRUint32 PRUint32 numRows = (PRUint32)CalculateSize(aPresContext, this, styleSize, textSpec, - calcSize, widthExplicit, heightExplicit, rowHeight); + calcSize, widthExplicit, heightExplicit, rowHeight, + aReflowState.rendContext); // here it is determined whether we are a combo box PRInt32 sizeAttr; diff --git a/mozilla/layout/html/forms/src/nsTextControlFrame.cpp b/mozilla/layout/html/forms/src/nsTextControlFrame.cpp index 0054efd54aa..277fe047690 100644 --- a/mozilla/layout/html/forms/src/nsTextControlFrame.cpp +++ b/mozilla/layout/html/forms/src/nsTextControlFrame.cpp @@ -197,12 +197,14 @@ nsTextControlFrame::GetDesiredSize(nsIPresContext* aPresContext, nsInputDimensionSpec textSpec(nsnull, PR_FALSE, nsnull, nsnull, width, PR_FALSE, nsnull, 1); CalculateSize(aPresContext, this, styleSize, textSpec, size, - widthExplicit, heightExplicit, ignore); + widthExplicit, heightExplicit, ignore, + aReflowState.rendContext); } else { nsInputDimensionSpec areaSpec(nsHTMLAtoms::cols, PR_FALSE, nsnull, nsnull, 20, PR_FALSE, nsHTMLAtoms::rows, 1); CalculateSize(aPresContext, this, styleSize, areaSpec, size, - widthExplicit, heightExplicit, ignore); + widthExplicit, heightExplicit, ignore, + aReflowState.rendContext); } if (NS_FORM_TEXTAREA == type) { diff --git a/mozilla/widget/src/windows/nsImageButton.cpp b/mozilla/widget/src/windows/nsImageButton.cpp index 6aac3a0a942..2a7b5aa0d20 100644 --- a/mozilla/widget/src/windows/nsImageButton.cpp +++ b/mozilla/widget/src/windows/nsImageButton.cpp @@ -895,9 +895,12 @@ void nsImageButton::PerformAlignment(const nsRect & aRect, if (mShowText) { nsIFontMetrics* metrics; mContext->GetMetricsFor(mFont, metrics); - + nsIRenderingContext *cx; + mContext->CreateRenderingContext(this, cx); + cx->SetFont(metrics); metrics->GetHeight(string_height); - metrics->GetWidth(aText, string_width); + cx->GetWidth(aText, string_width); + NS_RELEASE(cx); NS_RELEASE(metrics); diff --git a/mozilla/widget/src/windows/nsLabel.cpp b/mozilla/widget/src/windows/nsLabel.cpp index c05ab840f8e..07ec56533c6 100644 --- a/mozilla/widget/src/windows/nsLabel.cpp +++ b/mozilla/widget/src/windows/nsLabel.cpp @@ -204,9 +204,13 @@ NS_METHOD nsLabel::GetPreferredSize(PRInt32& aWidth, PRInt32& aHeight) nsString text; GetLabel(text); + nsIRenderingContext *cx; + mContext->CreateRenderingContext(this, cx); + cx->SetFont(metrics); nscoord string_height, string_width; metrics->GetHeight(string_height); - metrics->GetWidth(text, string_width); + cx->GetWidth(text, string_width); + NS_RELEASE(cx); NS_RELEASE(metrics); if (mPreferredWidth != 0) {