~ubuntu-branches/ubuntu/raring/qtwebkit-source/raring-proposed

« back to all changes in this revision

Viewing changes to Source/WebCore/platform/graphics/cg/ImageBufferDataCG.cpp

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2013-02-18 14:24:18 UTC
  • Revision ID: package-import@ubuntu.com-20130218142418-eon0jmjg3nj438uy
Tags: upstream-2.3
ImportĀ upstreamĀ versionĀ 2.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 
 
41
using namespace std;
 
42
 
 
43
#if USE(ACCELERATE)
 
44
struct ScanlineData {
 
45
    vImagePixelCount scanlineWidth;
 
46
    unsigned char* srcData;
 
47
    size_t srcRowBytes;
 
48
    unsigned char* destData;
 
49
    size_t destRowBytes;
 
50
};
 
51
#endif
 
52
 
 
53
namespace WebCore {
 
54
 
 
55
ImageBufferData::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
 
66
static bool haveVImageRoundingErrorFix() { return true; }
 
67
#else
 
68
// The vImage unpremultiply routine had a rounding bug before 10.6.7 <rdar://problem/8631548>
 
69
static 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)
 
78
static 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
 
 
107
static void unpremultitplyScanline(void* data, size_t tileNumber)
 
108
{
 
109
    convertScanline(data, tileNumber, false);
 
110
}
 
111
 
 
112
static 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
 
 
119
PassRefPtr<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
 
 
354
void 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