1563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark/* 2563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * Copyright (C) 2005, 2006, 2007 Apple Inc. All rights reserved. 3563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * (C) 2007 Graham Dennis (graham.dennis@gmail.com) 4563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * (C) 2007 Eric Seidel <eric@webkit.org> 5563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * 6563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * Redistribution and use in source and binary forms, with or without 7563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * modification, are permitted provided that the following conditions 8563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * are met: 9563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * 10563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * 1. Redistributions of source code must retain the above copyright 11563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * notice, this list of conditions and the following disclaimer. 12563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * 2. Redistributions in binary form must reproduce the above copyright 13563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * notice, this list of conditions and the following disclaimer in the 14563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * documentation and/or other materials provided with the distribution. 15563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of 16563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * its contributors may be used to endorse or promote products derived 17563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * from this software without specific prior written permission. 18563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * 19563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 20563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 23563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 26563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark */ 30563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark 310bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch#include "config.h" 32563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark#include "PixelDumpSupport.h" 33563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark#include "PixelDumpSupportCG.h" 34563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark 350bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch#include "DumpRenderTree.h" 36563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark#include "LayoutTestController.h" 37563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark#include <CoreGraphics/CGBitmapContext.h> 38563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark#include <wtf/Assertions.h> 39563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark#include <wtf/RefPtr.h> 40563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark 41967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch#import <WebKit/WebCoreStatistics.h> 42563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark#import <WebKit/WebDocumentPrivate.h> 43563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark#import <WebKit/WebHTMLViewPrivate.h> 44563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark#import <WebKit/WebKit.h> 45563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark#import <WebKit/WebViewPrivate.h> 46563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark 470bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch#if defined(BUILDING_ON_TIGER) 480bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch#include <OpenGL/OpenGL.h> 490bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch#include <OpenGL/CGLMacro.h> 500bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch#endif 510bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch 52563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark// To ensure pixel tests consistency, we need to always render in the same colorspace. 53563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark// Unfortunately, because of AppKit / WebKit constraints, we can't render directly in the colorspace of our choice. 54563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark// This implies we have to temporarily change the profile of the main display to the colorspace we want to render into. 55563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark// We also need to make sure the CGBitmapContext we return is in that same colorspace. 56563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark 57563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark#define PROFILE_PATH "/System/Library/ColorSync/Profiles/Generic RGB Profile.icc" // FIXME: This cannot be more than CS_MAX_PATH (256 characters) 58563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark 59563af33bc48281d19dce701398dbb88cb54fd7ecCary Clarkstatic CMProfileLocation sInitialProfileLocation; // The locType field is initialized to 0 which is the same as cmNoProfileBase 60563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark 61563af33bc48281d19dce701398dbb88cb54fd7ecCary Clarkvoid restoreMainDisplayColorProfile(int ignored) 62563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark{ 63563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark // This is used as a signal handler, and thus the calls into ColorSync are unsafe 64563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark // But we might as well try to restore the user's color profile, we're going down anyway... 65563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark if (sInitialProfileLocation.locType != cmNoProfileBase) { 66563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark const CMDeviceScope scope = { kCFPreferencesCurrentUser, kCFPreferencesCurrentHost }; 67563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark int error = CMSetDeviceProfile(cmDisplayDeviceClass, (CMDeviceID)kCGDirectMainDisplay, &scope, cmDefaultProfileID, &sInitialProfileLocation); 68563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark if (error) 69563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark fprintf(stderr, "Failed to restore initial color profile for main display! Open System Preferences > Displays > Color and manually re-select the profile. (Error: %i)", error); 70563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark sInitialProfileLocation.locType = cmNoProfileBase; 71563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark } 72563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark} 73563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark 74563af33bc48281d19dce701398dbb88cb54fd7ecCary Clarkvoid setupMainDisplayColorProfile() 75563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark{ 76563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark const CMDeviceScope scope = { kCFPreferencesCurrentUser, kCFPreferencesCurrentHost }; 77563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark int error; 78563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark 79563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark CMProfileRef profile = 0; 80563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark error = CMGetProfileByAVID((CMDisplayIDType)kCGDirectMainDisplay, &profile); 81563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark if (!error) { 82563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark UInt32 size = sizeof(CMProfileLocation); 83563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark error = NCMGetProfileLocation(profile, &sInitialProfileLocation, &size); 84563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark CMCloseProfile(profile); 85563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark } 86563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark if (error) { 87563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark fprintf(stderr, "Failed to retrieve current color profile for main display, thus it won't be changed. Many pixel tests may fail as a result. (Error: %i)", error); 88563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark sInitialProfileLocation.locType = cmNoProfileBase; 89563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark return; 90563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark } 91563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark 92563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark CMProfileLocation location; 93563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark location.locType = cmPathBasedProfile; 94563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark strcpy(location.u.pathLoc.path, PROFILE_PATH); 95563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark error = CMSetDeviceProfile(cmDisplayDeviceClass, (CMDeviceID)kCGDirectMainDisplay, &scope, cmDefaultProfileID, &location); 96563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark if (error) { 97563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark fprintf(stderr, "Failed to set color profile for main display! Many pixel tests may fail as a result. (Error: %i)", error); 98563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark sInitialProfileLocation.locType = cmNoProfileBase; 99563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark return; 100563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark } 101563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark 102563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark // Other signals are handled in installSignalHandlers() which also calls restoreMainDisplayColorProfile() 103563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark signal(SIGINT, restoreMainDisplayColorProfile); 104563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark signal(SIGHUP, restoreMainDisplayColorProfile); 105563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark signal(SIGTERM, restoreMainDisplayColorProfile); 106563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark} 107563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark 108967717af5423377c967781471ee106e2bb4e11c8Ben Murdochstatic PassRefPtr<BitmapContext> createBitmapContext(size_t pixelsWide, size_t pixelsHigh, size_t& rowBytes, void*& buffer) 109563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark{ 110967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch rowBytes = (4 * pixelsWide + 63) & ~63; // Use a multiple of 64 bytes to improve CG performance 111563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark 112967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch buffer = calloc(pixelsHigh, rowBytes); 113563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark if (!buffer) 114563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark return 0; 115563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark 116563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark static CGColorSpaceRef colorSpace = 0; 117563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark if (!colorSpace) { 118563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark CMProfileLocation location; 119563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark location.locType = cmPathBasedProfile; 120563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark strcpy(location.u.pathLoc.path, PROFILE_PATH); 121563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark CMProfileRef profile; 122563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark if (CMOpenProfile(&profile, &location) == noErr) { 123563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark colorSpace = CGColorSpaceCreateWithPlatformColorSpace(profile); 124563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark CMCloseProfile(profile); 125563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark } 126563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark } 127563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark 128563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark CGContextRef context = CGBitmapContextCreate(buffer, pixelsWide, pixelsHigh, 8, rowBytes, colorSpace, kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host); // Use ARGB8 on PPC or BGRA8 on X86 to improve CG performance 129563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark if (!context) { 130563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark free(buffer); 131563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark return 0; 132563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark } 133563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark 134967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch return BitmapContext::createByAdoptingBitmapAndContext(buffer, context); 135967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch} 136967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch 137967717af5423377c967781471ee106e2bb4e11c8Ben MurdochPassRefPtr<BitmapContext> createBitmapContextFromWebView(bool onscreen, bool incrementalRepaint, bool sweepHorizontally, bool drawSelectionRect) 138967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch{ 139967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch WebView* view = [mainFrame webView]; 140967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch 141967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch // If the WebHTMLView uses accelerated compositing, we need for force the on-screen capture path 142967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch // and also force Core Animation to start its animations with -display since the DRT window has autodisplay disabled. 143967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch if ([view _isUsingAcceleratedCompositing]) 144967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch onscreen = YES; 145967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch 146967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch NSSize webViewSize = [view frame].size; 147967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch size_t pixelsWide = static_cast<size_t>(webViewSize.width); 148967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch size_t pixelsHigh = static_cast<size_t>(webViewSize.height); 149967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch size_t rowBytes = 0; 150967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch void* buffer = 0; 151967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch RefPtr<BitmapContext> bitmapContext = createBitmapContext(pixelsWide, pixelsHigh, rowBytes, buffer); 152967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch if (!bitmapContext) 153967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch return 0; 154967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch CGContextRef context = bitmapContext->cgContext(); 155967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch 156563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark NSGraphicsContext *nsContext = [NSGraphicsContext graphicsContextWithGraphicsPort:context flipped:NO]; 157563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark ASSERT(nsContext); 158563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark 159563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark if (incrementalRepaint) { 160563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark if (sweepHorizontally) { 161563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark for (NSRect column = NSMakeRect(0, 0, 1, webViewSize.height); column.origin.x < webViewSize.width; column.origin.x++) 162563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark [view displayRectIgnoringOpacity:column inContext:nsContext]; 163563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark } else { 164563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark for (NSRect line = NSMakeRect(0, 0, webViewSize.width, 1); line.origin.y < webViewSize.height; line.origin.y++) 165563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark [view displayRectIgnoringOpacity:line inContext:nsContext]; 166563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark } 167563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark } else { 1680bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch 169563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark if (onscreen) { 1700bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch#if !defined(BUILDING_ON_TIGER) 1710bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch // displayIfNeeded does not update the CA layers if the layer-hosting view was not marked as needing display, so 1720bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch // we're at the mercy of CA's display-link callback to update layers in time. So we need to force a display of the view 1730bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch // to get AppKit to update the CA layers synchronously. 1740bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch // FIXME: this will break repaint testing if we have compositing in repaint tests 1750bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch // (displayWebView() painted gray over the webview, but we'll be making everything repaint again). 1760bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch [view display]; 1770bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch 178563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark // Ask the window server to provide us a composited version of the *real* window content including surfaces (i.e. OpenGL content) 179563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark // Note that the returned image might differ very slightly from the window backing because of dithering artifacts in the window server compositor 180563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark CGImageRef image = CGWindowListCreateImage(CGRectNull, kCGWindowListOptionIncludingWindow, [[view window] windowNumber], kCGWindowImageBoundsIgnoreFraming | kCGWindowImageShouldBeOpaque); 181563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark CGContextDrawImage(context, CGRectMake(0, 0, CGImageGetWidth(image), CGImageGetHeight(image)), image); 182563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark CGImageRelease(image); 183563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark#else 184563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark // On 10.4 and earlier, we have to move the window temporarily "onscreen" and read directly from the display framebuffer using OpenGL 185563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark // In this code path, we need to ensure the window is above any other window or captured result will be corrupted 186563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark 187563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark NSWindow *window = [view window]; 188563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark int oldLevel = [window level]; 189563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark NSRect oldFrame = [window frame]; 190563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark 191563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark NSRect newFrame = [[[NSScreen screens] objectAtIndex:0] frame]; 192563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark newFrame = NSMakeRect(newFrame.origin.x + (newFrame.size.width - oldFrame.size.width) / 2, newFrame.origin.y + (newFrame.size.height - oldFrame.size.height) / 2, oldFrame.size.width, oldFrame.size.height); 193563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark [window setLevel:NSScreenSaverWindowLevel]; 194563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark [window setFrame:newFrame display:NO animate:NO]; 195563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark 196563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark CGRect rect = CGRectMake(newFrame.origin.x, newFrame.origin.y, webViewSize.width, webViewSize.height); 197563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark CGDirectDisplayID displayID; 198563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark CGDisplayCount count; 199563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark if (CGGetDisplaysWithRect(rect, 1, &displayID, &count) == kCGErrorSuccess) { 200563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark CGRect bounds = CGDisplayBounds(displayID); 201563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark rect.origin.x -= bounds.origin.x; 202563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark rect.origin.y -= bounds.origin.y; 203563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark 204563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark CGLPixelFormatAttribute attributes[] = {kCGLPFAAccelerated, kCGLPFANoRecovery, kCGLPFAFullScreen, kCGLPFADisplayMask, (CGLPixelFormatAttribute)CGDisplayIDToOpenGLDisplayMask(displayID), (CGLPixelFormatAttribute)0}; 205563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark CGLPixelFormatObj pixelFormat; 206563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark GLint num; 207563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark if (CGLChoosePixelFormat(attributes, &pixelFormat, &num) == kCGLNoError) { 208563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark CGLContextObj cgl_ctx; 209563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark if (CGLCreateContext(pixelFormat, 0, &cgl_ctx) == kCGLNoError) { 210563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark if (CGLSetFullScreen(cgl_ctx) == kCGLNoError) { 211563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark void *flipBuffer = calloc(pixelsHigh, rowBytes); 212563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark if (flipBuffer) { 213563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark glPixelStorei(GL_PACK_ROW_LENGTH, rowBytes / 4); 214563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark glPixelStorei(GL_PACK_ALIGNMENT, 4); 215563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark#if __BIG_ENDIAN__ 216563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark glReadPixels(rect.origin.x, rect.origin.y, rect.size.width, rect.size.height, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, flipBuffer); 217563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark#else 218563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark glReadPixels(rect.origin.x, rect.origin.y, rect.size.width, rect.size.height, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, flipBuffer); 219563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark#endif 220563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark if (!glGetError()) { 221563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark for(size_t i = 0; i < pixelsHigh; ++i) 222563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark bcopy((char*)flipBuffer + rowBytes * i, (char*)buffer + rowBytes * (pixelsHigh - i - 1), pixelsWide * 4); 223563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark } 224563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark 225563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark free(flipBuffer); 226563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark } 227563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark } 228563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark CGLDestroyContext(cgl_ctx); 229563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark } 230563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark CGLDestroyPixelFormat(pixelFormat); 231563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark } 232563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark } 233563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark 234563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark [window setFrame:oldFrame display:NO animate:NO]; 235563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark [window setLevel:oldLevel]; 236563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark#endif 237563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark } else { 2380bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch // Make sure the view has been painted. 2390bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch [view displayIfNeeded]; 2400bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch 241563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark // Grab directly the contents of the window backing buffer (this ignores any surfaces on the window) 242563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark // FIXME: This path is suboptimal: data is read from window backing store, converted to RGB8 then drawn again into an RGBA8 bitmap 243563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark [view lockFocus]; 244563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark NSBitmapImageRep *imageRep = [[[NSBitmapImageRep alloc] initWithFocusedViewRect:[view frame]] autorelease]; 245563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark [view unlockFocus]; 246563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark 247563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark RetainPtr<NSGraphicsContext> savedContext = [NSGraphicsContext currentContext]; 248563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark [NSGraphicsContext setCurrentContext:nsContext]; 249563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark [imageRep draw]; 250563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark [NSGraphicsContext setCurrentContext:savedContext.get()]; 251563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark } 252563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark } 253563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark 254563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark if (drawSelectionRect) { 255563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark NSView *documentView = [[mainFrame frameView] documentView]; 256563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark ASSERT([documentView conformsToProtocol:@protocol(WebDocumentSelection)]); 257563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark NSRect rect = [documentView convertRect:[(id <WebDocumentSelection>)documentView selectionRect] fromView:nil]; 258563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark CGContextSaveGState(context); 259563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark CGContextSetLineWidth(context, 1.0); 260563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark CGContextSetRGBStrokeColor(context, 1.0, 0.0, 0.0, 1.0); 261563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark CGContextStrokeRect(context, CGRectMake(rect.origin.x, rect.origin.y, rect.size.width, rect.size.height)); 262563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark CGContextRestoreGState(context); 263563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark } 264563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark 265563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark return bitmapContext.release(); 266563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark} 267967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch 268967717af5423377c967781471ee106e2bb4e11c8Ben MurdochPassRefPtr<BitmapContext> createPagedBitmapContext() 269967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch{ 270967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch int pageWidthInPixels = LayoutTestController::maxViewWidth; 271967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch int pageHeightInPixels = LayoutTestController::maxViewHeight; 272967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch int numberOfPages = [mainFrame numberOfPages:pageWidthInPixels:pageHeightInPixels]; 273967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch size_t rowBytes = 0; 274967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch void* buffer = 0; 275967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch 276967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch RefPtr<BitmapContext> bitmapContext = createBitmapContext(pageWidthInPixels, numberOfPages * (pageHeightInPixels + 1) - 1, rowBytes, buffer); 277967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch [mainFrame printToCGContext:bitmapContext->cgContext():pageWidthInPixels:pageHeightInPixels]; 278967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch return bitmapContext.release(); 279967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch} 280