[iOS] Fix iphoneos SDK builds for ios-ews queue
[WebKit-https.git] / Source / WebCore / platform / graphics / cg / ImageBufferDataCG.cpp
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 "IOSurfaceSPI.h"
39 #include <dispatch/dispatch.h>
40 #endif
41
42 #if USE(ACCELERATE)
43 struct 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
55 namespace WebCore {
56
57 ImageBufferData::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)
68 static 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
97 static void unpremultitplyScanline(void* data, size_t tileNumber)
98 {
99     convertScanline(data, tileNumber, false);
100 }
101
102 static 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
109 PassRefPtr<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
380 void 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