1 /* 2 * Copyright (C) 2011 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 #include "config.h" 27 #include "ImageBufferData.h" 28 29 #include <wtf/Assertions.h> 30 31 #if USE(ACCELERATE) 32 #include <Accelerate/Accelerate.h> 33 #endif 34 35 #if USE(IOSURFACE_CANVAS_BACKING_STORE) 36 #include <IOSurface/IOSurface.h> 37 #include <dispatch/dispatch.h> 38 #endif 39 40 #if USE(ACCELERATE) 41 struct ScanlineData { 42 vImagePixelCount scanlineWidth; 43 unsigned char* srcData; 44 size_t srcRowBytes; 45 unsigned char* destData; 46 size_t destRowBytes; 47 }; 48 #endif 49 50 namespace WebCore { 51 52 ImageBufferData::ImageBufferData(const IntSize&) 53 : m_data(0) 54 #if USE(IOSURFACE_CANVAS_BACKING_STORE) 55 , m_surface(0) 56 #endif 57 { 58 } 59 60 #if USE(ACCELERATE) 61 // The vImage unpremultiply routine had a rounding bug before 10.6.7 <rdar://problem/8631548> 62 static bool haveVImageRoundingErrorFix() 63 { 64 SInt32 version; 65 static bool result = (Gestalt(gestaltSystemVersion, &version) == noErr && version > 0x1066); 66 return result; 67 } 68 69 #if USE(IOSURFACE_CANVAS_BACKING_STORE) 70 static void convertScanline(void* data, size_t tileNumber, bool premultiply) 71 { 72 ScanlineData* scanlineData = static_cast<ScanlineData*>(data); 73 74 vImage_Buffer src; 75 src.data = scanlineData->srcData + tileNumber * scanlineData->srcRowBytes; 76 src.height = 1; 77 src.width = scanlineData->scanlineWidth; 78 src.rowBytes = scanlineData->srcRowBytes; 79 80 vImage_Buffer dest; 81 dest.data = scanlineData->destData + tileNumber * scanlineData->destRowBytes; 82 dest.height = 1; 83 dest.width = scanlineData->scanlineWidth; 84 dest.rowBytes = scanlineData->destRowBytes; 85 86 if (premultiply) { 87 if (kvImageNoError != vImagePremultiplyData_RGBA8888(&src, &dest, kvImageDoNotTile)) 88 return; 89 } else { 90 if (kvImageNoError != vImageUnpremultiplyData_RGBA8888(&src, &dest, kvImageDoNotTile)) 91 return; 92 } 93 94 // Swap channels 1 and 3, to convert BGRA<->RGBA. IOSurfaces is BGRA, ImageData expects RGBA. 95 const uint8_t map[4] = { 2, 1, 0, 3 }; 96 vImagePermuteChannels_ARGB8888(&dest, &dest, map, kvImageDoNotTile); 97 } 98 99 static void unpremultitplyScanline(void* data, size_t tileNumber) 100 { 101 convertScanline(data, tileNumber, false); 102 } 103 104 static void premultitplyScanline(void* data, size_t tileNumber) 105 { 106 convertScanline(data, tileNumber, true); 107 } 108 #endif // USE(IOSURFACE_CANVAS_BACKING_STORE) 109 #endif // USE(ACCELERATE) 110 111 PassRefPtr<ByteArray> ImageBufferData::getData(const IntRect& rect, const IntSize& size, bool accelerateRendering, bool unmultiplied) const 112 { 113 float area = 4.0f * rect.width() * rect.height(); 114 if (area > static_cast<float>(std::numeric_limits<int>::max())) 115 return 0; 116 117 RefPtr<ByteArray> result = ByteArray::create(rect.width() * rect.height() * 4); 118 unsigned char* data = result->data(); 119 120 if (rect.x() < 0 || rect.y() < 0 || rect.maxX() > size.width() || rect.maxY() > size.height()) 121 memset(data, 0, result->length()); 122 123 int originx = rect.x(); 124 int destx = 0; 125 if (originx < 0) { 126 destx = -originx; 127 originx = 0; 128 } 129 int endx = rect.maxX(); 130 if (endx > size.width()) 131 endx = size.width(); 132 int width = endx - originx; 133 134 int originy = rect.y(); 135 int desty = 0; 136 if (originy < 0) { 137 desty = -originy; 138 originy = 0; 139 } 140 int endy = rect.maxY(); 141 if (endy > size.height()) 142 endy = size.height(); 143 int height = endy - originy; 144 145 if (width <= 0 || height <= 0) 146 return result.release(); 147 148 unsigned destBytesPerRow = 4 * rect.width(); 149 unsigned char* destRows = data + desty * destBytesPerRow + destx * 4; 150 151 unsigned srcBytesPerRow; 152 unsigned char* srcRows; 153 154 if (!accelerateRendering) { 155 srcBytesPerRow = 4 * size.width(); 156 srcRows = reinterpret_cast<unsigned char*>(m_data) + originy * srcBytesPerRow + originx * 4; 157 158 #if USE(ACCELERATE) 159 if (unmultiplied && haveVImageRoundingErrorFix()) { 160 vImage_Buffer src; 161 src.height = height; 162 src.width = width; 163 src.rowBytes = srcBytesPerRow; 164 src.data = srcRows; 165 166 vImage_Buffer dst; 167 dst.height = height; 168 dst.width = width; 169 dst.rowBytes = destBytesPerRow; 170 dst.data = destRows; 171 172 vImageUnpremultiplyData_RGBA8888(&src, &dst, kvImageNoFlags); 173 return result.release(); 174 } 175 #endif 176 for (int y = 0; y < height; ++y) { 177 for (int x = 0; x < width; x++) { 178 int basex = x * 4; 179 unsigned char alpha = srcRows[basex + 3]; 180 if (unmultiplied && alpha) { 181 destRows[basex] = (srcRows[basex] * 255) / alpha; 182 destRows[basex + 1] = (srcRows[basex + 1] * 255) / alpha; 183 destRows[basex + 2] = (srcRows[basex + 2] * 255) / alpha; 184 destRows[basex + 3] = alpha; 185 } else 186 reinterpret_cast<uint32_t*>(destRows + basex)[0] = reinterpret_cast<uint32_t*>(srcRows + basex)[0]; 187 } 188 srcRows += srcBytesPerRow; 189 destRows += destBytesPerRow; 190 } 191 } else { 192 #if USE(IOSURFACE_CANVAS_BACKING_STORE) 193 IOSurfaceRef surface = m_surface.get(); 194 IOSurfaceLock(surface, kIOSurfaceLockReadOnly, 0); 195 srcBytesPerRow = IOSurfaceGetBytesPerRow(surface); 196 srcRows = (unsigned char*)(IOSurfaceGetBaseAddress(surface)) + originy * srcBytesPerRow + originx * 4; 197 198 #if USE(ACCELERATE) 199 if (unmultiplied) { 200 ScanlineData scanlineData; 201 scanlineData.scanlineWidth = width; 202 scanlineData.srcData = srcRows; 203 scanlineData.srcRowBytes = srcBytesPerRow; 204 scanlineData.destData = destRows; 205 scanlineData.destRowBytes = destBytesPerRow; 206 207 dispatch_apply_f(height, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), &scanlineData, unpremultitplyScanline); 208 } else { 209 vImage_Buffer src; 210 src.height = height; 211 src.width = width; 212 src.rowBytes = srcBytesPerRow; 213 src.data = srcRows; 214 215 vImage_Buffer dest; 216 dest.height = height; 217 dest.width = width; 218 dest.rowBytes = destBytesPerRow; 219 dest.data = destRows; 220 221 // Swap pixel channels from BGRA to RGBA. 222 const uint8_t map[4] = { 2, 1, 0, 3 }; 223 vImagePermuteChannels_ARGB8888(&src, &dest, map, kvImageNoFlags); 224 } 225 #else 226 for (int y = 0; y < height; ++y) { 227 for (int x = 0; x < width; x++) { 228 int basex = x * 4; 229 unsigned char alpha = srcRows[basex + 3]; 230 if (unmultiplied && alpha) { 231 destRows[basex] = (srcRows[basex + 2] * 255) / alpha; 232 destRows[basex + 1] = (srcRows[basex + 1] * 255) / alpha; 233 destRows[basex + 2] = (srcRows[basex] * 255) / alpha; 234 destRows[basex + 3] = alpha; 235 } else { 236 destRows[basex] = srcRows[basex + 2]; 237 destRows[basex + 1] = srcRows[basex + 1]; 238 destRows[basex + 2] = srcRows[basex]; 239 destRows[basex + 3] = alpha; 240 } 241 } 242 srcRows += srcBytesPerRow; 243 destRows += destBytesPerRow; 244 } 245 #endif // USE(ACCELERATE) 246 IOSurfaceUnlock(surface, kIOSurfaceLockReadOnly, 0); 247 #else 248 ASSERT_NOT_REACHED(); 249 #endif // USE(IOSURFACE_CANVAS_BACKING_STORE) 250 } 251 252 return result.release(); 253 } 254 255 void ImageBufferData::putData(ByteArray*& source, const IntSize& sourceSize, const IntRect& sourceRect, const IntPoint& destPoint, const IntSize& size, bool accelerateRendering, bool unmultiplied) 256 { 257 ASSERT(sourceRect.width() > 0); 258 ASSERT(sourceRect.height() > 0); 259 260 int originx = sourceRect.x(); 261 int destx = destPoint.x() + sourceRect.x(); 262 ASSERT(destx >= 0); 263 ASSERT(destx < size.width()); 264 ASSERT(originx >= 0); 265 ASSERT(originx <= sourceRect.maxX()); 266 267 int endx = destPoint.x() + sourceRect.maxX(); 268 ASSERT(endx <= size.width()); 269 270 int width = endx - destx; 271 272 int originy = sourceRect.y(); 273 int desty = destPoint.y() + sourceRect.y(); 274 ASSERT(desty >= 0); 275 ASSERT(desty < size.height()); 276 ASSERT(originy >= 0); 277 ASSERT(originy <= sourceRect.maxY()); 278 279 int endy = destPoint.y() + sourceRect.maxY(); 280 ASSERT(endy <= size.height()); 281 int height = endy - desty; 282 283 if (width <= 0 || height <= 0) 284 return; 285 286 unsigned srcBytesPerRow = 4 * sourceSize.width(); 287 unsigned char* srcRows = source->data() + originy * srcBytesPerRow + originx * 4; 288 unsigned destBytesPerRow; 289 unsigned char* destRows; 290 291 if (!accelerateRendering) { 292 destBytesPerRow = 4 * size.width(); 293 destRows = reinterpret_cast<unsigned char*>(m_data) + desty * destBytesPerRow + destx * 4; 294 295 #if USE(ACCELERATE) 296 if (haveVImageRoundingErrorFix() && unmultiplied) { 297 vImage_Buffer src; 298 src.height = height; 299 src.width = width; 300 src.rowBytes = srcBytesPerRow; 301 src.data = srcRows; 302 303 vImage_Buffer dst; 304 dst.height = height; 305 dst.width = width; 306 dst.rowBytes = destBytesPerRow; 307 dst.data = destRows; 308 309 vImagePremultiplyData_RGBA8888(&src, &dst, kvImageNoFlags); 310 return; 311 } 312 #endif 313 for (int y = 0; y < height; ++y) { 314 for (int x = 0; x < width; x++) { 315 int basex = x * 4; 316 unsigned char alpha = srcRows[basex + 3]; 317 if (unmultiplied && alpha != 255) { 318 destRows[basex] = (srcRows[basex] * alpha + 254) / 255; 319 destRows[basex + 1] = (srcRows[basex + 1] * alpha + 254) / 255; 320 destRows[basex + 2] = (srcRows[basex + 2] * alpha + 254) / 255; 321 destRows[basex + 3] = alpha; 322 } else 323 reinterpret_cast<uint32_t*>(destRows + basex)[0] = reinterpret_cast<uint32_t*>(srcRows + basex)[0]; 324 } 325 destRows += destBytesPerRow; 326 srcRows += srcBytesPerRow; 327 } 328 } else { 329 #if USE(IOSURFACE_CANVAS_BACKING_STORE) 330 IOSurfaceRef surface = m_surface.get(); 331 IOSurfaceLock(surface, 0, 0); 332 destBytesPerRow = IOSurfaceGetBytesPerRow(surface); 333 destRows = (unsigned char*)(IOSurfaceGetBaseAddress(surface)) + desty * destBytesPerRow + destx * 4; 334 335 #if USE(ACCELERATE) 336 if (unmultiplied) { 337 ScanlineData scanlineData; 338 scanlineData.scanlineWidth = width; 339 scanlineData.srcData = srcRows; 340 scanlineData.srcRowBytes = srcBytesPerRow; 341 scanlineData.destData = destRows; 342 scanlineData.destRowBytes = destBytesPerRow; 343 344 dispatch_apply_f(height, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), &scanlineData, premultitplyScanline); 345 } else { 346 vImage_Buffer src; 347 src.height = height; 348 src.width = width; 349 src.rowBytes = srcBytesPerRow; 350 src.data = srcRows; 351 352 vImage_Buffer dest; 353 dest.height = height; 354 dest.width = width; 355 dest.rowBytes = destBytesPerRow; 356 dest.data = destRows; 357 358 // Swap pixel channels from RGBA to BGRA. 359 const uint8_t map[4] = { 2, 1, 0, 3 }; 360 vImagePermuteChannels_ARGB8888(&src, &dest, map, kvImageNoFlags); 361 } 362 #else 363 for (int y = 0; y < height; ++y) { 364 for (int x = 0; x < width; x++) { 365 int basex = x * 4; 366 unsigned char alpha = srcRows[basex + 3]; 367 if (unmultiplied && alpha != 255) { 368 destRows[basex] = (srcRows[basex + 2] * alpha + 254) / 255; 369 destRows[basex + 1] = (srcRows[basex + 1] * alpha + 254) / 255; 370 destRows[basex + 2] = (srcRows[basex] * alpha + 254) / 255; 371 destRows[basex + 3] = alpha; 372 } else { 373 destRows[basex] = srcRows[basex + 2]; 374 destRows[basex + 1] = srcRows[basex + 1]; 375 destRows[basex + 2] = srcRows[basex]; 376 destRows[basex + 3] = alpha; 377 } 378 } 379 destRows += destBytesPerRow; 380 srcRows += srcBytesPerRow; 381 } 382 #endif // USE(ACCELERATE) 383 384 IOSurfaceUnlock(surface, 0, 0); 385 #else 386 ASSERT_NOT_REACHED(); 387 #endif // USE(IOSURFACE_CANVAS_BACKING_STORE) 388 } 389 } 390 391 } // namespace WebCore 392