javascriptfirefox-addonxuljsctypes

Get absolute screen bounds of a DOM element from a Firefox extension


I have a firefox extension that needs to get the exact screen co-ordinates of a DOM element and passes it to a native DLL via js/c-types.

Now I have it mostly covered :

var gDomWindowUtils = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(nsIDOMWindowUtils);

function getScreenRect(oElem)
{
    var rc =
    {
        x : 0,
        y : 0,
        w : 0,
        h : 0
    };

    var o = oElement;
    while(o != null)
    {
        rc.y += o.offsetTop;
        rc.x += o.offsetLeft;
        o = o.offsetParent;
    }

    var x = {}, y = {};
    gDomWindowUtils.getScrollXY(false, x, y);
    rc.x -= x.value;
    rc.y -= y.value;

    var scale = gDomWindowUtils.screenPixelsPerCSSPixel;
    rc.x *= scale;
    rc.y *= scale;
    rc.w *= scale;
    rc.h *= scale;

    return rc;
};

This handles scrolling and zooming, but the values I get are relative to the browser window, and not the screen.

How do I detect the offset of the client area of the actual rendering area of the browser? I can even use native code (Win32) via js/ctypes so I tried to see if I could use FindWindow() / GetWindowRect() to get it, but the whole of firefox is a single HWND, the controls are all not native windows.

So one idea I have is, since the UI of firefox is an XUL document, I should be able to get the menubar, tab bar etc etc and find the browser areas absolute offset. But, I have no clue how to access the XUL tree that defines the browser UI.

Can someone give me a pointer?

[Edit] Ignore rc.w and rc.h being undefined in the above code , it is irrelevant to the question.


Solution

  • You mostly got it already but I would recommend using getBoundingClientRect() instead of offsetLeft/offsetTop:

    var rect = oElement.getBoundingClientRect();
    var rc = {
      x: rect.left,
      y: rect.top,
      w: rect.width,
      h: rect.height
    };
    

    getBoundingClientRect() considers scrolling so that you no longer need to add it. You get the coordinates relative to screen using window.mozInnerScreenX and window.mozInnerScreenY:

    rc.x += window.mozInnerScreenX;
    rc.y += window.mozInnerScreenY;
    

    And after that you multiply the values with screenPixelsPerCSSPixel. That should give you proper screen coordinates.