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