def chromedriver_element_center_patch():
    """
    Patch move_to_element on ActionChains to work around a bug present
    in Chromedriver 2.14 to 2.20.

    Calling this function multiple times in the same process will
    install the patch once, and just once.
    """

    patch_name = "_selenic_chromedriver_element_center_patched"
    if getattr(ActionChains, patch_name, None):
        return  # We've patched ActionChains already!!

    # This is the patched method, which uses getBoundingClientRect
    # to get the location of the center.
    def move_to_element(self, el):
        pos = self._driver.execute_script("""
        var rect = arguments[0].getBoundingClientRect();
        return { x: rect.width / 2, y: rect.height / 2};
        """, el)
        self.move_to_element_with_offset(el, pos["x"], pos["y"])
        return self

    old_init = ActionChains.__init__

    def init(self, driver):
        old_init(self, driver)

        # Patch the instance, only if the driver needs it.
        if getattr(driver, CHROMEDRIVER_ELEMENT_CENTER_PATCH_FLAG, None):
            self.move_to_element = types.MethodType(move_to_element, self)

    ActionChains.__init__ = init

    # Mark ActionChains as patched!
    setattr(ActionChains, patch_name, True)