Bug 54488 - "[Mac] Non-draggable widgets in background windows should look disabled...
[mozilla-central.git] / layout / generic / nsFrameFrame.cpp
blobc2672e3cb29eed86e09856284ed87ce0c50f614a
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 "nsIScrollableView.h"
70 #include "nsStyleCoord.h"
71 #include "nsStyleContext.h"
72 #include "nsStyleConsts.h"
73 #include "nsFrameSetFrame.h"
74 #include "nsIDOMHTMLFrameElement.h"
75 #include "nsIDOMHTMLIFrameElement.h"
76 #include "nsIDOMXULElement.h"
77 #include "nsIFrameLoader.h"
78 #include "nsIScriptSecurityManager.h"
79 #include "nsXPIDLString.h"
80 #include "nsIScrollable.h"
81 #include "nsINameSpaceManager.h"
82 #include "nsIWidget.h"
83 #include "nsWeakReference.h"
84 #include "nsIDOMWindow.h"
85 #include "nsIDOMDocument.h"
86 #include "nsIRenderingContext.h"
87 #include "nsIFrameFrame.h"
88 #include "nsAutoPtr.h"
89 #include "nsIDOMNSHTMLDocument.h"
90 #include "nsDisplayList.h"
91 #include "nsUnicharUtils.h"
92 #include "nsIReflowCallback.h"
93 #include "nsIScrollableFrame.h"
94 #include "nsIObjectLoadingContent.h"
95 #include "nsLayoutUtils.h"
97 #ifdef MOZ_XUL
98 #include "nsXULPopupManager.h"
99 #endif
101 // For Accessibility
102 #ifdef ACCESSIBILITY
103 #include "nsIAccessibilityService.h"
104 #endif
105 #include "nsIServiceManager.h"
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 nsSubDocumentFrame(nsStyleContext* aContext);
119 #ifdef DEBUG
120 NS_IMETHOD GetFrameName(nsAString& aResult) const;
121 #endif
123 // nsISupports
124 NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr);
125 NS_IMETHOD_(nsrefcnt) AddRef(void) { return 2; }
126 NS_IMETHOD_(nsrefcnt) Release(void) { return 1; }
128 virtual nsIAtom* GetType() const;
130 virtual PRBool IsFrameOfType(PRUint32 aFlags) const
132 // nsLeafFrame is already eReplacedContainsBlock, but that's somewhat bogus
133 return nsLeafFrame::IsFrameOfType(aFlags &
134 ~(nsIFrame::eReplaced | nsIFrame::eReplacedContainsBlock));
137 NS_IMETHOD Init(nsIContent* aContent,
138 nsIFrame* aParent,
139 nsIFrame* aPrevInFlow);
141 virtual void Destroy();
143 virtual nscoord GetMinWidth(nsIRenderingContext *aRenderingContext);
144 virtual nscoord GetPrefWidth(nsIRenderingContext *aRenderingContext);
146 virtual IntrinsicSize GetIntrinsicSize();
147 virtual nsSize GetIntrinsicRatio();
149 virtual nsSize ComputeAutoSize(nsIRenderingContext *aRenderingContext,
150 nsSize aCBSize, nscoord aAvailableWidth,
151 nsSize aMargin, nsSize aBorder,
152 nsSize aPadding, PRBool aShrinkWrap);
154 virtual nsSize ComputeSize(nsIRenderingContext *aRenderingContext,
155 nsSize aCBSize, nscoord aAvailableWidth,
156 nsSize aMargin, nsSize aBorder, nsSize aPadding,
157 PRBool aShrinkWrap);
159 NS_IMETHOD Reflow(nsPresContext* aPresContext,
160 nsHTMLReflowMetrics& aDesiredSize,
161 const nsHTMLReflowState& aReflowState,
162 nsReflowStatus& aStatus);
164 NS_IMETHOD BuildDisplayList(nsDisplayListBuilder* aBuilder,
165 const nsRect& aDirtyRect,
166 const nsDisplayListSet& aLists);
168 NS_IMETHOD AttributeChanged(PRInt32 aNameSpaceID,
169 nsIAtom* aAttribute,
170 PRInt32 aModType);
172 // if the content is "visibility:hidden", then just hide the view
173 // and all our contents. We don't extend "visibility:hidden" to
174 // the child content ourselves, since it belongs to a different
175 // document and CSS doesn't inherit in there.
176 virtual PRBool SupportsVisibilityHidden() { return PR_FALSE; }
178 #ifdef ACCESSIBILITY
179 NS_IMETHOD GetAccessible(nsIAccessible** aAccessible);
180 #endif
182 // nsIFrameFrame
183 NS_IMETHOD GetDocShell(nsIDocShell **aDocShell);
184 NS_IMETHOD BeginSwapDocShells(nsIFrame* aOther);
185 virtual void EndSwapDocShells(nsIFrame* aOther);
187 NS_IMETHOD VerifyTree() const;
189 // nsIReflowCallback
190 virtual PRBool ReflowFinished();
191 virtual void ReflowCallbackCanceled();
193 protected:
194 nsSize GetMargin();
195 PRBool IsInline() { return mIsInline; }
196 nsresult ShowDocShell();
197 nsresult CreateViewAndWidget(nsContentType aContentType);
199 virtual nscoord GetIntrinsicWidth();
200 virtual nscoord GetIntrinsicHeight();
202 virtual PRIntn GetSkipSides() const;
204 // Hide or show our document viewer
205 void HideViewer();
206 void ShowViewer();
208 /* Obtains the frame we should use for intrinsic size information if we are
209 * an HTML <object>, <embed> or <applet> (a replaced element - not <iframe>)
210 * and our sub-document has an intrinsic size. The frame returned is the
211 * frame for the document element of the document we're embedding.
213 * Called "Obtain*" and not "Get*" because of comment on GetDocShell that
214 * says it should be called ObtainDocShell because of it's side effects.
216 nsIFrame* ObtainIntrinsicSizeFrame();
218 nsCOMPtr<nsIFrameLoader> mFrameLoader;
219 nsIView* mInnerView;
220 PRPackedBool mDidCreateDoc;
221 PRPackedBool mIsInline;
222 PRPackedBool mPostedReflowCallback;
225 nsSubDocumentFrame::nsSubDocumentFrame(nsStyleContext* aContext)
226 : nsLeafFrame(aContext), mDidCreateDoc(PR_FALSE),
227 mIsInline(PR_FALSE), mPostedReflowCallback(PR_FALSE)
231 #ifdef ACCESSIBILITY
232 NS_IMETHODIMP nsSubDocumentFrame::GetAccessible(nsIAccessible** aAccessible)
234 nsCOMPtr<nsIAccessibilityService> accService = do_GetService("@mozilla.org/accessibilityService;1");
236 if (accService) {
237 nsCOMPtr<nsIDOMNode> node = do_QueryInterface(mContent);
238 return accService->CreateOuterDocAccessible(node, aAccessible);
241 return NS_ERROR_FAILURE;
243 #endif
245 //--------------------------------------------------------------
246 // Frames are not refcounted, no need to AddRef
247 NS_IMETHODIMP
248 nsSubDocumentFrame::QueryInterface(const nsIID& aIID, void** aInstancePtr)
250 NS_PRECONDITION(aInstancePtr, "null out param");
252 if (aIID.Equals(NS_GET_IID(nsIFrameFrame))) {
253 *aInstancePtr = static_cast<nsIFrameFrame*>(this);
254 return NS_OK;
257 return nsLeafFrame::QueryInterface(aIID, aInstancePtr);
260 NS_IMETHODIMP
261 nsSubDocumentFrame::Init(nsIContent* aContent,
262 nsIFrame* aParent,
263 nsIFrame* aPrevInFlow)
265 // determine if we are a <frame> or <iframe>
266 if (aContent) {
267 nsCOMPtr<nsIDOMHTMLFrameElement> frameElem = do_QueryInterface(aContent);
268 mIsInline = frameElem ? PR_FALSE : PR_TRUE;
271 nsresult rv = nsLeafFrame::Init(aContent, aParent, aPrevInFlow);
272 if (NS_FAILED(rv))
273 return rv;
275 nsPresContext *aPresContext = PresContext();
277 // We are going to create an inner view. If we need a view for the
278 // OuterFrame but we wait for the normal view creation path in
279 // nsCSSFrameConstructor, then we will lose because the inner view's
280 // parent will already have been set to some outer view (e.g., the
281 // canvas) when it really needs to have this frame's view as its
282 // parent. So, create this frame's view right away, whether we
283 // really need it or not, and the inner view will get it as the
284 // parent.
285 if (!HasView()) {
286 // To properly initialize the view we need to know the frame for the content
287 // that is the parent of content for this frame. This might not be our actual
288 // frame parent if we are out of flow (e.g., positioned) so our parent frame
289 // may have been set to some other ancestor.
290 // We look for a content parent frame in the frame property list, where it
291 // will have been set by nsCSSFrameConstructor if necessary.
292 nsCOMPtr<nsIAtom> contentParentAtom = do_GetAtom("contentParent");
293 nsIFrame* contentParent = nsnull;
295 void *value =
296 aPresContext->PropertyTable()->UnsetProperty(this,
297 contentParentAtom, &rv);
298 if (NS_SUCCEEDED(rv)) {
299 contentParent = (nsIFrame*)value;
302 rv = nsHTMLContainerFrame::CreateViewForFrame(this, contentParent, PR_TRUE);
303 NS_ENSURE_SUCCESS(rv, rv);
305 nsIView* view = GetView();
307 if (aParent->GetStyleDisplay()->mDisplay == NS_STYLE_DISPLAY_DECK
308 && !view->HasWidget()) {
309 view->CreateWidget(kCChildCID);
312 ShowViewer();
313 return NS_OK;
316 void
317 nsSubDocumentFrame::ShowViewer()
319 if (!PresContext()->IsDynamic()) {
320 // We let the printing code take care of loading the document; just
321 // create a widget for it to use
322 nsresult rv = CreateViewAndWidget(eContentTypeContent);
323 if (NS_FAILED(rv)) {
324 return;
326 } else {
327 nsresult rv = ShowDocShell();
328 if (NS_FAILED(rv)) {
329 return;
331 mDidCreateDoc = PR_TRUE;
335 PRIntn
336 nsSubDocumentFrame::GetSkipSides() const
338 return 0;
341 NS_IMETHODIMP
342 nsSubDocumentFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
343 const nsRect& aDirtyRect,
344 const nsDisplayListSet& aLists)
346 if (!IsVisibleForPainting(aBuilder))
347 return NS_OK;
349 nsresult rv = DisplayBorderBackgroundOutline(aBuilder, aLists);
350 NS_ENSURE_SUCCESS(rv, rv);
352 if (!mInnerView)
353 return NS_OK;
354 nsIView* subdocView = mInnerView->GetFirstChild();
355 if (!subdocView)
356 return NS_OK;
357 nsIFrame* f = static_cast<nsIFrame*>(subdocView->GetClientData());
358 if (!f)
359 return NS_OK;
361 nsRect dirty = aDirtyRect - f->GetOffsetTo(this);
363 aBuilder->EnterPresShell(f, dirty);
365 // Clip children to the child root frame's rectangle
366 nsDisplayList childItems;
367 rv = f->BuildDisplayListForStackingContext(aBuilder, dirty, &childItems);
368 if (NS_SUCCEEDED(rv)) {
369 rv = aLists.Content()->AppendNewToTop(
370 new (aBuilder) nsDisplayClip(nsnull, this, &childItems,
371 nsRect(aBuilder->ToReferenceFrame(f), f->GetSize())));
372 // delete childItems in case of OOM
373 childItems.DeleteAll();
376 aBuilder->LeavePresShell(f, dirty);
377 return rv;
380 nscoord
381 nsSubDocumentFrame::GetIntrinsicWidth()
383 if (!IsInline()) {
384 return 0; // HTML <frame> has no useful intrinsic width
387 if (mContent->IsNodeOfType(nsINode::eXUL)) {
388 return 0; // XUL <iframe> and <browser> have no useful intrinsic width
391 NS_ASSERTION(ObtainIntrinsicSizeFrame() == nsnull,
392 "Intrinsic width should come from the embedded document.");
394 // We must be an HTML <iframe>. Default to a width of 300, for IE
395 // compat (and per CSS2.1 draft).
396 return nsPresContext::CSSPixelsToAppUnits(300);
399 nscoord
400 nsSubDocumentFrame::GetIntrinsicHeight()
402 // <frame> processing does not use this routine, only <iframe>
403 NS_ASSERTION(IsInline(), "Shouldn't have been called");
405 if (mContent->IsNodeOfType(nsINode::eXUL)) {
406 return 0;
409 NS_ASSERTION(ObtainIntrinsicSizeFrame() == nsnull,
410 "Intrinsic height should come from the embedded document.");
412 // Use 150px, for compatibility with IE, and per CSS2.1 draft.
413 return nsPresContext::CSSPixelsToAppUnits(150);
416 #ifdef DEBUG
417 NS_IMETHODIMP nsSubDocumentFrame::GetFrameName(nsAString& aResult) const
419 return MakeFrameName(NS_LITERAL_STRING("FrameOuter"), aResult);
421 #endif
423 nsIAtom*
424 nsSubDocumentFrame::GetType() const
426 return nsGkAtoms::subDocumentFrame;
429 /* virtual */ nscoord
430 nsSubDocumentFrame::GetMinWidth(nsIRenderingContext *aRenderingContext)
432 nscoord result;
433 DISPLAY_MIN_WIDTH(this, result);
435 nsIFrame* subDocRoot = ObtainIntrinsicSizeFrame();
436 if (subDocRoot) {
437 result = subDocRoot->GetMinWidth(aRenderingContext);
438 } else {
439 result = GetIntrinsicWidth();
442 return result;
445 /* virtual */ nscoord
446 nsSubDocumentFrame::GetPrefWidth(nsIRenderingContext *aRenderingContext)
448 nscoord result;
449 DISPLAY_PREF_WIDTH(this, result);
451 nsIFrame* subDocRoot = ObtainIntrinsicSizeFrame();
452 if (subDocRoot) {
453 result = subDocRoot->GetPrefWidth(aRenderingContext);
454 } else {
455 result = GetIntrinsicWidth();
458 return result;
461 /* virtual */ nsIFrame::IntrinsicSize
462 nsSubDocumentFrame::GetIntrinsicSize()
464 nsIFrame* subDocRoot = ObtainIntrinsicSizeFrame();
465 if (subDocRoot) {
466 return subDocRoot->GetIntrinsicSize();
468 return nsLeafFrame::GetIntrinsicSize();
471 /* virtual */ nsSize
472 nsSubDocumentFrame::GetIntrinsicRatio()
474 nsIFrame* subDocRoot = ObtainIntrinsicSizeFrame();
475 if (subDocRoot) {
476 return subDocRoot->GetIntrinsicRatio();
478 return nsLeafFrame::GetIntrinsicRatio();
481 /* virtual */ nsSize
482 nsSubDocumentFrame::ComputeAutoSize(nsIRenderingContext *aRenderingContext,
483 nsSize aCBSize, nscoord aAvailableWidth,
484 nsSize aMargin, nsSize aBorder,
485 nsSize aPadding, PRBool aShrinkWrap)
487 if (!IsInline()) {
488 return nsFrame::ComputeAutoSize(aRenderingContext, aCBSize,
489 aAvailableWidth, aMargin, aBorder,
490 aPadding, aShrinkWrap);
493 return nsLeafFrame::ComputeAutoSize(aRenderingContext, aCBSize,
494 aAvailableWidth, aMargin, aBorder,
495 aPadding, aShrinkWrap);
499 /* virtual */ nsSize
500 nsSubDocumentFrame::ComputeSize(nsIRenderingContext *aRenderingContext,
501 nsSize aCBSize, nscoord aAvailableWidth,
502 nsSize aMargin, nsSize aBorder, nsSize aPadding,
503 PRBool aShrinkWrap)
505 nsIFrame* subDocRoot = ObtainIntrinsicSizeFrame();
506 if (subDocRoot) {
507 return nsLayoutUtils::ComputeSizeWithIntrinsicDimensions(
508 aRenderingContext, this,
509 subDocRoot->GetIntrinsicSize(),
510 subDocRoot->GetIntrinsicRatio(),
511 aCBSize, aMargin, aBorder, aPadding);
513 return nsLeafFrame::ComputeSize(aRenderingContext, aCBSize, aAvailableWidth,
514 aMargin, aBorder, aPadding, aShrinkWrap);
517 NS_IMETHODIMP
518 nsSubDocumentFrame::Reflow(nsPresContext* aPresContext,
519 nsHTMLReflowMetrics& aDesiredSize,
520 const nsHTMLReflowState& aReflowState,
521 nsReflowStatus& aStatus)
523 DO_GLOBAL_REFLOW_COUNT("nsSubDocumentFrame");
524 DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);
525 // printf("OuterFrame::Reflow %X (%d,%d) \n", this, aReflowState.availableWidth, aReflowState.availableHeight);
526 NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,
527 ("enter nsSubDocumentFrame::Reflow: maxSize=%d,%d",
528 aReflowState.availableWidth, aReflowState.availableHeight));
530 aStatus = NS_FRAME_COMPLETE;
532 NS_ASSERTION(aPresContext->GetPresShell()->GetPrimaryFrameFor(mContent) == this,
533 "Shouldn't happen");
535 // "offset" is the offset of our content area from our frame's
536 // top-left corner.
537 nsPoint offset(0, 0);
539 if (IsInline()) {
540 // XUL <iframe> or <browser>, or HTML <iframe>, <object> or <embed>
541 nsresult rv = nsLeafFrame::DoReflow(aPresContext, aDesiredSize, aReflowState,
542 aStatus);
543 NS_ENSURE_SUCCESS(rv, rv);
545 offset = nsPoint(aReflowState.mComputedBorderPadding.left,
546 aReflowState.mComputedBorderPadding.top);
547 } else {
548 // HTML <frame>
549 SizeToAvailSize(aReflowState, aDesiredSize);
552 nsSize innerSize(aDesiredSize.width, aDesiredSize.height);
553 if (IsInline()) {
554 innerSize.width -= aReflowState.mComputedBorderPadding.LeftRight();
555 innerSize.height -= aReflowState.mComputedBorderPadding.TopBottom();
558 nsIViewManager* vm = mInnerView->GetViewManager();
559 vm->MoveViewTo(mInnerView, offset.x, offset.y);
560 vm->ResizeView(mInnerView, nsRect(nsPoint(0, 0), innerSize), PR_TRUE);
562 // Determine if we need to repaint our border, background or outline
563 CheckInvalidateSizeChange(aDesiredSize);
565 FinishAndStoreOverflow(&aDesiredSize);
567 // Invalidate the frame contents
568 // XXX is this really needed?
569 nsRect rect(nsPoint(0, 0), GetSize());
570 Invalidate(rect);
572 if (!aPresContext->IsPaginated() && !mPostedReflowCallback) {
573 PresContext()->PresShell()->PostReflowCallback(this);
574 mPostedReflowCallback = PR_TRUE;
577 // printf("OuterFrame::Reflow DONE %X (%d,%d)\n", this,
578 // aDesiredSize.width, aDesiredSize.height);
580 NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,
581 ("exit nsSubDocumentFrame::Reflow: size=%d,%d status=%x",
582 aDesiredSize.width, aDesiredSize.height, aStatus));
584 NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
585 return NS_OK;
588 PRBool
589 nsSubDocumentFrame::ReflowFinished()
591 nsCOMPtr<nsIDocShell> docShell;
592 GetDocShell(getter_AddRefs(docShell));
594 nsCOMPtr<nsIBaseWindow> baseWindow(do_QueryInterface(docShell));
596 // resize the sub document
597 if (baseWindow) {
598 PRInt32 x = 0;
599 PRInt32 y = 0;
601 nsWeakFrame weakFrame(this);
603 nsPresContext* presContext = PresContext();
604 baseWindow->GetPositionAndSize(&x, &y, nsnull, nsnull);
606 if (!weakFrame.IsAlive()) {
607 // GetPositionAndSize() killed us
608 return PR_FALSE;
611 // GetPositionAndSize might have resized us. So now is the time to
612 // get our size.
613 mPostedReflowCallback = PR_FALSE;
615 nsSize innerSize(GetSize());
616 if (IsInline()) {
617 nsMargin usedBorderPadding = GetUsedBorderAndPadding();
619 // Sadly, XUL smacks the frame size without changing the used
620 // border and padding, so we can't trust those. Subtracting
621 // them might make things negative.
622 innerSize.width -= usedBorderPadding.LeftRight();
623 innerSize.width = PR_MAX(innerSize.width, 0);
625 innerSize.height -= usedBorderPadding.TopBottom();
626 innerSize.height = PR_MAX(innerSize.height, 0);
629 PRInt32 cx = presContext->AppUnitsToDevPixels(innerSize.width);
630 PRInt32 cy = presContext->AppUnitsToDevPixels(innerSize.height);
631 baseWindow->SetPositionAndSize(x, y, cx, cy, PR_FALSE);
632 } else {
633 // Make sure that we can post a reflow callback in the future.
634 mPostedReflowCallback = PR_FALSE;
637 return PR_FALSE;
640 void
641 nsSubDocumentFrame::ReflowCallbackCanceled()
643 mPostedReflowCallback = PR_FALSE;
646 NS_IMETHODIMP
647 nsSubDocumentFrame::VerifyTree() const
649 // XXX Completely disabled for now; once pseud-frames are reworked
650 // then we can turn it back on.
651 return NS_OK;
654 NS_IMETHODIMP
655 nsSubDocumentFrame::AttributeChanged(PRInt32 aNameSpaceID,
656 nsIAtom* aAttribute,
657 PRInt32 aModType)
659 if (aNameSpaceID != kNameSpaceID_None) {
660 return NS_OK;
663 // If the noResize attribute changes, dis/allow frame to be resized
664 if (aAttribute == nsGkAtoms::noresize) {
665 // Note that we're not doing content type checks, but that's ok -- if
666 // they'd fail we will just end up with a null framesetFrame.
667 if (mContent->GetParent()->Tag() == nsGkAtoms::frameset) {
668 nsIFrame* parentFrame = GetParent();
670 if (parentFrame) {
671 // There is no interface for nsHTMLFramesetFrame so QI'ing to
672 // concrete class, yay!
673 nsHTMLFramesetFrame* framesetFrame = nsnull;
674 parentFrame->QueryInterface(NS_GET_IID(nsHTMLFramesetFrame),
675 (void **)&framesetFrame);
677 if (framesetFrame) {
678 framesetFrame->RecalculateBorderResize();
683 else if (aAttribute == nsGkAtoms::type) {
684 if (!mFrameLoader)
685 return NS_OK;
687 if (!mContent->IsNodeOfType(nsINode::eXUL)) {
688 return NS_OK;
691 // Note: This logic duplicates a lot of logic in
692 // nsFrameLoader::EnsureDocShell. We should fix that.
694 // Notify our enclosing chrome that our type has changed. We only do this
695 // if our parent is chrome, since in all other cases we're random content
696 // subframes and the treeowner shouldn't worry about us.
698 nsCOMPtr<nsIDocShell> docShell;
699 mFrameLoader->GetDocShell(getter_AddRefs(docShell));
700 nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryInterface(docShell));
701 if (!docShellAsItem) {
702 return NS_OK;
705 nsCOMPtr<nsIDocShellTreeItem> parentItem;
706 docShellAsItem->GetParent(getter_AddRefs(parentItem));
708 PRInt32 parentType;
709 parentItem->GetItemType(&parentType);
711 if (parentType != nsIDocShellTreeItem::typeChrome) {
712 return NS_OK;
715 nsCOMPtr<nsIDocShellTreeOwner> parentTreeOwner;
716 parentItem->GetTreeOwner(getter_AddRefs(parentTreeOwner));
717 if (parentTreeOwner) {
718 nsAutoString value;
719 mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::type, value);
721 PRBool is_primary = value.LowerCaseEqualsLiteral("content-primary");
723 #ifdef MOZ_XUL
724 // when a content panel is no longer primary, hide any open popups it may have
725 if (!is_primary) {
726 nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
727 if (pm)
728 pm->HidePopupsInDocShell(docShellAsItem);
730 #endif
732 parentTreeOwner->ContentShellRemoved(docShellAsItem);
734 if (value.LowerCaseEqualsLiteral("content") ||
735 StringBeginsWith(value, NS_LITERAL_STRING("content-"),
736 nsCaseInsensitiveStringComparator())) {
737 PRBool is_targetable = is_primary ||
738 value.LowerCaseEqualsLiteral("content-targetable");
740 parentTreeOwner->ContentShellAdded(docShellAsItem, is_primary,
741 is_targetable, value);
746 return NS_OK;
749 nsIFrame*
750 NS_NewSubDocumentFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
752 return new (aPresShell) nsSubDocumentFrame(aContext);
755 void
756 nsSubDocumentFrame::Destroy()
758 if (mPostedReflowCallback) {
759 PresContext()->PresShell()->CancelReflowCallback(this);
760 mPostedReflowCallback = PR_FALSE;
763 HideViewer();
765 nsLeafFrame::Destroy();
768 void
769 nsSubDocumentFrame::HideViewer()
771 if (mFrameLoader && mDidCreateDoc) {
772 // Get the content viewer through the docshell, but don't call
773 // GetDocShell() since we don't want to create one if we don't
774 // have one.
776 nsCOMPtr<nsIDocShell> docShell;
777 mFrameLoader->GetDocShell(getter_AddRefs(docShell));
779 if (docShell) {
780 nsCOMPtr<nsIContentViewer> content_viewer;
781 docShell->GetContentViewer(getter_AddRefs(content_viewer));
783 if (content_viewer) {
784 // Mark the content viewer as non-sticky so that the presentation
785 // can safely go away when this frame is destroyed.
787 content_viewer->SetSticky(PR_FALSE);
790 nsCOMPtr<nsIBaseWindow> baseWin = do_QueryInterface(docShell);
791 NS_ASSERTION(baseWin, "Docshell must be an nsIBaseWindow");
793 // Now reverse the steps we took in ShowDocShell(). But don't call
794 // Destroy(); that will be handled by destroying our frame loader, if
795 // needed.
797 // Hide the content viewer now that the frame is going away...
798 baseWin->SetVisibility(PR_FALSE);
800 // Clear out the parentWidget, since it might be about to die with us
801 baseWin->SetParentWidget(nsnull);
806 nsSize nsSubDocumentFrame::GetMargin()
808 nsSize result(-1, -1);
809 nsGenericHTMLElement *content = nsGenericHTMLElement::FromContent(mContent);
810 if (content) {
811 const nsAttrValue* attr = content->GetParsedAttr(nsGkAtoms::marginwidth);
812 if (attr && attr->Type() == nsAttrValue::eInteger)
813 result.width = attr->GetIntegerValue();
814 attr = content->GetParsedAttr(nsGkAtoms::marginheight);
815 if (attr && attr->Type() == nsAttrValue::eInteger)
816 result.height = attr->GetIntegerValue();
818 return result;
821 // XXX this should be called ObtainDocShell or something like that,
822 // to indicate that it could have side effects
823 NS_IMETHODIMP
824 nsSubDocumentFrame::GetDocShell(nsIDocShell **aDocShell)
826 *aDocShell = nsnull;
828 nsIContent* content = GetContent();
829 if (!content) {
830 // Hmm, no content in this frame
831 // that's odd, not much to be done here then.
832 return NS_OK;
835 if (!mFrameLoader) {
836 nsCOMPtr<nsIFrameLoaderOwner> loaderOwner = do_QueryInterface(content);
838 if (loaderOwner) {
839 loaderOwner->GetFrameLoader(getter_AddRefs(mFrameLoader));
842 NS_ENSURE_STATE(mFrameLoader);
845 return mFrameLoader->GetDocShell(aDocShell);
848 NS_IMETHODIMP
849 nsSubDocumentFrame::BeginSwapDocShells(nsIFrame* aOther)
851 if (!aOther || aOther->GetType() != nsGkAtoms::subDocumentFrame) {
852 return NS_ERROR_NOT_IMPLEMENTED;
855 nsSubDocumentFrame* other = static_cast<nsSubDocumentFrame*>(aOther);
856 if (!mFrameLoader || !mDidCreateDoc || !other->mFrameLoader ||
857 !other->mDidCreateDoc) {
858 return NS_ERROR_NOT_IMPLEMENTED;
861 HideViewer();
862 other->HideViewer();
864 mFrameLoader.swap(other->mFrameLoader);
865 return NS_OK;
868 void
869 nsSubDocumentFrame::EndSwapDocShells(nsIFrame* aOther)
871 nsSubDocumentFrame* other = static_cast<nsSubDocumentFrame*>(aOther);
872 ShowViewer();
873 other->ShowViewer();
875 // Now make sure we reflow both frames, in case their contents
876 // determine their size.
877 PresContext()->PresShell()->
878 FrameNeedsReflow(this, nsIPresShell::eTreeChange, NS_FRAME_IS_DIRTY);
879 other->PresContext()->PresShell()->
880 FrameNeedsReflow(other, nsIPresShell::eTreeChange, NS_FRAME_IS_DIRTY);
882 // And repaint them, for good measure, in case there's nothing
883 // interesting that happens during reflow.
884 InvalidateOverflowRect();
885 other->InvalidateOverflowRect();
888 inline PRInt32 ConvertOverflow(PRUint8 aOverflow)
890 switch (aOverflow) {
891 case NS_STYLE_OVERFLOW_VISIBLE:
892 case NS_STYLE_OVERFLOW_AUTO:
893 return nsIScrollable::Scrollbar_Auto;
894 case NS_STYLE_OVERFLOW_HIDDEN:
895 case NS_STYLE_OVERFLOW_CLIP:
896 return nsIScrollable::Scrollbar_Never;
897 case NS_STYLE_OVERFLOW_SCROLL:
898 return nsIScrollable::Scrollbar_Always;
900 NS_NOTREACHED("invalid overflow value passed to ConvertOverflow");
901 return nsIScrollable::Scrollbar_Auto;
904 nsresult
905 nsSubDocumentFrame::ShowDocShell()
907 nsCOMPtr<nsIDocShell> docShell;
908 nsresult rv = GetDocShell(getter_AddRefs(docShell));
909 NS_ENSURE_SUCCESS(rv, rv);
911 nsCOMPtr<nsIPresShell> presShell;
912 docShell->GetPresShell(getter_AddRefs(presShell));
914 if (presShell) {
915 // The docshell is already showing, nothing left to do...
916 NS_ASSERTION(mInnerView, "What's going on?");
917 return NS_OK;
920 // pass along marginwidth, marginheight, scrolling so sub document
921 // can use it
922 nsSize margin = GetMargin();
923 docShell->SetMarginWidth(margin.width);
924 docShell->SetMarginHeight(margin.height);
926 // Current and initial scrolling is set so that all succeeding docs
927 // will use the scrolling value set here, regardless if scrolling is
928 // set by viewing a particular document (e.g. XUL turns off scrolling)
929 nsCOMPtr<nsIScrollable> sc(do_QueryInterface(docShell));
931 if (sc) {
932 const nsStyleDisplay *disp = GetStyleDisplay();
933 sc->SetDefaultScrollbarPreferences(nsIScrollable::ScrollOrientation_X,
934 ConvertOverflow(disp->mOverflowX));
935 sc->SetDefaultScrollbarPreferences(nsIScrollable::ScrollOrientation_Y,
936 ConvertOverflow(disp->mOverflowY));
939 PRInt32 itemType = nsIDocShellTreeItem::typeContent;
940 nsCOMPtr<nsIDocShellTreeItem> treeItem(do_QueryInterface(docShell));
941 if (treeItem) {
942 treeItem->GetItemType(&itemType);
945 nsContentType contentType;
946 if (itemType == nsIDocShellTreeItem::typeChrome) {
947 contentType = eContentTypeUI;
949 else {
950 nsCOMPtr<nsIDocShellTreeItem> sameTypeParent;
951 treeItem->GetSameTypeParent(getter_AddRefs(sameTypeParent));
952 contentType = sameTypeParent ? eContentTypeContentFrame : eContentTypeContent;
954 rv = CreateViewAndWidget(contentType);
955 if (NS_FAILED(rv)) {
956 return rv;
959 nsCOMPtr<nsIBaseWindow> baseWindow(do_QueryInterface(docShell));
961 if (baseWindow) {
962 baseWindow->InitWindow(nsnull, mInnerView->GetWidget(), 0, 0, 10, 10);
964 // This is kinda whacky, this "Create()" call doesn't really
965 // create anything, one starts to wonder why this was named
966 // "Create"...
968 baseWindow->Create();
970 baseWindow->SetVisibility(PR_TRUE);
973 // Trigger editor re-initialization if midas is turned on in the
974 // sub-document. This shouldn't be necessary, but given the way our
975 // editor works, it is. See
976 // https://bugzilla.mozilla.org/show_bug.cgi?id=284245
977 docShell->GetPresShell(getter_AddRefs(presShell));
978 if (presShell) {
979 nsCOMPtr<nsIDOMNSHTMLDocument> doc =
980 do_QueryInterface(presShell->GetDocument());
982 if (doc) {
983 nsAutoString designMode;
984 doc->GetDesignMode(designMode);
986 if (designMode.EqualsLiteral("on")) {
987 doc->SetDesignMode(NS_LITERAL_STRING("off"));
988 doc->SetDesignMode(NS_LITERAL_STRING("on"));
993 return NS_OK;
996 nsresult
997 nsSubDocumentFrame::CreateViewAndWidget(nsContentType aContentType)
999 if (mInnerView) {
1000 // Nothing to do here
1001 return NS_OK;
1004 // create, init, set the parent of the view
1005 nsIView* outerView = GetView();
1006 NS_ASSERTION(outerView, "Must have an outer view already");
1007 nsRect viewBounds(0, 0, 0, 0); // size will be fixed during reflow
1009 nsIViewManager* viewMan = outerView->GetViewManager();
1010 // Create the inner view hidden if the outer view is already hidden
1011 // (it won't get hidden properly otherwise)
1012 nsIView* innerView = viewMan->CreateView(viewBounds, outerView,
1013 outerView->GetVisibility());
1014 if (!innerView) {
1015 NS_ERROR("Could not create inner view");
1016 return NS_ERROR_OUT_OF_MEMORY;
1018 mInnerView = innerView;
1019 viewMan->InsertChild(outerView, innerView, nsnull, PR_TRUE);
1021 return innerView->CreateWidget(kCChildCID, nsnull, nsnull, PR_TRUE, PR_TRUE,
1022 aContentType);
1025 nsIFrame*
1026 nsSubDocumentFrame::ObtainIntrinsicSizeFrame()
1028 nsCOMPtr<nsIObjectLoadingContent> olc = do_QueryInterface(GetContent());
1029 if (olc) {
1030 // We are an HTML <object>, <embed> or <applet> (a replaced element).
1032 // Try to get an nsIFrame for our sub-document's document element
1033 nsIFrame* subDocRoot = nsnull;
1035 nsCOMPtr<nsIDocShell> docShell;
1036 GetDocShell(getter_AddRefs(docShell));
1037 if (docShell) {
1038 nsCOMPtr<nsIPresShell> presShell;
1039 docShell->GetPresShell(getter_AddRefs(presShell));
1040 if (presShell) {
1041 nsIScrollableFrame* scrollable = presShell->GetRootScrollFrameAsScrollable();
1042 if (scrollable) {
1043 nsIFrame* scrolled = scrollable->GetScrolledFrame();
1044 if (scrolled) {
1045 subDocRoot = scrolled->GetFirstChild(nsnull);
1051 #ifdef MOZ_SVG
1052 if (subDocRoot && subDocRoot->GetContent() &&
1053 subDocRoot->GetContent()->NodeInfo()->Equals(nsGkAtoms::svg, kNameSpaceID_SVG)) {
1054 return subDocRoot; // SVG documents have an intrinsic size
1056 #endif
1058 return nsnull;