10bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch/*
20bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch * Copyright (C) 2009 Apple, Inc. All rights reserved.
30bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch *
40bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch * Redistribution and use in source and binary forms, with or without
50bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch * modification, are permitted provided that the following conditions
60bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch * are met:
70bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch *
80bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch * 1.  Redistributions of source code must retain the above copyright
90bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch *     notice, this list of conditions and the following disclaimer.
100bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch * 2.  Redistributions in binary form must reproduce the above copyright
110bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch *     notice, this list of conditions and the following disclaimer in the
120bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch *     documentation and/or other materials provided with the distribution.
130bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
140bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch *     its contributors may be used to endorse or promote products derived
150bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch *     from this software without specific prior written permission.
160bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch *
170bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
180bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
190bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
200bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
210bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
220bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
230bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
240bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
250bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
260bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
270bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch */
280bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
290bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch#include "config.h"
30e14391e94c850b8bd03680c23b38978db68687a8John Reck#include "PixelDumpSupport.h"
31e14391e94c850b8bd03680c23b38978db68687a8John Reck
322daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch#include "CyclicRedundancyCheck.h"
330bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch#include "DumpRenderTree.h"
340bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch#include "LayoutTestController.h"
35e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke#include <cstdio>
360bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch#include <wtf/Assertions.h>
370bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch#include <wtf/RefPtr.h>
382daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch#include <wtf/Vector.h>
390bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
402daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch#if USE(CG)
410bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch#include "PixelDumpSupportCG.h"
422daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch#elif USE(CAIRO)
430bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch#include "PixelDumpSupportCairo.h"
440bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch#endif
450bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
460bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochvoid dumpWebViewAsPixelsAndCompareWithExpected(const std::string& expectedHash)
470bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch{
48967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch    RefPtr<BitmapContext> context;
49967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch#if PLATFORM(MAC)
50967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch    if (gLayoutTestController->isPrinting())
51967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch        context = createPagedBitmapContext();
52967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch    else
53967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch#endif
54967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch        context = createBitmapContextFromWebView(gLayoutTestController->testOnscreen(), gLayoutTestController->testRepaint(), gLayoutTestController->testRepaintSweepHorizontally(), gLayoutTestController->dumpSelectionRect());
550bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    ASSERT(context);
560bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
570bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    // Compute the hash of the bitmap context pixels
580bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    char actualHash[33];
590bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    computeMD5HashStringForBitmapContext(context.get(), actualHash);
600bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    printf("\nActualHash: %s\n", actualHash);
610bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
620bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    // Check the computed hash against the expected one and dump image on mismatch
630bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    bool dumpImage = true;
640bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if (expectedHash.length() > 0) {
650bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        ASSERT(expectedHash.length() == 32);
660bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
670bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        printf("\nExpectedHash: %s\n", expectedHash.c_str());
680bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
690bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if (expectedHash == actualHash)     // FIXME: do case insensitive compare
700bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            dumpImage = false;
710bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    }
720bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
730bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if (dumpImage)
742daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch      dumpBitmap(context.get(), actualHash);
750bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch}
760bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
772daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdochstatic void appendIntToVector(unsigned number, Vector<unsigned char>& vector)
780bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch{
792daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    size_t offset = vector.size();
802daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    vector.grow(offset + 4);
812daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    vector[offset] = ((number >> 24) & 0xff);
822daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    vector[offset + 1] = ((number >> 16) & 0xff);
832daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    vector[offset + 2] = ((number >> 8) & 0xff);
842daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    vector[offset + 3] = (number & 0xff);
852daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch}
862daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
872daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdochstatic void convertChecksumToPNGComment(const char* checksum, Vector<unsigned char>& bytesToAdd)
882daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch{
892daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    // Chunks of PNG files are <length>, <type>, <data>, <crc>.
902daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    static const char textCommentPrefix[] = "\x00\x00\x00\x29tEXtchecksum\x00";
912daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    static const size_t prefixLength = sizeof(textCommentPrefix) - 1; // The -1 is for the null at the end of the char[].
922daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    static const size_t checksumLength = 32;
932daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
942daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    bytesToAdd.append(textCommentPrefix, prefixLength);
952daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    bytesToAdd.append(checksum, checksumLength);
962daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
972daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    Vector<unsigned char> dataToCrc;
982daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    dataToCrc.append(textCommentPrefix + 4, prefixLength - 4); // Don't include the chunk length in the crc.
992daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    dataToCrc.append(checksum, checksumLength);
1002daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    unsigned crc32 = computeCrc(dataToCrc);
1012daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
1022daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    appendIntToVector(crc32, bytesToAdd);
1032daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch}
1042daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
1052daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdochstatic size_t offsetAfterIHDRChunk(const unsigned char* data, const size_t dataLength)
1062daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch{
1072daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    const int pngHeaderLength = 8;
1082daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    const int pngIHDRChunkLength = 25; // chunk length + "IHDR" + 13 bytes of data + checksum
1092daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    return pngHeaderLength + pngIHDRChunkLength;
1102daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch}
1112daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
1122daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdochvoid printPNG(const unsigned char* data, const size_t dataLength, const char* checksum)
1132daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch{
1142daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    Vector<unsigned char> bytesToAdd;
1152daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    convertChecksumToPNGComment(checksum, bytesToAdd);
1162daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
1170bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    printf("Content-Type: %s\n", "image/png");
1182daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    printf("Content-Length: %lu\n", static_cast<unsigned long>(dataLength + bytesToAdd.size()));
1192daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
1202daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    size_t insertOffset = offsetAfterIHDRChunk(data, dataLength);
1212daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch
1222daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    fwrite(data, 1, insertOffset, stdout);
1232daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    fwrite(bytesToAdd.data(), 1, bytesToAdd.size(), stdout);
1240bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
1250bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    const size_t bytesToWriteInOneChunk = 1 << 15;
1262daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    data += insertOffset;
1272daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch    size_t dataRemainingToWrite = dataLength - insertOffset;
1280bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    while (dataRemainingToWrite) {
1290bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        size_t bytesToWriteInThisChunk = std::min(dataRemainingToWrite, bytesToWriteInOneChunk);
1300bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        size_t bytesWritten = fwrite(data, 1, bytesToWriteInThisChunk, stdout);
1310bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if (bytesWritten != bytesToWriteInThisChunk)
1320bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            break;
1330bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        dataRemainingToWrite -= bytesWritten;
1340bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        data += bytesWritten;
1350bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    }
1360bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch}
137