Bug 574454 - Cleanup nsNativeThemeWin's GetMinimumWidgetSize a bit. r=roc.
[mozilla-central.git] / layout / generic / nsFrameFrame.cpp
blob3992debbc7d30f61e444694dea8ab5e12e2cb689
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):
23 * Travis Bogard <travis@netscape.com>
24 * HÂkan Waara <hwaara@chello.se>
26 * Alternatively, the contents of this file may be used under the terms of
27 * either of the GNU General Public License Version 2 or later (the "GPL"),
28 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 * in which case the provisions of the GPL or the LGPL are applicable instead
30 * of those above. If you wish to allow use of your version of this file only
31 * under the terms of either the GPL or the LGPL, and not to allow others to
32 * use your version of this file under the terms of the MPL, indicate your
33 * decision by deleting the provisions above and replace them with the notice
34 * and other provisions required by the GPL or the LGPL. If you do not delete
35 * the provisions above, a recipient may use your version of this file under
36 * the terms of any one of the MPL, the GPL or the LGPL.
38 * ***** END LICENSE BLOCK ***** */
41 * rendering object for replaced elements that contain a document, such
42 * as <frame>, <iframe>, and some <object>s
45 #include "nsCOMPtr.h"
46 #include "nsLeafFrame.h"
47 #include "nsGenericHTMLElement.h"
48 #include "nsIDocShell.h"
49 #include "nsIDocShellLoadInfo.h"
50 #include "nsIDocShellTreeItem.h"
51 #include "nsIDocShellTreeNode.h"
52 #include "nsIDocShellTreeOwner.h"
53 #include "nsIBaseWindow.h"
54 #include "nsIContentViewer.h"
55 #include "nsIMarkupDocumentViewer.h"
56 #include "nsPresContext.h"
57 #include "nsIPresShell.h"
58 #include "nsIComponentManager.h"
59 #include "nsFrameManager.h"
60 #include "nsIStreamListener.h"
61 #include "nsIURL.h"
62 #include "nsNetUtil.h"
63 #include "nsIDocument.h"
64 #include "nsIView.h"
65 #include "nsIViewManager.h"
66 #include "nsWidgetsCID.h"
67 #include "nsViewsCID.h"
68 #include "nsGkAtoms.h"
69 #include "nsStyleCoord.h"
70 #include "nsStyleContext.h"
71 #include "nsStyleConsts.h"
72 #include "nsFrameSetFrame.h"
73 #include "nsIDOMHTMLFrameElement.h"
74 #include "nsIDOMHTMLIFrameElement.h"
75 #include "nsIDOMXULElement.h"
76 #include "nsFrameLoader.h"
77 #include "nsIScriptSecurityManager.h"
78 #include "nsXPIDLString.h"
79 #include "nsIScrollable.h"
80 #include "nsINameSpaceManager.h"
81 #include "nsWeakReference.h"
82 #include "nsIDOMWindow.h"
83 #include "nsIDOMDocument.h"
84 #include "nsIRenderingContext.h"
85 #include "nsIFrameFrame.h"
86 #include "nsAutoPtr.h"
87 #include "nsIDOMNSHTMLDocument.h"
88 #include "nsDisplayList.h"
89 #include "nsUnicharUtils.h"
90 #include "nsIReflowCallback.h"
91 #include "nsIScrollableFrame.h"
92 #include "nsIObjectLoadingContent.h"
93 #include "nsLayoutUtils.h"
95 #ifdef MOZ_XUL
96 #include "nsXULPopupManager.h"
97 #endif
99 // For Accessibility
100 #ifdef ACCESSIBILITY
101 #include "nsIAccessibilityService.h"
102 #endif
103 #include "nsIServiceManager.h"
105 class AsyncFrameInit;
107 static NS_DEFINE_CID(kCChildCID, NS_CHILD_CID);
109 /******************************************************************************
110 * nsSubDocumentFrame
111 *****************************************************************************/
112 class nsSubDocumentFrame : public nsLeafFrame,
113 public nsIFrameFrame,
114 public nsIReflowCallback
116 public:
117 NS_DECL_FRAMEARENA_HELPERS
119 nsSubDocumentFrame(nsStyleContext* aContext);
121 #ifdef DEBUG
122 NS_IMETHOD GetFrameName(nsAString& aResult) const;
123 #endif
125 NS_DECL_QUERYFRAME
127 virtual nsIAtom* GetType() const;
129 virtual PRBool IsFrameOfType(PRUint32 aFlags) const
131 // nsLeafFrame is already eReplacedContainsBlock, but that's somewhat bogus
132 return nsLeafFrame::IsFrameOfType(aFlags &
133 ~(nsIFrame::eReplaced | nsIFrame::eReplacedContainsBlock));
136 NS_IMETHOD Init(nsIContent* aContent,
137 nsIFrame* aParent,
138 nsIFrame* aPrevInFlow);
140 virtual void DestroyFrom(nsIFrame* aDestructRoot);
142 virtual nscoord GetMinWidth(nsIRenderingContext *aRenderingContext);
143 virtual nscoord GetPrefWidth(nsIRenderingContext *aRenderingContext);
145 virtual IntrinsicSize GetIntrinsicSize();
146 virtual nsSize GetIntrinsicRatio();
148 virtual nsSize ComputeAutoSize(nsIRenderingContext *aRenderingContext,
149 nsSize aCBSize, nscoord aAvailableWidth,
150 nsSize aMargin, nsSize aBorder,
151 nsSize aPadding, PRBool aShrinkWrap);
153 virtual nsSize ComputeSize(nsIRenderingContext *aRenderingContext,
154 nsSize aCBSize, nscoord aAvailableWidth,
155 nsSize aMargin, nsSize aBorder, nsSize aPadding,
156 PRBool aShrinkWrap);
158 NS_IMETHOD Reflow(nsPresContext* aPresContext,
159 nsHTMLReflowMetrics& aDesiredSize,
160 const nsHTMLReflowState& aReflowState,
161 nsReflowStatus& aStatus);
163 NS_IMETHOD BuildDisplayList(nsDisplayListBuilder* aBuilder,
164 const nsRect& aDirtyRect,
165 const nsDisplayListSet& aLists);
167 NS_IMETHOD AttributeChanged(PRInt32 aNameSpaceID,
168 nsIAtom* aAttribute,
169 PRInt32 aModType);
171 // if the content is "visibility:hidden", then just hide the view
172 // and all our contents. We don't extend "visibility:hidden" to
173 // the child content ourselves, since it belongs to a different
174 // document and CSS doesn't inherit in there.
175 virtual PRBool SupportsVisibilityHidden() { return PR_FALSE; }
177 #ifdef ACCESSIBILITY
178 virtual already_AddRefed<nsAccessible> CreateAccessible();
179 #endif
181 // nsIFrameFrame
182 NS_IMETHOD GetDocShell(nsIDocShell **aDocShell);
183 NS_IMETHOD BeginSwapDocShells(nsIFrame* aOther);
184 virtual void EndSwapDocShells(nsIFrame* aOther);
185 virtual nsIFrame* GetFrame() { return this; }
187 // nsIReflowCallback
188 virtual PRBool ReflowFinished();
189 virtual void ReflowCallbackCanceled();
191 protected:
192 friend class AsyncFrameInit;
194 // Helper method to look up the HTML marginwidth & marginheight attributes
195 nsIntSize GetMarginAttributes();
197 nsFrameLoader* FrameLoader();
199 PRBool IsInline() { return mIsInline; }
200 nsIView* CreateViewAndWidget(nsContentType aContentType);
202 virtual nscoord GetIntrinsicWidth();
203 virtual nscoord GetIntrinsicHeight();
205 virtual PRIntn GetSkipSides() const;
207 // Hide or show our document viewer
208 void HideViewer();
209 void ShowViewer();
211 /* Obtains the frame we should use for intrinsic size information if we are
212 * an HTML <object>, <embed> or <applet> (a replaced element - not <iframe>)
213 * and our sub-document has an intrinsic size. The frame returned is the
214 * frame for the document element of the document we're embedding.
216 * Called "Obtain*" and not "Get*" because of comment on GetDocShell that
217 * says it should be called ObtainDocShell because of it's side effects.
219 nsIFrame* ObtainIntrinsicSizeFrame();
221 nsRefPtr<nsFrameLoader> mFrameLoader;
222 nsIView* mInnerView;
223 PRPackedBool mIsInline;
224 PRPackedBool mPostedReflowCallback;
225 PRPackedBool mDidCreateDoc;
226 PRPackedBool mCallingShow;
229 nsSubDocumentFrame::nsSubDocumentFrame(nsStyleContext* aContext)
230 : nsLeafFrame(aContext)
231 , mIsInline(PR_FALSE)
232 , mPostedReflowCallback(PR_FALSE)
233 , mDidCreateDoc(PR_FALSE)
234 , mCallingShow(PR_FALSE)
238 #ifdef ACCESSIBILITY
239 already_AddRefed<nsAccessible>
240 nsSubDocumentFrame::CreateAccessible()
242 nsCOMPtr<nsIAccessibilityService> accService = do_GetService("@mozilla.org/accessibilityService;1");
243 return accService ?
244 accService->CreateOuterDocAccessible(mContent, PresContext()->PresShell()) :
245 nsnull;
247 #endif
249 NS_QUERYFRAME_HEAD(nsSubDocumentFrame)
250 NS_QUERYFRAME_ENTRY(nsIFrameFrame)
251 NS_QUERYFRAME_TAIL_INHERITING(nsLeafFrame)
253 class AsyncFrameInit : public nsRunnable
255 public:
256 AsyncFrameInit(nsIFrame* aFrame) : mFrame(aFrame) {}
257 NS_IMETHOD Run()
259 if (mFrame.IsAlive()) {
260 static_cast<nsSubDocumentFrame*>(mFrame.GetFrame())->ShowViewer();
262 return NS_OK;
264 private:
265 nsWeakFrame mFrame;
268 NS_IMETHODIMP
269 nsSubDocumentFrame::Init(nsIContent* aContent,
270 nsIFrame* aParent,
271 nsIFrame* aPrevInFlow)
273 // determine if we are a <frame> or <iframe>
274 if (aContent) {
275 nsCOMPtr<nsIDOMHTMLFrameElement> frameElem = do_QueryInterface(aContent);
276 mIsInline = frameElem ? PR_FALSE : PR_TRUE;
279 nsresult rv = nsLeafFrame::Init(aContent, aParent, aPrevInFlow);
280 if (NS_FAILED(rv))
281 return rv;
283 // We are going to create an inner view. If we need a view for the
284 // OuterFrame but we wait for the normal view creation path in
285 // nsCSSFrameConstructor, then we will lose because the inner view's
286 // parent will already have been set to some outer view (e.g., the
287 // canvas) when it really needs to have this frame's view as its
288 // parent. So, create this frame's view right away, whether we
289 // really need it or not, and the inner view will get it as the
290 // parent.
291 if (!HasView()) {
292 rv = nsHTMLContainerFrame::CreateViewForFrame(this, PR_TRUE);
293 NS_ENSURE_SUCCESS(rv, rv);
295 nsIView* view = GetView();
297 if (aParent->GetStyleDisplay()->mDisplay == NS_STYLE_DISPLAY_DECK
298 && !view->HasWidget()) {
299 view->CreateWidget(kCChildCID);
302 // Set the primary frame now so that
303 // DocumentViewerImpl::FindContainerView called by ShowViewer below
304 // can find it if necessary.
305 aContent->SetPrimaryFrame(this);
307 nsContentUtils::AddScriptRunner(new AsyncFrameInit(this));
308 return NS_OK;
311 inline PRInt32 ConvertOverflow(PRUint8 aOverflow)
313 switch (aOverflow) {
314 case NS_STYLE_OVERFLOW_VISIBLE:
315 case NS_STYLE_OVERFLOW_AUTO:
316 return nsIScrollable::Scrollbar_Auto;
317 case NS_STYLE_OVERFLOW_HIDDEN:
318 case NS_STYLE_OVERFLOW_CLIP:
319 return nsIScrollable::Scrollbar_Never;
320 case NS_STYLE_OVERFLOW_SCROLL:
321 return nsIScrollable::Scrollbar_Always;
323 NS_NOTREACHED("invalid overflow value passed to ConvertOverflow");
324 return nsIScrollable::Scrollbar_Auto;
327 void
328 nsSubDocumentFrame::ShowViewer()
330 if (mCallingShow) {
331 return;
334 if (!PresContext()->IsDynamic()) {
335 // We let the printing code take care of loading the document; just
336 // create a widget for it to use
337 (void) CreateViewAndWidget(eContentTypeContent);
338 } else {
339 nsRefPtr<nsFrameLoader> frameloader = FrameLoader();
340 if (frameloader) {
341 nsIntSize margin = GetMarginAttributes();
342 const nsStyleDisplay* disp = GetStyleDisplay();
343 nsWeakFrame weakThis(this);
344 mCallingShow = PR_TRUE;
345 PRBool didCreateDoc =
346 frameloader->Show(margin.width, margin.height,
347 ConvertOverflow(disp->mOverflowX),
348 ConvertOverflow(disp->mOverflowY),
349 this);
350 if (!weakThis.IsAlive()) {
351 return;
353 mCallingShow = PR_FALSE;
354 mDidCreateDoc = didCreateDoc;
359 PRIntn
360 nsSubDocumentFrame::GetSkipSides() const
362 return 0;
365 NS_IMETHODIMP
366 nsSubDocumentFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
367 const nsRect& aDirtyRect,
368 const nsDisplayListSet& aLists)
370 if (!IsVisibleForPainting(aBuilder))
371 return NS_OK;
373 if (aBuilder->IsForEventDelivery() &&
374 GetStyleVisibility()->mPointerEvents == NS_STYLE_POINTER_EVENTS_NONE)
375 return NS_OK;
377 nsresult rv = DisplayBorderBackgroundOutline(aBuilder, aLists);
378 NS_ENSURE_SUCCESS(rv, rv);
380 if (!mInnerView)
381 return NS_OK;
382 nsIView* subdocView = mInnerView->GetFirstChild();
383 if (!subdocView)
384 return NS_OK;
386 nsCOMPtr<nsIPresShell> presShell;
388 nsIFrame* subdocRootFrame =
389 static_cast<nsIFrame*>(subdocView->GetClientData());
391 if (subdocRootFrame) {
392 presShell = subdocRootFrame->PresContext()->PresShell();
393 } else {
394 // During page transition mInnerView will sometimes have two children, the
395 // first being the new page that may not have any frame, and the second
396 // being the old page that will probably have a frame.
397 nsIView* nextView = subdocView->GetNextSibling();
398 if (nextView) {
399 subdocRootFrame = static_cast<nsIFrame*>(nextView->GetClientData());
401 if (subdocRootFrame) {
402 subdocView = nextView;
403 presShell = subdocRootFrame->PresContext()->PresShell();
404 } else {
405 // If we don't have a frame we use this roundabout way to get the pres shell.
406 if (!mFrameLoader)
407 return NS_OK;
408 nsCOMPtr<nsIDocShell> docShell;
409 mFrameLoader->GetDocShell(getter_AddRefs(docShell));
410 if (!docShell)
411 return NS_OK;
412 docShell->GetPresShell(getter_AddRefs(presShell));
413 if (!presShell)
414 return NS_OK;
418 nsPresContext* presContext = presShell->GetPresContext();
420 nsDisplayList childItems;
422 PRInt32 parentAPD = PresContext()->AppUnitsPerDevPixel();
423 PRInt32 subdocAPD = presContext->AppUnitsPerDevPixel();
425 nsRect dirty;
426 if (subdocRootFrame) {
427 // get the dirty rect relative to the root frame of the subdoc
428 dirty = aDirtyRect + GetOffsetToCrossDoc(subdocRootFrame);
429 // and convert into the appunits of the subdoc
430 dirty = dirty.ConvertAppUnitsRoundOut(parentAPD, subdocAPD);
432 aBuilder->EnterPresShell(subdocRootFrame, dirty);
435 // The subdocView's bounds are in appunits of the subdocument, so adjust
436 // them.
437 nsRect subdocBoundsInParentUnits =
438 subdocView->GetBounds().ConvertAppUnitsRoundOut(subdocAPD, parentAPD);
440 // Get the bounds of subdocView relative to the reference frame.
441 subdocBoundsInParentUnits = subdocBoundsInParentUnits +
442 mInnerView->GetPosition() +
443 GetOffsetToCrossDoc(aBuilder->ReferenceFrame());
445 if (subdocRootFrame && NS_SUCCEEDED(rv)) {
446 rv = subdocRootFrame->
447 BuildDisplayListForStackingContext(aBuilder, dirty, &childItems);
450 if (!aBuilder->IsForEventDelivery()) {
451 // If we are going to use a displayzoom below then any items we put under
452 // it need to have underlying frames from the subdocument. So we need to
453 // calculate the bounds based on which frame will be the underlying frame
454 // for the canvas background color item.
455 nsRect bounds;
456 if (subdocRootFrame) {
457 nsPoint offset = mInnerView->GetPosition() +
458 GetOffsetToCrossDoc(aBuilder->ReferenceFrame());
459 offset = offset.ConvertAppUnits(parentAPD, subdocAPD);
460 bounds = subdocView->GetBounds() + offset;
461 } else {
462 bounds = subdocBoundsInParentUnits;
465 // If we are in print preview/page layout we want to paint the grey
466 // background behind the page, not the canvas color. The canvas color gets
467 // painted on the page itself.
468 if (nsLayoutUtils::NeedsPrintPreviewBackground(presContext)) {
469 rv = presShell->AddPrintPreviewBackgroundItem(
470 *aBuilder, childItems, subdocRootFrame ? subdocRootFrame : this,
471 bounds);
472 } else {
473 // Add the canvas background color to the bottom of the list. This
474 // happens after we've built the list so that AddCanvasBackgroundColorItem
475 // can monkey with the contents if necessary.
476 rv = presShell->AddCanvasBackgroundColorItem(
477 *aBuilder, childItems, subdocRootFrame ? subdocRootFrame : this,
478 bounds, NS_RGBA(0,0,0,0), PR_TRUE);
482 if (NS_SUCCEEDED(rv)) {
483 if (subdocRootFrame && parentAPD != subdocAPD) {
484 nsDisplayZoom* zoomItem =
485 new (aBuilder) nsDisplayZoom(subdocRootFrame, &childItems,
486 subdocAPD, parentAPD);
487 childItems.AppendToTop(zoomItem);
489 // Clip children to the child root frame's rectangle
490 rv = aLists.Content()->AppendNewToTop(
491 new (aBuilder) nsDisplayClip(this, this, &childItems,
492 subdocBoundsInParentUnits));
494 // delete childItems in case of OOM
495 childItems.DeleteAll();
497 if (subdocRootFrame) {
498 aBuilder->LeavePresShell(subdocRootFrame, dirty);
501 return rv;
504 nscoord
505 nsSubDocumentFrame::GetIntrinsicWidth()
507 if (!IsInline()) {
508 return 0; // HTML <frame> has no useful intrinsic width
511 if (mContent->IsXUL()) {
512 return 0; // XUL <iframe> and <browser> have no useful intrinsic width
515 NS_ASSERTION(ObtainIntrinsicSizeFrame() == nsnull,
516 "Intrinsic width should come from the embedded document.");
518 // We must be an HTML <iframe>. Default to a width of 300, for IE
519 // compat (and per CSS2.1 draft).
520 return nsPresContext::CSSPixelsToAppUnits(300);
523 nscoord
524 nsSubDocumentFrame::GetIntrinsicHeight()
526 // <frame> processing does not use this routine, only <iframe>
527 NS_ASSERTION(IsInline(), "Shouldn't have been called");
529 if (mContent->IsXUL()) {
530 return 0;
533 NS_ASSERTION(ObtainIntrinsicSizeFrame() == nsnull,
534 "Intrinsic height should come from the embedded document.");
536 // Use 150px, for compatibility with IE, and per CSS2.1 draft.
537 return nsPresContext::CSSPixelsToAppUnits(150);
540 #ifdef DEBUG
541 NS_IMETHODIMP nsSubDocumentFrame::GetFrameName(nsAString& aResult) const
543 return MakeFrameName(NS_LITERAL_STRING("FrameOuter"), aResult);
545 #endif
547 nsIAtom*
548 nsSubDocumentFrame::GetType() const
550 return nsGkAtoms::subDocumentFrame;
553 /* virtual */ nscoord
554 nsSubDocumentFrame::GetMinWidth(nsIRenderingContext *aRenderingContext)
556 nscoord result;
557 DISPLAY_MIN_WIDTH(this, result);
559 nsIFrame* subDocRoot = ObtainIntrinsicSizeFrame();
560 if (subDocRoot) {
561 result = subDocRoot->GetMinWidth(aRenderingContext);
562 } else {
563 result = GetIntrinsicWidth();
566 return result;
569 /* virtual */ nscoord
570 nsSubDocumentFrame::GetPrefWidth(nsIRenderingContext *aRenderingContext)
572 nscoord result;
573 DISPLAY_PREF_WIDTH(this, result);
575 nsIFrame* subDocRoot = ObtainIntrinsicSizeFrame();
576 if (subDocRoot) {
577 result = subDocRoot->GetPrefWidth(aRenderingContext);
578 } else {
579 result = GetIntrinsicWidth();
582 return result;
585 /* virtual */ nsIFrame::IntrinsicSize
586 nsSubDocumentFrame::GetIntrinsicSize()
588 nsIFrame* subDocRoot = ObtainIntrinsicSizeFrame();
589 if (subDocRoot) {
590 return subDocRoot->GetIntrinsicSize();
592 return nsLeafFrame::GetIntrinsicSize();
595 /* virtual */ nsSize
596 nsSubDocumentFrame::GetIntrinsicRatio()
598 nsIFrame* subDocRoot = ObtainIntrinsicSizeFrame();
599 if (subDocRoot) {
600 return subDocRoot->GetIntrinsicRatio();
602 return nsLeafFrame::GetIntrinsicRatio();
605 /* virtual */ nsSize
606 nsSubDocumentFrame::ComputeAutoSize(nsIRenderingContext *aRenderingContext,
607 nsSize aCBSize, nscoord aAvailableWidth,
608 nsSize aMargin, nsSize aBorder,
609 nsSize aPadding, PRBool aShrinkWrap)
611 if (!IsInline()) {
612 return nsFrame::ComputeAutoSize(aRenderingContext, aCBSize,
613 aAvailableWidth, aMargin, aBorder,
614 aPadding, aShrinkWrap);
617 return nsLeafFrame::ComputeAutoSize(aRenderingContext, aCBSize,
618 aAvailableWidth, aMargin, aBorder,
619 aPadding, aShrinkWrap);
623 /* virtual */ nsSize
624 nsSubDocumentFrame::ComputeSize(nsIRenderingContext *aRenderingContext,
625 nsSize aCBSize, nscoord aAvailableWidth,
626 nsSize aMargin, nsSize aBorder, nsSize aPadding,
627 PRBool aShrinkWrap)
629 nsIFrame* subDocRoot = ObtainIntrinsicSizeFrame();
630 if (subDocRoot) {
631 return nsLayoutUtils::ComputeSizeWithIntrinsicDimensions(
632 aRenderingContext, this,
633 subDocRoot->GetIntrinsicSize(),
634 subDocRoot->GetIntrinsicRatio(),
635 aCBSize, aMargin, aBorder, aPadding);
637 return nsLeafFrame::ComputeSize(aRenderingContext, aCBSize, aAvailableWidth,
638 aMargin, aBorder, aPadding, aShrinkWrap);
641 NS_IMETHODIMP
642 nsSubDocumentFrame::Reflow(nsPresContext* aPresContext,
643 nsHTMLReflowMetrics& aDesiredSize,
644 const nsHTMLReflowState& aReflowState,
645 nsReflowStatus& aStatus)
647 DO_GLOBAL_REFLOW_COUNT("nsSubDocumentFrame");
648 DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);
649 // printf("OuterFrame::Reflow %X (%d,%d) \n", this, aReflowState.availableWidth, aReflowState.availableHeight);
650 NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,
651 ("enter nsSubDocumentFrame::Reflow: maxSize=%d,%d",
652 aReflowState.availableWidth, aReflowState.availableHeight));
654 aStatus = NS_FRAME_COMPLETE;
656 NS_ASSERTION(mContent->GetPrimaryFrame() == this,
657 "Shouldn't happen");
659 // "offset" is the offset of our content area from our frame's
660 // top-left corner.
661 nsPoint offset(0, 0);
663 if (IsInline()) {
664 // XUL <iframe> or <browser>, or HTML <iframe>, <object> or <embed>
665 nsresult rv = nsLeafFrame::DoReflow(aPresContext, aDesiredSize, aReflowState,
666 aStatus);
667 NS_ENSURE_SUCCESS(rv, rv);
669 offset = nsPoint(aReflowState.mComputedBorderPadding.left,
670 aReflowState.mComputedBorderPadding.top);
671 } else {
672 // HTML <frame>
673 SizeToAvailSize(aReflowState, aDesiredSize);
676 nsSize innerSize(aDesiredSize.width, aDesiredSize.height);
677 if (IsInline()) {
678 innerSize.width -= aReflowState.mComputedBorderPadding.LeftRight();
679 innerSize.height -= aReflowState.mComputedBorderPadding.TopBottom();
682 if (mInnerView) {
683 nsIViewManager* vm = mInnerView->GetViewManager();
684 vm->MoveViewTo(mInnerView, offset.x, offset.y);
685 vm->ResizeView(mInnerView, nsRect(nsPoint(0, 0), innerSize), PR_TRUE);
688 // Determine if we need to repaint our border, background or outline
689 CheckInvalidateSizeChange(aDesiredSize);
691 FinishAndStoreOverflow(&aDesiredSize);
693 // Invalidate the frame contents
694 // XXX is this really needed?
695 nsRect rect(nsPoint(0, 0), GetSize());
696 Invalidate(rect);
698 if (!aPresContext->IsPaginated() && !mPostedReflowCallback) {
699 PresContext()->PresShell()->PostReflowCallback(this);
700 mPostedReflowCallback = PR_TRUE;
703 // printf("OuterFrame::Reflow DONE %X (%d,%d)\n", this,
704 // aDesiredSize.width, aDesiredSize.height);
706 NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,
707 ("exit nsSubDocumentFrame::Reflow: size=%d,%d status=%x",
708 aDesiredSize.width, aDesiredSize.height, aStatus));
710 NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
711 return NS_OK;
714 PRBool
715 nsSubDocumentFrame::ReflowFinished()
717 if (mFrameLoader) {
718 nsWeakFrame weakFrame(this);
720 mFrameLoader->UpdatePositionAndSize(this);
722 if (weakFrame.IsAlive()) {
723 // Make sure that we can post a reflow callback in the future.
724 mPostedReflowCallback = PR_FALSE;
727 return PR_FALSE;
730 void
731 nsSubDocumentFrame::ReflowCallbackCanceled()
733 mPostedReflowCallback = PR_FALSE;
736 NS_IMETHODIMP
737 nsSubDocumentFrame::AttributeChanged(PRInt32 aNameSpaceID,
738 nsIAtom* aAttribute,
739 PRInt32 aModType)
741 if (aNameSpaceID != kNameSpaceID_None) {
742 return NS_OK;
745 // If the noResize attribute changes, dis/allow frame to be resized
746 if (aAttribute == nsGkAtoms::noresize) {
747 // Note that we're not doing content type checks, but that's ok -- if
748 // they'd fail we will just end up with a null framesetFrame.
749 if (mContent->GetParent()->Tag() == nsGkAtoms::frameset) {
750 nsIFrame* parentFrame = GetParent();
752 if (parentFrame) {
753 // There is no interface for nsHTMLFramesetFrame so QI'ing to
754 // concrete class, yay!
755 nsHTMLFramesetFrame* framesetFrame = do_QueryFrame(parentFrame);
756 if (framesetFrame) {
757 framesetFrame->RecalculateBorderResize();
762 else if (aAttribute == nsGkAtoms::type) {
763 if (!mFrameLoader)
764 return NS_OK;
766 if (!mContent->IsXUL()) {
767 return NS_OK;
770 // Note: This logic duplicates a lot of logic in
771 // nsFrameLoader::EnsureDocShell. We should fix that.
773 // Notify our enclosing chrome that our type has changed. We only do this
774 // if our parent is chrome, since in all other cases we're random content
775 // subframes and the treeowner shouldn't worry about us.
777 nsCOMPtr<nsIDocShell> docShell;
778 mFrameLoader->GetDocShell(getter_AddRefs(docShell));
779 nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryInterface(docShell));
780 if (!docShellAsItem) {
781 return NS_OK;
784 nsCOMPtr<nsIDocShellTreeItem> parentItem;
785 docShellAsItem->GetParent(getter_AddRefs(parentItem));
787 PRInt32 parentType;
788 parentItem->GetItemType(&parentType);
790 if (parentType != nsIDocShellTreeItem::typeChrome) {
791 return NS_OK;
794 nsCOMPtr<nsIDocShellTreeOwner> parentTreeOwner;
795 parentItem->GetTreeOwner(getter_AddRefs(parentTreeOwner));
796 if (parentTreeOwner) {
797 nsAutoString value;
798 mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::type, value);
800 PRBool is_primary = value.LowerCaseEqualsLiteral("content-primary");
802 #ifdef MOZ_XUL
803 // when a content panel is no longer primary, hide any open popups it may have
804 if (!is_primary) {
805 nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
806 if (pm)
807 pm->HidePopupsInDocShell(docShellAsItem);
809 #endif
811 parentTreeOwner->ContentShellRemoved(docShellAsItem);
813 if (value.LowerCaseEqualsLiteral("content") ||
814 StringBeginsWith(value, NS_LITERAL_STRING("content-"),
815 nsCaseInsensitiveStringComparator())) {
816 PRBool is_targetable = is_primary ||
817 value.LowerCaseEqualsLiteral("content-targetable");
819 parentTreeOwner->ContentShellAdded(docShellAsItem, is_primary,
820 is_targetable, value);
825 return NS_OK;
828 nsIFrame*
829 NS_NewSubDocumentFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
831 return new (aPresShell) nsSubDocumentFrame(aContext);
834 NS_IMPL_FRAMEARENA_HELPERS(nsSubDocumentFrame)
836 void
837 nsSubDocumentFrame::DestroyFrom(nsIFrame* aDestructRoot)
839 if (mPostedReflowCallback) {
840 PresContext()->PresShell()->CancelReflowCallback(this);
841 mPostedReflowCallback = PR_FALSE;
844 HideViewer();
846 nsLeafFrame::DestroyFrom(aDestructRoot);
849 void
850 nsSubDocumentFrame::HideViewer()
852 if (mFrameLoader && (mDidCreateDoc || mCallingShow))
853 mFrameLoader->Hide();
856 nsIntSize
857 nsSubDocumentFrame::GetMarginAttributes()
859 nsIntSize result(-1, -1);
860 nsGenericHTMLElement *content = nsGenericHTMLElement::FromContent(mContent);
861 if (content) {
862 const nsAttrValue* attr = content->GetParsedAttr(nsGkAtoms::marginwidth);
863 if (attr && attr->Type() == nsAttrValue::eInteger)
864 result.width = attr->GetIntegerValue();
865 attr = content->GetParsedAttr(nsGkAtoms::marginheight);
866 if (attr && attr->Type() == nsAttrValue::eInteger)
867 result.height = attr->GetIntegerValue();
869 return result;
872 nsFrameLoader*
873 nsSubDocumentFrame::FrameLoader()
875 nsIContent* content = GetContent();
876 if (!content)
877 return nsnull;
879 if (!mFrameLoader) {
880 nsCOMPtr<nsIFrameLoaderOwner> loaderOwner = do_QueryInterface(content);
881 if (loaderOwner) {
882 nsCOMPtr<nsIFrameLoader> loader;
883 loaderOwner->GetFrameLoader(getter_AddRefs(loader));
884 mFrameLoader = static_cast<nsFrameLoader*>(loader.get());
887 return mFrameLoader;
890 // XXX this should be called ObtainDocShell or something like that,
891 // to indicate that it could have side effects
892 NS_IMETHODIMP
893 nsSubDocumentFrame::GetDocShell(nsIDocShell **aDocShell)
895 *aDocShell = nsnull;
897 NS_ENSURE_STATE(FrameLoader());
898 return mFrameLoader->GetDocShell(aDocShell);
901 NS_IMETHODIMP
902 nsSubDocumentFrame::BeginSwapDocShells(nsIFrame* aOther)
904 if (!aOther || aOther->GetType() != nsGkAtoms::subDocumentFrame) {
905 return NS_ERROR_NOT_IMPLEMENTED;
908 nsSubDocumentFrame* other = static_cast<nsSubDocumentFrame*>(aOther);
909 if (!mFrameLoader || !mDidCreateDoc || mCallingShow ||
910 !other->mFrameLoader || !other->mDidCreateDoc) {
911 return NS_ERROR_NOT_IMPLEMENTED;
914 HideViewer();
915 other->HideViewer();
917 mFrameLoader.swap(other->mFrameLoader);
918 return NS_OK;
921 void
922 nsSubDocumentFrame::EndSwapDocShells(nsIFrame* aOther)
924 nsSubDocumentFrame* other = static_cast<nsSubDocumentFrame*>(aOther);
925 nsWeakFrame weakThis(this);
926 nsWeakFrame weakOther(aOther);
927 ShowViewer();
928 other->ShowViewer();
930 // Now make sure we reflow both frames, in case their contents
931 // determine their size.
932 // And repaint them, for good measure, in case there's nothing
933 // interesting that happens during reflow.
934 if (weakThis.IsAlive()) {
935 PresContext()->PresShell()->
936 FrameNeedsReflow(this, nsIPresShell::eTreeChange, NS_FRAME_IS_DIRTY);
937 InvalidateOverflowRect();
939 if (weakOther.IsAlive()) {
940 other->PresContext()->PresShell()->
941 FrameNeedsReflow(other, nsIPresShell::eTreeChange, NS_FRAME_IS_DIRTY);
942 other->InvalidateOverflowRect();
946 nsIView*
947 nsSubDocumentFrame::CreateViewAndWidget(nsContentType aContentType)
949 if (mInnerView) {
950 // Nothing to do here
951 return mInnerView;
954 // create, init, set the parent of the view
955 nsIView* outerView = GetView();
956 NS_ASSERTION(outerView, "Must have an outer view already");
957 nsRect viewBounds(0, 0, 0, 0); // size will be fixed during reflow
959 nsIViewManager* viewMan = outerView->GetViewManager();
960 nsIView* innerView = viewMan->CreateView(viewBounds, outerView);
961 if (!innerView) {
962 NS_ERROR("Could not create inner view");
963 return nsnull;
965 mInnerView = innerView;
966 viewMan->InsertChild(outerView, innerView, nsnull, PR_TRUE);
968 if (aContentType != eContentTypeContentFrame) {
969 // widget needed.
970 nsresult rv = innerView->CreateWidget(kCChildCID, nsnull, nsnull,
971 PR_TRUE, PR_TRUE, aContentType);
972 if (NS_FAILED(rv)) {
973 NS_WARNING("Couldn't create widget for frame.");
974 mInnerView = nsnull;
977 return mInnerView;
980 nsIFrame*
981 nsSubDocumentFrame::ObtainIntrinsicSizeFrame()
983 nsCOMPtr<nsIObjectLoadingContent> olc = do_QueryInterface(GetContent());
984 if (olc) {
985 // We are an HTML <object>, <embed> or <applet> (a replaced element).
987 // Try to get an nsIFrame for our sub-document's document element
988 nsIFrame* subDocRoot = nsnull;
990 nsCOMPtr<nsIDocShell> docShell;
991 GetDocShell(getter_AddRefs(docShell));
992 if (docShell) {
993 nsCOMPtr<nsIPresShell> presShell;
994 docShell->GetPresShell(getter_AddRefs(presShell));
995 if (presShell) {
996 nsIScrollableFrame* scrollable = presShell->GetRootScrollFrameAsScrollable();
997 if (scrollable) {
998 nsIFrame* scrolled = scrollable->GetScrolledFrame();
999 if (scrolled) {
1000 subDocRoot = scrolled->GetFirstChild(nsnull);
1006 #ifdef MOZ_SVG
1007 if (subDocRoot && subDocRoot->GetContent() &&
1008 subDocRoot->GetContent()->NodeInfo()->Equals(nsGkAtoms::svg, kNameSpaceID_SVG)) {
1009 return subDocRoot; // SVG documents have an intrinsic size
1011 #endif
1013 return nsnull;