def __attrs_post_init__(self):
        # type: () -> None
        self._screenshot_type = update_screenshot_type(
            self._screenshot_type, self._image, self._driver
        )
        position_provider = eyes_selenium_utils.get_cur_position_provider(self._driver)

        if not self._driver.is_mobile_app:
            self._frame_chain = self._driver.frame_chain.clone()
            frame_size = self.get_frame_size(position_provider)
            self._current_frame_scroll_position = eyes_selenium_utils.get_updated_scroll_position(  # noqa
                position_provider
            )
            self.updated_frame_location_in_screenshot(
                self._frame_location_in_screenshot
            )
            logger.debug("Calculating frame window...")
            self.frame_window = Region.from_(
                self._frame_location_in_screenshot, frame_size
            )
        else:
            self._frame_chain = FrameChain()
            self._current_frame_scroll_position = Point.ZERO()
            self._frame_location_in_screenshot = Point.ZERO()
            self.frame_window = Region.from_(
                self._frame_location_in_screenshot, self.image
            )
        self.frame_window = self.frame_window.intersect(Region.from_(self.image))
 def from_screenshot(cls, driver, image, screenshot_region):
     # type: (EyesWebDriver, Image.Image, Region) -> EyesWebDriverScreenshot
     return cls(
         driver,
         image,
         ScreenshotType.ENTIRE_FRAME,
         Point.ZERO(),
         frame_window=Region.from_(Point.ZERO(), screenshot_region.size),
         region_window=Region.from_(screenshot_region),
     )
    def get_image(self):
        image = TakesScreenshotImageProvider(self._eyes).get_image()

        if self._eyes.is_cut_provider_explicitly_set:
            return image

        scale_ratio = self._eyes.device_pixel_ratio
        original_viewport_size = self._eyes._get_viewport_size()
        viewport_size = original_viewport_size.scale(scale_ratio)

        logger.info("logical viewport size: {}".format(original_viewport_size))

        force_full_page_screenshot = self._eyes.configure.force_full_page_screenshot
        if force_full_page_screenshot is not None:
            if not force_full_page_screenshot:
                current_frame_chain = self._eyes.driver.frame_chain  # type: FrameChain

                if len(current_frame_chain) == 0:
                    position_provider = ScrollPositionProvider(
                        self._eyes.driver,
                        self._eyes.driver.find_element_by_tag_name("html"),
                    )
                    loc = position_provider.get_current_position()
                else:
                    loc = current_frame_chain.default_content_scroll_position

                loc = loc.scale(scale_ratio)
                image = image_utils.crop_image(
                    image, Region.from_(loc, viewport_size))
        return image
    def intersected_region(self, region, coordinates_type):
        # type: (Region, CoordinatesType) -> Region
        argument_guard.not_none(region)
        argument_guard.not_none(coordinates_type)

        if region.is_size_empty:
            return Region.from_(region)

        original_coordinates_type = region.coordinates_type

        intersected_region = self.convert_region_location(
            region, original_coordinates_type, self.SCREENSHOT_AS_IS
        )
        #  If the request was context based, we intersect with the frame window.
        if original_coordinates_type in [self.CONTEXT_AS_IS, self.CONTEXT_RELATIVE]:
            intersected_region = intersected_region.intersect(self.frame_window)
        # If the request is screenshot based, we intersect with the image
        elif original_coordinates_type == self.SCREENSHOT_AS_IS:
            intersected_region = intersected_region.intersect(
                Region(0, 0, self.image.width, self.image.height)
            )
        else:
            raise ValueError(
                "Unknown coordinates type: '%s'" % original_coordinates_type
            )
        #  If the intersection is empty we don't want to convert the coordinates.
        if intersected_region.is_size_empty:
            return intersected_region

        #  Converting the result to the required coordinates type
        intersected_region = self.convert_region_location(
            intersected_region, self.SCREENSHOT_AS_IS, coordinates_type
        )
        return intersected_region
