Closed Bug 1230062 Opened 7 years ago Closed 7 years ago

Getting nsIDOMWindow from nsIChannel e10s

Categories

(Firefox :: Extension Compatibility, defect)

44 Branch
defect
Not set
major

Tracking

()

RESOLVED INVALID
Tracking Status
e10s + ---

People

(Reporter: antdlmr, Unassigned)

References

Details

User Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; rv:11.0) like Gecko

Steps to reproduce:

The next code

var browser = objChannel.notificationCallbacks
													.getInterface(Components.interfaces.nsILoadContext).topFrameElement;
	var window = browser.contentWindow.QueryInterface(Components.interfaces.nsISupports);		 // *** CPOW ***

does not work without shim.

Without shim gBrowser.contentDocument =NULL; // https://developer.mozilla.org/en-US/Firefox/Multiprocess_Firefox/Limitations_of_chrome_scripts

Is there any way to get the window of a request from channel in e10s or all old ways are unsupported without shim?
	




Actual results:

CPOW 


Expected results:

nsIDOMWindow
Maybe Is possible to get a current Tab if nsIDOMWindow is not available?
Flags: needinfo?(wmccloskey)
The problem here is that the window you're asking for lives in the content process, and your add-on is running in the main process. The shims provide synchronous access to the window through IPC. But without the shims, you need to do the IPC yourself.

It's hard to know how to do this without knowing more about what you're doing. You can access the content process via the message manager [1]. Since you have a <browser> element, you can send messages to |browser| via |browser.messageManager.sendAsyncMessage| after you load a frame script with |browser.messageManager.loadFrameScript|. That would allow you to manipulate content on the page.

If you have more questions, please needinfo me again.

[1] https://developer.mozilla.org/en-US/Firefox/Multiprocess_Firefox/Message_Manager
Flags: needinfo?(wmccloskey)
Please assist - we are cleaning up bugs and do not want to leave items in "Untriaged" state. Please set approp Product/Component. Thanks.
Component: Untriaged → Extension Compatibility
Component: Extension Compatibility → Untriaged
Thanks Bill for replay.

I really have windowID from channel.loadInfo.innerWindowID but how do I get nsIDOMWindow from windowID?

I need to get nsIDOMWindow from channel in my addon. The content script cannot work with XPCOM objects and I will try work with windows ID.
Thanks.
Component: Untriaged → Extension Compatibility
window.getInterface( Components.interfaces.nsIDOMWindowUtils )is works!
but
window.getInterface( Components.interfaces.nsIDOMWindowUtils ).getOuterWindowWithId( channel.loadInfo.innerWindowID ) is null!
The code that does this:

var browser = objChannel.notificationCallbacks.getInterface(Components.interfaces.nsILoadContext).topFrameElement;

is correct. It will give you a <browser> element (which lives in the main process). You can get a tab from that by calling window.gBrowser.getTabForBrowser(browser).

> The content script cannot work with XPCOM objects and I will try work with windows ID.

Frame scripts (using the message manager, which I linked above) can use XPCOM.
Thanks Bill for replay!

My end goal is from channel get a node (IDOMNode) which sent request and to work with its sizes and position.
I have to reliaze chain channel->nsIDOMWindow->nsIDOMDocument->IDOMNode.

