Bug 54488 - "[Mac] Non-draggable widgets in background windows should look disabled...
[mozilla-central.git] / layout / generic / nsHTMLFrame.cpp
blob1309f0fc824541d22efd850599ed21259154b809
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
15 * The Original Code is mozilla.org code.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998
20 * the Initial Developer. All Rights Reserved.
22 * Contributor(s):
24 * Alternatively, the contents of this file may be used under the terms of
25 * either of the GNU General Public License Version 2 or later (the "GPL"),
26 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
36 * ***** END LICENSE BLOCK ***** */
38 /* rendering object that goes directly inside the document's scrollbars */
40 #include "nsIServiceManager.h"
41 #include "nsHTMLParts.h"
42 #include "nsHTMLContainerFrame.h"
43 #include "nsCSSRendering.h"
44 #include "nsPresContext.h"
45 #include "nsStyleContext.h"
46 #include "nsIView.h"
47 #include "nsIViewManager.h"
48 #include "nsIRenderingContext.h"
49 #include "nsGUIEvent.h"
50 #include "nsStyleConsts.h"
51 #include "nsGkAtoms.h"
52 #include "nsIEventStateManager.h"
53 #include "nsIDeviceContext.h"
54 #include "nsIPresShell.h"
55 #include "nsIScrollPositionListener.h"
56 #include "nsDisplayList.h"
57 #include "nsAbsoluteContainingBlock.h"
59 // for focus
60 #include "nsIDOMWindowInternal.h"
61 #include "nsIFocusController.h"
62 #include "nsIScrollableFrame.h"
63 #include "nsIScrollableView.h"
64 #include "nsIDocShell.h"
65 #include "nsICanvasFrame.h"
67 #ifdef DEBUG_rods
68 //#define DEBUG_CANVAS_FOCUS
69 #endif
71 #define CANVAS_ABS_POS_CHILD_LIST NS_CONTAINER_LIST_COUNT_INCL_OC
73 // Interface IDs
75 /**
76 * Root frame class.
78 * The root frame is the parent frame for the document element's frame.
79 * It only supports having a single child frame which must be an area
80 * frame
82 class CanvasFrame : public nsHTMLContainerFrame,
83 public nsIScrollPositionListener,
84 public nsICanvasFrame {
85 public:
86 CanvasFrame(nsStyleContext* aContext)
87 : nsHTMLContainerFrame(aContext), mDoPaintFocus(PR_FALSE),
88 mAbsoluteContainer(nsGkAtoms::absoluteList) {}
90 // nsISupports
91 NS_IMETHOD QueryInterface(const nsIID& aIID, void** aInstancePtr);
93 NS_IMETHOD Init(nsIContent* aContent,
94 nsIFrame* aParent,
95 nsIFrame* aPrevInFlow);
96 virtual void Destroy();
98 NS_IMETHOD SetInitialChildList(nsIAtom* aListName,
99 nsIFrame* aChildList);
100 NS_IMETHOD AppendFrames(nsIAtom* aListName,
101 nsIFrame* aFrameList);
102 NS_IMETHOD InsertFrames(nsIAtom* aListName,
103 nsIFrame* aPrevFrame,
104 nsIFrame* aFrameList);
105 NS_IMETHOD RemoveFrame(nsIAtom* aListName,
106 nsIFrame* aOldFrame);
108 virtual nsIAtom* GetAdditionalChildListName(PRInt32 aIndex) const;
109 virtual nsIFrame* GetFirstChild(nsIAtom* aListName) const;
111 virtual nscoord GetMinWidth(nsIRenderingContext *aRenderingContext);
112 virtual nscoord GetPrefWidth(nsIRenderingContext *aRenderingContext);
113 NS_IMETHOD Reflow(nsPresContext* aPresContext,
114 nsHTMLReflowMetrics& aDesiredSize,
115 const nsHTMLReflowState& aReflowState,
116 nsReflowStatus& aStatus);
117 virtual PRBool IsContainingBlock() const { return PR_TRUE; }
118 virtual PRBool IsFrameOfType(PRUint32 aFlags) const
120 return nsHTMLContainerFrame::IsFrameOfType(aFlags &
121 ~(nsIFrame::eCanContainOverflowContainers));
124 NS_IMETHOD BuildDisplayList(nsDisplayListBuilder* aBuilder,
125 const nsRect& aDirtyRect,
126 const nsDisplayListSet& aLists);
128 void PaintFocus(nsIRenderingContext& aRenderingContext, nsPoint aPt);
130 // nsIScrollPositionListener
131 NS_IMETHOD ScrollPositionWillChange(nsIScrollableView* aScrollable, nscoord aX, nscoord aY);
132 virtual void ViewPositionDidChange(nsIScrollableView* aScrollable) {}
133 NS_IMETHOD ScrollPositionDidChange(nsIScrollableView* aScrollable, nscoord aX, nscoord aY);
135 // nsICanvasFrame
136 NS_IMETHOD SetHasFocus(PRBool aHasFocus);
139 * Get the "type" of the frame
141 * @see nsGkAtoms::canvasFrame
143 virtual nsIAtom* GetType() const;
145 virtual nsresult StealFrame(nsPresContext* aPresContext,
146 nsIFrame* aChild,
147 PRBool aForceNormal)
149 NS_ASSERTION(!aForceNormal, "No-one should be passing this in here");
151 // CanvasFrame keeps overflow container continuations of its child
152 // frame in main child list
153 nsresult rv = nsContainerFrame::StealFrame(aPresContext, aChild, PR_TRUE);
154 if (NS_FAILED(rv)) {
155 rv = nsContainerFrame::StealFrame(aPresContext, aChild);
157 return rv;
160 #ifdef DEBUG
161 NS_IMETHOD GetFrameName(nsAString& aResult) const;
162 #endif
163 NS_IMETHOD GetContentForEvent(nsPresContext* aPresContext,
164 nsEvent* aEvent,
165 nsIContent** aContent);
167 nsRect CanvasArea() const;
169 protected:
170 virtual PRIntn GetSkipSides() const;
172 // Data members
173 PRPackedBool mDoPaintFocus;
174 nsCOMPtr<nsIViewManager> mViewManager;
175 nsAbsoluteContainingBlock mAbsoluteContainer;
177 private:
178 NS_IMETHOD_(nsrefcnt) AddRef() { return NS_OK; }
179 NS_IMETHOD_(nsrefcnt) Release() { return NS_OK; }
183 //----------------------------------------------------------------------
185 nsIFrame*
186 NS_NewCanvasFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
188 return new (aPresShell)CanvasFrame(aContext);
191 //--------------------------------------------------------------
192 // Frames are not refcounted, no need to AddRef
193 NS_IMETHODIMP
194 CanvasFrame::QueryInterface(const nsIID& aIID, void** aInstancePtr)
196 NS_PRECONDITION(aInstancePtr, "null out param");
198 if (aIID.Equals(NS_GET_IID(nsIScrollPositionListener))) {
199 *aInstancePtr = static_cast<nsIScrollPositionListener*>(this);
200 return NS_OK;
202 if (aIID.Equals(NS_GET_IID(nsICanvasFrame))) {
203 *aInstancePtr = static_cast<nsICanvasFrame*>(this);
204 return NS_OK;
207 return nsHTMLContainerFrame::QueryInterface(aIID, aInstancePtr);
210 NS_IMETHODIMP
211 CanvasFrame::Init(nsIContent* aContent,
212 nsIFrame* aParent,
213 nsIFrame* aPrevInFlow)
215 nsresult rv = nsHTMLContainerFrame::Init(aContent, aParent, aPrevInFlow);
217 mViewManager = PresContext()->GetViewManager();
219 nsIScrollableView* scrollingView = nsnull;
220 mViewManager->GetRootScrollableView(&scrollingView);
221 if (scrollingView) {
222 scrollingView->AddScrollPositionListener(this);
225 return rv;
228 void
229 CanvasFrame::Destroy()
231 mAbsoluteContainer.DestroyFrames(this);
233 nsIScrollableView* scrollingView = nsnull;
234 mViewManager->GetRootScrollableView(&scrollingView);
235 if (scrollingView) {
236 scrollingView->RemoveScrollPositionListener(this);
239 nsHTMLContainerFrame::Destroy();
242 NS_IMETHODIMP
243 CanvasFrame::ScrollPositionWillChange(nsIScrollableView* aScrollable, nscoord aX, nscoord aY)
245 #ifdef DEBUG_CANVAS_FOCUS
247 PRBool hasFocus = PR_FALSE;
248 nsCOMPtr<nsIViewObserver> observer;
249 mViewManager->GetViewObserver(*getter_AddRefs(observer));
250 nsCOMPtr<nsIPresShell> shell = do_QueryInterface(observer);
251 nsCOMPtr<nsPresContext> context;
252 shell->GetPresContext(getter_AddRefs(context));
253 nsCOMPtr<nsISupports> container;
254 context->GetContainer(getter_AddRefs(container));
255 nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(container));
256 if (docShell) {
257 docShell->GetHasFocus(&hasFocus);
259 printf("SPWC: %p HF: %s mDoPaintFocus: %s\n", docShell.get(), hasFocus?"Y":"N", mDoPaintFocus?"Y":"N");
261 #endif
263 if (mDoPaintFocus) {
264 mDoPaintFocus = PR_FALSE;
265 mViewManager->UpdateAllViews(NS_VMREFRESH_NO_SYNC);
267 return NS_OK;
270 NS_IMETHODIMP
271 CanvasFrame::ScrollPositionDidChange(nsIScrollableView* aScrollable, nscoord aX, nscoord aY)
273 return NS_OK;
276 NS_IMETHODIMP
277 CanvasFrame::SetHasFocus(PRBool aHasFocus)
279 if (mDoPaintFocus != aHasFocus) {
280 mDoPaintFocus = aHasFocus;
281 mViewManager->UpdateAllViews(NS_VMREFRESH_NO_SYNC);
283 return NS_OK;
286 NS_IMETHODIMP
287 CanvasFrame::SetInitialChildList(nsIAtom* aListName,
288 nsIFrame* aChildList)
290 if (nsGkAtoms::absoluteList == aListName)
291 return mAbsoluteContainer.SetInitialChildList(this, aListName, aChildList);
293 NS_ASSERTION(aListName || !aChildList || !aChildList->GetNextSibling(),
294 "Primary child list can have at most one frame in it");
295 return nsHTMLContainerFrame::SetInitialChildList(aListName, aChildList);
298 NS_IMETHODIMP
299 CanvasFrame::AppendFrames(nsIAtom* aListName,
300 nsIFrame* aFrameList)
302 nsresult rv;
304 if (nsGkAtoms::absoluteList == aListName)
305 return mAbsoluteContainer.AppendFrames(this, aListName, aFrameList);
307 NS_ASSERTION(!aListName, "unexpected child list name");
308 NS_PRECONDITION(mFrames.IsEmpty(), "already have a child frame");
309 if (aListName) {
310 // We only support unnamed principal child list
311 rv = NS_ERROR_INVALID_ARG;
313 } else if (!mFrames.IsEmpty()) {
314 // We only allow a single child frame
315 rv = NS_ERROR_FAILURE;
317 } else {
318 // Insert the new frames
319 #ifdef NS_DEBUG
320 nsFrame::VerifyDirtyBitSet(aFrameList);
321 #endif
322 mFrames.AppendFrame(nsnull, aFrameList);
324 rv = PresContext()->PresShell()->
325 FrameNeedsReflow(this, nsIPresShell::eTreeChange,
326 NS_FRAME_HAS_DIRTY_CHILDREN);
329 return rv;
332 NS_IMETHODIMP
333 CanvasFrame::InsertFrames(nsIAtom* aListName,
334 nsIFrame* aPrevFrame,
335 nsIFrame* aFrameList)
337 nsresult rv;
339 if (nsGkAtoms::absoluteList == aListName)
340 return mAbsoluteContainer.InsertFrames(this, aListName, aPrevFrame, aFrameList);
342 // Because we only support a single child frame inserting is the same
343 // as appending
344 NS_PRECONDITION(!aPrevFrame, "unexpected previous sibling frame");
345 if (aPrevFrame) {
346 rv = NS_ERROR_UNEXPECTED;
347 } else {
348 rv = AppendFrames(aListName, aFrameList);
351 return rv;
354 NS_IMETHODIMP
355 CanvasFrame::RemoveFrame(nsIAtom* aListName,
356 nsIFrame* aOldFrame)
358 nsresult rv;
360 if (nsGkAtoms::absoluteList == aListName)
361 return mAbsoluteContainer.RemoveFrame(this, aListName, aOldFrame);
363 NS_ASSERTION(!aListName, "unexpected child list name");
364 if (aListName) {
365 // We only support the unnamed principal child list
366 rv = NS_ERROR_INVALID_ARG;
368 } else if (aOldFrame == mFrames.FirstChild()) {
369 // It's our one and only child frame
370 // Damage the area occupied by the deleted frame
371 // The child of the canvas probably can't have an outline, but why bother
372 // thinking about that?
373 Invalidate(aOldFrame->GetOverflowRect() + aOldFrame->GetPosition());
375 // Remove the frame and destroy it
376 mFrames.DestroyFrame(aOldFrame);
378 rv = PresContext()->PresShell()->
379 FrameNeedsReflow(this, nsIPresShell::eTreeChange,
380 NS_FRAME_HAS_DIRTY_CHILDREN);
381 } else {
382 rv = NS_ERROR_FAILURE;
385 return rv;
388 nsIAtom*
389 CanvasFrame::GetAdditionalChildListName(PRInt32 aIndex) const
391 if (CANVAS_ABS_POS_CHILD_LIST == aIndex)
392 return nsGkAtoms::absoluteList;
394 return nsHTMLContainerFrame::GetAdditionalChildListName(aIndex);
397 nsIFrame*
398 CanvasFrame::GetFirstChild(nsIAtom* aListName) const
400 if (nsGkAtoms::absoluteList == aListName)
401 return mAbsoluteContainer.GetFirstChild();
403 return nsHTMLContainerFrame::GetFirstChild(aListName);
406 nsRect CanvasFrame::CanvasArea() const
408 nsRect result(GetOverflowRect());
410 nsIScrollableFrame *scrollableFrame;
411 CallQueryInterface(GetParent(), &scrollableFrame);
412 if (scrollableFrame) {
413 nsIScrollableView* scrollableView = scrollableFrame->GetScrollableView();
414 nsRect vcr = scrollableView->View()->GetBounds();
415 result.UnionRect(result, nsRect(nsPoint(0, 0), vcr.Size()));
417 return result;
421 * Override nsDisplayBackground methods so that we pass aBGClipRect to
422 * PaintBackground, covering the whole overflow area.
424 class nsDisplayCanvasBackground : public nsDisplayBackground {
425 public:
426 nsDisplayCanvasBackground(nsIFrame *aFrame)
427 : nsDisplayBackground(aFrame)
431 virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder)
433 CanvasFrame* frame = static_cast<CanvasFrame*>(mFrame);
434 return frame->CanvasArea() + aBuilder->ToReferenceFrame(mFrame);
437 virtual void Paint(nsDisplayListBuilder* aBuilder,
438 nsIRenderingContext* aCtx, const nsRect& aDirtyRect)
440 CanvasFrame* frame = static_cast<CanvasFrame*>(mFrame);
441 nsPoint offset = aBuilder->ToReferenceFrame(mFrame);
442 nsRect bgClipRect = frame->CanvasArea() + offset;
443 nsCSSRendering::PaintBackground(mFrame->PresContext(), *aCtx, mFrame,
444 aDirtyRect,
445 nsRect(offset, mFrame->GetSize()),
446 *mFrame->GetStyleBorder(),
447 *mFrame->GetStylePadding(),
448 mFrame->HonorPrintBackgroundSettings(),
449 &bgClipRect);
452 NS_DISPLAY_DECL_NAME("CanvasBackground")
456 * A display item to paint the focus ring for the document.
458 * The only reason this can't use nsDisplayGeneric is overriding GetBounds.
460 class nsDisplayCanvasFocus : public nsDisplayItem {
461 public:
462 nsDisplayCanvasFocus(CanvasFrame *aFrame)
463 : nsDisplayItem(aFrame)
467 virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder)
469 // This is an overestimate, but that's not a problem.
470 CanvasFrame* frame = static_cast<CanvasFrame*>(mFrame);
471 return frame->CanvasArea() + aBuilder->ToReferenceFrame(mFrame);
474 virtual void Paint(nsDisplayListBuilder* aBuilder,
475 nsIRenderingContext* aCtx, const nsRect& aDirtyRect)
477 CanvasFrame* frame = static_cast<CanvasFrame*>(mFrame);
478 frame->PaintFocus(*aCtx, aBuilder->ToReferenceFrame(mFrame));
481 NS_DISPLAY_DECL_NAME("CanvasFocus")
484 NS_IMETHODIMP
485 CanvasFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
486 const nsRect& aDirtyRect,
487 const nsDisplayListSet& aLists)
489 nsresult rv;
491 if (GetPrevInFlow()) {
492 DisplayOverflowContainers(aBuilder, aDirtyRect, aLists);
495 aBuilder->MarkFramesForDisplayList(this, mAbsoluteContainer.GetFirstChild(), aDirtyRect);
497 // Force a background to be shown. We may have a background propagated to us,
498 // in which case GetStyleBackground wouldn't have the right background
499 // and the code in nsFrame::DisplayBorderBackgroundOutline might not give us
500 // a background.
501 // We don't have any border or outline, and our background draws over
502 // the overflow area, so just add nsDisplayCanvasBackground instead of
503 // calling DisplayBorderBackgroundOutline.
504 if (IsVisibleForPainting(aBuilder)) {
505 rv = aLists.BorderBackground()->AppendNewToTop(new (aBuilder)
506 nsDisplayCanvasBackground(this));
507 NS_ENSURE_SUCCESS(rv, rv);
510 nsIFrame* kid;
511 for (kid = GetFirstChild(nsnull); kid; kid = kid->GetNextSibling()) {
512 // Put our child into its own pseudo-stack.
513 rv = BuildDisplayListForChild(aBuilder, kid, aDirtyRect, aLists,
514 DISPLAY_CHILD_FORCE_PSEUDO_STACKING_CONTEXT);
515 NS_ENSURE_SUCCESS(rv, rv);
518 #ifdef DEBUG_CANVAS_FOCUS
519 nsCOMPtr<nsIContent> focusContent;
520 aPresContext->EventStateManager()->
521 GetFocusedContent(getter_AddRefs(focusContent));
523 PRBool hasFocus = PR_FALSE;
524 nsCOMPtr<nsISupports> container;
525 aPresContext->GetContainer(getter_AddRefs(container));
526 nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(container));
527 if (docShell) {
528 docShell->GetHasFocus(&hasFocus);
529 printf("%p - CanvasFrame::Paint R:%d,%d,%d,%d DR: %d,%d,%d,%d\n", this,
530 mRect.x, mRect.y, mRect.width, mRect.height,
531 aDirtyRect.x, aDirtyRect.y, aDirtyRect.width, aDirtyRect.height);
533 printf("%p - Focus: %s c: %p DoPaint:%s\n", docShell.get(), hasFocus?"Y":"N",
534 focusContent.get(), mDoPaintFocus?"Y":"N");
535 #endif
537 if (!mDoPaintFocus)
538 return NS_OK;
539 // Only paint the focus if we're visible
540 if (!GetStyleVisibility()->IsVisible())
541 return NS_OK;
543 return aLists.Outlines()->AppendNewToTop(new (aBuilder)
544 nsDisplayCanvasFocus(this));
547 void
548 CanvasFrame::PaintFocus(nsIRenderingContext& aRenderingContext, nsPoint aPt)
550 nsRect focusRect(aPt, GetSize());
552 nsIScrollableFrame *scrollableFrame;
553 CallQueryInterface(GetParent(), &scrollableFrame);
555 if (scrollableFrame) {
556 nsIScrollableView* scrollableView = scrollableFrame->GetScrollableView();
557 nsRect vcr = scrollableView->View()->GetBounds();
558 focusRect.width = vcr.width;
559 focusRect.height = vcr.height;
560 nscoord x,y;
561 scrollableView->GetScrollPosition(x, y);
562 focusRect.x += x;
563 focusRect.y += y;
566 // XXX use the root frame foreground color, but should we find BODY frame
567 // for HTML documents?
568 nsIFrame* root = mFrames.FirstChild();
569 const nsStyleColor* color =
570 root ? root->GetStyleContext()->GetStyleColor() :
571 mStyleContext->GetStyleColor();
572 if (!color) {
573 NS_ERROR("current color cannot be found");
574 return;
577 nsCSSRendering::PaintFocus(PresContext(), aRenderingContext,
578 focusRect, color->mColor);
581 /* virtual */ nscoord
582 CanvasFrame::GetMinWidth(nsIRenderingContext *aRenderingContext)
584 nscoord result;
585 DISPLAY_MIN_WIDTH(this, result);
586 if (mFrames.IsEmpty())
587 result = 0;
588 else
589 result = mFrames.FirstChild()->GetMinWidth(aRenderingContext);
590 return result;
593 /* virtual */ nscoord
594 CanvasFrame::GetPrefWidth(nsIRenderingContext *aRenderingContext)
596 nscoord result;
597 DISPLAY_PREF_WIDTH(this, result);
598 if (mFrames.IsEmpty())
599 result = 0;
600 else
601 result = mFrames.FirstChild()->GetPrefWidth(aRenderingContext);
602 return result;
605 NS_IMETHODIMP
606 CanvasFrame::Reflow(nsPresContext* aPresContext,
607 nsHTMLReflowMetrics& aDesiredSize,
608 const nsHTMLReflowState& aReflowState,
609 nsReflowStatus& aStatus)
611 DO_GLOBAL_REFLOW_COUNT("CanvasFrame");
612 DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);
613 NS_FRAME_TRACE_REFLOW_IN("CanvasFrame::Reflow");
615 // Initialize OUT parameter
616 aStatus = NS_FRAME_COMPLETE;
618 CanvasFrame* prevCanvasFrame = static_cast<CanvasFrame*>
619 (GetPrevInFlow());
620 if (prevCanvasFrame) {
621 nsIFrame* overflow = prevCanvasFrame->GetOverflowFrames(aPresContext, PR_TRUE);
622 if (overflow) {
623 NS_ASSERTION(!overflow->GetNextSibling(),
624 "must have doc root as canvas frame's only child");
625 nsHTMLContainerFrame::ReparentFrameView(aPresContext, overflow, prevCanvasFrame, this);
626 // Prepend overflow to the our child list. There may already be
627 // children placeholders for fixed-pos elements, which don't get
628 // reflowed but must not be lost until the canvas frame is destroyed.
629 mFrames.InsertFrames(this, nsnull, overflow);
633 // Reflow our one and only normal child frame. It's either the root
634 // element's frame or a placeholder for that frame, if the root element
635 // is abs-pos or fixed-pos. We may have additional children which
636 // are placeholders for continuations of fixed-pos content, but those
637 // don't need to be reflowed. The normal child is always comes before
638 // the fixed-pos placeholders, because we insert it at the start
639 // of the child list, above.
640 nsHTMLReflowMetrics kidDesiredSize;
641 if (mFrames.IsEmpty()) {
642 // We have no child frame, so return an empty size
643 aDesiredSize.width = aDesiredSize.height = 0;
644 } else {
645 nsIFrame* kidFrame = mFrames.FirstChild();
646 PRBool kidDirty = (kidFrame->GetStateBits() & NS_FRAME_IS_DIRTY) != 0;
648 nsHTMLReflowState kidReflowState(aPresContext, aReflowState, kidFrame,
649 nsSize(aReflowState.availableWidth,
650 aReflowState.availableHeight));
652 if (aReflowState.mFlags.mVResize &&
653 (kidFrame->GetStateBits() & NS_FRAME_CONTAINS_RELATIVE_HEIGHT)) {
654 // Tell our kid it's being vertically resized too. Bit of a
655 // hack for framesets.
656 kidReflowState.mFlags.mVResize = PR_TRUE;
659 nsPoint kidPt(kidReflowState.mComputedMargin.left,
660 kidReflowState.mComputedMargin.top);
661 // Apply CSS relative positioning
662 const nsStyleDisplay* styleDisp = kidFrame->GetStyleDisplay();
663 if (NS_STYLE_POSITION_RELATIVE == styleDisp->mPosition) {
664 kidPt += nsPoint(kidReflowState.mComputedOffsets.left,
665 kidReflowState.mComputedOffsets.top);
668 // Reflow the frame
669 ReflowChild(kidFrame, aPresContext, kidDesiredSize, kidReflowState,
670 kidPt.x, kidPt.y, 0, aStatus);
672 // Complete the reflow and position and size the child frame
673 FinishReflowChild(kidFrame, aPresContext, &kidReflowState, kidDesiredSize,
674 kidPt.x, kidPt.y, 0);
676 if (!NS_FRAME_IS_FULLY_COMPLETE(aStatus)) {
677 nsIFrame* nextFrame = kidFrame->GetNextInFlow();
678 NS_ASSERTION(nextFrame || aStatus & NS_FRAME_REFLOW_NEXTINFLOW,
679 "If it's incomplete and has no nif yet, it must flag a nif reflow.");
680 if (!nextFrame) {
681 nsresult rv = nsHTMLContainerFrame::CreateNextInFlow(aPresContext,
682 this, kidFrame, nextFrame);
683 NS_ENSURE_SUCCESS(rv, rv);
684 kidFrame->SetNextSibling(nextFrame->GetNextSibling());
685 nextFrame->SetNextSibling(nsnull);
686 SetOverflowFrames(aPresContext, nextFrame);
687 // Root overflow containers will be normal children of
688 // the canvas frame, but that's ok because there
689 // aren't any other frames we need to isolate them from
690 // during reflow.
692 if (NS_FRAME_OVERFLOW_IS_INCOMPLETE(aStatus)) {
693 nextFrame->AddStateBits(NS_FRAME_IS_OVERFLOW_CONTAINER);
697 // If the child frame was just inserted, then we're responsible for making sure
698 // it repaints
699 if (kidDirty) {
700 // But we have a new child, which will affect our background, so
701 // invalidate our whole rect.
702 // Note: Even though we request to be sized to our child's size, our
703 // scroll frame ensures that we are always the size of the viewport.
704 // Also note: GetPosition() on a CanvasFrame is always going to return
705 // (0, 0). We only want to invalidate GetRect() since GetOverflowRect()
706 // could also include overflow to our top and left (out of the viewport)
707 // which doesn't need to be painted.
708 nsIFrame* viewport = PresContext()->GetPresShell()->GetRootFrame();
709 viewport->Invalidate(nsRect(nsPoint(0, 0), viewport->GetSize()));
712 // Return our desired size (which doesn't matter)
713 aDesiredSize.width = aReflowState.ComputedWidth();
714 aDesiredSize.height = aReflowState.ComputedHeight();
716 aDesiredSize.mOverflowArea.UnionRect(
717 nsRect(0, 0, aDesiredSize.width, aDesiredSize.height),
718 kidDesiredSize.mOverflowArea + kidPt);
720 if (mAbsoluteContainer.HasAbsoluteFrames()) {
721 PRBool widthChanged = aDesiredSize.width != mRect.width;
722 PRBool heightChanged = aDesiredSize.height != mRect.height;
723 nsRect absPosBounds;
724 mAbsoluteContainer.Reflow(this, aPresContext, aReflowState, aStatus,
725 aDesiredSize.width, aDesiredSize.height,
726 PR_TRUE, widthChanged, heightChanged,
727 &absPosBounds);
728 aDesiredSize.mOverflowArea.UnionRect(aDesiredSize.mOverflowArea, absPosBounds);
732 if (prevCanvasFrame) {
733 ReflowOverflowContainerChildren(aPresContext, aReflowState,
734 aDesiredSize.mOverflowArea, 0,
735 aStatus);
738 FinishAndStoreOverflow(&aDesiredSize);
740 NS_FRAME_TRACE_REFLOW_OUT("CanvasFrame::Reflow", aStatus);
741 NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
742 return NS_OK;
745 PRIntn
746 CanvasFrame::GetSkipSides() const
748 return 0;
751 nsIAtom*
752 CanvasFrame::GetType() const
754 return nsGkAtoms::canvasFrame;
757 NS_IMETHODIMP
758 CanvasFrame::GetContentForEvent(nsPresContext* aPresContext,
759 nsEvent* aEvent,
760 nsIContent** aContent)
762 NS_ENSURE_ARG_POINTER(aContent);
763 nsresult rv = nsFrame::GetContentForEvent(aPresContext,
764 aEvent,
765 aContent);
766 if (NS_FAILED(rv) || !*aContent) {
767 nsIFrame* kid = mFrames.FirstChild();
768 if (kid) {
769 rv = kid->GetContentForEvent(aPresContext,
770 aEvent,
771 aContent);
775 return rv;
778 #ifdef DEBUG
779 NS_IMETHODIMP
780 CanvasFrame::GetFrameName(nsAString& aResult) const
782 return MakeFrameName(NS_LITERAL_STRING("Canvas"), aResult);
784 #endif