Commit a756d86e authored by Robert O'Callahan's avatar Robert O'Callahan
Browse files

Bug 352093. Part 12: Teach nsDocShell/nsDocumentViewer to deal with not having a widget

parent 556aebfd
Loading
Loading
Loading
Loading
+8 −27
Original line number Diff line number Diff line
@@ -4141,8 +4141,6 @@ nsDocShell::InitWindow(nativeWindow parentNativeWindow,
                       nsIWidget * parentWidget, PRInt32 x, PRInt32 y,
                       PRInt32 cx, PRInt32 cy)
{
    NS_ENSURE_ARG(parentWidget);        // DocShells must get a widget for a parent

    SetParentWidget(parentWidget);
    SetPositionAndSize(x, y, cx, cy, PR_FALSE);

@@ -6341,22 +6339,11 @@ nsDocShell::CaptureState()
    NS_ENSURE_SUCCESS(rv, rv);

    // Capture the current content viewer bounds.
    nsCOMPtr<nsIPresShell> shell;
    nsDocShell::GetPresShell(getter_AddRefs(shell));
    if (shell) {
        nsIViewManager *vm = shell->GetViewManager();
        if (vm) {
            nsIView *rootView = nsnull;
            vm->GetRootView(rootView);
            if (rootView) {
                nsIWidget *widget = rootView->GetWidget();
                if (widget) {
                    nsIntRect bounds(0, 0, 0, 0);
                    widget->GetBounds(bounds);
    if (mContentViewer) {
        nsIntRect bounds;
        mContentViewer->GetBounds(bounds);
        rv = mOSHE->SetViewerBounds(bounds);
                }
            }
        }
        NS_ENSURE_SUCCESS(rv, rv);
    }

    // Capture the docshell hierarchy.
@@ -6690,10 +6677,7 @@ nsDocShell::RestoreFromHistory()
                rootViewSibling = oldRootView->GetNextSibling();
                rootViewParent = oldRootView->GetParent();

                nsIWidget *widget = oldRootView->GetWidget();
                if (widget) {
                    widget->GetBounds(newBounds);
                }
                mContentViewer->GetBounds(newBounds);
            }
        }
    }
