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