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); }
void ImageBufferData::putData(Uint8ClampedArray*& source, const IntSize& sourceSize, const IntRect& sourceRect, const IntPoint& destPoint, const IntSize& size, bool accelerateRendering, bool unmultiplied, float resolutionScale) { ASSERT(sourceRect.width() > 0); ASSERT(sourceRect.height() > 0); int originx = sourceRect.x(); int destx = (destPoint.x() + sourceRect.x()) * resolutionScale; ASSERT(destx >= 0); ASSERT(destx < size.width()); ASSERT(originx >= 0); ASSERT(originx <= sourceRect.maxX()); int endx = (destPoint.x() + sourceRect.maxX()) * resolutionScale; ASSERT(endx <= size.width()); int width = sourceRect.width(); int destw = endx - destx; int originy = sourceRect.y(); int desty = (destPoint.y() + sourceRect.y()) * resolutionScale; ASSERT(desty >= 0); ASSERT(desty < size.height()); ASSERT(originy >= 0); ASSERT(originy <= sourceRect.maxY()); int endy = (destPoint.y() + sourceRect.maxY()) * resolutionScale; ASSERT(endy <= size.height()); int height = sourceRect.height(); int desth = 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 = desth; dst.width = destw; dst.rowBytes = destBytesPerRow; dst.data = destRows; if (resolutionScale != 1) { vImage_AffineTransform scaleTransform = { resolutionScale, 0, 0, resolutionScale, 0, 0 }; // FIXME: Add subpixel translation. Pixel_8888 backgroundColor; vImageAffineWarp_ARGB8888(&src, &dst, 0, &scaleTransform, backgroundColor, kvImageEdgeExtend); // The premultiplying will be done in-place. src = dst; } vImagePremultiplyData_RGBA8888(&src, &dst, kvImageNoFlags); return; } #endif if (resolutionScale != 1) { RetainPtr<CGContextRef> sourceContext(AdoptCF, CGBitmapContextCreate(srcRows, width, height, 8, srcBytesPerRow, m_colorSpace, kCGImageAlphaPremultipliedLast)); RetainPtr<CGImageRef> sourceImage(AdoptCF, CGBitmapContextCreateImage(sourceContext.get())); RetainPtr<CGContextRef> destinationContext(AdoptCF, CGBitmapContextCreate(destRows, destw, desth, 8, destBytesPerRow, m_colorSpace, kCGImageAlphaPremultipliedLast)); CGContextSetBlendMode(destinationContext.get(), kCGBlendModeCopy); CGContextDrawImage(destinationContext.get(), CGRectMake(0, 0, width / resolutionScale, height / resolutionScale), sourceImage.get()); // FIXME: Add subpixel translation. if (!unmultiplied) return; srcRows = destRows; srcBytesPerRow = destBytesPerRow; width = destw; height = desth; } 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) vImage_Buffer src; src.height = height; src.width = width; src.rowBytes = srcBytesPerRow; src.data = srcRows; vImage_Buffer dest; dest.height = desth; dest.width = destw; dest.rowBytes = destBytesPerRow; dest.data = destRows; if (resolutionScale != 1) { vImage_AffineTransform scaleTransform = { resolutionScale, 0, 0, resolutionScale, 0, 0 }; // FIXME: Add subpixel translation. Pixel_8888 backgroundColor; vImageAffineWarp_ARGB8888(&src, &dest, 0, &scaleTransform, backgroundColor, kvImageEdgeExtend); // The unpremultiplying and channel-swapping will be done in-place. if (unmultiplied) { srcRows = destRows; width = destw; height = desth; srcBytesPerRow = destBytesPerRow; } else src = dest; } 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 { // Swap pixel channels from RGBA to BGRA. const uint8_t map[4] = { 2, 1, 0, 3 }; vImagePermuteChannels_ARGB8888(&src, &dest, map, kvImageNoFlags); } #else if (resolutionScale != 1) { RetainPtr<CGContextRef> sourceContext(AdoptCF, CGBitmapContextCreate(srcRows, width, height, 8, srcBytesPerRow, m_colorSpace, kCGImageAlphaPremultipliedLast)); RetainPtr<CGImageRef> sourceImage(AdoptCF, CGBitmapContextCreateImage(sourceContext.get())); RetainPtr<CGContextRef> destinationContext(AdoptCF, CGBitmapContextCreate(destRows, destw, desth, 8, destBytesPerRow, m_colorSpace, kCGImageAlphaPremultipliedLast)); CGContextSetBlendMode(destinationContext.get(), kCGBlendModeCopy); CGContextDrawImage(destinationContext.get(), CGRectMake(0, 0, width / resolutionScale, height / resolutionScale), sourceImage.get()); // FIXME: Add subpixel translation. srcRows = destRows; srcBytesPerRow = destBytesPerRow; width = destw; height = desth; } for (int y = 0; y < height; ++y) { for (int x = 0; x < width; x++) { int basex = x * 4; unsigned char b = srcRows[basex]; 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] = (b * alpha + 254) / 255; destRows[basex + 3] = alpha; } else { destRows[basex] = srcRows[basex + 2]; destRows[basex + 1] = srcRows[basex + 1]; destRows[basex + 2] = b; 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) } }
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) } }