@@ -6938,15 +6922,12 @@ nsDocShell::RestoreFromHistory()
    // cached viewer size (skipping the resize if they are equal).

    if (newRootView) {
        nsIWidget *widget = newRootView->GetWidget();
        if (widget && !newBounds.IsEmpty() && newBounds != oldBounds) {
        if (!newBounds.IsEmpty() && newBounds != oldBounds) {
#ifdef DEBUG_PAGE_CACHE
            printf("resize widget(%d, %d, %d, %d)\n", newBounds.x,
                   newBounds.y, newBounds.width, newBounds.height);
#endif

            widget->Resize(newBounds.x, newBounds.y, newBounds.width,
                           newBounds.height, PR_FALSE);
            mContentViewer->SetBounds(newBounds);
        }
    }

+114 −76
Original line number Diff line number Diff line
@@ -363,17 +363,21 @@ private:
  nsresult MakeWindow(const nsSize& aSize, nsIView* aContainerView);

  /**
   * Find the view to use as the container view for MakeWindow.
   * Find the view to use as the container view for MakeWindow. Returns
   * null if this will be the root of a view manager hierarchy. In that
   * case, if mParentWidget is null then this document should not even
   * be displayed.
   */
  nsIView* FindContainerView();

  /**
   * Create our device context
   */
  nsresult CreateDeviceContext(nsIWidget* aWidget);
  nsresult CreateDeviceContext(nsIView* aContainerView);

  /**
   * Make sure to set up mDeviceContext as needed before calling this
   * If aDoCreation is true, this creates the device context, creates a
   * prescontext if necessary, and calls MakeWindow.
   */
  nsresult InitInternal(nsIWidget* aParentWidget,
                        nsISupports *aState,
@@ -431,7 +435,7 @@ protected:
  // the following six items are explicitly in this order
  // so they will be destroyed in the reverse order (pinkerton, scc)
  nsCOMPtr<nsIDocument>    mDocument;
  nsCOMPtr<nsIWidget>      mWindow;      // ??? should we really own it?
  nsCOMPtr<nsIWidget>      mWindow;      // may be null
  nsCOMPtr<nsIViewManager> mViewManager;
  nsCOMPtr<nsPresContext> mPresContext;
  nsCOMPtr<nsIPresShell>   mPresShell;
@@ -444,6 +448,8 @@ protected:

  nsIWidget* mParentWidget; // purposely won't be ref counted.  May be null

  nsIntRect mBounds;

  // mTextZoom/mPageZoom record the textzoom/pagezoom of the first (galley)
  // presshell only.
  float mTextZoom;      // Text zoom, defaults to 1.0
@@ -687,9 +693,6 @@ NS_IMETHODIMP
DocumentViewerImpl::Init(nsIWidget* aParentWidget,
                         const nsIntRect& aBounds)
{
  nsresult rv = CreateDeviceContext(aParentWidget);
  NS_ENSURE_SUCCESS(rv, rv);
  
  return InitInternal(aParentWidget, nsnull, aBounds, PR_TRUE, PR_FALSE);
}

@@ -731,11 +734,8 @@ DocumentViewerImpl::InitPresentationStuff(PRBool aDoInitialReflow, PRBool aReena
  mPresShell->BeginObservingDocument();

  // Initialize our view manager
  nsIntRect bounds;
  mWindow->GetBounds(bounds);

  nscoord width = mPresContext->DeviceContext()->UnscaledAppUnitsPerDevPixel() * bounds.width;
  nscoord height = mPresContext->DeviceContext()->UnscaledAppUnitsPerDevPixel() * bounds.height;
  nscoord width = mPresContext->DeviceContext()->UnscaledAppUnitsPerDevPixel() * mBounds.width;
  nscoord height = mPresContext->DeviceContext()->UnscaledAppUnitsPerDevPixel() * mBounds.height;

  mViewManager->DisableRefresh();
  mViewManager->SetWindowDimensions(width, height);
@@ -839,6 +839,7 @@ DocumentViewerImpl::InitInternal(nsIWidget* aParentWidget,
                                 PRBool aNeedMakeCX /*= PR_TRUE*/)
{
  mParentWidget = aParentWidget; // not ref counted
  mBounds = aBounds;

  nsresult rv = NS_OK;
  NS_ENSURE_TRUE(mDocument, NS_ERROR_NULL_POINTER);
@@ -847,11 +848,15 @@ DocumentViewerImpl::InitInternal(nsIWidget* aParentWidget,

  PRBool makeCX = PR_FALSE;
  if (aDoCreation) {
    nsresult rv = CreateDeviceContext(containerView);
    NS_ENSURE_SUCCESS(rv, rv);

    // XXXbz this is a nasty hack to do with the fact that we create
    // presentations both in Init() and in Show()...  Ideally we would only do
    // it in one place (Show()) and require that callers call init(), open(),
    // show() in that order or something.
    if ((aParentWidget || mDocument->GetDisplayDocument()) && !mPresContext) {
    if (!mPresContext &&
        (aParentWidget || containerView || mDocument->GetDisplayDocument())) {
      // Create presentation context
      if (mIsPageMode) {
        //Presentation context already created in SetPageMode which is calling this method
@@ -1298,13 +1303,10 @@ DocumentViewerImpl::Open(nsISupports *aState, nsISHEntry *aSHEntry)
{
  NS_ENSURE_TRUE(mPresShell, NS_ERROR_NOT_INITIALIZED);

  nsIntRect bounds;
  mWindow->GetBounds(bounds);

  if (mDocument)
    mDocument->SetContainer(nsCOMPtr<nsISupports>(do_QueryReferent(mContainer)));

  nsresult rv = InitInternal(mParentWidget, aState, bounds, PR_FALSE, PR_FALSE);
  nsresult rv = InitInternal(mParentWidget, aState, mBounds, PR_FALSE, PR_FALSE);
  NS_ENSURE_SUCCESS(rv, rv);

  if (mPresShell)
@@ -1770,13 +1772,7 @@ NS_IMETHODIMP
DocumentViewerImpl::GetBounds(nsIntRect& aResult)
{
  NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_AVAILABLE);
  NS_PRECONDITION(mWindow, "null window");
  if (mWindow) {
    mWindow->GetBounds(aResult);
  }
  else {
    aResult.SetRect(0, 0, 0, 0);
  }
  aResult = mBounds;
  return NS_OK;
}

@@ -1826,11 +1822,16 @@ DocumentViewerImpl::SetBounds(const nsIntRect& aBounds)
{
  NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_AVAILABLE);

  mBounds = aBounds;
  if (mWindow) {
    // Don't have the widget repaint. Layout will generate repaint requests
    // during reflow
    mWindow->Resize(aBounds.x, aBounds.y, aBounds.width, aBounds.height,
                    PR_FALSE);
  } else if (mPresContext && mViewManager) {
    PRInt32 p2a = mPresContext->AppUnitsPerDevPixel();
    mViewManager->SetWindowDimensions(NSIntPixelsToAppUnits(mBounds.width, p2a),
                                      NSIntPixelsToAppUnits(mBounds.height, p2a));
  }

  // If there's a previous viewer, it's the one that's actually showing,
@@ -1857,7 +1858,7 @@ NS_IMETHODIMP
DocumentViewerImpl::Move(PRInt32 aX, PRInt32 aY)
{
  NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_AVAILABLE);
  NS_PRECONDITION(mWindow, "null window");
  mBounds.MoveTo(aX, aY);
  if (mWindow) {
    mWindow->Move(aX, aY);
  }
@@ -1907,19 +1908,22 @@ DocumentViewerImpl::Show(void)
    mWindow->Show(PR_TRUE);
  }

  if (mDocument && !mPresShell && !mWindow) {
  if (mDocument && !mPresShell) {
    NS_ASSERTION(!mWindow, "Window already created but no presshell?");

    nsCOMPtr<nsIBaseWindow> base_win(do_QueryReferent(mContainer));
    if (base_win) {
      base_win->GetParentWidget(&mParentWidget);
      NS_ENSURE_TRUE(mParentWidget, NS_ERROR_UNEXPECTED);
      if (mParentWidget) {
        mParentWidget->Release(); // GetParentWidget AddRefs, but mParentWidget is weak
      }

    nsresult rv = CreateDeviceContext(mParentWidget);
    NS_ENSURE_SUCCESS(rv, rv);
    }

    nsIView* containerView = FindContainerView();

    nsresult rv = CreateDeviceContext(containerView);
    NS_ENSURE_SUCCESS(rv, rv);

    // Create presentation context
    NS_ASSERTION(!mPresContext, "Shouldn't have a prescontext if we have no shell!");
    mPresContext = CreatePresContext(mDocument,
@@ -1932,16 +1936,8 @@ DocumentViewerImpl::Show(void)
      return rv;
    }

    nsIntRect tbounds;
    if (mParentWidget) {
      mParentWidget->GetBounds(tbounds);
    } else {
      // No good default size; just size to 0 by 0 for lack of anything better.
      tbounds = nsIntRect(0, 0, 0, 0);
    }

    rv = MakeWindow(nsSize(mPresContext->DevPixelsToAppUnits(tbounds.width),
                           mPresContext->DevPixelsToAppUnits(tbounds.height)),
    rv = MakeWindow(nsSize(mPresContext->DevPixelsToAppUnits(mBounds.width),
                           mPresContext->DevPixelsToAppUnits(mBounds.height)),
                           containerView);
    if (NS_FAILED(rv))
      return rv;
@@ -1977,7 +1973,6 @@ DocumentViewerImpl::Show(void)
NS_IMETHODIMP
DocumentViewerImpl::Hide(void)
{
  NS_PRECONDITION(mWindow, "null window");
  if (mWindow) {
    mWindow->Show(PR_FALSE);
  }
@@ -2261,6 +2256,9 @@ DocumentViewerImpl::MakeWindow(const nsSize& aSize, nsIView* aContainerView)
  if (!view)
    return NS_ERROR_OUT_OF_MEMORY;

  // Don't create a widget if we weren't given a parent widget but we
  // have a container view we can hook up to without a widget
  if (mParentWidget || !aContainerView) {
    // pass in a native widget to be the parent widget ONLY if the view hierarchy will stand alone.
    // otherwise the view will find its own parent widget and "do the right thing" to
    // establish a parent/child widget relationship
@@ -2282,6 +2280,7 @@ DocumentViewerImpl::MakeWindow(const nsSize& aSize, nsIView* aContainerView)
                            PR_TRUE, PR_FALSE);
    if (NS_FAILED(rv))
      return rv;
  }

  // Setup hierarchical relationship in view manager
  mViewManager->SetRootView(view);
@@ -2299,14 +2298,50 @@ DocumentViewerImpl::MakeWindow(const nsSize& aSize, nsIView* aContainerView)
nsIView*
DocumentViewerImpl::FindContainerView()
{
  // If mParentWidget has a view, we can hook our view manager up
  // to its view tree
  if (!mParentWidget)
    return nsnull;
  nsIView* containerView = nsIView::GetViewFor(mParentWidget);
  nsIView* containerView = nsnull;

  if (mParentWidget) {
    containerView = nsIView::GetViewFor(mParentWidget);
  } else if (mContainer) {
    nsCOMPtr<nsIDocShellTreeItem> docShellItem = do_QueryReferent(mContainer);
    nsCOMPtr<nsPIDOMWindow> pwin(do_GetInterface(docShellItem));
    if (pwin) {
      nsCOMPtr<nsIContent> content = do_QueryInterface(pwin->GetFrameElementInternal());
      nsCOMPtr<nsIPresShell> parentPresShell;
      if (docShellItem) {
        nsCOMPtr<nsIDocShellTreeItem> parentDocShellItem;
        docShellItem->GetParent(getter_AddRefs(parentDocShellItem));
        if (parentDocShellItem) {
          nsCOMPtr<nsIDocShell> parentDocShell = do_QueryInterface(parentDocShellItem);
          parentDocShell->GetPresShell(getter_AddRefs(parentPresShell));
        }
      }
      if (content && parentPresShell) {
        nsIFrame* f = parentPresShell->GetRealPrimaryFrameFor(content);
        if (f) {
          nsIFrame* subdocFrame = f->GetContentInsertionFrame();
          // subdocFrame might not be a subdocument frame; the frame
          // constructor can treat a <frame> as an inline in some XBL
          // cases. Treat that as display:none, the document is not
          // displayed.
          if (subdocFrame->GetType() == nsGkAtoms::subDocumentFrame) {
            nsIView* subdocFrameView = subdocFrame->GetView();
            NS_ASSERTION(subdocFrameView, "Subdoc frames must have views");
            nsIView* innerView = subdocFrameView->GetFirstChild();
            NS_ASSERTION(innerView, "Subdoc frames must have an inner view too");
            containerView = innerView;
          }
        }
      }
    }
  }

  if (!containerView)
    return nsnull;
  if (mParentWidget->GetTransparencyMode() == eTransparencyTransparent)

  nsIWidget* outerWidget = containerView->GetNearestWidget(nsnull);
  if (outerWidget &&
      outerWidget->GetTransparencyMode() == eTransparencyTransparent)
    return containerView;

  // see if the containerView has already been hooked into a foreign view manager hierarchy
@@ -2339,7 +2374,7 @@ DocumentViewerImpl::FindContainerView()
}

nsresult
DocumentViewerImpl::CreateDeviceContext(nsIWidget* aWidget)
DocumentViewerImpl::CreateDeviceContext(nsIView* aContainerView)
{
  NS_PRECONDITION(!mPresShell && !mPresContext && !mWindow,
                  "This will screw up our existing presentation");
@@ -2347,8 +2382,7 @@ DocumentViewerImpl::CreateDeviceContext(nsIWidget* aWidget)
  
  nsIDocument* doc = mDocument->GetDisplayDocument();
  if (doc) {
    NS_ASSERTION(!aWidget, "Shouldn't have a widget here");
    
    NS_ASSERTION(!aContainerView, "External resource document embedded somewhere?");
    // We want to use our display document's device context if possible
    nsIPresShell* shell = doc->GetPrimaryShell();
    if (shell) {
@@ -2364,7 +2398,14 @@ DocumentViewerImpl::CreateDeviceContext(nsIWidget* aWidget)
  // might have changed.
  mDeviceContext = do_CreateInstance(kDeviceContextCID);
  NS_ENSURE_TRUE(mDeviceContext, NS_ERROR_FAILURE);
  mDeviceContext->Init(aWidget ? aWidget->GetTopLevelWidget() : nsnull);
  nsIWidget* widget = nsnull;
  if (aContainerView) {
    widget = aContainerView->GetNearestWidget(nsnull);
    if (widget) {
      widget = widget->GetTopLevelWidget();
    }
  }
  mDeviceContext->Init(widget);
  return NS_OK;
}

@@ -4235,9 +4276,6 @@ NS_IMETHODIMP DocumentViewerImpl::SetPageMode(PRBool aPageMode, nsIPrintSettings
  // XXX Page mode is only partially working; it's currently used for
  // reftests that require a paginated context
  mIsPageMode = aPageMode;
  // Get the current size of what is being viewed
  nsIntRect bounds;
  mWindow->GetBounds(bounds);

  if (mPresShell) {
    DestroyPresShell();
@@ -4264,7 +4302,7 @@ NS_IMETHODIMP DocumentViewerImpl::SetPageMode(PRBool aPageMode, nsIPrintSettings
    nsresult rv = mPresContext->Init(mDeviceContext);
    NS_ENSURE_SUCCESS(rv, rv);
  }
  InitInternal(mParentWidget, nsnull, bounds, PR_TRUE, PR_FALSE, PR_FALSE);
  InitInternal(mParentWidget, nsnull, mBounds, PR_TRUE, PR_FALSE, PR_FALSE);
  mViewManager->EnableRefresh(NS_VMREFRESH_NO_SYNC);

  Show();
+5 −0
Original line number Diff line number Diff line
@@ -274,6 +274,11 @@ nsSubDocumentFrame::Init(nsIContent* aContent,
    view->CreateWidget(kCChildCID);
  }

  // Set the primary frame now so that
  // DocumentViewerImpl::FindContainerView called by ShowViewer below
  // can find it if necessary.
  PresContext()->FrameManager()->SetPrimaryFrameFor(aContent, this);

  ShowViewer();
  return NS_OK;
}
+8 −7
Original line number Diff line number Diff line
@@ -60,19 +60,19 @@ interface nsIBaseWindow : nsISupports
	/*
	Allows a client to initialize an object implementing this interface with
	the usually required window setup information.
	It is possible to pass null for both parentNativeWindow and parentWidget,
	but only docshells support this.

	@param parentNativeWindow - This allows a system to pass in the parenting
		window as a native reference rather than relying on the calling
		application to have created the parent window as an nsIWidget.  This 
		value will be ignored (should be nsnull) if an nsIWidget is passed in to
		the parentWidget parameter.  One of the two parameters however must be
		passed.
		the parentWidget parameter.

	@param parentWidget - This allows a system to pass in the parenting widget.
		This allows some objects to optimize themselves and rely on the view
		system for event flow rather than creating numerous native windows.  If
		one of these is not available, nsnull should be passed and a 
		valid native window should be passed to the parentNativeWindow parameter.
		one of these is not available, nsnull should be passed.

	@param x - This is the x co-ordinate relative to the parent to place the
		window.
@@ -161,9 +161,10 @@ interface nsIBaseWindow : nsISupports
	void repaint(in boolean force);

	/*			  
	This is the parenting widget for the control.  This may be null if only the
	native window was handed in for the parent during initialization.  If this
	is returned, it should refer to the same object as parentNativeWindow.
	This is the parenting widget for the control.  This may be null if the
	native window was handed in for the parent during initialization.
	If this	is returned, it should refer to the same object as
	parentNativeWindow.

	Setting this after Create() has been called may not be supported by some
	implementations.