Bug 575870 - Enable the firefox button on xp themed, classic, and aero basic. r=dao...
[mozilla-central.git] / layout / generic / nsFrameFrame.cpp
blob1e0a92b51f70b648a0cb2ee62566de53631e16a5
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 /******************************************************************************
108 * nsSubDocumentFrame
109 *****************************************************************************/
110 class nsSubDocumentFrame : public nsLeafFrame,
111 public nsIFrameFrame,
112 public nsIReflowCallback
114 public:
115 NS_DECL_FRAMEARENA_HELPERS
117 nsSubDocumentFrame(nsStyleContext* aContext);
119 #ifdef DEBUG
120 NS_IMETHOD GetFrameName(nsAString& aResult) const;
121 #endif
123 NS_DECL_QUERYFRAME
125 virtual nsIAtom* GetType() const;
127 virtual PRBool IsFrameOfType(PRUint32 aFlags) const
129 // nsLeafFrame is already eReplacedContainsBlock, but that's somewhat bogus
130 return nsLeafFrame::IsFrameOfType(aFlags &
131 ~(nsIFrame::eReplaced | nsIFrame::eReplacedContainsBlock));
134 NS_IMETHOD Init(nsIContent* aContent,
135 nsIFrame* aParent,
136 nsIFrame* aPrevInFlow);
138 virtual void DestroyFrom(nsIFrame* aDestructRoot);
140 virtual nscoord GetMinWidth(nsIRenderingContext *aRenderingContext);
141 virtual nscoord GetPrefWidth(nsIRenderingContext *aRenderingContext);
143 virtual IntrinsicSize GetIntrinsicSize();
144 virtual nsSize GetIntrinsicRatio();
146 virtual nsSize ComputeAutoSize(nsIRenderingContext *aRenderingContext,
147 nsSize aCBSize, nscoord aAvailableWidth,
148 nsSize aMargin, nsSize aBorder,
149 nsSize aPadding, PRBool aShrinkWrap);
151 virtual nsSize ComputeSize(nsIRenderingContext *aRenderingContext,
152 nsSize aCBSize, nscoord aAvailableWidth,
153 nsSize aMargin, nsSize aBorder, nsSize aPadding,
154 PRBool aShrinkWrap);
156 NS_IMETHOD Reflow(nsPresContext* aPresContext,
157 nsHTMLReflowMetrics& aDesiredSize,
158 const nsHTMLReflowState& aReflowState,
159 nsReflowStatus& aStatus);
161 NS_IMETHOD BuildDisplayList(nsDisplayListBuilder* aBuilder,
162 const nsRect& aDirtyRect,
163 const nsDisplayListSet& aLists);
165 NS_IMETHOD AttributeChanged(PRInt32 aNameSpaceID,
166 nsIAtom* aAttribute,
167 PRInt32 aModType);
169 // if the content is "visibility:hidden", then just hide the view
170 // and all our contents. We don't extend "visibility:hidden" to
171 // the child content ourselves, since it belongs to a different
172 // document and CSS doesn't inherit in there.
173 virtual PRBool SupportsVisibilityHidden() { return PR_FALSE; }
175 #ifdef ACCESSIBILITY
176 virtual already_AddRefed<nsAccessible> CreateAccessible();
177 #endif
179 // nsIFrameFrame
180 NS_IMETHOD GetDocShell(nsIDocShell **aDocShell);
181 NS_IMETHOD BeginSwapDocShells(nsIFrame* aOther);
182 virtual void EndSwapDocShells(nsIFrame* aOther);
183 virtual nsIFrame* GetFrame() { return this; }
185 // nsIReflowCallback
186 virtual PRBool ReflowFinished();
187 virtual void ReflowCallbackCanceled();
189 protected:
190 friend class AsyncFrameInit;
192 // Helper method to look up the HTML marginwidth & marginheight attributes
193 nsIntSize GetMarginAttributes();
195 nsFrameLoader* FrameLoader();
197 PRBool IsInline() { return mIsInline; }
198 nsIView* CreateViewAndWidget(nsContentType aContentType);
200 virtual nscoord GetIntrinsicWidth();
201 virtual nscoord GetIntrinsicHeight();
203 virtual PRIntn GetSkipSides() const;
205 // Hide or show our document viewer
206 void HideViewer();
207 void ShowViewer();
209 /* Obtains the frame we should use for intrinsic size information if we are
210 * an HTML <object>, <embed> or <applet> (a replaced element - not <iframe>)
211 * and our sub-document has an intrinsic size. The frame returned is the
212 * frame for the document element of the document we're embedding.
214 * Called "Obtain*" and not "Get*" because of comment on GetDocShell that
215 * says it should be called ObtainDocShell because of it's side effects.
217 nsIFrame* ObtainIntrinsicSizeFrame();
219 nsRefPtr<nsFrameLoader> mFrameLoader;
220 nsIView* mInnerView;
221 PRPackedBool mIsInline;
222 PRPackedBool mPostedReflowCallback;
223 PRPackedBool mDidCreateDoc;
224 PRPackedBool mCallingShow;
227 nsSubDocumentFrame::nsSubDocumentFrame(nsStyleContext* aContext)
228 : nsLeafFrame(aContext)
229 , mIsInline(PR_FALSE)
230 , mPostedReflowCallback(PR_FALSE)
231 , mDidCreateDoc(PR_FALSE)
232 , mCallingShow(PR_FALSE)
236 #ifdef ACCESSIBILITY
237 already_AddRefed<nsAccessible>
238 nsSubDocumentFrame::CreateAccessible()
240 nsCOMPtr<nsIAccessibilityService> accService = do_GetService("@mozilla.org/accessibilityService;1");
241 return accService ?
242 accService->CreateOuterDocAccessible(mContent, PresContext()->PresShell()) :
243 nsnull;
245 #endif
247 NS_QUERYFRAME_HEAD(nsSubDocumentFrame)
248 NS_QUERYFRAME_ENTRY(nsIFrameFrame)
249 NS_QUERYFRAME_TAIL_INHERITING(nsLeafFrame)
251 class AsyncFrameInit : public nsRunnable
253 public:
254 AsyncFrameInit(nsIFrame* aFrame) : mFrame(aFrame) {}
255 NS_IMETHOD Run()
257 if (mFrame.IsAlive()) {
258 static_cast<nsSubDocumentFrame*>(mFrame.GetFrame())->ShowViewer();
260 return NS_OK;
262 private:
263 nsWeakFrame mFrame;
266 NS_IMETHODIMP
267 nsSubDocumentFrame::Init(nsIContent* aContent,
268 nsIFrame* aParent,
269 nsIFrame* aPrevInFlow)
271 // determine if we are a <frame> or <iframe>
272 if (aContent) {
273 nsCOMPtr<nsIDOMHTMLFrameElement> frameElem = do_QueryInterface(aContent);
274 mIsInline = frameElem ? PR_FALSE : PR_TRUE;
277 nsresult rv = nsLeafFrame::Init(aContent, aParent, aPrevInFlow);
278 if (NS_FAILED(rv))
279 return rv;
281 // We are going to create an inner view. If we need a view for the
282 // OuterFrame but we wait for the normal view creation path in
283 // nsCSSFrameConstructor, then we will lose because the inner view's
284 // parent will already have been set to some outer view (e.g., the
285 // canvas) when it really needs to have this frame's view as its
286 // parent. So, create this frame's view right away, whether we
287 // really need it or not, and the inner view will get it as the
288 // parent.
289 if (!HasView()) {
290 rv = nsHTMLContainerFrame::CreateViewForFrame(this, PR_TRUE);
291 NS_ENSURE_SUCCESS(rv, rv);
293 nsIView* view = GetView();
295 // Set the primary frame now so that
296 // DocumentViewerImpl::FindContainerView called by ShowViewer below
297 // can find it if necessary.
298 aContent->SetPrimaryFrame(this);
300 nsContentUtils::AddScriptRunner(new AsyncFrameInit(this));
301 return NS_OK;
304 inline PRInt32 ConvertOverflow(PRUint8 aOverflow)
306 switch (aOverflow) {
307 case NS_STYLE_OVERFLOW_VISIBLE:
308 case NS_STYLE_OVERFLOW_AUTO:
309 return nsIScrollable::Scrollbar_Auto;
310 case NS_STYLE_OVERFLOW_HIDDEN:
311 case NS_STYLE_OVERFLOW_CLIP:
312 return nsIScrollable::Scrollbar_Never;
313 case NS_STYLE_OVERFLOW_SCROLL:
314 return nsIScrollable::Scrollbar_Always;
316 NS_NOTREACHED("invalid overflow value passed to ConvertOverflow");
317 return nsIScrollable::Scrollbar_Auto;
320 void
321 nsSubDocumentFrame::ShowViewer()
323 if (mCallingShow) {
324 return;
327 if (!PresContext()->IsDynamic()) {
328 // We let the printing code take care of loading the document; just
329 // create a widget for it to use
330 (void) CreateViewAndWidget(eContentTypeContent);
331 } else {
332 nsRefPtr<nsFrameLoader> frameloader = FrameLoader();
333 if (frameloader) {
334 nsIntSize margin = GetMarginAttributes();
335 const nsStyleDisplay* disp = GetStyleDisplay();
336 nsWeakFrame weakThis(this);
337 mCallingShow = PR_TRUE;
338 PRBool didCreateDoc =
339 frameloader->Show(margin.width, margin.height,
340 ConvertOverflow(disp->mOverflowX),
341 ConvertOverflow(disp->mOverflowY),
342 this);
343 if (!weakThis.IsAlive()) {
344 return;
346 mCallingShow = PR_FALSE;
347 mDidCreateDoc = didCreateDoc;
352 PRIntn
353 nsSubDocumentFrame::GetSkipSides() const
355 return 0;
358 NS_IMETHODIMP
359 nsSubDocumentFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
360 const nsRect& aDirtyRect,
361 const nsDisplayListSet& aLists)
363 if (!IsVisibleForPainting(aBuilder))
364 return NS_OK;
366 if (aBuilder->IsForEventDelivery() &&
367 GetStyleVisibility()->mPointerEvents == NS_STYLE_POINTER_EVENTS_NONE)
368 return NS_OK;
370 nsresult rv = DisplayBorderBackgroundOutline(aBuilder, aLists);
371 NS_ENSURE_SUCCESS(rv, rv);
373 if (!mInnerView)
374 return NS_OK;
375 nsIView* subdocView = mInnerView->GetFirstChild();
376 if (!subdocView)
377 return NS_OK;
379 nsCOMPtr<nsIPresShell> presShell;
381 nsIFrame* subdocRootFrame =
382 static_cast<nsIFrame*>(subdocView->GetClientData());
384 if (subdocRootFrame) {
385 presShell = subdocRootFrame->PresContext()->PresShell();
386 } else {
387 // During page transition mInnerView will sometimes have two children, the
388 // first being the new page that may not have any frame, and the second
389 // being the old page that will probably have a frame.
390 nsIView* nextView = subdocView->GetNextSibling();
391 if (nextView) {
392 subdocRootFrame = static_cast<nsIFrame*>(nextView->GetClientData());
394 if (subdocRootFrame) {
395 subdocView = nextView;
396 presShell = subdocRootFrame->PresContext()->PresShell();
397 } else {
398 // If we don't have a frame we use this roundabout way to get the pres shell.
399 if (!mFrameLoader)
400 return NS_OK;
401 nsCOMPtr<nsIDocShell> docShell;
402 mFrameLoader->GetDocShell(getter_AddRefs(docShell));
403 if (!docShell)
404 return NS_OK;
405 docShell->GetPresShell(getter_AddRefs(presShell));
406 if (!presShell)
407 return NS_OK;
411 nsPresContext* presContext = presShell->GetPresContext();
413 nsDisplayList childItems;
415 PRInt32 parentAPD = PresContext()->AppUnitsPerDevPixel();
416 PRInt32 subdocAPD = presContext->AppUnitsPerDevPixel();
418 nsRect dirty;
419 if (subdocRootFrame) {
420 // get the dirty rect relative to the root frame of the subdoc
421 dirty = aDirtyRect + GetOffsetToCrossDoc(subdocRootFrame);
422 // and convert into the appunits of the subdoc
423 dirty = dirty.ConvertAppUnitsRoundOut(parentAPD, subdocAPD);
425 aBuilder->EnterPresShell(subdocRootFrame, dirty);
428 // The subdocView's bounds are in appunits of the subdocument, so adjust
429 // them.
430 nsRect subdocBoundsInParentUnits =
431 subdocView->GetBounds().ConvertAppUnitsRoundOut(subdocAPD, parentAPD);
433 // Get the bounds of subdocView relative to the reference frame.
434 subdocBoundsInParentUnits = subdocBoundsInParentUnits +
435 mInnerView->GetPosition() +
436 GetOffsetToCrossDoc(aBuilder->ReferenceFrame());
438 if (subdocRootFrame && NS_SUCCEEDED(rv)) {
439 rv = subdocRootFrame->
440 BuildDisplayListForStackingContext(aBuilder, dirty, &childItems);
443 if (!aBuilder->IsForEventDelivery()) {
444 // If we are going to use a displayzoom below then any items we put under
445 // it need to have underlying frames from the subdocument. So we need to
446 // calculate the bounds based on which frame will be the underlying frame
447 // for the canvas background color item.
448 nsRect bounds;
449 if (subdocRootFrame) {
450 nsPoint offset = mInnerView->GetPosition() +
451 GetOffsetToCrossDoc(aBuilder->ReferenceFrame());
452 offset = offset.ConvertAppUnits(parentAPD, subdocAPD);
453 bounds = subdocView->GetBounds() + offset;
454 } else {
455 bounds = subdocBoundsInParentUnits;
458 // If we are in print preview/page layout we want to paint the grey
459 // background behind the page, not the canvas color. The canvas color gets
460 // painted on the page itself.
461 if (nsLayoutUtils::NeedsPrintPreviewBackground(presContext)) {
462 rv = presShell->AddPrintPreviewBackgroundItem(
463 *aBuilder, childItems, subdocRootFrame ? subdocRootFrame : this,
464 bounds);
465 } else {
466 // Add the canvas background color to the bottom of the list. This
467 // happens after we've built the list so that AddCanvasBackgroundColorItem
468 // can monkey with the contents if necessary.
469 rv = presShell->AddCanvasBackgroundColorItem(
470 *aBuilder, childItems, subdocRootFrame ? subdocRootFrame : this,
471 bounds, NS_RGBA(0,0,0,0), PR_TRUE);
475 if (NS_SUCCEEDED(rv)) {
476 if (subdocRootFrame && parentAPD != subdocAPD) {
477 nsDisplayZoom* zoomItem =
478 new (aBuilder) nsDisplayZoom(aBuilder, subdocRootFrame, &childItems,
479 subdocAPD, parentAPD);
480 childItems.AppendToTop(zoomItem);
481 } else if (!nsContentUtils::IsChildOfSameType(presShell->GetDocument())) {
482 // We always want top level content documents to be in their own layer.
483 // If we need a zoom item then we are good because it creates a layer. If
484 // not then create our own layer.
485 nsDisplayOwnLayer* layerItem = new (aBuilder) nsDisplayOwnLayer(
486 aBuilder, subdocRootFrame ? subdocRootFrame : this, &childItems);
487 childItems.AppendToTop(layerItem);
490 // Clip children to the child root frame's rectangle
491 rv = aLists.Content()->AppendNewToTop(
492 new (aBuilder) nsDisplayClip(aBuilder, this, this, &childItems,
493 subdocBoundsInParentUnits));
495 // delete childItems in case of OOM
496 childItems.DeleteAll();
498 if (subdocRootFrame) {
499 aBuilder->LeavePresShell(subdocRootFrame, dirty);
502 return rv;
505 nscoord
506 nsSubDocumentFrame::GetIntrinsicWidth()
508 if (!IsInline()) {
509 return 0; // HTML <frame> has no useful intrinsic width
512 if (mContent->IsXUL()) {
513 return 0; // XUL <iframe> and <browser> have no useful intrinsic width
516 NS_ASSERTION(ObtainIntrinsicSizeFrame() == nsnull,
517 "Intrinsic width should come from the embedded document.");
519 // We must be an HTML <iframe>. Default to a width of 300, for IE
520 // compat (and per CSS2.1 draft).
521 return nsPresContext::CSSPixelsToAppUnits(300);
524 nscoord
525 nsSubDocumentFrame::GetIntrinsicHeight()
527 // <frame> processing does not use this routine, only <iframe>
528 NS_ASSERTION(IsInline(), "Shouldn't have been called");
530 if (mContent->IsXUL()) {
531 return 0;
534 NS_ASSERTION(ObtainIntrinsicSizeFrame() == nsnull,
535 "Intrinsic height should come from the embedded document.");
537 // Use 150px, for compatibility with IE, and per CSS2.1 draft.
538 return nsPresContext::CSSPixelsToAppUnits(150);
541 #ifdef DEBUG
542 NS_IMETHODIMP nsSubDocumentFrame::GetFrameName(nsAString& aResult) const
544 return MakeFrameName(NS_LITERAL_STRING("FrameOuter"), aResult);
546 #endif
548 nsIAtom*
549 nsSubDocumentFrame::GetType() const
551 return nsGkAtoms::subDocumentFrame;
554 /* virtual */ nscoord
555 nsSubDocumentFrame::GetMinWidth(nsIRenderingContext *aRenderingContext)
557 nscoord result;
558 DISPLAY_MIN_WIDTH(this, result);
560 nsIFrame* subDocRoot = ObtainIntrinsicSizeFrame();
561 if (subDocRoot) {
562 result = subDocRoot->GetMinWidth(aRenderingContext);
563 } else {
564 result = GetIntrinsicWidth();
567 return result;
570 /* virtual */ nscoord
571 nsSubDocumentFrame::GetPrefWidth(nsIRenderingContext *aRenderingContext)
573 nscoord result;
574 DISPLAY_PREF_WIDTH(this, result);
576 nsIFrame* subDocRoot = ObtainIntrinsicSizeFrame();
577 if (subDocRoot) {
578 result = subDocRoot->GetPrefWidth(aRenderingContext);
579 } else {
580 result = GetIntrinsicWidth();
583 return result;
586 /* virtual */ nsIFrame::IntrinsicSize
587 nsSubDocumentFrame::GetIntrinsicSize()
589 nsIFrame* subDocRoot = ObtainIntrinsicSizeFrame();
590 if (subDocRoot) {
591 return subDocRoot->GetIntrinsicSize();
593 return nsLeafFrame::GetIntrinsicSize();
596 /* virtual */ nsSize
597 nsSubDocumentFrame::GetIntrinsicRatio()
599 nsIFrame* subDocRoot = ObtainIntrinsicSizeFrame();
600 if (subDocRoot) {
601 return subDocRoot->GetIntrinsicRatio();
603 return nsLeafFrame::GetIntrinsicRatio();
606 /* virtual */ nsSize
607 nsSubDocumentFrame::ComputeAutoSize(nsIRenderingContext *aRenderingContext,
608 nsSize aCBSize, nscoord aAvailableWidth,
609 nsSize aMargin, nsSize aBorder,
610 nsSize aPadding, PRBool aShrinkWrap)
612 if (!IsInline()) {
613 return nsFrame::ComputeAutoSize(aRenderingContext, aCBSize,
614 aAvailableWidth, aMargin, aBorder,
615 aPadding, aShrinkWrap);
618 return nsLeafFrame::ComputeAutoSize(aRenderingContext, aCBSize,
619 aAvailableWidth, aMargin, aBorder,
620 aPadding, aShrinkWrap);
624 /* virtual */ nsSize
625 nsSubDocumentFrame::ComputeSize(nsIRenderingContext *aRenderingContext,
626 nsSize aCBSize, nscoord aAvailableWidth,
627 nsSize aMargin, nsSize aBorder, nsSize aPadding,
628 PRBool aShrinkWrap)
630 nsIFrame* subDocRoot = ObtainIntrinsicSizeFrame();
631 if (subDocRoot) {
632 return nsLayoutUtils::ComputeSizeWithIntrinsicDimensions(
633 aRenderingContext, this,
634 subDocRoot->GetIntrinsicSize(),
635 subDocRoot->GetIntrinsicRatio(),
636 aCBSize, aMargin, aBorder, aPadding);
638 return nsLeafFrame::ComputeSize(aRenderingContext, aCBSize, aAvailableWidth,
639 aMargin, aBorder, aPadding, aShrinkWrap);
642 NS_IMETHODIMP
643 nsSubDocumentFrame::Reflow(nsPresContext* aPresContext,
644 nsHTMLReflowMetrics& aDesiredSize,
645 const nsHTMLReflowState& aReflowState,
646 nsReflowStatus& aStatus)
648 DO_GLOBAL_REFLOW_COUNT("nsSubDocumentFrame");
649 DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);
650 // printf("OuterFrame::Reflow %X (%d,%d) \n", this, aReflowState.availableWidth, aReflowState.availableHeight);
651 NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,
652 ("enter nsSubDocumentFrame::Reflow: maxSize=%d,%d",
653 aReflowState.availableWidth, aReflowState.availableHeight));
655 aStatus = NS_FRAME_COMPLETE;
657 NS_ASSERTION(mContent->GetPrimaryFrame() == this,
658 "Shouldn't happen");
660 // "offset" is the offset of our content area from our frame's
661 // top-left corner.
662 nsPoint offset(0, 0);
664 if (IsInline()) {
665 // XUL <iframe> or <browser>, or HTML <iframe>, <object> or <embed>
666 nsresult rv = nsLeafFrame::DoReflow(aPresContext, aDesiredSize, aReflowState,
667 aStatus);
668 NS_ENSURE_SUCCESS(rv, rv);
670 offset = nsPoint(aReflowState.mComputedBorderPadding.left,
671 aReflowState.mComputedBorderPadding.top);
672 } else {
673 // HTML <frame>
674 SizeToAvailSize(aReflowState, aDesiredSize);
677 nsSize innerSize(aDesiredSize.width, aDesiredSize.height);
678 if (IsInline()) {
679 innerSize.width -= aReflowState.mComputedBorderPadding.LeftRight();
680 innerSize.height -= aReflowState.mComputedBorderPadding.TopBottom();
683 if (mInnerView) {
684 nsIViewManager* vm = mInnerView->GetViewManager();
685 vm->MoveViewTo(mInnerView, offset.x, offset.y);
686 vm->ResizeView(mInnerView, nsRect(nsPoint(0, 0), innerSize), PR_TRUE);
689 // Determine if we need to repaint our border, background or outline
690 CheckInvalidateSizeChange(aDesiredSize);
692 FinishAndStoreOverflow(&aDesiredSize);
694 // Invalidate the frame contents
695 // XXX is this really needed?
696 nsRect rect(nsPoint(0, 0), GetSize());
697 Invalidate(rect);
699 if (!aPresContext->IsPaginated() && !mPostedReflowCallback) {
700 PresContext()->PresShell()->PostReflowCallback(this);
701 mPostedReflowCallback = PR_TRUE;
704 // printf("OuterFrame::Reflow DONE %X (%d,%d)\n", this,
705 // aDesiredSize.width, aDesiredSize.height);
707 NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,
708 ("exit nsSubDocumentFrame::Reflow: size=%d,%d status=%x",
709 aDesiredSize.width, aDesiredSize.height, aStatus));
711 NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
712 return NS_OK;
715 PRBool
716 nsSubDocumentFrame::ReflowFinished()
718 if (mFrameLoader) {
719 nsWeakFrame weakFrame(this);
721 mFrameLoader->UpdatePositionAndSize(this);
723 if (weakFrame.IsAlive()) {
724 // Make sure that we can post a reflow callback in the future.
725 mPostedReflowCallback = PR_FALSE;
728 return PR_FALSE;
731 void
732 nsSubDocumentFrame::ReflowCallbackCanceled()
734 mPostedReflowCallback = PR_FALSE;
737 NS_IMETHODIMP
738 nsSubDocumentFrame::AttributeChanged(PRInt32 aNameSpaceID,
739 nsIAtom* aAttribute,
740 PRInt32 aModType)
742 if (aNameSpaceID != kNameSpaceID_None) {
743 return NS_OK;
746 // If the noResize attribute changes, dis/allow frame to be resized
747 if (aAttribute == nsGkAtoms::noresize) {
748 // Note that we're not doing content type checks, but that's ok -- if
749 // they'd fail we will just end up with a null framesetFrame.
750 if (mContent->GetParent()->Tag() == nsGkAtoms::frameset) {
751 nsIFrame* parentFrame = GetParent();
753 if (parentFrame) {
754 // There is no interface for nsHTMLFramesetFrame so QI'ing to
755 // concrete class, yay!
756 nsHTMLFramesetFrame* framesetFrame = do_QueryFrame(parentFrame);
757 if (framesetFrame) {
758 framesetFrame->RecalculateBorderResize();
763 else if (aAttribute == nsGkAtoms::type) {
764 if (!mFrameLoader)
765 return NS_OK;
767 if (!mContent->IsXUL()) {
768 return NS_OK;
771 // Note: This logic duplicates a lot of logic in
772 // nsFrameLoader::EnsureDocShell. We should fix that.
774 // Notify our enclosing chrome that our type has changed. We only do this
775 // if our parent is chrome, since in all other cases we're random content
776 // subframes and the treeowner shouldn't worry about us.
778 nsCOMPtr<nsIDocShell> docShell;
779 mFrameLoader->GetDocShell(getter_AddRefs(docShell));
780 nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryInterface(docShell));
781 if (!docShellAsItem) {
782 return NS_OK;
785 nsCOMPtr<nsIDocShellTreeItem> parentItem;
786 docShellAsItem->GetParent(getter_AddRefs(parentItem));
788 PRInt32 parentType;
789 parentItem->GetItemType(&parentType);
791 if (parentType != nsIDocShellTreeItem::typeChrome) {
792 return NS_OK;
795 nsCOMPtr<nsIDocShellTreeOwner> parentTreeOwner;
796 parentItem->GetTreeOwner(getter_AddRefs(parentTreeOwner));
797 if (parentTreeOwner) {
798 nsAutoString value;
799 mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::type, value);
801 PRBool is_primary = value.LowerCaseEqualsLiteral("content-primary");
803 #ifdef MOZ_XUL
804 // when a content panel is no longer primary, hide any open popups it may have
805 if (!is_primary) {
806 nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
807 if (pm)
808 pm->HidePopupsInDocShell(docShellAsItem);
810 #endif
812 parentTreeOwner->ContentShellRemoved(docShellAsItem);
814 if (value.LowerCaseEqualsLiteral("content") ||
815 StringBeginsWith(value, NS_LITERAL_STRING("content-"),
816 nsCaseInsensitiveStringComparator())) {
817 PRBool is_targetable = is_primary ||
818 value.LowerCaseEqualsLiteral("content-targetable");
820 parentTreeOwner->ContentShellAdded(docShellAsItem, is_primary,
821 is_targetable, value);
826 return NS_OK;
829 nsIFrame*
830 NS_NewSubDocumentFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
832 return new (aPresShell) nsSubDocumentFrame(aContext);
835 NS_IMPL_FRAMEARENA_HELPERS(nsSubDocumentFrame)
837 void
838 nsSubDocumentFrame::DestroyFrom(nsIFrame* aDestructRoot)
840 if (mPostedReflowCallback) {
841 PresContext()->PresShell()->CancelReflowCallback(this);
842 mPostedReflowCallback = PR_FALSE;
845 HideViewer();
847 nsLeafFrame::DestroyFrom(aDestructRoot);
850 void
851 nsSubDocumentFrame::HideViewer()
853 if (mFrameLoader && (mDidCreateDoc || mCallingShow))
854 mFrameLoader->Hide();
857 nsIntSize
858 nsSubDocumentFrame::GetMarginAttributes()
860 nsIntSize result(-1, -1);
861 nsGenericHTMLElement *content = nsGenericHTMLElement::FromContent(mContent);
862 if (content) {
863 const nsAttrValue* attr = content->GetParsedAttr(nsGkAtoms::marginwidth);
864 if (attr && attr->Type() == nsAttrValue::eInteger)
865 result.width = attr->GetIntegerValue();
866 attr = content->GetParsedAttr(nsGkAtoms::marginheight);
867 if (attr && attr->Type() == nsAttrValue::eInteger)
868 result.height = attr->GetIntegerValue();
870 return result;
873 nsFrameLoader*
874 nsSubDocumentFrame::FrameLoader()
876 nsIContent* content = GetContent();
877 if (!content)
878 return nsnull;
880 if (!mFrameLoader) {
881 nsCOMPtr<nsIFrameLoaderOwner> loaderOwner = do_QueryInterface(content);
882 if (loaderOwner) {
883 nsCOMPtr<nsIFrameLoader> loader;
884 loaderOwner->GetFrameLoader(getter_AddRefs(loader));
885 mFrameLoader = static_cast<nsFrameLoader*>(loader.get());
888 return mFrameLoader;
891 // XXX this should be called ObtainDocShell or something like that,
892 // to indicate that it could have side effects
893 NS_IMETHODIMP
894 nsSubDocumentFrame::GetDocShell(nsIDocShell **aDocShell)
896 *aDocShell = nsnull;
898 NS_ENSURE_STATE(FrameLoader());
899 return mFrameLoader->GetDocShell(aDocShell);
902 NS_IMETHODIMP
903 nsSubDocumentFrame::BeginSwapDocShells(nsIFrame* aOther)
905 if (!aOther || aOther->GetType() != nsGkAtoms::subDocumentFrame) {
906 return NS_ERROR_NOT_IMPLEMENTED;
909 nsSubDocumentFrame* other = static_cast<nsSubDocumentFrame*>(aOther);
910 if (!mFrameLoader || !mDidCreateDoc || mCallingShow ||
911 !other->mFrameLoader || !other->mDidCreateDoc) {
912 return NS_ERROR_NOT_IMPLEMENTED;
915 HideViewer();
916 other->HideViewer();
918 mFrameLoader.swap(other->mFrameLoader);
919 return NS_OK;
922 void
923 nsSubDocumentFrame::EndSwapDocShells(nsIFrame* aOther)
925 nsSubDocumentFrame* other = static_cast<nsSubDocumentFrame*>(aOther);
926 nsWeakFrame weakThis(this);
927 nsWeakFrame weakOther(aOther);
928 ShowViewer();
929 other->ShowViewer();
931 // Now make sure we reflow both frames, in case their contents
932 // determine their size.
933 // And repaint them, for good measure, in case there's nothing
934 // interesting that happens during reflow.
935 if (weakThis.IsAlive()) {
936 PresContext()->PresShell()->
937 FrameNeedsReflow(this, nsIPresShell::eTreeChange, NS_FRAME_IS_DIRTY);
938 InvalidateOverflowRect();
940 if (weakOther.IsAlive()) {
941 other->PresContext()->PresShell()->
942 FrameNeedsReflow(other, nsIPresShell::eTreeChange, NS_FRAME_IS_DIRTY);
943 other->InvalidateOverflowRect();
947 nsIView*
948 nsSubDocumentFrame::CreateViewAndWidget(nsContentType aContentType)
950 if (mInnerView) {
951 // Nothing to do here
952 return mInnerView;
955 // create, init, set the parent of the view
956 nsIView* outerView = GetView();
957 NS_ASSERTION(outerView, "Must have an outer view already");
958 nsRect viewBounds(0, 0, 0, 0); // size will be fixed during reflow
960 nsIViewManager* viewMan = outerView->GetViewManager();
961 nsIView* innerView = viewMan->CreateView(viewBounds, outerView);
962 if (!innerView) {
963 NS_ERROR("Could not create inner view");
964 return nsnull;
966 mInnerView = innerView;
967 viewMan->InsertChild(outerView, innerView, nsnull, PR_TRUE);
969 if (aContentType == eContentTypeContent) {
970 // widget needed.
971 nsresult rv = innerView->CreateWidget(nsnull,
972 PR_TRUE, PR_TRUE, aContentType);
973 if (NS_FAILED(rv)) {
974 NS_WARNING("Couldn't create widget for frame.");
975 mInnerView = nsnull;
978 return mInnerView;
981 nsIFrame*
982 nsSubDocumentFrame::ObtainIntrinsicSizeFrame()
984 nsCOMPtr<nsIObjectLoadingContent> olc = do_QueryInterface(GetContent());
985 if (olc) {
986 // We are an HTML <object>, <embed> or <applet> (a replaced element).
988 // Try to get an nsIFrame for our sub-document's document element
989 nsIFrame* subDocRoot = nsnull;
991 nsCOMPtr<nsIDocShell> docShell;
992 GetDocShell(getter_AddRefs(docShell));
993 if (docShell) {
994 nsCOMPtr<nsIPresShell> presShell;
995 docShell->GetPresShell(getter_AddRefs(presShell));
996 if (presShell) {
997 nsIScrollableFrame* scrollable = presShell->GetRootScrollFrameAsScrollable();
998 if (scrollable) {
999 nsIFrame* scrolled = scrollable->GetScrolledFrame();
1000 if (scrolled) {
1001 subDocRoot = scrolled->GetFirstChild(nsnull);
1007 #ifdef MOZ_SVG
1008 if (subDocRoot && subDocRoot->GetContent() &&
1009 subDocRoot->GetContent()->NodeInfo()->Equals(nsGkAtoms::svg, kNameSpaceID_SVG)) {
1010 return subDocRoot; // SVG documents have an intrinsic size
1012 #endif
1014 return nsnull;