1.
> window.gBrowser.getTabForBrowser(browser).
Its will chrome tab but I need a content object for getting nsIDOMWindow of cannel.
I something do not understand. (:

I thought that having a window identifier windowID can I get a window object nsIDOMWindow. or not?


2.
> The content script cannot work with XPCOM objects and I will try work with windows ID.
Getting of Components.classes["@antff/event_gateway;1"].getService( Components.interfaces.IFFEvent );
in content script give error (TypeError: Components.classes['@antff/event_gateway;1'] is undefined)

*** chrome
var Gateway = 
{
  Init : function() 
  {
    obj.addMessageListener( "antff@get_parent_obj",        this );
  },
  receiveMessage: function ( mes ) 
  {
    switch ( mes.name ) 
    {
      case "antff@get_parent_obj":
        ............
        break;
    }
  },
  VTContentScript : function() <-- it is  a content injected script
  { 
    addMessageListener("antff@get_parent_obj", function ( message ) 
    {
      !! Here is error - TypeError: Components.classes['@antff/event_gateway;1'] is undefined 
      var antFFEvent = Components.classes["@antff/event_gateway;1"].getService( Components.interfaces.IFFEvent ); <--   it my component
      
			
			I would want to send a window object to IFFEvent
      antFFEvent.some_function( window );
  },
  MarkDoc : function( channel ) 
  {
    if ( channel.notificationCallbacks )
    {
      var loadContext = channel.notificationCallbacks.getInterface( Components.interfaces.nsILoadContext );
      if ( loadContext && loadContext.topFrameElement )
      {
        var windowMM = loadContext.topFrameElement.messageManager;
        windowMM.loadFrameScript( "data:,new " + this.VTContentScript.toString(), true ); <-- inject of content script
        windowMM.sendAsyncMessage( "antff@get_parent_obj", {} );
      }
    }
  }
  ...............
}
Gateway.Init();
The question still is very actual!
Severity: normal → major
Blocks: 1231878
(In reply to Andrey from comment #8)
> The question still is very actual!
No longer blocks: 1231878
Flags: needinfo?(wmccloskey)
The code you posted is close to what you need. However, your content script needs to be more self-contained. It isn't allowed to access your component, since that lives in the main Firefox process. The content script is running in the content process.

Instead, you need to send a message back to the main process that contains whatever data you need from the DOM. Here is an example:

    addMessageListener("antff@get_parent_obj", function ( message ) 
    {
      var node = content.document.body; // access some node
      var data = node.style.color;
      sendAsyncMessage("antff@node_color", data);
    },

Then, in MarkDoc, you would need to do something like this:

  MarkDoc : function( channel ) 
  {
    if ( channel.notificationCallbacks )
    {
      var loadContext = channel.notificationCallbacks.getInterface( Components.interfaces.nsILoadContext );
      if ( loadContext && loadContext.topFrameElement )
      {
        var mm = loadContext.topFrameElement.messageManager;
        mm.loadFrameScript( "data:,new " + this.VTContentScript.toString(), true ); <-- inject of content script
        mm.sendAsyncMessage( "antff@get_parent_obj", {} );
        mm.addMessageListener("antff@node_color", function(message) {
          var color = message.data;
        });
      }
    }
  }

However, there are also some problems here. Namely, the content script is being re-loaded every time MarkDoc is called. So you can end up with multiple listeners installed on the same frame. You should probably load your frame script into all tabs at startup.
Flags: needinfo?(wmccloskey)
Your example is quite clear.

I do not understand how to put into the scheme channel->nsIDOMWindow->nsIDOMDocument->IDOMNode.

The code is working now:

try
{
  var notificationCallbacks = objChannel.QueryInterface(Components.interfaces.nsIHttpChannel).notificationCallbacks;
  if ( !notificationCallbacks )
  {
    var loadGroup = objChannel.QueryInterface(Components.interfaces.nsIRequest).loadGroup.notificationCallbacks; 
    if ( loadGroup ) notificationCallbacks = loadGroup.notificationCallbacks;
  }
  if ( notificationCallbacks )
  {
    return notificationCallbacks.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
                                .getInterface(Components.interfaces.nsIDOMWindow)
                                .QueryInterface(Components.interfaces.nsISupports);
  }
}
catch ( err ) {}

The goal is also to make for e10s.
1. Is there a solution to this problem for e10s?




2. I can get innerWindowID in content script but how to convert it into nsIDOMWindow in chrome script?

addMessageListener("antff@get_parent_obj", function ( message ) 
{
  let windowUtils = content.QueryInterface( Components.interfaces.nsIInterfaceRequestor ).getInterface( Components.interfaces.nsIDOMWindowUtils );
  sendAsyncMessage("antff@node_color", windowUtils.innerWindowID );
},
Flags: needinfo?(wmccloskey)
You cannot use an nsIDOMWindow or an nsIDOMNode from chrome. It's simply not possible. If you need to access these objects, you need to do it from a frame script.
Flags: needinfo?(wmccloskey)
2. I can get innerWindowID in content script but how to convert it into nsIDOMWindow in chrome script?

addMessageListener("antff@get_parent_obj", function ( message ) 
{
  let windowUtils = content.QueryInterface( Components.interfaces.nsIInterfaceRequestor ).getInterface( Components.interfaces.nsIDOMWindowUtils );
  sendAsyncMessage("antff@node_color", windowUtils.innerWindowID );
}, 


How can I convert innerWindowID(it was received in content script) to nsIDOMWindow in frame script?
You should be able to use Services.wm.getCurrentInnerWindowWithId(innerWindowId).
Due to the amount of comments from developers, we will be changing the bug from Unconfirmed to New so that items with a component no longer display unconfirmed
Status: UNCONFIRMED → NEW
Ever confirmed: true
Status: NEW → RESOLVED
Closed: 7 years ago
Resolution: --- → INVALID
You need to log in before you can comment on or make changes to this bug.