HRESULT ScreenshotCommandHandler::CaptureViewport(BrowserHandle browser) { LOG(TRACE) << "Entering ScreenshotCommandHandler::CaptureViewport"; HWND content_window_handle = browser->GetContentWindowHandle(); int content_width = 0, content_height = 0; this->GetWindowDimensions(content_window_handle, &content_width, &content_height); CaptureWindow(content_window_handle, content_width, content_height); return S_OK; }
HRESULT ScreenshotCommandHandler::CaptureFullPage(BrowserHandle browser) { LOG(TRACE) << "Entering ScreenshotCommandHandler::CaptureFullPage"; HWND ie_window_handle = browser->GetTopLevelWindowHandle(); HWND content_window_handle = browser->GetContentWindowHandle(); CComPtr<IHTMLDocument2> document; browser->GetDocument(true, &document); if (!document) { LOG(WARN) << "Unable to get document from browser. Are you viewing a non-HTML document?"; return E_ABORT; } LocationInfo document_info; bool result = DocumentHost::GetDocumentDimensions(document, &document_info); if (!result) { LOG(DEBUG) << "Unable to get document dimensions"; return E_FAIL; } LOG(DEBUG) << "Initial document sizes (scrollWidth, scrollHeight) are (w, h): " << document_info.width << ", " << document_info.height; int chrome_width(0); int chrome_height(0); this->GetBrowserChromeDimensions(ie_window_handle, content_window_handle, &chrome_width, &chrome_height); LOG(DEBUG) << "Initial chrome sizes are (w, h): " << chrome_width << ", " << chrome_height; int target_window_width = document_info.width + chrome_width; int target_window_height = document_info.height + chrome_height; // For some reason, this technique does not allow the user to resize // the browser window to greater than SIZE_LIMIT x SIZE_LIMIT. This is // pretty big, so we'll cap the allowable screenshot size to that. // // GDI+ limit after which it may report Generic error for some image types int SIZE_LIMIT = 65534; if (target_window_height > SIZE_LIMIT) { LOG(WARN) << "Required height is greater than limit. Truncating screenshot height."; target_window_height = SIZE_LIMIT; document_info.height = target_window_height - chrome_height; } if (target_window_width > SIZE_LIMIT) { LOG(WARN) << "Required width is greater than limit. Truncating screenshot width."; target_window_width = SIZE_LIMIT; document_info.width = target_window_width - chrome_width; } long original_width = browser->GetWidth(); long original_height = browser->GetHeight(); LOG(DEBUG) << "Initial browser window sizes are (w, h): " << original_width << ", " << original_height; // If the window is already wide enough to accomodate // the document, don't resize that dimension. Otherwise, // the window will display a horizontal scroll bar, and // we need to retain the scrollbar to avoid rerendering // during the resize, so reduce the target window width // by two pixels. if (original_width > target_window_width) { target_window_width = original_width; } else { target_window_width -= 2; } // If the window is already tall enough to accomodate // the document, don't resize that dimension. Otherwise, // the window will display a vertical scroll bar, and // we need to retain the scrollbar to avoid rerendering // during the resize, so reduce the target window height // by two pixels. if (original_height > target_window_height) { target_window_height = original_height; } else { target_window_height -= 2; } BOOL is_maximized = ::IsZoomed(ie_window_handle); bool requires_resize = original_width < target_window_width || original_height < target_window_height; if (requires_resize) { // The resize message is being ignored if the window appears to be // maximized. There's likely a way to bypass that. The kludgy way // is to unmaximize the window, then move on with setting the window // to the dimensions we really want. This is okay because we revert // back to the original dimensions afterward. if (is_maximized) { LOG(DEBUG) << "Window is maximized currently. Demaximizing."; ::ShowWindow(ie_window_handle, SW_SHOWNORMAL); } // NOTE: There is a *very* slight chance that resizing the window // so there are no longer scroll bars to be displayed *might* cause // layout redraws such that the screenshot does not show the entire // DOM after the resize. Since we should always be expanding the // window size, never contracting it, this is a corner case that // explicitly will *not* be fixed. Any issue reports describing this // corner case will be closed without action. RECT ie_window_rect; ::GetWindowRect(ie_window_handle, &ie_window_rect); ::SetWindowPos(ie_window_handle, NULL, ie_window_rect.left, ie_window_rect.top, target_window_width, target_window_height, SWP_NOSENDCHANGING); } CaptureWindow(content_window_handle, document_info.width, document_info.height); if (requires_resize) { // Restore the browser to the original dimensions. if (is_maximized) { ::ShowWindow(ie_window_handle, SW_MAXIMIZE); } else { browser->SetHeight(original_height); browser->SetWidth(original_width); } } return S_OK; }