Back to index

lightning-sunbird  0.9+nobinonly
nsFrameFrame.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Travis Bogard <travis@netscape.com>
00024  *   Håkan Waara <hwaara@chello.se>
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either of the GNU General Public License Version 2 or later (the "GPL"),
00028  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 #include "nsCOMPtr.h"
00040 #include "nsLeafFrame.h"
00041 #include "nsGenericHTMLElement.h"
00042 #include "nsIDocShell.h"
00043 #include "nsIDocShellLoadInfo.h"
00044 #include "nsIDocShellTreeItem.h"
00045 #include "nsIDocShellTreeNode.h"
00046 #include "nsIDocShellTreeOwner.h"
00047 #include "nsIBaseWindow.h"
00048 #include "nsIContentViewer.h"
00049 #include "nsIMarkupDocumentViewer.h"
00050 #include "nsPresContext.h"
00051 #include "nsIPresShell.h"
00052 #include "nsIComponentManager.h"
00053 #include "nsFrameManager.h"
00054 #include "nsIStreamListener.h"
00055 #include "nsIURL.h"
00056 #include "nsNetUtil.h"
00057 #include "nsIDocument.h"
00058 #include "nsIView.h"
00059 #include "nsIViewManager.h"
00060 #include "nsWidgetsCID.h"
00061 #include "nsViewsCID.h"
00062 #include "nsHTMLAtoms.h"
00063 #include "nsIScrollableView.h"
00064 #include "nsStyleCoord.h"
00065 #include "nsStyleContext.h"
00066 #include "nsStyleConsts.h"
00067 #include "nsIDocumentLoader.h"
00068 #include "nsFrameSetFrame.h"
00069 #include "nsIDOMHTMLFrameElement.h"
00070 #include "nsIDOMHTMLIFrameElement.h"
00071 #include "nsIDOMXULElement.h"
00072 #include "nsIFrameLoader.h"
00073 #include "nsLayoutAtoms.h"
00074 #include "nsIScriptSecurityManager.h"
00075 #include "nsXPIDLString.h"
00076 #include "nsIScrollable.h"
00077 #include "nsINameSpaceManager.h"
00078 #include "nsIWidget.h"
00079 #include "nsIWebBrowserPrint.h"
00080 #include "nsWeakReference.h"
00081 #include "nsIDOMWindow.h"
00082 #include "nsIDOMDocument.h"
00083 #include "nsIRenderingContext.h"
00084 #include "nsIFrameFrame.h"
00085 #include "nsAutoPtr.h"
00086 #include "nsIDOMNSHTMLDocument.h"
00087 #include "nsUnicharUtils.h"
00088 
00089 // For Accessibility
00090 #ifdef ACCESSIBILITY
00091 #include "nsIAccessibilityService.h"
00092 #endif
00093 #include "nsIServiceManager.h"
00094 
00095 static NS_DEFINE_CID(kCChildCID, NS_CHILD_CID);
00096 
00097 /******************************************************************************
00098  * nsSubDocumentFrame
00099  *****************************************************************************/
00100 class nsSubDocumentFrame : public nsLeafFrame,
00101                            public nsIFrameFrame
00102 {
00103 public:
00104   nsSubDocumentFrame();
00105 
00106 #ifdef DEBUG
00107   NS_IMETHOD GetFrameName(nsAString& aResult) const;
00108 #endif
00109 
00110   // nsISupports
00111   NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr);
00112   NS_IMETHOD_(nsrefcnt) AddRef(void) { return 2; }
00113   NS_IMETHOD_(nsrefcnt) Release(void) { return 1; }
00114 
00115   virtual nsIAtom* GetType() const;
00116 
00117   NS_IMETHOD Init(nsPresContext*  aPresContext,
00118                   nsIContent*      aContent,
00119                   nsIFrame*        aParent,
00120                   nsStyleContext*  aContext,
00121                   nsIFrame*        aPrevInFlow);
00122 
00123   NS_IMETHOD Destroy(nsPresContext* aPresContext);
00124 
00125   NS_IMETHOD Reflow(nsPresContext*          aPresContext,
00126                     nsHTMLReflowMetrics&     aDesiredSize,
00127                     const nsHTMLReflowState& aReflowState,
00128                     nsReflowStatus&          aStatus);
00129 
00130   NS_IMETHOD AttributeChanged(nsIContent* aChild,
00131                               PRInt32 aNameSpaceID,
00132                               nsIAtom* aAttribute,
00133                               PRInt32 aModType);
00134 
00135   // if the content is "visibility:hidden", then just hide the view
00136   // and all our contents. We don't extend "visibility:hidden" to
00137   // the child content ourselves, since it belongs to a different
00138   // document and CSS doesn't inherit in there.
00139   virtual PRBool SupportsVisibilityHidden() { return PR_FALSE; }
00140 
00141 #ifdef ACCESSIBILITY
00142   NS_IMETHOD GetAccessible(nsIAccessible** aAccessible);
00143 #endif
00144 
00145   // nsIFrameFrame
00146   NS_IMETHOD GetDocShell(nsIDocShell **aDocShell);
00147 
00148   NS_IMETHOD  VerifyTree() const;
00149 
00150 protected:
00151   nsSize GetMargin();
00152   PRBool IsInline() { return mIsInline; }
00153   nsresult ReloadURL();
00154   nsresult ShowDocShell();
00155   nsresult CreateViewAndWidget(nsContentType aContentType);
00156 
00157   virtual void GetDesiredSize(nsPresContext* aPresContext,
00158                               const nsHTMLReflowState& aReflowState,
00159                               nsHTMLReflowMetrics& aDesiredSize);
00160   virtual PRIntn GetSkipSides() const;
00161 
00162   nsCOMPtr<nsIFrameLoader> mFrameLoader;
00163   nsIView* mInnerView;
00164   PRPackedBool mDidCreateDoc;
00165   PRPackedBool mOwnsFrameLoader;
00166   PRPackedBool mIsInline;
00167 };
00168 
00169 nsSubDocumentFrame::nsSubDocumentFrame()
00170   : nsLeafFrame(), mDidCreateDoc(PR_FALSE), mOwnsFrameLoader(PR_FALSE),
00171     mIsInline(PR_FALSE)
00172 {
00173 }
00174 
00175 #ifdef ACCESSIBILITY
00176 NS_IMETHODIMP nsSubDocumentFrame::GetAccessible(nsIAccessible** aAccessible)
00177 {
00178   nsCOMPtr<nsIAccessibilityService> accService = do_GetService("@mozilla.org/accessibilityService;1");
00179 
00180   if (accService) {
00181     nsCOMPtr<nsIDOMNode> node = do_QueryInterface(mContent);
00182     return accService->CreateOuterDocAccessible(node, aAccessible);
00183   }
00184 
00185   return NS_ERROR_FAILURE;
00186 }
00187 #endif
00188 
00189 //--------------------------------------------------------------
00190 // Frames are not refcounted, no need to AddRef
00191 NS_IMETHODIMP
00192 nsSubDocumentFrame::QueryInterface(const nsIID& aIID, void** aInstancePtr)
00193 {
00194   NS_PRECONDITION(0 != aInstancePtr, "null ptr");
00195   if (NULL == aInstancePtr) {
00196     return NS_ERROR_NULL_POINTER;
00197   }
00198 
00199   if (aIID.Equals(NS_GET_IID(nsIFrameFrame))) {
00200     nsISupports *tmp = NS_STATIC_CAST(nsIFrameFrame *, this);
00201     *aInstancePtr = tmp;
00202     return NS_OK;
00203   }
00204 
00205   return nsLeafFrame::QueryInterface(aIID, aInstancePtr);
00206 }
00207 
00208 NS_IMETHODIMP
00209 nsSubDocumentFrame::Init(nsPresContext* aPresContext,
00210                          nsIContent*     aContent,
00211                          nsIFrame*       aParent,
00212                          nsStyleContext* aContext,
00213                          nsIFrame*       aPrevInFlow)
00214 {
00215   // determine if we are a <frame> or <iframe>
00216   if (aContent) {
00217     nsCOMPtr<nsIDOMHTMLFrameElement> frameElem = do_QueryInterface(aContent);
00218     mIsInline = frameElem ? PR_FALSE : PR_TRUE;
00219   }
00220 
00221   nsresult rv =  nsLeafFrame::Init(aPresContext, aContent, aParent,
00222                                    aContext, aPrevInFlow);
00223   if (NS_FAILED(rv))
00224     return rv;
00225 
00226   // We are going to create an inner view.  If we need a view for the
00227   // OuterFrame but we wait for the normal view creation path in
00228   // nsCSSFrameConstructor, then we will lose because the inner view's
00229   // parent will already have been set to some outer view (e.g., the
00230   // canvas) when it really needs to have this frame's view as its
00231   // parent. So, create this frame's view right away, whether we
00232   // really need it or not, and the inner view will get it as the
00233   // parent.
00234   if (!HasView()) {
00235     // To properly initialize the view we need to know the frame for the content
00236     // that is the parent of content for this frame. This might not be our actual
00237     // frame parent if we are out of flow (e.g., positioned) so our parent frame
00238     // may have been set to some other ancestor.
00239     // We look for a content parent frame in the frame property list, where it
00240     // will have been set by nsCSSFrameConstructor if necessary.
00241     nsCOMPtr<nsIAtom> contentParentAtom = do_GetAtom("contentParent");
00242     nsIFrame* contentParent = nsnull;
00243 
00244     void *value =
00245       aPresContext->PropertyTable()->UnsetProperty(this,
00246                                                    contentParentAtom, &rv);
00247     if (NS_SUCCEEDED(rv)) {
00248           contentParent = (nsIFrame*)value;
00249     }
00250 
00251     nsHTMLContainerFrame::CreateViewForFrame(this, contentParent, PR_TRUE);
00252   }
00253   nsIView* view = GetView();
00254   NS_ASSERTION(view, "We should always have a view now");
00255 
00256   if (aParent->GetStyleDisplay()->mDisplay == NS_STYLE_DISPLAY_DECK
00257       && !view->HasWidget()) {
00258     view->CreateWidget(kCChildCID);
00259   }
00260 
00261   // determine if we are a printcontext
00262   PRBool shouldCreateDoc;
00263 
00264   if (aPresContext->Medium() == nsLayoutAtoms::print) {
00265     if (aPresContext->Type() == nsPresContext::eContext_PrintPreview) {
00266       // for print preview we want to create the view and widget but
00267       // we do not want to load the document, it is already loaded.
00268       rv = CreateViewAndWidget(eContentTypeContent);
00269       NS_ENSURE_SUCCESS(rv,rv);
00270     }
00271 
00272     shouldCreateDoc = PR_FALSE;
00273   } else {
00274     shouldCreateDoc = PR_TRUE;
00275   }
00276 
00277   if (shouldCreateDoc) {
00278     rv = ShowDocShell();
00279     NS_ENSURE_SUCCESS(rv,rv);
00280     mDidCreateDoc = PR_TRUE;
00281   }
00282 
00283   return NS_OK;
00284 }
00285 
00286 PRIntn
00287 nsSubDocumentFrame::GetSkipSides() const
00288 {
00289   return 0;
00290 }
00291 
00292 void
00293 nsSubDocumentFrame::GetDesiredSize(nsPresContext* aPresContext,
00294                                    const nsHTMLReflowState& aReflowState,
00295                                    nsHTMLReflowMetrics& aDesiredSize)
00296 {
00297   // <frame> processing does not use this routine, only <iframe>
00298   float p2t = 0;
00299   if (!mContent->IsContentOfType(nsIContent::eXUL))
00300     // If no width/height was specified, use 300/150.
00301     // This is for compatability with IE.
00302     p2t = aPresContext->ScaledPixelsToTwips();
00303 
00304   if (NS_UNCONSTRAINEDSIZE != aReflowState.mComputedWidth) {
00305     aDesiredSize.width = aReflowState.mComputedWidth;
00306   }
00307   else {
00308     aDesiredSize.width = PR_MAX(PR_MIN(NSIntPixelsToTwips(300, p2t),
00309                                        aReflowState.mComputedMaxWidth), 
00310                                 aReflowState.mComputedMinWidth);
00311   }
00312   if (NS_UNCONSTRAINEDSIZE != aReflowState.mComputedHeight) {
00313     aDesiredSize.height = aReflowState.mComputedHeight;
00314   }
00315   else {
00316     aDesiredSize.height = PR_MAX(PR_MIN(NSIntPixelsToTwips(150, p2t),
00317                                         aReflowState.mComputedMaxHeight),
00318                                  aReflowState.mComputedMinHeight);
00319   }
00320   aDesiredSize.ascent = aDesiredSize.height;
00321   aDesiredSize.descent = 0;
00322 }
00323 
00324 #ifdef DEBUG
00325 NS_IMETHODIMP nsSubDocumentFrame::GetFrameName(nsAString& aResult) const
00326 {
00327   return MakeFrameName(NS_LITERAL_STRING("FrameOuter"), aResult);
00328 }
00329 #endif
00330 
00331 nsIAtom*
00332 nsSubDocumentFrame::GetType() const
00333 {
00334   return nsLayoutAtoms::subDocumentFrame;
00335 }
00336 
00337 NS_IMETHODIMP
00338 nsSubDocumentFrame::Reflow(nsPresContext*          aPresContext,
00339                            nsHTMLReflowMetrics&     aDesiredSize,
00340                            const nsHTMLReflowState& aReflowState,
00341                            nsReflowStatus&          aStatus)
00342 {
00343   DO_GLOBAL_REFLOW_COUNT("nsSubDocumentFrame", aReflowState.reason);
00344   DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);
00345   // printf("OuterFrame::Reflow %X (%d,%d) \n", this, aReflowState.availableWidth, aReflowState.availableHeight);
00346   NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,
00347      ("enter nsSubDocumentFrame::Reflow: maxSize=%d,%d reason=%d",
00348       aReflowState.availableWidth, aReflowState.availableHeight, aReflowState.reason));
00349 
00350   aStatus = NS_FRAME_COMPLETE;
00351 
00352   if (IsInline()) {
00353     GetDesiredSize(aPresContext, aReflowState, aDesiredSize); // IFRAME
00354   } else {
00355     aDesiredSize.width  = aReflowState.availableWidth; // FRAME
00356     aDesiredSize.height = aReflowState.availableHeight;
00357   }
00358 
00359   nsSize innerSize(aDesiredSize.width, aDesiredSize.height);
00360   nsPoint offset(0, 0);
00361   nsMargin border = aReflowState.mComputedBorderPadding;
00362 
00363   if (IsInline()) {
00364     offset = nsPoint(border.left, border.top);
00365     aDesiredSize.width += border.left + border.right;
00366     aDesiredSize.height += border.top + border.bottom;
00367   }
00368   
00369   // might not have an inner view yet during printing
00370   if (mInnerView) {
00371     nsIViewManager* vm = mInnerView->GetViewManager();
00372     vm->MoveViewTo(mInnerView, offset.x, offset.y);
00373     vm->ResizeView(mInnerView, nsRect(0, 0, innerSize.width, innerSize.height), PR_TRUE);
00374   }
00375 
00376   if (aDesiredSize.mComputeMEW) {   
00377     nscoord defaultAutoWidth = NSIntPixelsToTwips(300, aPresContext->ScaledPixelsToTwips());
00378     if (mContent->IsContentOfType(nsIContent::eXUL)) {
00379         // XUL frames don't have a default 300px width
00380         defaultAutoWidth = 0;
00381     }
00382     nsStyleUnit widthUnit = GetStylePosition()->mWidth.GetUnit();
00383     switch (widthUnit) {
00384     case eStyleUnit_Percent:
00385       // if our width is percentage, then we can shrink until
00386       // there's nothing left but our borders
00387       aDesiredSize.mMaxElementWidth = border.left + border.right;
00388       break;
00389     case eStyleUnit_Auto:
00390       aDesiredSize.mMaxElementWidth = PR_MAX(PR_MIN(defaultAutoWidth,
00391                                                     aReflowState.mComputedMaxWidth),
00392                                              aReflowState.mComputedMinWidth) +
00393                                       border.left + border.right;
00394       break;
00395     default:
00396       // If our width is set by style to some fixed length,
00397       // then our actual width is our minimum width
00398       aDesiredSize.mMaxElementWidth = aDesiredSize.width;
00399       break;
00400     }
00401   }
00402 
00403   // Determine if we need to repaint our border, background or outline
00404   CheckInvalidateSizeChange(aPresContext, aDesiredSize, aReflowState);
00405 
00406   // Invalidate the frame contents
00407   nsRect rect(nsPoint(0, 0), GetSize());
00408   Invalidate(rect, PR_FALSE);
00409 
00410   if (!aPresContext->IsPaginated()) {
00411     nsCOMPtr<nsIDocShell> docShell;
00412     GetDocShell(getter_AddRefs(docShell));
00413 
00414     nsCOMPtr<nsIBaseWindow> baseWindow(do_QueryInterface(docShell));
00415 
00416     // resize the sub document
00417     if (baseWindow) {
00418       float t2p;
00419       t2p = aPresContext->TwipsToPixels();
00420       PRInt32 x = 0;
00421       PRInt32 y = 0;
00422       
00423       baseWindow->GetPositionAndSize(&x, &y, nsnull, nsnull);
00424       PRInt32 cx = NSToCoordRound(innerSize.width * t2p);
00425       PRInt32 cy = NSToCoordRound(innerSize.height * t2p);
00426       baseWindow->SetPositionAndSize(x, y, cx, cy, PR_FALSE);
00427     }
00428   }
00429 
00430   // printf("OuterFrame::Reflow DONE %X (%d,%d), MEW=%d(%d)\n", this,
00431   //        aDesiredSize.width, aDesiredSize.height, aDesiredSize.mMaxElementWidth,
00432   //        aDesiredSize.mComputeMEW);
00433 
00434   NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,
00435      ("exit nsSubDocumentFrame::Reflow: size=%d,%d status=%x",
00436       aDesiredSize.width, aDesiredSize.height, aStatus));
00437 
00438   NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
00439   return NS_OK;
00440 }
00441 
00442 NS_IMETHODIMP
00443 nsSubDocumentFrame::VerifyTree() const
00444 {
00445   // XXX Completely disabled for now; once pseud-frames are reworked
00446   // then we can turn it back on.
00447   return NS_OK;
00448 }
00449 
00450 NS_IMETHODIMP
00451 nsSubDocumentFrame::AttributeChanged(nsIContent* aChild,
00452                                      PRInt32 aNameSpaceID,
00453                                      nsIAtom* aAttribute,
00454                                      PRInt32 aModType)
00455 {
00456   if (aNameSpaceID != kNameSpaceID_None) {
00457     return NS_OK;
00458   }
00459   
00460   nsIAtom *type = aChild->Tag();
00461 
00462   if ((type != nsHTMLAtoms::object && aAttribute == nsHTMLAtoms::src) ||
00463       (type == nsHTMLAtoms::object && aAttribute == nsHTMLAtoms::data)) {
00464     ReloadURL();
00465   }
00466   // If the noResize attribute changes, dis/allow frame to be resized
00467   else if (aAttribute == nsHTMLAtoms::noresize) {
00468     // Note that we're not doing content type checks, but that's ok -- if
00469     // they'd fail we will just end up with a null framesetFrame.
00470     if (mContent->GetParent()->Tag() == nsHTMLAtoms::frameset) {
00471       nsIFrame* parentFrame = GetParent();
00472 
00473       if (parentFrame) {
00474         // There is no interface for nsHTMLFramesetFrame so QI'ing to
00475         // concrete class, yay!
00476         nsHTMLFramesetFrame* framesetFrame = nsnull;
00477         parentFrame->QueryInterface(NS_GET_IID(nsHTMLFramesetFrame),
00478                                     (void **)&framesetFrame);
00479 
00480         if (framesetFrame) {
00481           framesetFrame->RecalculateBorderResize();
00482         }
00483       }
00484     }
00485   }
00486   else if (aAttribute == nsHTMLAtoms::type) {
00487     if (!mFrameLoader) 
00488       return NS_OK;
00489 
00490     if (!mContent->IsContentOfType(nsIContent::eXUL)) {
00491       return NS_OK;
00492     }
00493 
00494     // Note: This logic duplicates a lot of logic in
00495     // nsFrameLoader::EnsureDocShell.  We should fix that.
00496 
00497     // Notify our enclosing chrome that our type has changed.  We only do this
00498     // if our parent is chrome, since in all other cases we're random content
00499     // subframes and the treeowner shouldn't worry about us.
00500 
00501     nsCOMPtr<nsIDocShell> docShell;
00502     mFrameLoader->GetDocShell(getter_AddRefs(docShell));
00503     nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryInterface(docShell));
00504     if (!docShellAsItem) {
00505       return NS_OK;
00506     }
00507 
00508     nsCOMPtr<nsIDocShellTreeItem> parentItem;
00509     docShellAsItem->GetParent(getter_AddRefs(parentItem));
00510 
00511     PRInt32 parentType;
00512     parentItem->GetItemType(&parentType);
00513 
00514     if (parentType != nsIDocShellTreeItem::typeChrome) {
00515       return NS_OK;
00516     }
00517 
00518     nsCOMPtr<nsIDocShellTreeOwner> parentTreeOwner;
00519     parentItem->GetTreeOwner(getter_AddRefs(parentTreeOwner));
00520     if (parentTreeOwner) {
00521       nsAutoString value;
00522       mContent->GetAttr(kNameSpaceID_None, nsHTMLAtoms::type, value);
00523 
00524       PRBool is_primary = value.LowerCaseEqualsLiteral("content-primary");
00525 
00526       // when a content panel is no longer primary, hide any open popups it may have
00527       if (!is_primary) {
00528         nsCOMPtr<nsIDocShell> docShell;
00529         GetDocShell(getter_AddRefs(docShell));
00530         if (docShell) {
00531           nsCOMPtr<nsIPresShell> presShell;
00532           docShell->GetPresShell(getter_AddRefs(presShell));
00533 
00534           nsCOMPtr<nsIPresShell_MOZILLA_1_8_BRANCH> presShell18 = do_QueryInterface(presShell);
00535           if (presShell18)
00536             presShell18->HidePopups();
00537         }
00538       }
00539 
00540       nsCOMPtr<nsIDocShellTreeOwner_MOZILLA_1_8_BRANCH> owner2 =
00541         do_QueryInterface(parentTreeOwner);
00542 
00543       if (!owner2) {
00544         // XXXbz this adds stuff even if it's not of type content-*, but not
00545         // much we can do about that....
00546         parentTreeOwner->ContentShellAdded(docShellAsItem, is_primary,
00547                                            value.get());
00548       } else {
00549         owner2->ContentShellRemoved(docShellAsItem);
00550 
00551         if (value.LowerCaseEqualsLiteral("content") ||
00552             StringBeginsWith(value, NS_LITERAL_STRING("content-"),
00553                              nsCaseInsensitiveStringComparator())) {
00554           PRBool is_targetable = is_primary ||
00555             value.LowerCaseEqualsLiteral("content-targetable");
00556 
00557           owner2->ContentShellAdded2(docShellAsItem, is_primary, is_targetable,
00558                                      value);
00559         }
00560       }
00561     }
00562   }
00563 
00564   return NS_OK;
00565 }
00566 
00567 nsresult
00568 NS_NewSubDocumentFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame)
00569 {
00570   NS_PRECONDITION(aNewFrame, "null OUT ptr");
00571   if (nsnull == aNewFrame) {
00572     return NS_ERROR_NULL_POINTER;
00573   }
00574   nsSubDocumentFrame* it = new (aPresShell) nsSubDocumentFrame;
00575   if (!it) {
00576     return NS_ERROR_OUT_OF_MEMORY;
00577   }
00578   *aNewFrame = it;
00579   return NS_OK;
00580 }
00581 
00582 NS_IMETHODIMP
00583 nsSubDocumentFrame::Destroy(nsPresContext* aPresContext)
00584 {
00585   if (mFrameLoader && mDidCreateDoc) {
00586     // Get the content viewer through the docshell, but don't call
00587     // GetDocShell() since we don't want to create one if we don't
00588     // have one.
00589 
00590     nsCOMPtr<nsIDocShell> docShell;
00591     mFrameLoader->GetDocShell(getter_AddRefs(docShell));
00592 
00593     if (docShell) {
00594       nsCOMPtr<nsIContentViewer> content_viewer;
00595       docShell->GetContentViewer(getter_AddRefs(content_viewer));
00596 
00597       if (content_viewer) {
00598         // Mark the content viewer as non-sticky so that the presentation
00599         // can safely go away when this frame is destroyed.
00600 
00601         content_viewer->SetSticky(PR_FALSE);
00602       }
00603 
00604       nsCOMPtr<nsIBaseWindow> baseWin = do_QueryInterface(docShell);
00605       NS_ASSERTION(baseWin, "Docshell must be an nsIBaseWindow");
00606 
00607       // Now reverse the steps we took in ShowDocShell().  But don't call
00608       // Destroy(); that will be handled by destroying our frame loader, if
00609       // needed.
00610 
00611       // Hide the content viewer now that the frame is going away...
00612       baseWin->SetVisibility(PR_FALSE);
00613 
00614       // Clear out the parentWidget, since it's about to die with us
00615       baseWin->SetParentWidget(nsnull);
00616     }
00617   }
00618 
00619   if (mFrameLoader && mOwnsFrameLoader) {
00620     // We own this frame loader, and we're going away, so destroy our
00621     // frame loader.
00622 
00623     mFrameLoader->Destroy();
00624   }
00625 
00626   return nsLeafFrame::Destroy(aPresContext);
00627 }
00628 
00629 nsSize nsSubDocumentFrame::GetMargin()
00630 {
00631   nsSize result(-1, -1);
00632   nsGenericHTMLElement *content = nsGenericHTMLElement::FromContent(mContent);
00633   if (content) {
00634     const nsAttrValue* attr = content->GetParsedAttr(nsHTMLAtoms::marginwidth);
00635     if (attr && attr->Type() == nsAttrValue::eInteger)
00636       result.width = attr->GetIntegerValue();
00637     attr = content->GetParsedAttr(nsHTMLAtoms::marginheight);
00638     if (attr && attr->Type() == nsAttrValue::eInteger)
00639       result.height = attr->GetIntegerValue();
00640   }
00641   return result;
00642 }
00643 
00644 // XXX this should be called ObtainDocShell or something like that,
00645 // to indicate that it could have side effects
00646 NS_IMETHODIMP
00647 nsSubDocumentFrame::GetDocShell(nsIDocShell **aDocShell)
00648 {
00649   *aDocShell = nsnull;
00650 
00651   nsIContent* content = GetContent();
00652   if (!content) {
00653     // Hmm, no content in this frame
00654     // that's odd, not much to be done here then.
00655     return NS_OK;
00656   }
00657 
00658   if (!mFrameLoader) {
00659     nsCOMPtr<nsIFrameLoaderOwner> loaderOwner = do_QueryInterface(content);
00660 
00661     if (loaderOwner) {
00662       loaderOwner->GetFrameLoader(getter_AddRefs(mFrameLoader));
00663     }
00664 
00665     if (!mFrameLoader) {
00666       // No frame loader available from the content, create our own...
00667       mFrameLoader = new nsFrameLoader(content);
00668       if (!mFrameLoader)
00669         return NS_ERROR_OUT_OF_MEMORY;
00670 
00671       // ... remember that we own this frame loader...
00672       mOwnsFrameLoader = PR_TRUE;
00673 
00674       // ... and tell it to start loading.
00675       // the failure to load a URL does not constitute failure to 
00676       // create/initialize the docshell and therefore the LoadFrame() 
00677       // call's return value should not be propagated.
00678       mFrameLoader->LoadFrame();
00679     }
00680   }
00681 
00682   return mFrameLoader->GetDocShell(aDocShell);
00683 }
00684 
00685 inline PRInt32 ConvertOverflow(PRUint8 aOverflow)
00686 {
00687   switch (aOverflow) {
00688     case NS_STYLE_OVERFLOW_VISIBLE:
00689     case NS_STYLE_OVERFLOW_AUTO:
00690       return nsIScrollable::Scrollbar_Auto;
00691     case NS_STYLE_OVERFLOW_HIDDEN:
00692     case NS_STYLE_OVERFLOW_CLIP:
00693       return nsIScrollable::Scrollbar_Never;
00694     case NS_STYLE_OVERFLOW_SCROLL:
00695       return nsIScrollable::Scrollbar_Always;
00696   }
00697   NS_NOTREACHED("invalid overflow value passed to ConvertOverflow");
00698   return nsIScrollable::Scrollbar_Auto;
00699 }
00700 
00701 nsresult
00702 nsSubDocumentFrame::ShowDocShell()
00703 {
00704   nsCOMPtr<nsIDocShell> docShell;
00705   nsresult rv = GetDocShell(getter_AddRefs(docShell));
00706   NS_ENSURE_SUCCESS(rv, rv);
00707 
00708   nsCOMPtr<nsIPresShell> presShell;
00709   docShell->GetPresShell(getter_AddRefs(presShell));
00710 
00711   if (presShell) {
00712     // The docshell is already showing, nothing left to do...
00713 
00714     return NS_OK;
00715   }
00716 
00717   // pass along marginwidth, marginheight, scrolling so sub document
00718   // can use it
00719   nsSize margin = GetMargin();
00720   docShell->SetMarginWidth(margin.width);
00721   docShell->SetMarginHeight(margin.height);
00722 
00723   // Current and initial scrolling is set so that all succeeding docs
00724   // will use the scrolling value set here, regardless if scrolling is
00725   // set by viewing a particular document (e.g. XUL turns off scrolling)
00726   nsCOMPtr<nsIScrollable> sc(do_QueryInterface(docShell));
00727 
00728   if (sc) {
00729     const nsStyleDisplay *disp = GetStyleDisplay();
00730     sc->SetDefaultScrollbarPreferences(nsIScrollable::ScrollOrientation_X,
00731                                        ConvertOverflow(disp->mOverflowX));
00732     sc->SetDefaultScrollbarPreferences(nsIScrollable::ScrollOrientation_Y,
00733                                        ConvertOverflow(disp->mOverflowY));
00734   }
00735 
00736   PRInt32 itemType = nsIDocShellTreeItem::typeContent;
00737   nsCOMPtr<nsIDocShellTreeItem> treeItem(do_QueryInterface(docShell));
00738   if (treeItem) {
00739     treeItem->GetItemType(&itemType);
00740   }
00741 
00742   nsContentType contentType;
00743   if (itemType == nsIDocShellTreeItem::typeChrome) {
00744     contentType = eContentTypeUI;
00745   }
00746   else {
00747     nsCOMPtr<nsIDocShellTreeItem> sameTypeParent;
00748     treeItem->GetSameTypeParent(getter_AddRefs(sameTypeParent));
00749     contentType = sameTypeParent ? eContentTypeContentFrame : eContentTypeContent;
00750   }
00751   rv = CreateViewAndWidget(contentType);
00752   if (NS_FAILED(rv)) {
00753     return rv;
00754   }
00755 
00756   nsCOMPtr<nsIBaseWindow> baseWindow(do_QueryInterface(docShell));
00757 
00758   if (baseWindow) {
00759     baseWindow->InitWindow(nsnull, mInnerView->GetWidget(), 0, 0, 10, 10);
00760 
00761     // This is kinda whacky, this "Create()" call doesn't really
00762     // create anything, one starts to wonder why this was named
00763     // "Create"...
00764 
00765     baseWindow->Create();
00766 
00767     baseWindow->SetVisibility(PR_TRUE);
00768   }
00769 
00770   // Trigger editor re-initialization if midas is turned on in the
00771   // sub-document. This shouldn't be necessary, but given the way our
00772   // editor works, it is. See
00773   // https://bugzilla.mozilla.org/show_bug.cgi?id=284245
00774   docShell->GetPresShell(getter_AddRefs(presShell));
00775   if (presShell) {
00776     nsCOMPtr<nsIDOMNSHTMLDocument> doc =
00777       do_QueryInterface(presShell->GetDocument());
00778 
00779     if (doc) {
00780       nsAutoString designMode;
00781       doc->GetDesignMode(designMode);
00782 
00783       if (designMode.EqualsLiteral("on")) {
00784         doc->SetDesignMode(NS_LITERAL_STRING("off"));
00785         doc->SetDesignMode(NS_LITERAL_STRING("on"));
00786       }
00787     }
00788   }
00789 
00790   return NS_OK;
00791 }
00792 
00793 nsresult
00794 nsSubDocumentFrame::CreateViewAndWidget(nsContentType aContentType)
00795 {
00796   // create, init, set the parent of the view
00797   nsIView* outerView = GetView();
00798   NS_ASSERTION(outerView, "Must have an outer view already");
00799   nsRect viewBounds(0, 0, 0, 0); // size will be fixed during reflow
00800 
00801   nsIViewManager* viewMan = outerView->GetViewManager();
00802   // Create the inner view hidden if the outer view is already hidden
00803   // (it won't get hidden properly otherwise)
00804   nsIView* innerView = viewMan->CreateView(viewBounds, outerView,
00805                                            outerView->GetVisibility());
00806   if (!innerView) {
00807     NS_ERROR("Could not create inner view");
00808     return NS_ERROR_OUT_OF_MEMORY;
00809   }
00810   mInnerView = innerView;
00811   viewMan->InsertChild(outerView, innerView, nsnull, PR_TRUE);
00812 
00813   return innerView->CreateWidget(kCChildCID, nsnull, nsnull, PR_TRUE, PR_TRUE,
00814                                  aContentType);
00815 }
00816 
00817 // load a new url
00818 nsresult
00819 nsSubDocumentFrame::ReloadURL()
00820 {
00821   if (!mOwnsFrameLoader || !mFrameLoader) {
00822     // If we don't own the frame loader, we're not in charge of what's
00823     // loaded into it.
00824     return NS_OK;
00825   }
00826 
00827   return mFrameLoader->LoadFrame();
00828 }
00829 
00830