예제 #5
0
    def _get_region_in_screenshot(self, region, image, pixel_ratio):
        # type: (Region, Image, float) -> Region
        if region.is_size_empty:
            return region
        logger.info("Creating screenshot object...")
        #  We need the screenshot to be able to convert the region to screenshot coordinates.
        screenshot = self.screenshot_factory.make_screenshot(
            image
        )  # type: EyesWebDriverScreenshot
        logger.info("Getting region in screenshot...")

        region_in_screenshot = screenshot.intersected_region(
            region, CoordinatesType.SCREENSHOT_AS_IS
        )
        logger.info("Region in screenshot: {}".format(region_in_screenshot))
        region_in_screenshot = region_in_screenshot.scale(pixel_ratio)
        logger.info("Scaled region: {}".format(region_in_screenshot))

        region_in_screenshot = self.region_position_compensation.compensate_region_position(
            region_in_screenshot, pixel_ratio
        )
        # Handling a specific case where the region is actually larger than
        # the screenshot (e.g., when body width/height are set to 100%, and
        # an internal div is set to value which is larger than the viewport).
        region_in_screenshot.intersect(Region.from_(image))
        logger.info("Region after intersect: {}".format(region_in_screenshot))
        return region_in_screenshot
def demarshal_locate_result(results):
    # type: (dict) -> Dict[Text, List[APIRegion]]
    return {
        locator_id:
        [APIRegion.from_(region) for region in regions] if regions else []
        for locator_id, regions in results.items()
    }
예제 #7
0
    def _ensure_frame_visible(self):
        logger.debug("scroll_root_element_: {}".format(self._scroll_root_element))
        current_fc = self.driver.frame_chain.clone()
        fc = self.driver.frame_chain.clone()
        self.driver.execute_script("window.scrollTo(0,0);")
        origin_driver = eyes_selenium_utils.get_underlying_driver(self.driver)

        while len(fc) > 0:
            logger.debug("fc count: {}".format(fc.size))
            self.driver.switch_to.parent_frame_static(origin_driver.switch_to, fc)
            self.driver.execute_script("window.scrollTo(0,0);")
            child_frame = fc.pop()
            parent_frame = fc.peek
            scroll_root_element = None
            if fc.size == self._original_fc.size:
                logger.debug("PositionProvider: {}".format(self.position_provider))
                self._position_memento = self.position_provider.get_state()
                scroll_root_element = self._scroll_root_element
            else:
                if parent_frame:
                    scroll_root_element = parent_frame.scroll_root_element
                if not scroll_root_element:
                    scroll_root_element = self.driver.find_element_by_tag_name("html")
            logger.debug("scroll_root_element {}".format(scroll_root_element))

            position_provider = self._element_position_provider_from(
                scroll_root_element
            )
            position_provider.set_position(child_frame.location)
            reg = Region.from_(Point.ZERO(), child_frame.inner_size)
            self._effective_viewport.intersect(reg)
        self.driver.switch_to.frames(current_fc)
        return current_fc
 def create_entire_frame(cls, driver, image, entire_frame_size):
     # type: (EyesWebDriver, Image.Image, RectangleSize) -> EyesWebDriverScreenshot
     return cls(
         driver,
         image,
         ScreenshotType.ENTIRE_FRAME,
         frame_location_in_screenshot=Point(0, 0),
         current_frame_scroll_position=Point(0, 0),
         frame_window=Region.from_(Point(0, 0), entire_frame_size),
     )
예제 #9
0
 def from_screenshot(cls, driver, image, screenshot_region,
                     frame_location_in_parent_screenshot):
     # type: (EyesWebDriver, Image.Image, Region, Point) -> EyesWebDriverScreenshot
     return cls(
         driver,
         image,
         ScreenshotType.ENTIRE_FRAME,
         frame_location_in_parent_screenshot - screenshot_region.location,
         frame_window=Region.from_(Point.ZERO(), screenshot_region.size),
     )
예제 #10
0
 def _get_viewport_scroll_bounds(self):
     switch_to = self.driver.switch_to
     with switch_to.frames_and_back(self._original_fc):
         try:
             location = eyes_selenium_utils.get_current_position(
                 self.driver, self.scroll_root_element)
         except WebDriverException as e:
             logger.warning(str(e))
             logger.info("Assuming position is 0,0")
             location = Point(0, 0)
     viewport_bounds = Region.from_(location, self._get_viewport_size())
     return viewport_bounds
