Back to index

lightning-sunbird  0.9+nobinonly
nsHTMLFrame.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either of the GNU General Public License Version 2 or later (the "GPL"),
00026  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 #include "nsIServiceManager.h"
00038 #include "nsHTMLParts.h"
00039 #include "nsHTMLContainerFrame.h"
00040 #include "nsCSSRendering.h"
00041 #include "nsIDocument.h"
00042 #include "nsReflowPath.h"
00043 #include "nsPresContext.h"
00044 #include "nsStyleContext.h"
00045 #include "nsViewsCID.h"
00046 #include "nsIView.h"
00047 #include "nsIViewManager.h"
00048 #include "nsIWidget.h"
00049 #include "nsPageFrame.h"
00050 #include "nsIRenderingContext.h"
00051 #include "nsGUIEvent.h"
00052 #include "nsIDOMEvent.h"
00053 #include "nsStyleConsts.h"
00054 #include "nsIViewManager.h"
00055 #include "nsHTMLAtoms.h"
00056 #include "nsIEventStateManager.h"
00057 #include "nsIDeviceContext.h"
00058 #include "nsLayoutAtoms.h"
00059 #include "nsIPresShell.h"
00060 #include "nsIScrollPositionListener.h"
00061 
00062 // for focus
00063 #include "nsIDOMWindowInternal.h"
00064 #include "nsIScriptGlobalObject.h"
00065 #include "nsIFocusController.h"
00066 #include "nsIScrollableFrame.h"
00067 #include "nsIScrollableView.h"
00068 #include "nsIDocShell.h"
00069 #include "nsICanvasFrame.h"
00070 
00071 #ifdef DEBUG_rods
00072 //#define DEBUG_CANVAS_FOCUS
00073 #endif
00074 
00075 // Interface IDs
00076 
00084 class CanvasFrame : public nsHTMLContainerFrame, 
00085                     public nsIScrollPositionListener, 
00086                     public nsICanvasFrame {
00087 public:
00088   CanvasFrame() : mDoPaintFocus(PR_FALSE) {}
00089 
00090    // nsISupports
00091   NS_IMETHOD QueryInterface(const nsIID& aIID, void** aInstancePtr);
00092 
00093   NS_IMETHOD Init(nsPresContext*  aPresContext,
00094               nsIContent*      aContent,
00095               nsIFrame*        aParent,
00096               nsStyleContext*  aContext,
00097               nsIFrame*        aPrevInFlow);
00098   NS_IMETHOD Destroy(nsPresContext* aPresContext);
00099 
00100   NS_IMETHOD AppendFrames(nsIAtom*        aListName,
00101                           nsIFrame*       aFrameList);
00102   NS_IMETHOD InsertFrames(nsIAtom*        aListName,
00103                           nsIFrame*       aPrevFrame,
00104                           nsIFrame*       aFrameList);
00105   NS_IMETHOD RemoveFrame(nsIAtom*        aListName,
00106                          nsIFrame*       aOldFrame);
00107 
00108   NS_IMETHOD Reflow(nsPresContext*          aPresContext,
00109                     nsHTMLReflowMetrics&     aDesiredSize,
00110                     const nsHTMLReflowState& aReflowState,
00111                     nsReflowStatus&          aStatus);
00112   NS_IMETHOD HandleEvent(nsPresContext* aPresContext, 
00113                          nsGUIEvent*     aEvent,
00114                          nsEventStatus*  aEventStatus);
00115   NS_IMETHOD GetFrameForPoint(const nsPoint& aPoint, 
00116                               nsFramePaintLayer aWhichLayer,
00117                               nsIFrame**     aFrame);
00118   virtual PRBool IsContainingBlock() const { return PR_TRUE; }
00119 
00120   NS_IMETHOD Paint(nsPresContext*      aPresContext,
00121                    nsIRenderingContext& aRenderingContext,
00122                    const nsRect&        aDirtyRect,
00123                    nsFramePaintLayer    aWhichLayer,
00124                    PRUint32             aFlags);
00125 
00126   // nsIScrollPositionListener
00127   NS_IMETHOD ScrollPositionWillChange(nsIScrollableView* aScrollable, nscoord aX, nscoord aY);
00128        NS_IMETHOD ScrollPositionDidChange(nsIScrollableView* aScrollable, nscoord aX, nscoord aY);
00129 
00130   // nsICanvasFrame
00131   NS_IMETHOD SetHasFocus(PRBool aHasFocus);
00132 
00138   virtual nsIAtom* GetType() const;
00139 
00140 #ifdef DEBUG
00141   NS_IMETHOD GetFrameName(nsAString& aResult) const;
00142 #endif
00143   NS_IMETHOD GetContentForEvent(nsPresContext* aPresContext,
00144                                 nsEvent* aEvent,
00145                                 nsIContent** aContent);
00146 
00147 protected:
00148   virtual PRIntn GetSkipSides() const;
00149 
00150   // Data members
00151   PRPackedBool             mDoPaintFocus;
00152   nsCOMPtr<nsIViewManager> mViewManager;
00153 
00154 private:
00155   NS_IMETHOD_(nsrefcnt) AddRef() { return NS_OK; }
00156   NS_IMETHOD_(nsrefcnt) Release() { return NS_OK; }
00157 };
00158 
00159 
00160 //----------------------------------------------------------------------
00161 
00162 nsresult
00163 NS_NewCanvasFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame)
00164 {
00165   NS_PRECONDITION(aNewFrame, "null OUT ptr");
00166   if (nsnull == aNewFrame) {
00167     return NS_ERROR_NULL_POINTER;
00168   }
00169   CanvasFrame* it = new (aPresShell)CanvasFrame;
00170   if (nsnull == it) {
00171     return NS_ERROR_OUT_OF_MEMORY;
00172   }
00173   *aNewFrame = it;
00174   return NS_OK;
00175 }
00176 
00177 //--------------------------------------------------------------
00178 // Frames are not refcounted, no need to AddRef
00179 NS_IMETHODIMP
00180 CanvasFrame::QueryInterface(const nsIID& aIID, void** aInstancePtr)
00181 {
00182   NS_PRECONDITION(0 != aInstancePtr, "null ptr");
00183   if (NULL == aInstancePtr) {
00184     return NS_ERROR_NULL_POINTER;
00185   }
00186 
00187   if (aIID.Equals(NS_GET_IID(nsIScrollPositionListener))) {
00188     *aInstancePtr = (void*) ((nsIScrollPositionListener*) this);
00189     return NS_OK;
00190   } 
00191   
00192   if (aIID.Equals(NS_GET_IID(nsICanvasFrame))) {
00193     *aInstancePtr = (void*) ((nsICanvasFrame*) this);
00194     return NS_OK;
00195   } 
00196   
00197 
00198   return nsHTMLContainerFrame::QueryInterface(aIID, aInstancePtr);
00199 }
00200 
00201 NS_IMETHODIMP
00202 CanvasFrame::Init(nsPresContext*  aPresContext,
00203               nsIContent*      aContent,
00204               nsIFrame*        aParent,
00205               nsStyleContext*  aContext,
00206               nsIFrame*        aPrevInFlow)
00207 {
00208   nsresult rv = nsHTMLContainerFrame::Init(aPresContext,aContent,aParent,aContext,aPrevInFlow);
00209 
00210   mViewManager = aPresContext->GetViewManager();
00211 
00212   nsIScrollableView* scrollingView = nsnull;
00213   mViewManager->GetRootScrollableView(&scrollingView);
00214   if (scrollingView) {
00215     scrollingView->AddScrollPositionListener(this);
00216   }
00217 
00218   return rv;
00219 }
00220 
00221 NS_IMETHODIMP
00222 CanvasFrame::Destroy(nsPresContext* aPresContext)
00223 {
00224   nsIScrollableView* scrollingView = nsnull;
00225   mViewManager->GetRootScrollableView(&scrollingView);
00226   if (scrollingView) {
00227     scrollingView->RemoveScrollPositionListener(this);
00228   }
00229 
00230   return nsHTMLContainerFrame::Destroy(aPresContext);
00231 }
00232 
00233 NS_IMETHODIMP
00234 CanvasFrame::ScrollPositionWillChange(nsIScrollableView* aScrollable, nscoord aX, nscoord aY)
00235 {
00236 #ifdef DEBUG_CANVAS_FOCUS
00237   {
00238     PRBool hasFocus = PR_FALSE;
00239     nsCOMPtr<nsIViewObserver> observer;
00240     mViewManager->GetViewObserver(*getter_AddRefs(observer));
00241     nsCOMPtr<nsIPresShell> shell = do_QueryInterface(observer);
00242     nsCOMPtr<nsPresContext> context;
00243     shell->GetPresContext(getter_AddRefs(context));
00244     nsCOMPtr<nsISupports> container;
00245     context->GetContainer(getter_AddRefs(container));
00246     nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(container));
00247     if (docShell) {
00248       docShell->GetHasFocus(&hasFocus);
00249     }
00250     printf("SPWC: %p  HF: %s  mDoPaintFocus: %s\n", docShell.get(), hasFocus?"Y":"N", mDoPaintFocus?"Y":"N");
00251   }
00252 #endif
00253 
00254   if (mDoPaintFocus) {
00255     mDoPaintFocus = PR_FALSE;
00256     mViewManager->UpdateAllViews(NS_VMREFRESH_NO_SYNC);
00257   }
00258   return NS_OK;
00259 }
00260 
00261 NS_IMETHODIMP
00262 CanvasFrame::ScrollPositionDidChange(nsIScrollableView* aScrollable, nscoord aX, nscoord aY)
00263 {
00264   return NS_OK;
00265 }
00266 
00267 NS_IMETHODIMP
00268 CanvasFrame::SetHasFocus(PRBool aHasFocus)
00269 {
00270   if (mDoPaintFocus != aHasFocus) {
00271     mDoPaintFocus = aHasFocus;
00272     nsIViewManager* vm = GetPresContext()->PresShell()->GetViewManager();
00273     if (vm) {
00274       vm->UpdateAllViews(NS_VMREFRESH_NO_SYNC);
00275     }
00276   }
00277   return NS_OK;
00278 }
00279 
00280 
00281 NS_IMETHODIMP
00282 CanvasFrame::AppendFrames(nsIAtom*        aListName,
00283                           nsIFrame*       aFrameList)
00284 {
00285   nsresult  rv;
00286 
00287   NS_ASSERTION(!aListName, "unexpected child list name");
00288   NS_PRECONDITION(mFrames.IsEmpty(), "already have a child frame");
00289   if (aListName) {
00290     // We only support unnamed principal child list
00291     rv = NS_ERROR_INVALID_ARG;
00292 
00293   } else if (!mFrames.IsEmpty()) {
00294     // We only allow a single child frame
00295     rv = NS_ERROR_FAILURE;
00296 
00297   } else {
00298     // Insert the new frames
00299 #ifdef NS_DEBUG
00300     nsFrame::VerifyDirtyBitSet(aFrameList);
00301 #endif
00302     mFrames.AppendFrame(nsnull, aFrameList);
00303 
00304     // Generate a reflow command to reflow the newly inserted frame
00305     rv = GetPresContext()->PresShell()->
00306           AppendReflowCommand(this, eReflowType_ReflowDirty, nsnull);
00307   }
00308 
00309   return rv;
00310 }
00311 
00312 NS_IMETHODIMP
00313 CanvasFrame::InsertFrames(nsIAtom*        aListName,
00314                           nsIFrame*       aPrevFrame,
00315                           nsIFrame*       aFrameList)
00316 {
00317   nsresult  rv;
00318 
00319   // Because we only support a single child frame inserting is the same
00320   // as appending
00321   NS_PRECONDITION(!aPrevFrame, "unexpected previous sibling frame");
00322   if (aPrevFrame) {
00323     rv = NS_ERROR_UNEXPECTED;
00324   } else {
00325     rv = AppendFrames(aListName, aFrameList);
00326   }
00327 
00328   return rv;
00329 }
00330 
00331 NS_IMETHODIMP
00332 CanvasFrame::RemoveFrame(nsIAtom*        aListName,
00333                          nsIFrame*       aOldFrame)
00334 {
00335   nsresult  rv;
00336 
00337   NS_ASSERTION(!aListName, "unexpected child list name");
00338   if (aListName) {
00339     // We only support the unnamed principal child list
00340     rv = NS_ERROR_INVALID_ARG;
00341   
00342   } else if (aOldFrame == mFrames.FirstChild()) {
00343     // It's our one and only child frame
00344     // Damage the area occupied by the deleted frame
00345     // The child of the canvas probably can't have an outline, but why bother
00346     // thinking about that?
00347     Invalidate(aOldFrame->GetOverflowRect() + aOldFrame->GetPosition(), PR_FALSE);
00348 
00349     // Remove the frame and destroy it
00350     mFrames.DestroyFrame(GetPresContext(), aOldFrame);
00351 
00352     // Generate a reflow command so we get reflowed
00353     rv = GetPresContext()->PresShell()->
00354           AppendReflowCommand(this, eReflowType_ReflowDirty, nsnull);
00355   } else {
00356     rv = NS_ERROR_FAILURE;
00357   }
00358 
00359   return rv;
00360 }
00361 
00362 NS_IMETHODIMP
00363 CanvasFrame::Paint(nsPresContext*      aPresContext,
00364                    nsIRenderingContext& aRenderingContext,
00365                    const nsRect&        aDirtyRect,
00366                    nsFramePaintLayer    aWhichLayer,
00367                    PRUint32             aFlags)
00368 {
00369   // We are wrapping the root frame of a document. We
00370   // need to check the pres shell to find out if painting is locked
00371   // down (because we're still in the early stages of document
00372   // and frame construction.  If painting is locked down, then we
00373   // do not paint our children.  
00374   PRBool paintingSuppressed = PR_FALSE;
00375   aPresContext->PresShell()->IsPaintingSuppressed(&paintingSuppressed);
00376   if (paintingSuppressed) {
00377     if (NS_FRAME_PAINT_LAYER_BACKGROUND == aWhichLayer) {
00378       PaintSelf(aPresContext, aRenderingContext, aDirtyRect);
00379     }
00380     return NS_OK;
00381   }
00382 
00383   nsresult rv = nsHTMLContainerFrame::Paint(aPresContext, aRenderingContext, aDirtyRect, aWhichLayer);
00384 
00385   if (NS_FRAME_PAINT_LAYER_FOREGROUND == aWhichLayer) {
00386 
00387 #ifdef DEBUG_CANVAS_FOCUS
00388     nsCOMPtr<nsIContent> focusContent;
00389     aPresContext->EventStateManager()->
00390       GetFocusedContent(getter_AddRefs(focusContent));
00391 
00392     PRBool hasFocus = PR_FALSE;
00393     nsCOMPtr<nsISupports> container;
00394     aPresContext->GetContainer(getter_AddRefs(container));
00395     nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(container));
00396     if (docShell) {
00397       docShell->GetHasFocus(&hasFocus);
00398       printf("%p - CanvasFrame::Paint R:%d,%d,%d,%d  DR: %d,%d,%d,%d\n", this, 
00399               mRect.x, mRect.y, mRect.width, mRect.height,
00400               aDirtyRect.x, aDirtyRect.y, aDirtyRect.width, aDirtyRect.height);
00401     }
00402     printf("%p - Focus: %s   c: %p  DoPaint:%s\n", docShell.get(), hasFocus?"Y":"N", 
00403            focusContent.get(), mDoPaintFocus?"Y":"N");
00404 #endif
00405 
00406     if (mDoPaintFocus) {
00407       nsRect focusRect = GetRect();
00409       // draw focus
00410       // XXX This is only temporary
00411       // Only paint the focus if we're visible
00412       if (GetStyleVisibility()->IsVisible()) {
00413         nsIFrame * parentFrame = GetParent();
00414         nsIView* parentView = parentFrame->GetView();
00415 
00416         nsIScrollableView* scrollableView = parentView->ToScrollableView();
00417         if (scrollableView) {
00418           nscoord width, height;
00419           scrollableView->GetContainerSize(&width, &height);
00420           nsRect vcr = parentView->GetBounds();
00421           focusRect.width = vcr.width;
00422           focusRect.height = vcr.height;
00423           nscoord x,y;
00424           scrollableView->GetScrollPosition(x, y);
00425           focusRect.x += x;
00426           focusRect.y += y;
00427         }
00428 
00429         nsStyleOutline outlineStyle(aPresContext);
00430         outlineStyle.SetOutlineStyle(NS_STYLE_BORDER_STYLE_DOTTED);
00431         outlineStyle.SetOutlineInvert();
00432 
00433         float p2t = aPresContext->PixelsToTwips();
00434         // XXX the CSS border for links is specified as 2px, but it
00435         // is only drawn as 1px.  Match this here.
00436         nscoord onePixel = NSIntPixelsToTwips(1, p2t);
00437 
00438         nsRect borderInside(focusRect.x + onePixel,
00439                             focusRect.y + onePixel,
00440                             focusRect.width - 2 * onePixel,
00441                             focusRect.height - 2 * onePixel);
00442 
00443         nsCSSRendering::DrawDashedSides(0, aRenderingContext, 
00444                                         focusRect, nsnull,
00445                                         nsnull, &outlineStyle,
00446                                         PR_TRUE, focusRect,
00447                                         borderInside, 0, 
00448                                         nsnull);
00449       }
00450     }
00451   }
00452   return rv;
00453 }
00454 
00455 NS_IMETHODIMP
00456 CanvasFrame::Reflow(nsPresContext*          aPresContext,
00457                     nsHTMLReflowMetrics&     aDesiredSize,
00458                     const nsHTMLReflowState& aReflowState,
00459                     nsReflowStatus&          aStatus)
00460 {
00461   DO_GLOBAL_REFLOW_COUNT("CanvasFrame", aReflowState.reason);
00462   DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);
00463   NS_FRAME_TRACE_REFLOW_IN("CanvasFrame::Reflow");
00464   //NS_PRECONDITION(!aDesiredSize.mComputeMEW, "unexpected request");
00465 
00466   // Initialize OUT parameter
00467   aStatus = NS_FRAME_COMPLETE;
00468 
00469   PRBool  isStyleChange = PR_FALSE;
00470   PRBool  isDirtyChildReflow = PR_FALSE;
00471 
00472   // Check for an incremental reflow
00473   if (eReflowReason_Incremental == aReflowState.reason) {
00474     // See if we're the target frame
00475     nsHTMLReflowCommand *command = aReflowState.path->mReflowCommand;
00476     if (command) {
00477       // Get the reflow type
00478       switch (command->Type()) {
00479       case eReflowType_ReflowDirty:
00480         isDirtyChildReflow = PR_TRUE;
00481         break;
00482 
00483       case eReflowType_StyleChanged:
00484         // Remember it's a style change so we can set the reflow reason below
00485         isStyleChange = PR_TRUE;
00486         break;
00487 
00488       default:
00489         NS_ASSERTION(PR_FALSE, "unexpected reflow command type");
00490       }
00491     }
00492     else {
00493 #ifdef DEBUG
00494       nsReflowPath::iterator iter = aReflowState.path->FirstChild();
00495       NS_ASSERTION(*iter == mFrames.FirstChild(), "unexpected next reflow command frame");
00496 #endif
00497     }
00498   }
00499 
00500   // Reflow our one and only child frame
00501   nsHTMLReflowMetrics kidDesiredSize(nsnull);
00502   if (mFrames.IsEmpty()) {
00503     // We have no child frame, so return an empty size
00504     aDesiredSize.width = aDesiredSize.height = 0;
00505     aDesiredSize.ascent = aDesiredSize.descent = 0;
00506 
00507   } else {
00508     nsIFrame* kidFrame = mFrames.FirstChild();
00509 
00510     nsReflowReason reason;
00511     if (isDirtyChildReflow) {
00512       // Note: the only reason the frame would be dirty would be if it had
00513       // just been inserted or appended
00514       reason = eReflowReason_Initial;
00515     } else if (isStyleChange) {
00516       reason = eReflowReason_StyleChange;
00517     } else {
00518       reason = aReflowState.reason;
00519     }
00520 
00521     // We must specify an unconstrained available height, because constrained
00522     // is only for when we're paginated...
00523     nsHTMLReflowState kidReflowState(aPresContext, aReflowState, kidFrame,
00524                                      nsSize(aReflowState.availableWidth,
00525                                             NS_UNCONSTRAINEDSIZE),
00526                                      reason);
00527 
00528     // Reflow the frame
00529     ReflowChild(kidFrame, aPresContext, kidDesiredSize, kidReflowState,
00530                 kidReflowState.mComputedMargin.left, kidReflowState.mComputedMargin.top,
00531                 0, aStatus);
00532 
00533     // Complete the reflow and position and size the child frame
00534     FinishReflowChild(kidFrame, aPresContext, &kidReflowState, kidDesiredSize,
00535                       kidReflowState.mComputedMargin.left,
00536                       kidReflowState.mComputedMargin.top, 0);
00537 
00538     // If the child frame was just inserted, then we're responsible for making sure
00539     // it repaints
00540     if (isDirtyChildReflow) {
00541       // But we have a new child, which will affect our background, so
00542       // invalidate our whole rect.
00543       // Note: Even though we request to be sized to our child's size, our
00544       // scroll frame ensures that we are always the size of the viewport.
00545       // Also note: GetPosition() on a CanvasFrame is always going to return
00546       // (0, 0). We only want to invalidate GetRect() since GetOverflowRect()
00547       // could also include overflow to our top and left (out of the viewport)
00548       // which doesn't need to be painted.
00549       Invalidate(GetRect(), PR_FALSE);
00550     }
00551 
00552     // Return our desired size
00553     // First check the combined area
00554     if (NS_FRAME_OUTSIDE_CHILDREN & kidFrame->GetStateBits()) {
00555       // Size ourselves to the size of the overflow area
00556       // XXXbz this ignores overflow up and left
00557       aDesiredSize.width = kidReflowState.mComputedMargin.left +
00558         PR_MAX(kidDesiredSize.mOverflowArea.XMost(),
00559                kidDesiredSize.width + kidReflowState.mComputedMargin.right);
00560       aDesiredSize.height = kidReflowState.mComputedMargin.top +
00561         PR_MAX(kidDesiredSize.mOverflowArea.YMost(),
00562                kidDesiredSize.height + kidReflowState.mComputedMargin.bottom);
00563     } else {
00564       aDesiredSize.width = kidDesiredSize.width +
00565         kidReflowState.mComputedMargin.left +
00566         kidReflowState.mComputedMargin.right;
00567       aDesiredSize.height = kidDesiredSize.height +
00568         kidReflowState.mComputedMargin.top +
00569         kidReflowState.mComputedMargin.bottom;
00570     }
00571     aDesiredSize.mOverflowArea.SetRect(0, 0, aDesiredSize.width, aDesiredSize.height);
00572     aDesiredSize.ascent = aDesiredSize.height;
00573     aDesiredSize.descent = 0;
00574     // XXX Don't completely ignore NS_FRAME_OUTSIDE_CHILDREN for child frames
00575     // that stick out on the left or top edges...
00576   }
00577 
00578   NS_FRAME_TRACE_REFLOW_OUT("CanvasFrame::Reflow", aStatus);
00579   NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
00580   return NS_OK;
00581 }
00582 
00583 PRIntn
00584 CanvasFrame::GetSkipSides() const
00585 {
00586   return 0;
00587 }
00588 
00589 NS_IMETHODIMP
00590 CanvasFrame::HandleEvent(nsPresContext* aPresContext, 
00591                          nsGUIEvent* aEvent,
00592                          nsEventStatus* aEventStatus)
00593 {
00594   NS_ENSURE_ARG_POINTER(aEventStatus);
00595   if (nsEventStatus_eConsumeNoDefault == *aEventStatus) {
00596     return NS_OK;
00597   }
00598 
00599   if (aEvent->message == NS_MOUSE_LEFT_BUTTON_UP ||
00600       aEvent->message == NS_MOUSE_MIDDLE_BUTTON_UP ||
00601       aEvent->message == NS_MOUSE_RIGHT_BUTTON_UP ||
00602       aEvent->message == NS_MOUSE_MOVE ) {
00603     nsIFrame *firstChild = GetFirstChild(nsnull);
00604     //canvas frame needs to pass mouse events to its area frame so that mouse movement
00605     //and selection code will work properly. this will still have the necessary effects
00606     //that would have happened if nsFrame::HandleEvent was called.
00607     if (firstChild) {
00608       nsIView* eventView;
00609       nsIView* newEventView;
00610       nsPoint pt1, pt2;
00611       GetOffsetFromView(pt1, &eventView);
00612       firstChild->GetOffsetFromView(pt2, &newEventView);
00613       nsPoint offset = eventView->GetOffsetTo(newEventView);
00614       aEvent->point += offset;
00615       firstChild->HandleEvent(aPresContext, aEvent, aEventStatus);
00616       aEvent->point -= offset;
00617     } else {
00618       nsFrame::HandleEvent(aPresContext, aEvent, aEventStatus);
00619     }
00620   }
00621 
00622   return NS_OK;
00623 }
00624 
00625 NS_IMETHODIMP
00626 CanvasFrame::GetFrameForPoint(const nsPoint& aPoint, 
00627                               nsFramePaintLayer aWhichLayer,
00628                               nsIFrame**     aFrame)
00629 {
00630   // this should act like a block, so we need to override
00631   return GetFrameForPointUsing(aPoint, nsnull, aWhichLayer, (aWhichLayer == NS_FRAME_PAINT_LAYER_BACKGROUND), aFrame);
00632 }
00633 
00634 nsIAtom*
00635 CanvasFrame::GetType() const
00636 {
00637   return nsLayoutAtoms::canvasFrame;
00638 }
00639 
00640 NS_IMETHODIMP 
00641 CanvasFrame::GetContentForEvent(nsPresContext* aPresContext,
00642                                 nsEvent* aEvent,
00643                                 nsIContent** aContent)
00644 {
00645   NS_ENSURE_ARG_POINTER(aContent);
00646   nsresult rv = nsFrame::GetContentForEvent(aPresContext,
00647                                             aEvent,
00648                                             aContent);
00649   if (NS_FAILED(rv) || !*aContent) {
00650     nsIFrame* kid = mFrames.FirstChild();
00651     if (kid) {
00652       rv = kid->GetContentForEvent(aPresContext,
00653                                    aEvent,
00654                                    aContent);
00655     }
00656   }
00657 
00658   return rv;
00659 }
00660 
00661 #ifdef DEBUG
00662 NS_IMETHODIMP
00663 CanvasFrame::GetFrameName(nsAString& aResult) const
00664 {
00665   return MakeFrameName(NS_LITERAL_STRING("Canvas"), aResult);
00666 }
00667 #endif