Determines whether an element is visible to the user. A list of
        ignorable elements can be passed to this function. These would
        typically be things like invisible layers sitting atop other
        elements. This function ignores these elements by setting
        their CSS ``display`` parameter to ``none`` before checking,
        and restoring them to their initial value after checking. The
        list of ignorable elements should not contain elements that
        would disturb the position of the element to check if their
        ``display`` parameter is set to ``none``. Otherwise, the
        algorithm is likely to fail.

        :param element: The element to check.
        :type element: :class:`selenium.webdriver.remote.webelement.WebElement`
        :param ignorable: The elements that can be ignored.
        :type ignorable: :class:`list` of :strings that are CSS selectors.

def visible_to_user(self, element, *ignorable):
        """
        Determines whether an element is visible to the user. A list of
        ignorable elements can be passed to this function. These would
        typically be things like invisible layers sitting atop other
        elements. This function ignores these elements by setting
        their CSS ``display`` parameter to ``none`` before checking,
        and restoring them to their initial value after checking. The
        list of ignorable elements should not contain elements that
        would disturb the position of the element to check if their
        ``display`` parameter is set to ``none``. Otherwise, the
        algorithm is likely to fail.

        :param element: The element to check.
        :type element: :class:`selenium.webdriver.remote.webelement.WebElement`
        :param ignorable: The elements that can be ignored.
        :type ignorable: :class:`list` of :strings that are CSS selectors.

        """
        if not element.is_displayed():
            return False
        return self.driver.execute_script("""
        var el = arguments[0];
        var ignorable = arguments[1];

        var old_displays = ignorable.map(function (x) {
            var old = x.style.display;
            x.style.display = "none";
            return old;
        });
        try {
            var rect = el.getBoundingClientRect();
            // Sigh... we need to round the numbers to avoid running into
            // factional pixels causing the following test to fail.
            rect = {
              left: Math.ceil(rect.left),
              right: Math.floor(rect.right),
              top: Math.ceil(rect.top),
              bottom: Math.floor(rect.bottom)
            }
            var ret = false;

            var efp = document.elementFromPoint.bind(document);
            var at_corner;
            ret = ((at_corner = efp(rect.left, rect.top)) === el) ||
                   el.contains(at_corner) ||
                  ((at_corner = efp(rect.left, rect.bottom)) === el) ||
                   el.contains(at_corner) ||
                  ((at_corner = efp(rect.right, rect.top)) === el) ||
                   el.contains(at_corner) ||
                  ((at_corner = efp(rect.right, rect.bottom)) === el) ||
                   el.contains(at_corner);
        }
        finally {
            var ix = 0;
            ignorable.forEach(function (x) {
                x.style.display = old_displays[ix];
                ix++;
            });
        }
        return ret;
        """, element, ignorable)