    /*

    Siesta 5.3.0
    Copyright(c) 2009-2019 Bryntum AB
    https://bryntum.com/contact
    https://bryntum.com/products/siesta/license

    */
    /**
    @class Siesta.Test.Browser.Role.CanGetElementFromPoint

    */
    Role('Siesta.Test.Browser.Role.CanGetElementFromPoint', {

        requires    : [
            '$'
        ],

        does        : [
            Siesta.Util.Role.CanCalculatePageScroll
        ],

        has : {
        },

        methods : {

            /**
             * This method will return the top-most DOM element at the specified coordinates from the test page. If
             * the resulting element is an iframe and `shallow` argument is not passed as `true`
             * it'll query the iframe for its element from the local point inside it.
             *
             * @param {Number} x The X coordinate, relative to the viewport area (currently visible part of the page)
             * @param {Number} y The Y coordinate, relative to the viewport area (currently visible part of the page)
             * @param {Boolean} [shallow] Pass `true` to _not_ check the nested iframe if element at original coordinates is an iframe.
             *
             * @return {HTMLElement} The top-most element at the specified position on the test page
             */
            elementFromPoint : function (viewportX, viewportY, shallow, fallbackEl, fullInfo) {
                var document    = this.global.document;
                var el          = document.elementFromPoint(viewportX, viewportY)

                // trying 2nd time if 1st attempt failed and returned null
                // this weird thing seems to be required sometimes for IE8 and may be for IE10
                if (!el) el     = document.elementFromPoint(viewportX, viewportY)

                // final fallback to the provided element or to the <body> element
                el              = el || fallbackEl || document.body;

                var localX      = viewportX
                var localY      = viewportY

                // If we found IFRAME and its not a `shallow` request, try to dig deeper
                if (el && el.nodeName.toUpperCase() == 'IFRAME' && !shallow) {
                    // if found iframe is loaded from different domain
                    // just accessing its "el.contentWindow.document" property will throw exception
                    try {
                        var iframeDoc       = el.contentWindow.document;
                        var offsetsToTop    = this.$(el).offset();

                        localX              = viewportX - this.pageXtoViewportX(offsetsToTop.left)
                        localY              = viewportY - this.pageYtoViewportY(offsetsToTop.top)

                        var resolvedEl      = iframeDoc.elementFromPoint(localX, localY)

                        // again weird 2nd attempt for IE
                        if (!resolvedEl) resolvedEl = iframeDoc.elementFromPoint(localX, localY)

                        resolvedEl          = resolvedEl || iframeDoc.body;

                        // Chrome reports 'HTML' in nested document.elementFromPoint calls which makes no sense
                        if (resolvedEl.nodeName.toUpperCase() === 'HTML') resolvedEl = iframeDoc.body;

                        el                  = resolvedEl;
                    } catch (e) {
                        // digging deeper failed, restore the local coordinates
                        localX              = viewportX
                        localY              = viewportY
                    }
                }

                return fullInfo ? {
                    el          : el,
                    // viewport coords in the inner frame
                    localXY     : [ localX, localY ],
                    // viewport coords in the top frame (seems not needed, as just the input values are reused)
                    globalXY    : [ viewportX, viewportY ]
                } : el
            }
        }
    });