diff options
author | Ben Murdoch <benm@google.com> | 2011-06-02 12:07:03 +0100 |
---|---|---|
committer | Ben Murdoch <benm@google.com> | 2011-06-10 10:47:21 +0100 |
commit | 2daae5fd11344eaa88a0d92b0f6d65f8d2255c00 (patch) | |
tree | e4964fbd1cb70599f7718ff03e50ea1dab33890b /Source/WebCore/platform/graphics/cg/ImageBufferDataCG.cpp | |
parent | 87bdf0060a247bfbe668342b87e0874182e0ffa9 (diff) | |
download | external_webkit-2daae5fd11344eaa88a0d92b0f6d65f8d2255c00.zip external_webkit-2daae5fd11344eaa88a0d92b0f6d65f8d2255c00.tar.gz external_webkit-2daae5fd11344eaa88a0d92b0f6d65f8d2255c00.tar.bz2 |
Merge WebKit at r84325: Initial merge by git.
Change-Id: Ic1a909300ecc0a13ddc6b4e784371d2ac6e3d59b
Diffstat (limited to 'Source/WebCore/platform/graphics/cg/ImageBufferDataCG.cpp')
-rw-r--r-- | Source/WebCore/platform/graphics/cg/ImageBufferDataCG.cpp | 387 |
1 files changed, 387 insertions, 0 deletions
diff --git a/Source/WebCore/platform/graphics/cg/ImageBufferDataCG.cpp b/Source/WebCore/platform/graphics/cg/ImageBufferDataCG.cpp new file mode 100644 index 0000000..f067b66 --- /dev/null +++ b/Source/WebCore/platform/graphics/cg/ImageBufferDataCG.cpp @@ -0,0 +1,387 @@ +/* + * Copyright (C) 2011 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "ImageBufferData.h" + +#include <wtf/Assertions.h> + +#if USE(ACCELERATE) +#include <Accelerate/Accelerate.h> +#endif + +#if USE(IOSURFACE_CANVAS_BACKING_STORE) +#include <IOSurface/IOSurface.h> +#include <dispatch/dispatch.h> +#endif + +#if USE(ACCELERATE) +struct ScanlineData { + vImagePixelCount scanlineWidth; + unsigned char* srcData; + size_t srcRowBytes; + unsigned char* destData; + size_t destRowBytes; +}; +#endif + +namespace WebCore { + +ImageBufferData::ImageBufferData(const IntSize&) +: m_data(0) +#if USE(IOSURFACE_CANVAS_BACKING_STORE) +, m_surface(0) +#endif +{ +} + +#if USE(ACCELERATE) +// The vImage unpremultiply routine had a rounding bug before 10.6.7 <rdar://problem/8631548> +static bool haveVImageRoundingErrorFix() +{ + SInt32 version; + static bool result = (Gestalt(gestaltSystemVersion, &version) == noErr && version > 0x1066); + return result; +} + +#if USE(IOSURFACE_CANVAS_BACKING_STORE) +static void convertScanline(void* data, size_t tileNumber, bool premultiply) +{ + ScanlineData* scanlineData = static_cast<ScanlineData*>(data); + + vImage_Buffer src; + src.data = scanlineData->srcData + tileNumber * scanlineData->srcRowBytes; + src.height = 1; + src.width = scanlineData->scanlineWidth; + src.rowBytes = scanlineData->srcRowBytes; + + vImage_Buffer dest; + dest.data = scanlineData->destData + tileNumber * scanlineData->destRowBytes; + dest.height = 1; + dest.width = scanlineData->scanlineWidth; + dest.rowBytes = scanlineData->destRowBytes; + + if (premultiply) { + if (kvImageNoError != vImagePremultiplyData_RGBA8888(&src, &dest, kvImageDoNotTile)) + return; + } else { + if (kvImageNoError != vImageUnpremultiplyData_RGBA8888(&src, &dest, kvImageDoNotTile)) + return; + } + + // Swap channels 1 and 3, to convert BGRA<->RGBA. IOSurfaces is BGRA, ImageData expects RGBA. + const uint8_t map[4] = { 2, 1, 0, 3 }; + vImagePermuteChannels_ARGB8888(&dest, &dest, map, kvImageDoNotTile); +} + +static void unpremultitplyScanline(void* data, size_t tileNumber) +{ + convertScanline(data, tileNumber, false); +} + +static void premultitplyScanline(void* data, size_t tileNumber) +{ + convertScanline(data, tileNumber, true); +} +#endif // USE(IOSURFACE_CANVAS_BACKING_STORE) +#endif // USE(ACCELERATE) + +PassRefPtr<ByteArray> ImageBufferData::getData(const IntRect& rect, const IntSize& size, bool accelerateRendering, bool unmultiplied) const +{ + RefPtr<ByteArray> result = ByteArray::create(rect.width() * rect.height() * 4); + unsigned char* data = result->data(); + + if (rect.x() < 0 || rect.y() < 0 || rect.maxX() > size.width() || rect.maxY() > size.height()) + memset(data, 0, result->length()); + + int originx = rect.x(); + int destx = 0; + if (originx < 0) { + destx = -originx; + originx = 0; + } + int endx = rect.maxX(); + if (endx > size.width()) + endx = size.width(); + int width = endx - originx; + + int originy = rect.y(); + int desty = 0; + if (originy < 0) { + desty = -originy; + originy = 0; + } + int endy = rect.maxY(); + if (endy > size.height()) + endy = size.height(); + int height = endy - originy; + + if (width <= 0 || height <= 0) + return result.release(); + + unsigned destBytesPerRow = 4 * rect.width(); + unsigned char* destRows = data + desty * destBytesPerRow + destx * 4; + + unsigned srcBytesPerRow; + unsigned char* srcRows; + + if (!accelerateRendering) { + srcBytesPerRow = 4 * size.width(); + srcRows = reinterpret_cast<unsigned char*>(m_data) + originy * srcBytesPerRow + originx * 4; + +#if USE(ACCELERATE) + if (unmultiplied && haveVImageRoundingErrorFix()) { + vImage_Buffer src; + src.height = height; + src.width = width; + src.rowBytes = srcBytesPerRow; + src.data = srcRows; + + vImage_Buffer dst; + dst.height = height; + dst.width = width; + dst.rowBytes = destBytesPerRow; + dst.data = destRows; + + vImageUnpremultiplyData_RGBA8888(&src, &dst, kvImageNoFlags); + return result.release(); + } +#endif + for (int y = 0; y < height; ++y) { + for (int x = 0; x < width; x++) { + int basex = x * 4; + unsigned char alpha = srcRows[basex + 3]; + if (unmultiplied && alpha) { + destRows[basex] = (srcRows[basex] * 255) / alpha; + destRows[basex + 1] = (srcRows[basex + 1] * 255) / alpha; + destRows[basex + 2] = (srcRows[basex + 2] * 255) / alpha; + destRows[basex + 3] = alpha; + } else + reinterpret_cast<uint32_t*>(destRows + basex)[0] = reinterpret_cast<uint32_t*>(srcRows + basex)[0]; + } + srcRows += srcBytesPerRow; + destRows += destBytesPerRow; + } + } else { +#if USE(IOSURFACE_CANVAS_BACKING_STORE) + IOSurfaceRef surface = m_surface.get(); + IOSurfaceLock(surface, kIOSurfaceLockReadOnly, 0); + srcBytesPerRow = IOSurfaceGetBytesPerRow(surface); + srcRows = (unsigned char*)(IOSurfaceGetBaseAddress(surface)) + originy * srcBytesPerRow + originx * 4; + +#if USE(ACCELERATE) + if (unmultiplied) { + ScanlineData scanlineData; + scanlineData.scanlineWidth = width; + scanlineData.srcData = srcRows; + scanlineData.srcRowBytes = srcBytesPerRow; + scanlineData.destData = destRows; + scanlineData.destRowBytes = destBytesPerRow; + + dispatch_apply_f(height, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), &scanlineData, unpremultitplyScanline); + } else { + vImage_Buffer src; + src.height = height; + src.width = width; + src.rowBytes = srcBytesPerRow; + src.data = srcRows; + + vImage_Buffer dest; + dest.height = height; + dest.width = width; + dest.rowBytes = destBytesPerRow; + dest.data = destRows; + + // Swap pixel channels from BGRA to RGBA. + const uint8_t map[4] = { 2, 1, 0, 3 }; + vImagePermuteChannels_ARGB8888(&src, &dest, map, kvImageNoFlags); + } +#else + for (int y = 0; y < height; ++y) { + for (int x = 0; x < width; x++) { + int basex = x * 4; + unsigned char alpha = srcRows[basex + 3]; + if (unmultiplied && alpha) { + destRows[basex] = (srcRows[basex + 2] * 255) / alpha; + destRows[basex + 1] = (srcRows[basex + 1] * 255) / alpha; + destRows[basex + 2] = (srcRows[basex] * 255) / alpha; + destRows[basex + 3] = alpha; + } else { + destRows[basex] = srcRows[basex + 2]; + destRows[basex + 1] = srcRows[basex + 1]; + destRows[basex + 2] = srcRows[basex]; + destRows[basex + 3] = alpha; + } + } + srcRows += srcBytesPerRow; + destRows += destBytesPerRow; + } +#endif // USE(ACCELERATE) + IOSurfaceUnlock(surface, kIOSurfaceLockReadOnly, 0); +#else + ASSERT_NOT_REACHED(); +#endif // USE(IOSURFACE_CANVAS_BACKING_STORE) + } + + return result.release(); +} + +void ImageBufferData::putData(ByteArray*& source, const IntSize& sourceSize, const IntRect& sourceRect, const IntPoint& destPoint, const IntSize& size, bool accelerateRendering, bool unmultiplied) +{ + ASSERT(sourceRect.width() > 0); + ASSERT(sourceRect.height() > 0); + + int originx = sourceRect.x(); + int destx = destPoint.x() + sourceRect.x(); + ASSERT(destx >= 0); + ASSERT(destx < size.width()); + ASSERT(originx >= 0); + ASSERT(originx <= sourceRect.maxX()); + + int endx = destPoint.x() + sourceRect.maxX(); + ASSERT(endx <= size.width()); + + int width = endx - destx; + + int originy = sourceRect.y(); + int desty = destPoint.y() + sourceRect.y(); + ASSERT(desty >= 0); + ASSERT(desty < size.height()); + ASSERT(originy >= 0); + ASSERT(originy <= sourceRect.maxY()); + + int endy = destPoint.y() + sourceRect.maxY(); + ASSERT(endy <= size.height()); + int height = endy - desty; + + if (width <= 0 || height <= 0) + return; + + unsigned srcBytesPerRow = 4 * sourceSize.width(); + unsigned char* srcRows = source->data() + originy * srcBytesPerRow + originx * 4; + unsigned destBytesPerRow; + unsigned char* destRows; + + if (!accelerateRendering) { + destBytesPerRow = 4 * size.width(); + destRows = reinterpret_cast<unsigned char*>(m_data) + desty * destBytesPerRow + destx * 4; + +#if USE(ACCELERATE) + if (haveVImageRoundingErrorFix() && unmultiplied) { + vImage_Buffer src; + src.height = height; + src.width = width; + src.rowBytes = srcBytesPerRow; + src.data = srcRows; + + vImage_Buffer dst; + dst.height = height; + dst.width = width; + dst.rowBytes = destBytesPerRow; + dst.data = destRows; + + vImagePremultiplyData_RGBA8888(&src, &dst, kvImageNoFlags); + return; + } +#endif + for (int y = 0; y < height; ++y) { + for (int x = 0; x < width; x++) { + int basex = x * 4; + unsigned char alpha = srcRows[basex + 3]; + if (unmultiplied && alpha != 255) { + destRows[basex] = (srcRows[basex] * alpha + 254) / 255; + destRows[basex + 1] = (srcRows[basex + 1] * alpha + 254) / 255; + destRows[basex + 2] = (srcRows[basex + 2] * alpha + 254) / 255; + destRows[basex + 3] = alpha; + } else + reinterpret_cast<uint32_t*>(destRows + basex)[0] = reinterpret_cast<uint32_t*>(srcRows + basex)[0]; + } + destRows += destBytesPerRow; + srcRows += srcBytesPerRow; + } + } else { +#if USE(IOSURFACE_CANVAS_BACKING_STORE) + IOSurfaceRef surface = m_surface.get(); + IOSurfaceLock(surface, 0, 0); + destBytesPerRow = IOSurfaceGetBytesPerRow(surface); + destRows = (unsigned char*)(IOSurfaceGetBaseAddress(surface)) + desty * destBytesPerRow + destx * 4; + +#if USE(ACCELERATE) + if (unmultiplied) { + ScanlineData scanlineData; + scanlineData.scanlineWidth = width; + scanlineData.srcData = srcRows; + scanlineData.srcRowBytes = srcBytesPerRow; + scanlineData.destData = destRows; + scanlineData.destRowBytes = destBytesPerRow; + + dispatch_apply_f(height, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), &scanlineData, premultitplyScanline); + } else { + vImage_Buffer src; + src.height = height; + src.width = width; + src.rowBytes = srcBytesPerRow; + src.data = srcRows; + + vImage_Buffer dest; + dest.height = height; + dest.width = width; + dest.rowBytes = destBytesPerRow; + dest.data = destRows; + + // Swap pixel channels from RGBA to BGRA. + const uint8_t map[4] = { 2, 1, 0, 3 }; + vImagePermuteChannels_ARGB8888(&src, &dest, map, kvImageNoFlags); + } +#else + for (int y = 0; y < height; ++y) { + for (int x = 0; x < width; x++) { + int basex = x * 4; + unsigned char alpha = srcRows[basex + 3]; + if (unmultiplied && alpha != 255) { + destRows[basex] = (srcRows[basex + 2] * alpha + 254) / 255; + destRows[basex + 1] = (srcRows[basex + 1] * alpha + 254) / 255; + destRows[basex + 2] = (srcRows[basex] * alpha + 254) / 255; + destRows[basex + 3] = alpha; + } else { + destRows[basex] = srcRows[basex + 2]; + destRows[basex + 1] = srcRows[basex + 1]; + destRows[basex + 2] = srcRows[basex]; + destRows[basex + 3] = alpha; + } + } + destRows += destBytesPerRow; + srcRows += srcBytesPerRow; + } +#endif // USE(ACCELERATE) + + IOSurfaceUnlock(surface, 0, 0); +#else + ASSERT_NOT_REACHED(); +#endif // USE(IOSURFACE_CANVAS_BACKING_STORE) + } +} + +} // namespace WebCore |