예제 #11
0
def _region_from_element(element, screenshot):
    location = element.location
    size = element.size
    if screenshot:
        # Element's coordinates are context relative, so we need to convert them first.
        adjusted_location = screenshot.location_in_screenshot(
            Point(location["x"], location["y"]),
            CoordinatesType.CONTEXT_RELATIVE)
    else:
        adjusted_location = Point(location["x"], location["y"])
    region = Region.from_(adjusted_location, size)
    return region
예제 #12
0
 def create_entire_element(
         cls,
         driver,  # type: EyesWebDriver
         image,  # type: Image.Image
         entire_element_size,  # type: RectangleSize
         frame_location_in_screenshot,  # type: Point
 ):
     # type: (...) -> EyesWebDriverScreenshot
     return cls(
         driver,
         image,
         ScreenshotType.ENTIRE_FRAME,
         frame_location_in_screenshot,
         current_frame_scroll_position=Point(0, 0),
         frame_window=Region.from_(Point(0, 0), entire_element_size),
     )
예제 #13
0
 def _floating_provider_from(self, region, bounds):
     if isinstance(region, Region):
         logger.debug("floating: FloatingRegionByRectangle")
         return FloatingRegionByRectangle(Region.from_(region), bounds)
     raise TypeError("Unknown region type.")
예제 #14
0
    def _check_element(self, name, check_settings):
        element = self._target_element  # type: EyesWebElement

        scroll_root_element = eyes_selenium_utils.curr_frame_scroll_root_element(
            self.driver, self._scroll_root_element)
        pos_provider = self._create_position_provider(scroll_root_element)

        self._region_to_check = Region.EMPTY()
        self._full_region_to_check = Region.EMPTY()

        result = None
        with eyes_selenium_utils.get_and_restore_state(pos_provider):
            with self._ensure_element_visible(element):
                pl = element.location
                try:
                    self._check_frame_or_element = True
                    display_style = element.get_computed_style("display")

                    if self.configure.hide_scrollbars:
                        element.hide_scrollbars()

                    size_and_borders = element.size_and_borders
                    border_widths = size_and_borders.borders
                    element_size = size_and_borders.size

                    use_entire_size = False
                    if display_style != "inline" and (
                            element_size["height"] <=
                            self._effective_viewport["height"]
                            and element_size["width"] <=
                            self._effective_viewport["width"]):
                        self._element_position_provider = ElementPositionProvider(
                            self.driver, element)
                        use_entire_size = True
                    else:
                        self._element_position_provider = None

                    element_region = Region(
                        pl["x"] + border_widths["left"],
                        pl["y"] + border_widths["top"],
                        element_size["width"],
                        element_size["height"],
                        coordinates_type=CoordinatesType.SCREENSHOT_AS_IS,
                    )
                    self._region_to_check = element_region

                    if use_entire_size:
                        self._full_region_to_check = Region.from_(
                            element_region.location,
                            self._element_position_provider.get_entire_size(),
                        )
                    else:
                        self._full_region_to_check = Region(
                            left=element_region.left,
                            top=element_region.top,
                            width=element_region.width,
                            height=element_region.height,
                        )

                    if not self._effective_viewport.is_size_empty:
                        self._region_to_check = self._region_to_check.intersect(
                            self._effective_viewport)

                    result = self._check_window_base(NULL_REGION_PROVIDER,
                                                     name, False,
                                                     check_settings)
                except Exception as e:
                    logger.exception(e)
                    raise e
                finally:
                    if self.configure.hide_scrollbars:
                        element.return_to_original_overflow()
                    self._check_frame_or_element = False
                    self._region_to_check = None
                    self._element_position_provider = None
        return result
