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 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 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 "IntRect.h" 30#include <CoreGraphics/CoreGraphics.h> 31#include <wtf/Assertions.h> 32 33#if USE(ACCELERATE) 34#include <Accelerate/Accelerate.h> 35#endif 36 37#if USE(IOSURFACE_CANVAS_BACKING_STORE) 38#include <IOSurface/IOSurface.h> 39#include <dispatch/dispatch.h> 40#endif 41 42#if USE(ACCELERATE) 43struct ScanlineData { 44 vImagePixelCount scanlineWidth; 45 unsigned char* srcData; 46 size_t srcRowBytes; 47 unsigned char* destData; 48 size_t destRowBytes; 49}; 50#endif 51 52// CA uses ARGB32 for textures and ARGB32 -> ARGB32 resampling is optimized. 53#define USE_ARGB32 PLATFORM(IOS) 54 55namespace WebCore { 56 57ImageBufferData::ImageBufferData(const IntSize&) 58: m_data(0) 59#if USE(IOSURFACE_CANVAS_BACKING_STORE) 60, m_surface(0) 61#endif 62{ 63} 64 65#if USE(ACCELERATE) 66 67#if USE_ARGB32 || USE(IOSURFACE_CANVAS_BACKING_STORE) 68static void convertScanline(void* data, size_t tileNumber, bool premultiply) 69{ 70 ScanlineData* scanlineData = static_cast<ScanlineData*>(data); 71 72 vImage_Buffer src; 73 src.data = scanlineData->srcData + tileNumber * scanlineData->srcRowBytes; 74 src.height = 1; 75 src.width = scanlineData->scanlineWidth; 76 src.rowBytes = scanlineData->srcRowBytes; 77 78 vImage_Buffer dest; 79 dest.data = scanlineData->destData + tileNumber * scanlineData->destRowBytes; 80 dest.height = 1; 81 dest.width = scanlineData->scanlineWidth; 82 dest.rowBytes = scanlineData->destRowBytes; 83 84 if (premultiply) { 85 if (kvImageNoError != vImagePremultiplyData_RGBA8888(&src, &dest, kvImageDoNotTile)) 86 return; 87 } else { 88 if (kvImageNoError != vImageUnpremultiplyData_RGBA8888(&src, &dest, kvImageDoNotTile)) 89 return; 90 } 91 92 // Swap channels 1 and 3, to convert BGRA<->RGBA. IOSurfaces is BGRA, ImageData expects RGBA. 93 const uint8_t map[4] = { 2, 1, 0, 3 }; 94 vImagePermuteChannels_ARGB8888(&dest, &dest, map, kvImageDoNotTile); 95} 96 97static void unpremultitplyScanline(void* data, size_t tileNumber) 98{ 99 convertScanline(data, tileNumber, false); 100} 101 102static void premultitplyScanline(void* data, size_t tileNumber) 103{ 104 convertScanline(data, tileNumber, true); 105} 106#endif // USE(IOSURFACE_CANVAS_BACKING_STORE) 107#endif // USE(ACCELERATE) 108 109PassRefPtr<Uint8ClampedArray> ImageBufferData::getData(const IntRect& rect, const IntSize& size, bool accelerateRendering, bool unmultiplied, float resolutionScale) const 110{ 111 Checked<unsigned, RecordOverflow> area = 4; 112 area *= rect.width(); 113 area *= rect.height(); 114 if (area.hasOverflowed()) 115 return 0; 116 117 RefPtr<Uint8ClampedArray> result = Uint8ClampedArray::createUninitialized(area.unsafeGet()); 118 unsigned char* data = result->data(); 119 120 Checked<int> endx = rect.maxX(); 121 endx *= ceilf(resolutionScale); 122 Checked<int> endy = rect.maxY(); 123 endy *= resolutionScale; 124 if (rect.x() < 0 || rect.y() < 0 || endx.unsafeGet() > size.width() || endy.unsafeGet() > size.height()) 125 result->zeroFill(); 126 127 int originx = rect.x(); 128 int destx = 0; 129 Checked<int> destw = rect.width(); 130 if (originx < 0) { 131 destw += originx; 132 destx = -originx; 133 originx = 0; 134 } 135 destw = std::min<int>(destw.unsafeGet(), ceilf(size.width() / resolutionScale) - originx); 136 originx *= resolutionScale; 137 if (endx.unsafeGet() > size.width()) 138 endx = size.width(); 139 Checked<int> width = endx - originx; 140 141 int originy = rect.y(); 142 int desty = 0; 143 Checked<int> desth = rect.height(); 144 if (originy < 0) { 145 desth += originy; 146 desty = -originy; 147 originy = 0; 148 } 149 desth = std::min<int>(desth.unsafeGet(), ceilf(size.height() / resolutionScale) - originy); 150 originy *= resolutionScale; 151 if (endy.unsafeGet() > size.height()) 152 endy = size.height(); 153 Checked<int> height = endy - originy; 154 155 if (width.unsafeGet() <= 0 || height.unsafeGet() <= 0) 156 return result.release(); 157 158 unsigned destBytesPerRow = 4 * rect.width(); 159 unsigned char* destRows = data + desty * destBytesPerRow + destx * 4; 160 161 unsigned srcBytesPerRow; 162 unsigned char* srcRows; 163 164 if (!accelerateRendering) { 165 srcBytesPerRow = m_bytesPerRow.unsafeGet(); 166 srcRows = reinterpret_cast<unsigned char*>(m_data) + originy * srcBytesPerRow + originx * 4; 167 168#if USE(ACCELERATE) 169 if (unmultiplied) { 170#if USE_ARGB32 171 ScanlineData scanlineData; 172 scanlineData.scanlineWidth = destw.unsafeGet(); 173 scanlineData.srcData = srcRows; 174 scanlineData.srcRowBytes = srcBytesPerRow; 175 scanlineData.destData = destRows; 176 scanlineData.destRowBytes = destBytesPerRow; 177 178 dispatch_apply_f(desth.unsafeGet(), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), &scanlineData, unpremultitplyScanline); 179#else 180 vImage_Buffer src; 181 src.height = height.unsafeGet(); 182 src.width = width.unsafeGet(); 183 src.rowBytes = srcBytesPerRow; 184 src.data = srcRows; 185 186 vImage_Buffer dst; 187 dst.height = desth.unsafeGet(); 188 dst.width = destw.unsafeGet(); 189 dst.rowBytes = destBytesPerRow; 190 dst.data = destRows; 191 192 if (resolutionScale != 1) { 193 vImage_AffineTransform scaleTransform = { 1 / resolutionScale, 0, 0, 1 / resolutionScale, 0, 0 }; // FIXME: Add subpixel translation. 194 Pixel_8888 backgroundColor; 195 vImageAffineWarp_ARGB8888(&src, &dst, 0, &scaleTransform, backgroundColor, kvImageEdgeExtend); 196 // The unpremultiplying will be done in-place. 197 src = dst; 198 } 199 200 vImageUnpremultiplyData_RGBA8888(&src, &dst, kvImageNoFlags); 201#endif 202 return result.release(); 203 } 204#endif 205 if (resolutionScale != 1) { 206 RetainPtr<CGContextRef> sourceContext = adoptCF(CGBitmapContextCreate(srcRows, width.unsafeGet(), height.unsafeGet(), 8, srcBytesPerRow, m_colorSpace, kCGImageAlphaPremultipliedLast)); 207 RetainPtr<CGImageRef> sourceImage = adoptCF(CGBitmapContextCreateImage(sourceContext.get())); 208 RetainPtr<CGContextRef> destinationContext = adoptCF(CGBitmapContextCreate(destRows, destw.unsafeGet(), desth.unsafeGet(), 8, destBytesPerRow, m_colorSpace, kCGImageAlphaPremultipliedLast)); 209 CGContextSetBlendMode(destinationContext.get(), kCGBlendModeCopy); 210 CGContextDrawImage(destinationContext.get(), CGRectMake(0, 0, width.unsafeGet() / resolutionScale, height.unsafeGet() / resolutionScale), sourceImage.get()); // FIXME: Add subpixel translation. 211 if (!unmultiplied) 212 return result.release(); 213 214 srcRows = destRows; 215 srcBytesPerRow = destBytesPerRow; 216 width = destw; 217 height = desth; 218 } 219 if (unmultiplied) { 220 if ((width * 4).hasOverflowed()) 221 CRASH(); 222 for (int y = 0; y < height.unsafeGet(); ++y) { 223 for (int x = 0; x < width.unsafeGet(); x++) { 224 int basex = x * 4; 225 unsigned char alpha = srcRows[basex + 3]; 226#if USE_ARGB32 227 // Byte order is different as we use image buffers of ARGB32 228 if (alpha) { 229 destRows[basex] = (srcRows[basex + 2] * 255) / alpha; 230 destRows[basex + 1] = (srcRows[basex + 1] * 255) / alpha; 231 destRows[basex + 2] = (srcRows[basex] * 255) / alpha; 232 destRows[basex + 3] = alpha; 233 } else { 234 destRows[basex] = srcRows[basex + 2]; 235 destRows[basex + 1] = srcRows[basex + 1]; 236 destRows[basex + 2] = srcRows[basex]; 237 destRows[basex + 3] = alpha; 238 } 239#else 240 if (alpha) { 241 destRows[basex] = (srcRows[basex] * 255) / alpha; 242 destRows[basex + 1] = (srcRows[basex + 1] * 255) / alpha; 243 destRows[basex + 2] = (srcRows[basex + 2] * 255) / alpha; 244 destRows[basex + 3] = alpha; 245 } else 246 reinterpret_cast<uint32_t*>(destRows + basex)[0] = reinterpret_cast<uint32_t*>(srcRows + basex)[0]; 247#endif 248 } 249 srcRows += srcBytesPerRow; 250 destRows += destBytesPerRow; 251 } 252 } else { 253 for (int y = 0; y < height.unsafeGet(); ++y) { 254#if USE_ARGB32 255 for (int x = 0; x < width.unsafeGet(); x++) { 256 int basex = x * 4; 257 destRows[basex] = srcRows[basex + 2]; 258 destRows[basex + 1] = srcRows[basex + 1]; 259 destRows[basex + 2] = srcRows[basex]; 260 destRows[basex + 3] = srcRows[basex + 3]; 261 } 262#else 263 for (int x = 0; x < (width * 4).unsafeGet(); x += 4) 264 reinterpret_cast<uint32_t*>(destRows + x)[0] = reinterpret_cast<uint32_t*>(srcRows + x)[0]; 265#endif 266 srcRows += srcBytesPerRow; 267 destRows += destBytesPerRow; 268 } 269 } 270 } else { 271#if USE(IOSURFACE_CANVAS_BACKING_STORE) 272 IOSurfaceRef surface = m_surface.get(); 273 IOSurfaceLock(surface, kIOSurfaceLockReadOnly, 0); 274 srcBytesPerRow = IOSurfaceGetBytesPerRow(surface); 275 srcRows = (unsigned char*)(IOSurfaceGetBaseAddress(surface)) + originy * srcBytesPerRow + originx * 4; 276 277#if USE(ACCELERATE) 278 vImage_Buffer src; 279 src.height = height.unsafeGet(); 280 src.width = width.unsafeGet(); 281 src.rowBytes = srcBytesPerRow; 282 src.data = srcRows; 283 284 vImage_Buffer dest; 285 dest.height = desth.unsafeGet(); 286 dest.width = destw.unsafeGet(); 287 dest.rowBytes = destBytesPerRow; 288 dest.data = destRows; 289 290 if (resolutionScale != 1) { 291 vImage_AffineTransform scaleTransform = { 1 / resolutionScale, 0, 0, 1 / resolutionScale, 0, 0 }; // FIXME: Add subpixel translation. 292 Pixel_8888 backgroundColor; 293 vImageAffineWarp_ARGB8888(&src, &dest, 0, &scaleTransform, backgroundColor, kvImageEdgeExtend); 294 // The unpremultiplying and channel-swapping will be done in-place. 295 if (unmultiplied) { 296 srcRows = destRows; 297 width = destw; 298 height = desth; 299 srcBytesPerRow = destBytesPerRow; 300 } else 301 src = dest; 302 } 303 304 if (unmultiplied) { 305 ScanlineData scanlineData; 306 scanlineData.scanlineWidth = destw.unsafeGet(); 307 scanlineData.srcData = srcRows; 308 scanlineData.srcRowBytes = srcBytesPerRow; 309 scanlineData.destData = destRows; 310 scanlineData.destRowBytes = destBytesPerRow; 311 312 dispatch_apply_f(desth.unsafeGet(), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), &scanlineData, unpremultitplyScanline); 313 } else { 314 // Swap pixel channels from BGRA to RGBA. 315 const uint8_t map[4] = { 2, 1, 0, 3 }; 316 vImagePermuteChannels_ARGB8888(&src, &dest, map, kvImageNoFlags); 317 } 318#else 319 if (resolutionScale != 1) { 320 RetainPtr<CGContextRef> sourceContext = adoptCF(CGBitmapContextCreate(srcRows, width.unsafeGet(), height.unsafeGet(), 8, srcBytesPerRow, m_colorSpace, kCGImageAlphaPremultipliedLast)); 321 RetainPtr<CGImageRef> sourceImage = adoptCF(CGBitmapContextCreateImage(sourceContext.get())); 322 RetainPtr<CGContextRef> destinationContext = adoptCF(CGBitmapContextCreate(destRows, destw.unsafeGet(), desth.unsafeGet(), 8, destBytesPerRow, m_colorSpace, kCGImageAlphaPremultipliedLast)); 323 CGContextSetBlendMode(destinationContext.get(), kCGBlendModeCopy); 324 CGContextDrawImage(destinationContext.get(), CGRectMake(0, 0, width.unsafeGet() / resolutionScale, height.unsafeGet() / resolutionScale), sourceImage.get()); // FIXME: Add subpixel translation. 325 326 srcRows = destRows; 327 srcBytesPerRow = destBytesPerRow; 328 width = destw; 329 height = desth; 330 } 331 332 if ((width * 4).hasOverflowed()) 333 CRASH(); 334 335 if (unmultiplied) { 336 for (int y = 0; y < height.unsafeGet(); ++y) { 337 for (int x = 0; x < width.unsafeGet(); x++) { 338 int basex = x * 4; 339 unsigned char b = srcRows[basex]; 340 unsigned char alpha = srcRows[basex + 3]; 341 if (alpha) { 342 destRows[basex] = (srcRows[basex + 2] * 255) / alpha; 343 destRows[basex + 1] = (srcRows[basex + 1] * 255) / alpha; 344 destRows[basex + 2] = (b * 255) / alpha; 345 destRows[basex + 3] = alpha; 346 } else { 347 destRows[basex] = srcRows[basex + 2]; 348 destRows[basex + 1] = srcRows[basex + 1]; 349 destRows[basex + 2] = b; 350 destRows[basex + 3] = srcRows[basex + 3]; 351 } 352 } 353 srcRows += srcBytesPerRow; 354 destRows += destBytesPerRow; 355 } 356 } else { 357 for (int y = 0; y < height.unsafeGet(); ++y) { 358 for (int x = 0; x < width.unsafeGet(); x++) { 359 int basex = x * 4; 360 unsigned char b = srcRows[basex]; 361 destRows[basex] = srcRows[basex + 2]; 362 destRows[basex + 1] = srcRows[basex + 1]; 363 destRows[basex + 2] = b; 364 destRows[basex + 3] = srcRows[basex + 3]; 365 } 366 srcRows += srcBytesPerRow; 367 destRows += destBytesPerRow; 368 } 369 } 370#endif // USE(ACCELERATE) 371 IOSurfaceUnlock(surface, kIOSurfaceLockReadOnly, 0); 372#else 373 ASSERT_NOT_REACHED(); 374#endif // USE(IOSURFACE_CANVAS_BACKING_STORE) 375 } 376 377 return result.release(); 378} 379 380void ImageBufferData::putData(Uint8ClampedArray*& source, const IntSize& sourceSize, const IntRect& sourceRect, const IntPoint& destPoint, const IntSize& size, bool accelerateRendering, bool unmultiplied, float resolutionScale) 381{ 382#if ASSERT_DISABLED 383 UNUSED_PARAM(size); 384#endif 385 386 ASSERT(sourceRect.width() > 0); 387 ASSERT(sourceRect.height() > 0); 388 389 Checked<int> originx = sourceRect.x(); 390 Checked<int> destx = (Checked<int>(destPoint.x()) + sourceRect.x()); 391 destx *= resolutionScale; 392 ASSERT(destx.unsafeGet() >= 0); 393 ASSERT(destx.unsafeGet() < size.width()); 394 ASSERT(originx.unsafeGet() >= 0); 395 ASSERT(originx.unsafeGet() <= sourceRect.maxX()); 396 397 Checked<int> endx = (Checked<int>(destPoint.x()) + sourceRect.maxX()); 398 endx *= resolutionScale; 399 ASSERT(endx.unsafeGet() <= size.width()); 400 401 Checked<int> width = sourceRect.width(); 402 Checked<int> destw = endx - destx; 403 404 Checked<int> originy = sourceRect.y(); 405 Checked<int> desty = (Checked<int>(destPoint.y()) + sourceRect.y()); 406 desty *= resolutionScale; 407 ASSERT(desty.unsafeGet() >= 0); 408 ASSERT(desty.unsafeGet() < size.height()); 409 ASSERT(originy.unsafeGet() >= 0); 410 ASSERT(originy.unsafeGet() <= sourceRect.maxY()); 411 412 Checked<int> endy = (Checked<int>(destPoint.y()) + sourceRect.maxY()); 413 endy *= resolutionScale; 414 ASSERT(endy.unsafeGet() <= size.height()); 415 416 Checked<int> height = sourceRect.height(); 417 Checked<int> desth = endy - desty; 418 419 if (width <= 0 || height <= 0) 420 return; 421 422 unsigned srcBytesPerRow = 4 * sourceSize.width(); 423 unsigned char* srcRows = source->data() + (originy * srcBytesPerRow + originx * 4).unsafeGet(); 424 unsigned destBytesPerRow; 425 unsigned char* destRows; 426 427 if (!accelerateRendering) { 428 destBytesPerRow = m_bytesPerRow.unsafeGet(); 429 destRows = reinterpret_cast<unsigned char*>(m_data) + (desty * destBytesPerRow + destx * 4).unsafeGet(); 430 431#if USE(ACCELERATE) 432 if (unmultiplied) { 433#if USE_ARGB32 434 // FIXME: Are scanlineData.scanlineWidth and the number of iterations specified to dispatch_apply_f() correct? 435 ScanlineData scanlineData; 436 scanlineData.scanlineWidth = width.unsafeGet(); 437 scanlineData.srcData = srcRows; 438 scanlineData.srcRowBytes = srcBytesPerRow; 439 scanlineData.destData = destRows; 440 scanlineData.destRowBytes = destBytesPerRow; 441 442 dispatch_apply_f(height.unsafeGet(), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), &scanlineData, premultitplyScanline); 443#else 444 vImage_Buffer src; 445 src.height = height.unsafeGet(); 446 src.width = width.unsafeGet(); 447 src.rowBytes = srcBytesPerRow; 448 src.data = srcRows; 449 450 vImage_Buffer dst; 451 dst.height = desth.unsafeGet(); 452 dst.width = destw.unsafeGet(); 453 dst.rowBytes = destBytesPerRow; 454 dst.data = destRows; 455 456 if (resolutionScale != 1) { 457 vImage_AffineTransform scaleTransform = { resolutionScale, 0, 0, resolutionScale, 0, 0 }; // FIXME: Add subpixel translation. 458 Pixel_8888 backgroundColor; 459 vImageAffineWarp_ARGB8888(&src, &dst, 0, &scaleTransform, backgroundColor, kvImageEdgeExtend); 460 // The premultiplying will be done in-place. 461 src = dst; 462 } 463 464 vImagePremultiplyData_RGBA8888(&src, &dst, kvImageNoFlags); 465#endif 466 return; 467 } 468#endif 469 if (resolutionScale != 1) { 470 RetainPtr<CGContextRef> sourceContext = adoptCF(CGBitmapContextCreate(srcRows, width.unsafeGet(), height.unsafeGet(), 8, srcBytesPerRow, m_colorSpace, kCGImageAlphaPremultipliedLast)); 471 RetainPtr<CGImageRef> sourceImage = adoptCF(CGBitmapContextCreateImage(sourceContext.get())); 472 RetainPtr<CGContextRef> destinationContext = adoptCF(CGBitmapContextCreate(destRows, destw.unsafeGet(), desth.unsafeGet(), 8, destBytesPerRow, m_colorSpace, kCGImageAlphaPremultipliedLast)); 473 CGContextSetBlendMode(destinationContext.get(), kCGBlendModeCopy); 474 CGContextDrawImage(destinationContext.get(), CGRectMake(0, 0, width.unsafeGet() / resolutionScale, height.unsafeGet() / resolutionScale), sourceImage.get()); // FIXME: Add subpixel translation. 475 if (!unmultiplied) 476 return; 477 478 srcRows = destRows; 479 srcBytesPerRow = destBytesPerRow; 480 width = destw; 481 height = desth; 482 } 483 484 for (int y = 0; y < height.unsafeGet(); ++y) { 485 for (int x = 0; x < width.unsafeGet(); x++) { 486 int basex = x * 4; 487 unsigned char alpha = srcRows[basex + 3]; 488#if USE_ARGB32 489 // Byte order is different as we use image buffers of ARGB32 490 if (unmultiplied && alpha != 255) { 491 destRows[basex] = (srcRows[basex + 2] * alpha + 254) / 255; 492 destRows[basex + 1] = (srcRows[basex + 1] * alpha + 254) / 255; 493 destRows[basex + 2] = (srcRows[basex + 0] * alpha + 254) / 255; 494 destRows[basex + 3] = alpha; 495 } else { 496 destRows[basex] = srcRows[basex + 2]; 497 destRows[basex + 1] = srcRows[basex + 1]; 498 destRows[basex + 2] = srcRows[basex]; 499 destRows[basex + 3] = alpha; 500 } 501#else 502 if (unmultiplied && alpha != 255) { 503 destRows[basex] = (srcRows[basex] * alpha + 254) / 255; 504 destRows[basex + 1] = (srcRows[basex + 1] * alpha + 254) / 255; 505 destRows[basex + 2] = (srcRows[basex + 2] * alpha + 254) / 255; 506 destRows[basex + 3] = alpha; 507 } else 508 reinterpret_cast<uint32_t*>(destRows + basex)[0] = reinterpret_cast<uint32_t*>(srcRows + basex)[0]; 509#endif 510 } 511 destRows += destBytesPerRow; 512 srcRows += srcBytesPerRow; 513 } 514 } else { 515#if USE(IOSURFACE_CANVAS_BACKING_STORE) 516 IOSurfaceRef surface = m_surface.get(); 517 IOSurfaceLock(surface, 0, 0); 518 destBytesPerRow = IOSurfaceGetBytesPerRow(surface); 519 destRows = (unsigned char*)(IOSurfaceGetBaseAddress(surface)) + (desty * destBytesPerRow + destx * 4).unsafeGet(); 520 521#if USE(ACCELERATE) 522 vImage_Buffer src; 523 src.height = height.unsafeGet(); 524 src.width = width.unsafeGet(); 525 src.rowBytes = srcBytesPerRow; 526 src.data = srcRows; 527 528 vImage_Buffer dest; 529 dest.height = desth.unsafeGet(); 530 dest.width = destw.unsafeGet(); 531 dest.rowBytes = destBytesPerRow; 532 dest.data = destRows; 533 534 if (resolutionScale != 1) { 535 vImage_AffineTransform scaleTransform = { resolutionScale, 0, 0, resolutionScale, 0, 0 }; // FIXME: Add subpixel translation. 536 Pixel_8888 backgroundColor; 537 vImageAffineWarp_ARGB8888(&src, &dest, 0, &scaleTransform, backgroundColor, kvImageEdgeExtend); 538 // The unpremultiplying and channel-swapping will be done in-place. 539 if (unmultiplied) { 540 srcRows = destRows; 541 width = destw; 542 height = desth; 543 srcBytesPerRow = destBytesPerRow; 544 } else 545 src = dest; 546 } 547 548 if (unmultiplied) { 549 ScanlineData scanlineData; 550 scanlineData.scanlineWidth = width.unsafeGet(); 551 scanlineData.srcData = srcRows; 552 scanlineData.srcRowBytes = srcBytesPerRow; 553 scanlineData.destData = destRows; 554 scanlineData.destRowBytes = destBytesPerRow; 555 556 dispatch_apply_f(height.unsafeGet(), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), &scanlineData, premultitplyScanline); 557 } else { 558 // Swap pixel channels from RGBA to BGRA. 559 const uint8_t map[4] = { 2, 1, 0, 3 }; 560 vImagePermuteChannels_ARGB8888(&src, &dest, map, kvImageNoFlags); 561 } 562#else 563 if (resolutionScale != 1) { 564 RetainPtr<CGContextRef> sourceContext = adoptCF(CGBitmapContextCreate(srcRows, width.unsafeGet(), height.unsafeGet(), 8, srcBytesPerRow, m_colorSpace, kCGImageAlphaPremultipliedLast)); 565 RetainPtr<CGImageRef> sourceImage = adoptCF(CGBitmapContextCreateImage(sourceContext.get())); 566 RetainPtr<CGContextRef> destinationContext = adoptCF(CGBitmapContextCreate(destRows, destw.unsafeGet(), desth.unsafeGet(), 8, destBytesPerRow, m_colorSpace, kCGImageAlphaPremultipliedLast)); 567 CGContextSetBlendMode(destinationContext.get(), kCGBlendModeCopy); 568 CGContextDrawImage(destinationContext.get(), CGRectMake(0, 0, width.unsafeGet() / resolutionScale, height.unsafeGet() / resolutionScale), sourceImage.get()); // FIXME: Add subpixel translation. 569 570 srcRows = destRows; 571 srcBytesPerRow = destBytesPerRow; 572 width = destw; 573 height = desth; 574 } 575 576 for (int y = 0; y < height.unsafeGet(); ++y) { 577 for (int x = 0; x < width.unsafeGet(); x++) { 578 int basex = x * 4; 579 unsigned char b = srcRows[basex]; 580 unsigned char alpha = srcRows[basex + 3]; 581 if (unmultiplied && alpha != 255) { 582 destRows[basex] = (srcRows[basex + 2] * alpha + 254) / 255; 583 destRows[basex + 1] = (srcRows[basex + 1] * alpha + 254) / 255; 584 destRows[basex + 2] = (b * alpha + 254) / 255; 585 destRows[basex + 3] = alpha; 586 } else { 587 destRows[basex] = srcRows[basex + 2]; 588 destRows[basex + 1] = srcRows[basex + 1]; 589 destRows[basex + 2] = b; 590 destRows[basex + 3] = alpha; 591 } 592 } 593 destRows += destBytesPerRow; 594 srcRows += srcBytesPerRow; 595 } 596#endif // USE(ACCELERATE) 597 598 IOSurfaceUnlock(surface, 0, 0); 599#else 600 ASSERT_NOT_REACHED(); 601#endif // USE(IOSURFACE_CANVAS_BACKING_STORE) 602 } 603} 604 605} // namespace WebCore 606