X-Git-Url: http://git.osdn.net/view?a=blobdiff_plain;f=WebCore%2Fplatform%2Fgraphics%2Fcg%2FGraphicsContext3DCG.cpp;h=0c6acf9bb2c5157d182cd38f4ea7fa980d3e1c68;hb=28040489d744e0c5d475a88663056c9040ed5320;hp=2a81fd2835ec3fac03380b7038d1bc783612c2e3;hpb=df4d664a4f545d9ddf794f39ad0716870b723e24;p=android-x86%2Fexternal-webkit.git diff --git a/WebCore/platform/graphics/cg/GraphicsContext3DCG.cpp b/WebCore/platform/graphics/cg/GraphicsContext3DCG.cpp index 2a81fd283..0c6acf9bb 100644 --- a/WebCore/platform/graphics/cg/GraphicsContext3DCG.cpp +++ b/WebCore/platform/graphics/cg/GraphicsContext3DCG.cpp @@ -41,6 +41,52 @@ namespace WebCore { +enum SourceDataFormatBase { + SourceFormatBaseR = 0, + SourceFormatBaseA, + SourceFormatBaseRA, + SourceFormatBaseAR, + SourceFormatBaseRGB, + SourceFormatBaseRGBA, + SourceFormatBaseARGB, + SourceFormatBaseNumFormats +}; + +enum AlphaFormat { + AlphaFormatNone = 0, + AlphaFormatFirst, + AlphaFormatLast, + AlphaFormatNumFormats +}; + +// This returns SourceFormatNumFormats if the combination of input parameters is unsupported. +static GraphicsContext3D::SourceDataFormat getSourceDataFormat(unsigned int componentsPerPixel, AlphaFormat alphaFormat, bool is16BitFormat, bool bigEndian) +{ + const static SourceDataFormatBase formatTableBase[4][AlphaFormatNumFormats] = { // componentsPerPixel x AlphaFormat + // AlphaFormatNone AlphaFormatFirst AlphaFormatLast + { SourceFormatBaseR, SourceFormatBaseA, SourceFormatBaseA }, // 1 componentsPerPixel + { SourceFormatBaseNumFormats, SourceFormatBaseAR, SourceFormatBaseRA }, // 2 componentsPerPixel + { SourceFormatBaseRGB, SourceFormatBaseNumFormats, SourceFormatBaseNumFormats }, // 3 componentsPerPixel + { SourceFormatBaseNumFormats, SourceFormatBaseARGB, SourceFormatBaseRGBA } // 4 componentsPerPixel + }; + const static GraphicsContext3D::SourceDataFormat formatTable[SourceFormatBaseNumFormats][4] = { // SourceDataFormatBase x bitsPerComponent x endian + // 8bits, little endian 8bits, big endian 16bits, little endian 16bits, big endian + { GraphicsContext3D::SourceFormatR8, GraphicsContext3D::SourceFormatR8, GraphicsContext3D::SourceFormatR16Little, GraphicsContext3D::SourceFormatR16Big }, + { GraphicsContext3D::SourceFormatA8, GraphicsContext3D::SourceFormatA8, GraphicsContext3D::SourceFormatA16Little, GraphicsContext3D::SourceFormatA16Big }, + { GraphicsContext3D::SourceFormatAR8, GraphicsContext3D::SourceFormatRA8, GraphicsContext3D::SourceFormatRA16Little, GraphicsContext3D::SourceFormatRA16Big }, + { GraphicsContext3D::SourceFormatRA8, GraphicsContext3D::SourceFormatAR8, GraphicsContext3D::SourceFormatAR16Little, GraphicsContext3D::SourceFormatAR16Big }, + { GraphicsContext3D::SourceFormatBGR8, GraphicsContext3D::SourceFormatRGB8, GraphicsContext3D::SourceFormatRGB16Little, GraphicsContext3D::SourceFormatRGB16Big }, + { GraphicsContext3D::SourceFormatABGR8, GraphicsContext3D::SourceFormatRGBA8, GraphicsContext3D::SourceFormatRGBA16Little, GraphicsContext3D::SourceFormatRGBA16Big }, + { GraphicsContext3D::SourceFormatBGRA8, GraphicsContext3D::SourceFormatARGB8, GraphicsContext3D::SourceFormatARGB16Little, GraphicsContext3D::SourceFormatARGB16Big } + }; + + ASSERT(componentsPerPixel <= 4 && componentsPerPixel > 0); + SourceDataFormatBase formatBase = formatTableBase[componentsPerPixel - 1][alphaFormat]; + if (formatBase == SourceFormatBaseNumFormats) + return GraphicsContext3D::SourceFormatNumFormats; + return formatTable[formatBase][(is16BitFormat ? 2 : 0) + (bigEndian ? 1 : 0)]; +} + bool GraphicsContext3D::getImageData(Image* image, unsigned int format, unsigned int type, @@ -62,13 +108,61 @@ bool GraphicsContext3D::getImageData(Image* image, cgImage = image->nativeImageForCurrentFrame(); if (!cgImage) return false; + size_t width = CGImageGetWidth(cgImage); size_t height = CGImageGetHeight(cgImage); - if (!width || !height || CGImageGetBitsPerComponent(cgImage) != 8) + if (!width || !height) + return false; + size_t bitsPerComponent = CGImageGetBitsPerComponent(cgImage); + size_t bitsPerPixel = CGImageGetBitsPerPixel(cgImage); + if (bitsPerComponent != 8 && bitsPerComponent != 16) return false; - size_t componentsPerPixel = CGImageGetBitsPerPixel(cgImage) / 8; - SourceDataFormat srcDataFormat = kSourceFormatRGBA8; - AlphaOp neededAlphaOp = kAlphaDoNothing; + if (bitsPerPixel % bitsPerComponent) + return false; + size_t componentsPerPixel = bitsPerPixel / bitsPerComponent; + + CGBitmapInfo bitInfo = CGImageGetBitmapInfo(cgImage); + bool bigEndianSource = false; + // These could technically be combined into one large switch + // statement, but we prefer not to so that we fail fast if we + // encounter an unexpected image configuration. + if (bitsPerComponent == 16) { + switch (bitInfo & kCGBitmapByteOrderMask) { + case kCGBitmapByteOrder16Big: + bigEndianSource = true; + break; + case kCGBitmapByteOrder16Little: + bigEndianSource = false; + break; + case kCGBitmapByteOrderDefault: + // This is a bug in earlier version of cg where the default endian + // is little whereas the decoded 16-bit png image data is actually + // Big. Later version (10.6.4) no longer returns ByteOrderDefault. + bigEndianSource = true; + break; + default: + return false; + } + } else { + switch (bitInfo & kCGBitmapByteOrderMask) { + case kCGBitmapByteOrder32Big: + bigEndianSource = true; + break; + case kCGBitmapByteOrder32Little: + bigEndianSource = false; + break; + case kCGBitmapByteOrderDefault: + // It appears that the default byte order is actually big + // endian even on little endian architectures. + bigEndianSource = true; + break; + default: + return false; + } + } + + AlphaOp neededAlphaOp = AlphaDoNothing; + AlphaFormat alphaFormat = AlphaFormatNone; switch (CGImageGetAlphaInfo(cgImage)) { case kCGImageAlphaPremultipliedFirst: // This path is only accessible for MacOS earlier than 10.6.4. @@ -76,110 +170,45 @@ bool GraphicsContext3D::getImageData(Image* image, // in which case image->data() should be null. ASSERT(!image->data()); if (!premultiplyAlpha) - neededAlphaOp = kAlphaDoUnmultiply; - switch (componentsPerPixel) { - case 2: - srcDataFormat = kSourceFormatAR8; - break; - case 4: - srcDataFormat = kSourceFormatARGB8; - break; - default: - return false; - } + neededAlphaOp = AlphaDoUnmultiply; + alphaFormat = AlphaFormatFirst; break; case kCGImageAlphaFirst: // This path is only accessible for MacOS earlier than 10.6.4. if (premultiplyAlpha) - neededAlphaOp = kAlphaDoPremultiply; - switch (componentsPerPixel) { - case 1: - srcDataFormat = kSourceFormatA8; - break; - case 2: - srcDataFormat = kSourceFormatAR8; - break; - case 4: - srcDataFormat = kSourceFormatARGB8; - break; - default: - return false; - } + neededAlphaOp = AlphaDoPremultiply; + alphaFormat = AlphaFormatFirst; break; case kCGImageAlphaNoneSkipFirst: // This path is only accessible for MacOS earlier than 10.6.4. - switch (componentsPerPixel) { - case 2: - srcDataFormat = kSourceFormatAR8; - break; - case 4: - srcDataFormat = kSourceFormatARGB8; - break; - default: - return false; - } + alphaFormat = AlphaFormatFirst; break; case kCGImageAlphaPremultipliedLast: // This is a special case for texImage2D with HTMLCanvasElement input, // in which case image->data() should be null. ASSERT(!image->data()); if (!premultiplyAlpha) - neededAlphaOp = kAlphaDoUnmultiply; - switch (componentsPerPixel) { - case 2: - srcDataFormat = kSourceFormatRA8; - break; - case 4: - srcDataFormat = kSourceFormatRGBA8; - break; - default: - return false; - } + neededAlphaOp = AlphaDoUnmultiply; + alphaFormat = AlphaFormatLast; break; case kCGImageAlphaLast: if (premultiplyAlpha) - neededAlphaOp = kAlphaDoPremultiply; - switch (componentsPerPixel) { - case 1: - srcDataFormat = kSourceFormatA8; - break; - case 2: - srcDataFormat = kSourceFormatRA8; - break; - case 4: - srcDataFormat = kSourceFormatRGBA8; - break; - default: - return false; - } + neededAlphaOp = AlphaDoPremultiply; + alphaFormat = AlphaFormatLast; break; case kCGImageAlphaNoneSkipLast: - switch (componentsPerPixel) { - case 2: - srcDataFormat = kSourceFormatRA8; - break; - case 4: - srcDataFormat = kSourceFormatRGBA8; - break; - default: - return false; - } + alphaFormat = AlphaFormatLast; break; case kCGImageAlphaNone: - switch (componentsPerPixel) { - case 1: - srcDataFormat = kSourceFormatR8; - break; - case 3: - srcDataFormat = kSourceFormatRGB8; - break; - default: - return false; - } + alphaFormat = AlphaFormatNone; break; default: return false; } + SourceDataFormat srcDataFormat = getSourceDataFormat(componentsPerPixel, alphaFormat, bitsPerComponent == 16, bigEndianSource); + if (srcDataFormat == SourceFormatNumFormats) + return false; + RetainPtr pixelData; pixelData.adoptCF(CGDataProviderCopyData(CGImageGetDataProvider(cgImage))); if (!pixelData) @@ -188,7 +217,7 @@ bool GraphicsContext3D::getImageData(Image* image, outputVector.resize(width * height * 4); unsigned int srcUnpackAlignment = 0; size_t bytesPerRow = CGImageGetBytesPerRow(cgImage); - unsigned int padding = bytesPerRow - componentsPerPixel * width; + unsigned int padding = bytesPerRow - bitsPerPixel / 8 * width; if (padding) { srcUnpackAlignment = padding + 1; while (bytesPerRow % srcUnpackAlignment)