예제 #15
0
    def get_stitched_region(self, region, full_area, position_provider):
        # type: (Region, Optional[Region], Optional[PositionProvider]) -> Image.Image
        argument_guard.not_none(region)
        argument_guard.not_none(position_provider)

        logger.info(
            "region: %s ; full_area: %s ; position_provider: %s"
            % (region, full_area, position_provider.__class__.__name__)
        )

        origin_state = self.origin_provider.get_state()

        if self.origin_provider != position_provider:
            self.origin_provider.set_position(
                Point.ZERO()
            )  # first scroll to 0,0 so CSS stitching works.

        # Saving the original position (in case we were already in the outermost frame).
        original_stitched_state = position_provider.get_state()

        datetime_utils.sleep(self.wait_before_screenshots)
        initial_screenshot = self.image_provider.get_image()
        initial_size = RectangleSize.from_(initial_screenshot)

        pixel_ratio = self._get_pixel_ratio(initial_screenshot)
        scaled_cut_provider = self.cut_provider.scale(pixel_ratio)
        cutted_initial_screenshot = self._cut_if_needed(
            initial_screenshot, scaled_cut_provider
        )
        self.debug_screenshot_provider.save(
            cutted_initial_screenshot, self._debug_msg("cutted_initial_screenshot")
        )

        region_in_initial_screenshot = self._get_region_in_screenshot(
            region, cutted_initial_screenshot, pixel_ratio
        )
        cropped_initial_screenshot = self._crop_if_needed(
            cutted_initial_screenshot, region_in_initial_screenshot
        )
        self.debug_screenshot_provider.save(
            cropped_initial_screenshot, self._debug_msg("cropped_initial_screenshot")
        )

        scaled_initial_screenshot = image_utils.scale_image(
            cropped_initial_screenshot, self.scale_provider
        )
        self.debug_screenshot_provider.save(
            scaled_initial_screenshot, self._debug_msg("scaled_initial_screenshot")
        )
        if full_area is None or full_area.is_empty:
            entire_size = self._get_entire_size(initial_screenshot, position_provider)
            # Notice that this might still happen even if we used
            # "get_image_part", since "entire_page_size" might be that of a
            # frame
            if (
                scaled_initial_screenshot.width >= entire_size.width
                and scaled_initial_screenshot.height >= entire_size.height
            ):
                self.origin_provider.restore_state(origin_state)
                return scaled_initial_screenshot

            full_area = Region.from_(Point.ZERO(), entire_size)

        scaled_cropped_location = full_area.location
        physical_crop_location = Point.from_(scaled_cropped_location).scale(pixel_ratio)

        if region_in_initial_screenshot.is_empty:
            physical_crop_size = RectangleSize(
                initial_size.width - physical_crop_location.x,
                initial_size.height - physical_crop_location.y,
            )
            source_region = Region.from_(physical_crop_location, physical_crop_size)
        else:
            # Starting with the screenshot we already captured at (0,0).
            source_region = region_in_initial_screenshot

        scaled_cropped_source_rect = self.cut_provider.to_region(source_region.size)
        scaled_cropped_source_rect = scaled_cropped_source_rect.offset(
            source_region.left, source_region.top
        )
        scaled_cropped_source_region = dict(
            x=int(math.ceil(scaled_cropped_source_rect.left / pixel_ratio)),
            y=int(math.ceil(scaled_cropped_source_rect.top / pixel_ratio)),
            width=int(math.ceil(scaled_cropped_source_rect.width / pixel_ratio)),
            height=int(math.ceil(scaled_cropped_source_rect.height / pixel_ratio)),
        )
        scaled_cropped_size = dict(
            width=scaled_cropped_source_region["width"],
            height=scaled_cropped_source_region["height"],
        )

        # Getting the list of viewport regions composing the page
        # (we'll take screenshot for each one).
        if region_in_initial_screenshot.is_empty:
            x = max(0, full_area.left)
            y = max(0, full_area.top)
            w = min(full_area.width, scaled_cropped_size["width"])
            h = min(full_area.height, scaled_cropped_size["height"])
            rect_in_initial_screenshot = Region(
                round(x * pixel_ratio),
                round(y * pixel_ratio),
                round(w * pixel_ratio),
                round(h * pixel_ratio),
            )
        else:
            rect_in_initial_screenshot = region_in_initial_screenshot

        screenshot_parts = self._get_image_parts(
            full_area, scaled_cropped_size, pixel_ratio, rect_in_initial_screenshot
        )

        # Starting with element region size part of the screenshot. Use it as a size
        # template.
        stitched_image = Image.new("RGBA", (full_area.width, full_area.height))
        # Take screenshot and stitch for each screenshot part.
        stitched_image = self._stitch_screenshot(
            original_stitched_state,
            position_provider,
            screenshot_parts,
            stitched_image,
            self.scale_provider.scale_ratio,
            scaled_cut_provider,
        )
        position_provider.restore_state(original_stitched_state)
        self.origin_provider.restore_state(origin_state)
        return stitched_image