Changeset 113457 in webkit


Ignore:
Timestamp:
Apr 6, 2012, 10:48:34 AM (13 years ago)
Author:
mitz@apple.com
Message:

<rdar://problem/10912476> Pixel access canvas APIs do not work transparently with high-DPI backing store
https://bugs.webkit.org/show_bug.cgi?id=83072

Reviewed by Simon Fraser.

Made getImageData, putImageData, and toDataURL downsample/upsample when pixels in the canvas
backing store are not in a 1:1 ratio to CSS pixels. This makes clients of these APIs
indifferent to the backing store resolution, up to sampling artifacts.

In order for this to work, ImageBuffer has to know and respect the resolutionScale
parameter. This change makes the Core Graphics-based implementation of ImageBuffer do this,
but on other platforms, resolutionScale values other than 1 will not work. Such platforms
should not enable the HIGH_DPI_CANVAS feature.

  • html/HTMLCanvasElement.cpp:

(WebCore::HTMLCanvasElement::HTMLCanvasElement): Updated a comment.
(WebCore::HTMLCanvasElement::createImageBuffer): Changed to create an ImageBuffer with
the desired resolution instead of 1.

  • html/canvas/CanvasRenderingContext2D.cpp:

(WebCore::CanvasRenderingContext2D::drawImage): Removed code that scaled the source rect,
since this is now handled at the ImageBuffer level.
(WebCore::CanvasRenderingContext2D::createImageData): Now returns ImageData of the requested
size regardless of the backing store resolution.
(WebCore::CanvasRenderingContext2D::getImageData): Ditto.

  • platform/graphics/ImageBuffer.h:

(WebCore::ImageBuffer::create): Removed some code that tried to apply the resolution scale
to the buffer after creating it, and changed to pass the resolution scale down to the
(platform-specific) constructor, which can apply it correctly.

  • platform/graphics/cairo/ImageBufferCairo.cpp:

(WebCore::ImageBuffer::ImageBuffer):

  • platform/graphics/cg/ImageBufferCG.cpp:

(WebCore::ImageBuffer::ImageBuffer): Added a resolutionScale parameter, which is used to
compute the backing buffer size, and to apply a device scale factor to the context.
(WebCore::ImageBuffer::copyImage): Changed to return an image scaled down to the logical
size of the buffer.
(WebCore::ImageBuffer::getUnmultipliedImageData): Changed to pass the resolution scale to
ImageData::getData().
(WebCore::ImageBuffer::getPremultipliedImageData): Ditto.
(WebCore::ImageBuffer::putByteArray): Changed to pass the resolution scale to
ImageData::putData(). When drawing the byte array as an image, changed to preserve the base
CTM in the destination context (thus mapping from image data pixels to backing store pixels).
(WebCore::ImageBuffer::toDataURL): Fixed a CGColorSpace leak. Made the returned image have
the buffer’s logical size instead of the backing buffer’s size.
(WebCore::ImageDataToDataURL): Fixed a CGColorSpace leak.

  • platform/graphics/cg/ImageBufferDataCG.cpp:

(WebCore::ImageBufferData::getData): Added a resolutionScale parameter. The source
coordinates are scaled by the value of that parameter, and a reverse scaling transform
is applied when copying from the backing store into the destination (either explicitly
using Accelerate or implicitly by drawing as an image). Since after scaling,
unpremultiplication and component permutation are done in-place, made the
non-Accelerate code that does these things safe in this case.
(WebCore::ImageBufferData::putData): Added a resolutionScale parameter. The destination
coordinates are scaled by the value of that parameter, and a scaling transform is applied
when copying from the source into the backing store (either explicitly using Accelerate or
implicitly by drawing as an image). Since after scaling, premultiplication and component
permutation are done in-place, made the non-Accelerate code that does these things safe in
this case.

  • platform/graphics/cg/ImageBufferDataCG.h:
  • platform/graphics/qt/ImageBufferQt.cpp:

(WebCore::ImageBuffer::ImageBuffer):

  • platform/graphics/skia/ImageBufferSkia.cpp:

(WebCore::ImageBuffer::ImageBuffer):

  • platform/graphics/wince/ImageBufferWinCE.cpp:

(WebCore::ImageBuffer::ImageBuffer):

  • platform/graphics/wx/ImageBufferWx.cpp:

(WebCore::ImageBuffer::ImageBuffer):

Location:
trunk/Source/WebCore
Files:
12 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r113456 r113457  
     12012-04-06  Dan Bernstein  <mitz@apple.com>
     2
     3        <rdar://problem/10912476> Pixel access canvas APIs do not work transparently with high-DPI backing store
     4        https://bugs.webkit.org/show_bug.cgi?id=83072
     5
     6        Reviewed by Simon Fraser.
     7
     8        Made getImageData, putImageData, and toDataURL downsample/upsample when pixels in the canvas
     9        backing store are not in a 1:1 ratio to CSS pixels. This makes clients of these APIs
     10        indifferent to the backing store resolution, up to sampling artifacts.
     11
     12        In order for this to work, ImageBuffer has to know and respect the resolutionScale
     13        parameter. This change makes the Core Graphics-based implementation of ImageBuffer do this,
     14        but on other platforms, resolutionScale values other than 1 will not work. Such platforms
     15        should not enable the HIGH_DPI_CANVAS feature.
     16
     17        * html/HTMLCanvasElement.cpp:
     18        (WebCore::HTMLCanvasElement::HTMLCanvasElement): Updated a comment.
     19        (WebCore::HTMLCanvasElement::createImageBuffer): Changed to create an ImageBuffer with
     20        the desired resolution instead of 1.
     21        * html/canvas/CanvasRenderingContext2D.cpp:
     22        (WebCore::CanvasRenderingContext2D::drawImage): Removed code that scaled the source rect,
     23        since this is now handled at the ImageBuffer level.
     24        (WebCore::CanvasRenderingContext2D::createImageData): Now returns ImageData of the requested
     25        size regardless of the backing store resolution.
     26        (WebCore::CanvasRenderingContext2D::getImageData): Ditto.
     27        * platform/graphics/ImageBuffer.h:
     28        (WebCore::ImageBuffer::create): Removed some code that tried to apply the resolution scale
     29        to the buffer after creating it, and changed to pass the resolution scale down to the
     30        (platform-specific) constructor, which can apply it correctly.
     31        * platform/graphics/cairo/ImageBufferCairo.cpp:
     32        (WebCore::ImageBuffer::ImageBuffer):
     33        * platform/graphics/cg/ImageBufferCG.cpp:
     34        (WebCore::ImageBuffer::ImageBuffer): Added a resolutionScale parameter, which is used to
     35        compute the backing buffer size, and to apply a device scale factor to the context.
     36        (WebCore::ImageBuffer::copyImage): Changed to return an image scaled down to the logical
     37        size of the buffer.
     38        (WebCore::ImageBuffer::getUnmultipliedImageData): Changed to pass the resolution scale to
     39        ImageData::getData().
     40        (WebCore::ImageBuffer::getPremultipliedImageData): Ditto.
     41        (WebCore::ImageBuffer::putByteArray): Changed to pass the resolution scale to
     42        ImageData::putData(). When drawing the byte array as an image, changed to preserve the base
     43        CTM in the destination context (thus mapping from image data pixels to backing store pixels).
     44        (WebCore::ImageBuffer::toDataURL): Fixed a CGColorSpace leak. Made the returned image have
     45        the buffer’s logical size instead of the backing buffer’s size.
     46        (WebCore::ImageDataToDataURL): Fixed a CGColorSpace leak.
     47        * platform/graphics/cg/ImageBufferDataCG.cpp:
     48        (WebCore::ImageBufferData::getData): Added a resolutionScale parameter. The source
     49        coordinates are scaled by the value of that parameter, and a reverse scaling transform
     50        is applied when copying from the backing store into the destination (either explicitly
     51        using Accelerate or implicitly by drawing as an image). Since after scaling,
     52        unpremultiplication and component permutation are done in-place, made the
     53        non-Accelerate code that does these things safe in this case.
     54        (WebCore::ImageBufferData::putData): Added a resolutionScale parameter. The destination
     55        coordinates are scaled by the value of that parameter, and a scaling transform is applied
     56        when copying from the source into the backing store (either explicitly using Accelerate or
     57        implicitly by drawing as an image). Since after scaling, premultiplication and component
     58        permutation are done in-place, made the non-Accelerate code that does these things safe in
     59        this case.
     60        * platform/graphics/cg/ImageBufferDataCG.h:
     61        * platform/graphics/qt/ImageBufferQt.cpp:
     62        (WebCore::ImageBuffer::ImageBuffer):
     63        * platform/graphics/skia/ImageBufferSkia.cpp:
     64        (WebCore::ImageBuffer::ImageBuffer):
     65        * platform/graphics/wince/ImageBufferWinCE.cpp:
     66        (WebCore::ImageBuffer::ImageBuffer):
     67        * platform/graphics/wx/ImageBufferWx.cpp:
     68        (WebCore::ImageBuffer::ImageBuffer):
     69
    1702012-04-06  Dana Jansens  <danakj@chromium.org>
    271
  • trunk/Source/WebCore/html/HTMLCanvasElement.cpp

    r111872 r113457  
    8686    , m_ignoreReset(false)
    8787#if ENABLE(HIGH_DPI_CANVAS)
    88       // FIXME: Make this the default once https://bugs.webkit.org/show_bug.cgi?id=73645 has been fixed.
     88      // NOTE: High-DPI canvas requires the platform-specific ImageBuffer implementation to respect
     89      // the resolutionScale parameter.
    8990    , m_deviceScaleFactor(document->frame() ? document->frame()->page()->deviceScaleFactor() : 1)
    9091#else
     
    544545#endif
    545546    DeferralMode deferralMode = shouldDefer() ? Deferred : NonDeferred;
    546     m_imageBuffer = ImageBuffer::create(bufferSize, 1, ColorSpaceDeviceRGB, renderingMode, deferralMode);
     547    m_imageBuffer = ImageBuffer::create(size(), m_deviceScaleFactor, ColorSpaceDeviceRGB, renderingMode, deferralMode);
    547548    if (!m_imageBuffer)
    548549        return;
    549     m_imageBuffer->context()->scale(FloatSize(bufferSize.width() / logicalSize.width(), bufferSize.height() / logicalSize.height()));
    550550    m_imageBuffer->context()->setShadowsIgnoreTransforms(true);
    551551    m_imageBuffer->context()->setImageInterpolationQuality(DefaultInterpolationQuality);
  • trunk/Source/WebCore/html/canvas/CanvasRenderingContext2D.cpp

    r112537 r113457  
    13541354#endif
    13551355
    1356     // drawImageBuffer's srcRect is in buffer pixels (backing store pixels, in our case), dstRect is in canvas pixels.
    1357     FloatRect bufferSrcRect(sourceCanvas->convertLogicalToDevice(srcRect));
    1358 
    13591356    if (rectContainsCanvas(dstRect)) {
    1360         c->drawImageBuffer(buffer, ColorSpaceDeviceRGB, dstRect, bufferSrcRect, state().m_globalComposite);
     1357        c->drawImageBuffer(buffer, ColorSpaceDeviceRGB, dstRect, srcRect, state().m_globalComposite);
    13611358        didDrawEntireCanvas();
    13621359    } else if (isFullCanvasCompositeMode(state().m_globalComposite)) {
    1363         fullCanvasCompositedDrawImage(buffer, ColorSpaceDeviceRGB, dstRect, bufferSrcRect, state().m_globalComposite);
     1360        fullCanvasCompositedDrawImage(buffer, ColorSpaceDeviceRGB, dstRect, srcRect, state().m_globalComposite);
    13641361        didDrawEntireCanvas();
    13651362    } else if (state().m_globalComposite == CompositeCopy) {
    13661363        clearCanvas();
    1367         c->drawImageBuffer(buffer, ColorSpaceDeviceRGB, dstRect, bufferSrcRect, state().m_globalComposite);
     1364        c->drawImageBuffer(buffer, ColorSpaceDeviceRGB, dstRect, srcRect, state().m_globalComposite);
    13681365        didDrawEntireCanvas();
    13691366    } else {
    1370         c->drawImageBuffer(buffer, ColorSpaceDeviceRGB, dstRect, bufferSrcRect, state().m_globalComposite);
     1367        c->drawImageBuffer(buffer, ColorSpaceDeviceRGB, dstRect, srcRect, state().m_globalComposite);
    13711368        didDraw(dstRect);
    13721369    }
     
    17791776
    17801777    FloatSize logicalSize(fabs(sw), fabs(sh));
    1781     FloatSize deviceSize = canvas()->convertLogicalToDevice(logicalSize);
    1782     if (!deviceSize.isExpressibleAsIntSize())
     1778    if (!logicalSize.isExpressibleAsIntSize())
    17831779        return 0;
    17841780
    1785     IntSize size(deviceSize.width(), deviceSize.height());
     1781    IntSize size = expandedIntSize(logicalSize);
    17861782    if (size.width() < 1)
    17871783        size.setWidth(1);
     
    18191815   
    18201816    FloatRect logicalRect(sx, sy, sw, sh);
    1821     FloatRect deviceRect = canvas()->convertLogicalToDevice(logicalRect);
    1822     if (deviceRect.width() < 1)
    1823         deviceRect.setWidth(1);
    1824     if (deviceRect.height() < 1)
    1825         deviceRect.setHeight(1);
    1826     if (!deviceRect.isExpressibleAsIntRect())
     1817    if (logicalRect.width() < 1)
     1818        logicalRect.setWidth(1);
     1819    if (logicalRect.height() < 1)
     1820        logicalRect.setHeight(1);
     1821    if (!logicalRect.isExpressibleAsIntRect())
    18271822        return 0;
    18281823
    1829     IntRect imageDataRect(deviceRect);
     1824    IntRect imageDataRect = enclosingIntRect(logicalRect);
    18301825    ImageBuffer* buffer = canvas()->buffer();
    18311826    if (!buffer)
  • trunk/Source/WebCore/platform/graphics/ImageBuffer.h

    r109016 r113457  
    8181        {
    8282            bool success = false;
    83             float scaledWidth = ceilf(resolutionScale * size.width());
    84             float scaledHeight = ceilf(resolutionScale * size.height());
    85             IntSize internalSize(scaledWidth, scaledHeight);
    86 
    87             OwnPtr<ImageBuffer> buf = adoptPtr(new ImageBuffer(internalSize, colorSpace, renderingMode, deferralMode, success));
     83            OwnPtr<ImageBuffer> buf = adoptPtr(new ImageBuffer(size, resolutionScale, colorSpace, renderingMode, deferralMode, success));
    8884            if (!success)
    8985                return nullptr;
    90 
    91             buf->m_logicalSize = size;
    92             buf->m_resolutionScale = resolutionScale;
    93             buf->context()->scale(FloatSize(resolutionScale, resolutionScale));
    9486            return buf.release();
    9587        }
     
    154146        // This constructor will place its success into the given out-variable
    155147        // so that create() knows when it should return failure.
    156         ImageBuffer(const IntSize&, ColorSpace, RenderingMode, DeferralMode, bool& success);
     148        ImageBuffer(const IntSize&, float resolutionScale, ColorSpace, RenderingMode, DeferralMode, bool& success);
    157149    };
    158150
  • trunk/Source/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp

    r109016 r113457  
    5555}
    5656
    57 ImageBuffer::ImageBuffer(const IntSize& size, ColorSpace, RenderingMode, DeferralMode, bool& success)
     57ImageBuffer::ImageBuffer(const IntSize& size, float /* resolutionScale */, ColorSpace, RenderingMode, DeferralMode, bool& success)
    5858    : m_data(size)
    5959    , m_size(size)
     60    , m_logicalSize(size)
    6061{
    6162    success = false;  // Make early return mean error.
  • trunk/Source/WebCore/platform/graphics/cg/ImageBufferCG.cpp

    r109016 r113457  
    108108}
    109109
    110 ImageBuffer::ImageBuffer(const IntSize& size, ColorSpace imageColorSpace, RenderingMode renderingMode, DeferralMode, bool& success)
     110ImageBuffer::ImageBuffer(const IntSize& size, float resolutionScale, ColorSpace imageColorSpace, RenderingMode renderingMode, DeferralMode, bool& success)
    111111    : m_data(size) // NOTE: The input here isn't important as ImageBufferDataCG's constructor just ignores it.
    112     , m_size(size)
    113 {
     112    , m_logicalSize(size)
     113    , m_resolutionScale(resolutionScale)
     114{
     115    float scaledWidth = ceilf(resolutionScale * size.width());
     116    float scaledHeight = ceilf(resolutionScale * size.height());
     117
     118    // FIXME: Should we automatically use a lower resolution?
     119    if (!FloatSize(scaledWidth, scaledHeight).isExpressibleAsIntSize())
     120        return;
     121
     122    m_size = IntSize(scaledWidth, scaledHeight);
     123
    114124    success = false;  // Make early return mean failure.
    115125    bool accelerateRendering = renderingMode == Accelerated;
    116     if (size.width() <= 0 || size.height() <= 0)
     126    if (m_size.width() <= 0 || m_size.height() <= 0)
    117127        return;
    118128
    119     Checked<int, RecordOverflow> width = size.width();
    120     Checked<int, RecordOverflow> height = size.height();
     129    Checked<int, RecordOverflow> width = m_size.width();
     130    Checked<int, RecordOverflow> height = m_size.height();
    121131
    122132    // Prevent integer overflows
     
    148158    if (accelerateRendering) {
    149159#if USE(IOSURFACE_CANVAS_BACKING_STORE)
    150         m_data.m_surface = createIOSurface(size);
     160        m_data.m_surface = createIOSurface(m_size);
    151161        cgContext.adoptCF(wkIOSurfaceContextCreate(m_data.m_surface.get(), width.unsafeGet(), height.unsafeGet(), m_data.m_colorSpace));
    152162#endif
     
    170180
    171181    m_context = adoptPtr(new GraphicsContext(cgContext.get()));
     182    m_context->applyDeviceScaleFactor(m_resolutionScale);
    172183    m_context->scale(FloatSize(1, -1));
    173     m_context->translate(0, -height.unsafeGet());
     184    m_context->translate(0, -size.height());
    174185    m_context->setIsAcceleratedContext(accelerateRendering);
    175186#if defined(BUILDING_ON_LION)
     
    204215PassRefPtr<Image> ImageBuffer::copyImage(BackingStoreCopy copyBehavior) const
    205216{
    206     RetainPtr<CGImageRef> image = copyNativeImage(copyBehavior);
     217    RetainPtr<CGImageRef> image;
     218    if (m_resolutionScale == 1)
     219        image = copyNativeImage(copyBehavior);
     220    else {
     221        image.adoptCF(copyNativeImage(DontCopyBackingStore));
     222        RetainPtr<CGContextRef> context(AdoptCF, CGBitmapContextCreate(0, logicalSize().width(), logicalSize().height(), 8, 4 * logicalSize().width(), deviceRGBColorSpaceRef(), kCGImageAlphaPremultipliedLast));
     223        CGContextSetBlendMode(context.get(), kCGBlendModeCopy);
     224        CGContextDrawImage(context.get(), CGRectMake(0, 0, logicalSize().width(), logicalSize().height()), image.get());
     225        image = CGBitmapContextCreateImage(context.get());
     226    }
    207227
    208228    if (!image)
     
    295315#endif
    296316    }
    297     return m_data.getData(rect, internalSize(), m_context->isAcceleratedContext(), true);
     317    return m_data.getData(rect, internalSize(), m_context->isAcceleratedContext(), true, m_resolutionScale);
    298318}
    299319
     
    306326#endif
    307327    }
    308     return m_data.getData(rect, internalSize(), m_context->isAcceleratedContext(), false);
     328    return m_data.getData(rect, internalSize(), m_context->isAcceleratedContext(), false, m_resolutionScale);
    309329}
    310330
     
    312332{
    313333    if (!m_context->isAcceleratedContext()) {
    314         m_data.putData(source, sourceSize, sourceRect, destPoint, internalSize(), m_context->isAcceleratedContext(), multiplied == Unmultiplied);
     334        m_data.putData(source, sourceSize, sourceRect, destPoint, internalSize(), m_context->isAcceleratedContext(), multiplied == Unmultiplied, m_resolutionScale);
    315335        return;
    316336    }
     
    323343        return;
    324344
    325     sourceCopy->m_data.putData(source, sourceSize, sourceRect, IntPoint(-sourceRect.x(), -sourceRect.y()), sourceCopy->internalSize(), sourceCopy->context()->isAcceleratedContext(), multiplied == Unmultiplied);
     345    sourceCopy->m_data.putData(source, sourceSize, sourceRect, IntPoint(-sourceRect.x(), -sourceRect.y()), sourceCopy->internalSize(), sourceCopy->context()->isAcceleratedContext(), multiplied == Unmultiplied, 1);
    326346
    327347    // Set up context for using drawImage as a direct bit copy
    328348    CGContextRef destContext = context()->platformContext();
    329349    CGContextSaveGState(destContext);
    330     CGContextConcatCTM(destContext, AffineTransform(CGContextGetCTM(destContext)).inverse());
     350    CGContextConcatCTM(destContext, AffineTransform(wkGetUserToBaseCTM(destContext)).inverse());
    331351    wkCGContextResetClip(destContext);
    332352    CGContextSetInterpolationQuality(destContext, kCGInterpolationNone);
     
    336356
    337357    // Draw the image in CG coordinate space
    338     IntPoint destPointInCGCoords(destPoint.x() + sourceRect.x(), internalSize().height() - (destPoint.y()+sourceRect.y()) - sourceRect.height());
     358    IntPoint destPointInCGCoords(destPoint.x() + sourceRect.x(), logicalSize().height() - (destPoint.y()+sourceRect.y()) - sourceRect.height());
    339359    IntRect destRectInCGCoords(destPointInCGCoords, sourceCopySize);
    340360    RetainPtr<CGImageRef> sourceCopyImage(AdoptCF, sourceCopy->copyNativeImage());
     
    421441    if (CFEqual(uti.get(), jpegUTI())) {
    422442        // JPEGs don't have an alpha channel, so we have to manually composite on top of black.
    423         arr = getPremultipliedImageData(IntRect(IntPoint(0, 0), internalSize()));
     443        arr = getPremultipliedImageData(IntRect(IntPoint(0, 0), logicalSize()));
    424444
    425445        unsigned char *data = arr->data();
    426         for (int i = 0; i < internalSize().width() * internalSize().height(); i++)
     446        for (int i = 0; i < logicalSize().width() * logicalSize().height(); i++)
    427447            data[i * 4 + 3] = 255; // The image is already premultiplied, so we just need to make it opaque.
    428448
    429449        RetainPtr<CGDataProviderRef> dataProvider;
    430450   
    431         dataProvider.adoptCF(CGDataProviderCreateWithData(0, data, 4 * internalSize().width() * internalSize().height(), 0));
     451        dataProvider.adoptCF(CGDataProviderCreateWithData(0, data, 4 * logicalSize().width() * logicalSize().height(), 0));
    432452   
    433453        if (!dataProvider)
    434454            return "data:,";
    435455
    436         image.adoptCF(CGImageCreate(internalSize().width(), internalSize().height(), 8, 32, 4 * internalSize().width(),
    437                                     CGColorSpaceCreateDeviceRGB(), kCGBitmapByteOrderDefault | kCGImageAlphaLast,
     456        image.adoptCF(CGImageCreate(logicalSize().width(), logicalSize().height(), 8, 32, 4 * logicalSize().width(),
     457                                    deviceRGBColorSpaceRef(), kCGBitmapByteOrderDefault | kCGImageAlphaLast,
    438458                                    dataProvider.get(), 0, false, kCGRenderingIntentDefault));
    439     } else
     459    } else if (m_resolutionScale == 1)
    440460        image.adoptCF(copyNativeImage(CopyBackingStore));
     461    else {
     462        image.adoptCF(copyNativeImage(DontCopyBackingStore));
     463        RetainPtr<CGContextRef> context(AdoptCF, CGBitmapContextCreate(0, logicalSize().width(), logicalSize().height(), 8, 4 * logicalSize().width(), deviceRGBColorSpaceRef(), kCGImageAlphaPremultipliedLast));
     464        CGContextSetBlendMode(context.get(), kCGBlendModeCopy);
     465        CGContextDrawImage(context.get(), CGRectMake(0, 0, logicalSize().width(), logicalSize().height()), image.get());
     466        image.adoptCF(CGBitmapContextCreateImage(context.get()));
     467    }
    441468
    442469    if (!image)
     
    487514
    488515    image.adoptCF(CGImageCreate(source.width(), source.height(), 8, 32, 4 * source.width(),
    489                                 CGColorSpaceCreateDeviceRGB(), kCGBitmapByteOrderDefault | kCGImageAlphaLast,
     516                                deviceRGBColorSpaceRef(), kCGBitmapByteOrderDefault | kCGImageAlphaLast,
    490517                                dataProvider.get(), 0, false, kCGRenderingIntentDefault));
    491518                               
  • trunk/Source/WebCore/platform/graphics/cg/ImageBufferDataCG.cpp

    r100667 r113457  
    2727#include "ImageBufferData.h"
    2828
     29#include <CoreGraphics/CoreGraphics.h>
    2930#include <wtf/Assertions.h>
    3031
     
    3738#include <dispatch/dispatch.h>
    3839#endif
     40
     41using namespace std;
    3942
    4043#if USE(ACCELERATE)
     
    114117#endif // USE(ACCELERATE)
    115118
    116 PassRefPtr<ByteArray> ImageBufferData::getData(const IntRect& rect, const IntSize& size, bool accelerateRendering, bool unmultiplied) const
     119PassRefPtr<ByteArray> ImageBufferData::getData(const IntRect& rect, const IntSize& size, bool accelerateRendering, bool unmultiplied, float resolutionScale) const
    117120{
    118121    float area = 4.0f * rect.width() * rect.height();
     
    123126    unsigned char* data = result->data();
    124127   
    125     if (rect.x() < 0 || rect.y() < 0 || rect.maxX() > size.width() || rect.maxY() > size.height())
     128    int endx = ceilf(rect.maxX() * resolutionScale);
     129    int endy = ceilf(rect.maxY() * resolutionScale);
     130    if (rect.x() < 0 || rect.y() < 0 || endx > size.width() || endy > size.height())
    126131        memset(data, 0, result->length());
    127132   
    128133    int originx = rect.x();
    129134    int destx = 0;
     135    int destw = rect.width();
    130136    if (originx < 0) {
     137        destw += originx;
    131138        destx = -originx;
    132139        originx = 0;
    133140    }
    134     int endx = rect.maxX();
     141    destw = min<int>(destw, ceilf(size.width() / resolutionScale) - originx);
     142    originx *= resolutionScale;
    135143    if (endx > size.width())
    136144        endx = size.width();
     
    139147    int originy = rect.y();
    140148    int desty = 0;
     149    int desth = rect.height();
    141150    if (originy < 0) {
     151        desth += originy;
    142152        desty = -originy;
    143153        originy = 0;
    144154    }
    145     int endy = rect.maxY();
     155    desth = min<int>(desth, ceilf(size.height() / resolutionScale) - originy);
     156    originy *= resolutionScale;
    146157    if (endy > size.height())
    147158        endy = size.height();
     
    170181           
    171182            vImage_Buffer dst;
    172             dst.height = height;
    173             dst.width = width;
     183            dst.height = desth;
     184            dst.width = destw;
    174185            dst.rowBytes = destBytesPerRow;
    175186            dst.data = destRows;
    176            
     187
     188            if (resolutionScale != 1) {
     189                vImage_AffineTransform scaleTransform = { 1 / resolutionScale, 0, 0, 1 / resolutionScale, 0, 0 }; // FIXME: Add subpixel translation.
     190                Pixel_8888 backgroundColor;
     191                vImageAffineWarp_ARGB8888(&src, &dst, 0, &scaleTransform, backgroundColor, kvImageEdgeExtend);
     192                // The unpremultiplying will be done in-place.
     193                src = dst;
     194            }
     195
    177196            vImageUnpremultiplyData_RGBA8888(&src, &dst, kvImageNoFlags);
    178197            return result.release();
    179198        }
    180199#endif
     200        if (resolutionScale != 1) {
     201            RetainPtr<CGContextRef> sourceContext(AdoptCF, CGBitmapContextCreate(srcRows, width, height, 8, srcBytesPerRow, m_colorSpace, kCGImageAlphaPremultipliedLast));
     202            RetainPtr<CGImageRef> sourceImage(AdoptCF, CGBitmapContextCreateImage(sourceContext.get()));
     203            RetainPtr<CGContextRef> destinationContext(AdoptCF, CGBitmapContextCreate(destRows, destw, desth, 8, destBytesPerRow, m_colorSpace, kCGImageAlphaPremultipliedLast));
     204            CGContextSetBlendMode(destinationContext.get(), kCGBlendModeCopy);
     205            CGContextDrawImage(destinationContext.get(), CGRectMake(0, 0, width / resolutionScale, height / resolutionScale), sourceImage.get()); // FIXME: Add subpixel translation.
     206            if (!unmultiplied)
     207                return result.release();
     208
     209            srcRows = destRows;
     210            srcBytesPerRow = destBytesPerRow;
     211            width = destw;
     212            height = desth;
     213        }
    181214        if (unmultiplied) {
    182215            for (int y = 0; y < height; ++y) {
     
    211244
    212245#if USE(ACCELERATE)
     246        vImage_Buffer src;
     247        src.height = height;
     248        src.width = width;
     249        src.rowBytes = srcBytesPerRow;
     250        src.data = srcRows;
     251
     252        vImage_Buffer dest;
     253        dest.height = desth;
     254        dest.width = destw;
     255        dest.rowBytes = destBytesPerRow;
     256        dest.data = destRows;
     257
     258        if (resolutionScale != 1) {
     259            vImage_AffineTransform scaleTransform = { 1 / resolutionScale, 0, 0, 1 / resolutionScale, 0, 0 }; // FIXME: Add subpixel translation.
     260            Pixel_8888 backgroundColor;
     261            vImageAffineWarp_ARGB8888(&src, &dest, 0, &scaleTransform, backgroundColor, kvImageEdgeExtend);
     262            // The unpremultiplying and channel-swapping will be done in-place.
     263            if (unmultiplied) {
     264                srcRows = destRows;
     265                width = destw;
     266                height = desth;
     267                srcBytesPerRow = destBytesPerRow;
     268            } else
     269                src = dest;
     270        }
     271
    213272        if (unmultiplied) {
    214273            ScanlineData scanlineData;
     
    221280            dispatch_apply_f(height, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), &scanlineData, unpremultitplyScanline);
    222281        } else {
    223             vImage_Buffer src;
    224             src.height = height;
    225             src.width = width;
    226             src.rowBytes = srcBytesPerRow;
    227             src.data = srcRows;
    228 
    229             vImage_Buffer dest;
    230             dest.height = height;
    231             dest.width = width;
    232             dest.rowBytes = destBytesPerRow;
    233             dest.data = destRows;
    234 
    235282            // Swap pixel channels from BGRA to RGBA.
    236283            const uint8_t map[4] = { 2, 1, 0, 3 };
     
    238285        }
    239286#else
     287        if (resolutionScale != 1) {
     288            RetainPtr<CGContextRef> sourceContext(AdoptCF, CGBitmapContextCreate(srcRows, width, height, 8, srcBytesPerRow, m_colorSpace, kCGImageAlphaPremultipliedLast));
     289            RetainPtr<CGImageRef> sourceImage(AdoptCF, CGBitmapContextCreateImage(sourceContext.get()));
     290            RetainPtr<CGContextRef> destinationContext(AdoptCF, CGBitmapContextCreate(destRows, destw, desth, 8, destBytesPerRow, m_colorSpace, kCGImageAlphaPremultipliedLast));
     291            CGContextSetBlendMode(destinationContext.get(), kCGBlendModeCopy);
     292            CGContextDrawImage(destinationContext.get(), CGRectMake(0, 0, width / resolutionScale, height / resolutionScale), sourceImage.get()); // FIXME: Add subpixel translation.
     293
     294            srcRows = destRows;
     295            srcBytesPerRow = destBytesPerRow;
     296            width = destw;
     297            height = desth;
     298        }
     299
    240300        if (unmultiplied) {
    241301            for (int y = 0; y < height; ++y) {
    242302                for (int x = 0; x < width; x++) {
    243303                    int basex = x * 4;
     304                    unsigned char b = srcRows[basex];
    244305                    unsigned char alpha = srcRows[basex + 3];
    245306                    if (alpha) {
    246307                        destRows[basex] = (srcRows[basex + 2] * 255) / alpha;
    247308                        destRows[basex + 1] = (srcRows[basex + 1] * 255) / alpha;
    248                         destRows[basex + 2] = (srcRows[basex] * 255) / alpha;
     309                        destRows[basex + 2] = (b * 255) / alpha;
    249310                        destRows[basex + 3] = alpha;
    250311                    } else {
    251312                        destRows[basex] = srcRows[basex + 2];
    252313                        destRows[basex + 1] = srcRows[basex + 1];
    253                         destRows[basex + 2] = srcRows[basex];
     314                        destRows[basex + 2] = b;
    254315                        destRows[basex + 3] = srcRows[basex + 3];
    255316                    }
     
    262323                for (int x = 0; x < width; x++) {
    263324                    int basex = x * 4;
     325                    unsigned char b = srcRows[basex];
    264326                    destRows[basex] = srcRows[basex + 2];
    265327                    destRows[basex + 1] = srcRows[basex + 1];
    266                     destRows[basex + 2] = srcRows[basex];
     328                    destRows[basex + 2] = b;
    267329                    destRows[basex + 3] = srcRows[basex + 3];
    268330                }
     
    281343}
    282344
    283 void ImageBufferData::putData(ByteArray*& source, const IntSize& sourceSize, const IntRect& sourceRect, const IntPoint& destPoint, const IntSize& size, bool accelerateRendering, bool unmultiplied)
     345void ImageBufferData::putData(ByteArray*& source, const IntSize& sourceSize, const IntRect& sourceRect, const IntPoint& destPoint, const IntSize& size, bool accelerateRendering, bool unmultiplied, float resolutionScale)
    284346{
    285347    ASSERT(sourceRect.width() > 0);
     
    287349   
    288350    int originx = sourceRect.x();
    289     int destx = destPoint.x() + sourceRect.x();
     351    int destx = (destPoint.x() + sourceRect.x()) * resolutionScale;
    290352    ASSERT(destx >= 0);
    291353    ASSERT(destx < size.width());
     
    293355    ASSERT(originx <= sourceRect.maxX());
    294356   
    295     int endx = destPoint.x() + sourceRect.maxX();
     357    int endx = (destPoint.x() + sourceRect.maxX()) * resolutionScale;
    296358    ASSERT(endx <= size.width());
    297359   
    298     int width = endx - destx;
    299    
     360    int width = sourceRect.width();
     361    int destw = endx - destx;
     362
    300363    int originy = sourceRect.y();
    301     int desty = destPoint.y() + sourceRect.y();
     364    int desty = (destPoint.y() + sourceRect.y()) * resolutionScale;
    302365    ASSERT(desty >= 0);
    303366    ASSERT(desty < size.height());
     
    305368    ASSERT(originy <= sourceRect.maxY());
    306369   
    307     int endy = destPoint.y() + sourceRect.maxY();
     370    int endy = (destPoint.y() + sourceRect.maxY()) * resolutionScale;
    308371    ASSERT(endy <= size.height());
    309     int height = endy - desty;
     372
     373    int height = sourceRect.height();
     374    int desth = endy - desty;
    310375   
    311376    if (width <= 0 || height <= 0)
     
    330395           
    331396            vImage_Buffer dst;
    332             dst.height = height;
    333             dst.width = width;
     397            dst.height = desth;
     398            dst.width = destw;
    334399            dst.rowBytes = destBytesPerRow;
    335400            dst.data = destRows;
    336            
     401
     402            if (resolutionScale != 1) {
     403                vImage_AffineTransform scaleTransform = { resolutionScale, 0, 0, resolutionScale, 0, 0 }; // FIXME: Add subpixel translation.
     404                Pixel_8888 backgroundColor;
     405                vImageAffineWarp_ARGB8888(&src, &dst, 0, &scaleTransform, backgroundColor, kvImageEdgeExtend);
     406                // The premultiplying will be done in-place.
     407                src = dst;
     408            }
     409
    337410            vImagePremultiplyData_RGBA8888(&src, &dst, kvImageNoFlags);
    338411            return;
    339412        }
    340413#endif
     414        if (resolutionScale != 1) {
     415            RetainPtr<CGContextRef> sourceContext(AdoptCF, CGBitmapContextCreate(srcRows, width, height, 8, srcBytesPerRow, m_colorSpace, kCGImageAlphaPremultipliedLast));
     416            RetainPtr<CGImageRef> sourceImage(AdoptCF, CGBitmapContextCreateImage(sourceContext.get()));
     417            RetainPtr<CGContextRef> destinationContext(AdoptCF, CGBitmapContextCreate(destRows, destw, desth, 8, destBytesPerRow, m_colorSpace, kCGImageAlphaPremultipliedLast));
     418            CGContextSetBlendMode(destinationContext.get(), kCGBlendModeCopy);
     419            CGContextDrawImage(destinationContext.get(), CGRectMake(0, 0, width / resolutionScale, height / resolutionScale), sourceImage.get()); // FIXME: Add subpixel translation.
     420            if (!unmultiplied)
     421                return;
     422
     423            srcRows = destRows;
     424            srcBytesPerRow = destBytesPerRow;
     425            width = destw;
     426            height = desth;
     427        }
     428
    341429        for (int y = 0; y < height; ++y) {
    342430            for (int x = 0; x < width; x++) {
     
    362450
    363451#if USE(ACCELERATE)
     452        vImage_Buffer src;
     453        src.height = height;
     454        src.width = width;
     455        src.rowBytes = srcBytesPerRow;
     456        src.data = srcRows;
     457
     458        vImage_Buffer dest;
     459        dest.height = desth;
     460        dest.width = destw;
     461        dest.rowBytes = destBytesPerRow;
     462        dest.data = destRows;
     463
     464        if (resolutionScale != 1) {
     465            vImage_AffineTransform scaleTransform = { resolutionScale, 0, 0, resolutionScale, 0, 0 }; // FIXME: Add subpixel translation.
     466            Pixel_8888 backgroundColor;
     467            vImageAffineWarp_ARGB8888(&src, &dest, 0, &scaleTransform, backgroundColor, kvImageEdgeExtend);
     468            // The unpremultiplying and channel-swapping will be done in-place.
     469            if (unmultiplied) {
     470                srcRows = destRows;
     471                width = destw;
     472                height = desth;
     473                srcBytesPerRow = destBytesPerRow;
     474            } else
     475                src = dest;
     476        }
     477
    364478        if (unmultiplied) {
    365479            ScanlineData scanlineData;
     
    372486            dispatch_apply_f(height, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), &scanlineData, premultitplyScanline);
    373487        } else {
    374             vImage_Buffer src;
    375             src.height = height;
    376             src.width = width;
    377             src.rowBytes = srcBytesPerRow;
    378             src.data = srcRows;
    379 
    380             vImage_Buffer dest;
    381             dest.height = height;
    382             dest.width = width;
    383             dest.rowBytes = destBytesPerRow;
    384             dest.data = destRows;
    385 
    386488            // Swap pixel channels from RGBA to BGRA.
    387489            const uint8_t map[4] = { 2, 1, 0, 3 };
     
    389491        }
    390492#else
     493        if (resolutionScale != 1) {
     494            RetainPtr<CGContextRef> sourceContext(AdoptCF, CGBitmapContextCreate(srcRows, width, height, 8, srcBytesPerRow, m_colorSpace, kCGImageAlphaPremultipliedLast));
     495            RetainPtr<CGImageRef> sourceImage(AdoptCF, CGBitmapContextCreateImage(sourceContext.get()));
     496            RetainPtr<CGContextRef> destinationContext(AdoptCF, CGBitmapContextCreate(destRows, destw, desth, 8, destBytesPerRow, m_colorSpace, kCGImageAlphaPremultipliedLast));
     497            CGContextSetBlendMode(destinationContext.get(), kCGBlendModeCopy);
     498            CGContextDrawImage(destinationContext.get(), CGRectMake(0, 0, width / resolutionScale, height / resolutionScale), sourceImage.get()); // FIXME: Add subpixel translation.
     499
     500            srcRows = destRows;
     501            srcBytesPerRow = destBytesPerRow;
     502            width = destw;
     503            height = desth;
     504        }
     505
    391506        for (int y = 0; y < height; ++y) {
    392507            for (int x = 0; x < width; x++) {
    393508                int basex = x * 4;
     509                unsigned char b = srcRows[basex];
    394510                unsigned char alpha = srcRows[basex + 3];
    395511                if (unmultiplied && alpha != 255) {
    396512                    destRows[basex] = (srcRows[basex + 2] * alpha + 254) / 255;
    397513                    destRows[basex + 1] = (srcRows[basex + 1] * alpha + 254) / 255;
    398                     destRows[basex + 2] = (srcRows[basex] * alpha + 254) / 255;
     514                    destRows[basex + 2] = (b * alpha + 254) / 255;
    399515                    destRows[basex + 3] = alpha;
    400516                } else {
    401517                    destRows[basex] = srcRows[basex + 2];
    402518                    destRows[basex + 1] = srcRows[basex + 1];
    403                     destRows[basex + 2] = srcRows[basex];
     519                    destRows[basex + 2] = b;
    404520                    destRows[basex + 3] = alpha;
    405521                }
  • trunk/Source/WebCore/platform/graphics/cg/ImageBufferDataCG.h

    r106278 r113457  
    5959#endif
    6060
    61     PassRefPtr<ByteArray> getData(const IntRect& rect, const IntSize& size, bool accelerateRendering, bool unmultiplied) const;
    62     void putData(ByteArray*& source, const IntSize& sourceSize, const IntRect& sourceRect, const IntPoint& destPoint, const IntSize& size, bool accelerateRendering, bool unmultiplied);
     61    PassRefPtr<ByteArray> getData(const IntRect& rect, const IntSize& size, bool accelerateRendering, bool unmultiplied, float resolutionScale) const;
     62    void putData(ByteArray*& source, const IntSize& sourceSize, const IntRect& sourceRect, const IntPoint& destPoint, const IntSize& size, bool accelerateRendering, bool unmultiplied, float resolutionScale);
    6363};
    6464
  • trunk/Source/WebCore/platform/graphics/qt/ImageBufferQt.cpp

    r109016 r113457  
    9595}
    9696
    97 ImageBuffer::ImageBuffer(const IntSize& size, ColorSpace, RenderingMode, DeferralMode, bool& success)
     97ImageBuffer::ImageBuffer(const IntSize& size, float /* resolutionScale */, ColorSpace, RenderingMode, DeferralMode, bool& success)
    9898    : m_data(size)
    9999    , m_size(size)
     100    , m_logicalSize(size)
    100101{
    101102    success = m_data.m_painter && m_data.m_painter->isActive();
  • trunk/Source/WebCore/platform/graphics/skia/ImageBufferSkia.cpp

    r112343 r113457  
    125125}
    126126
    127 ImageBuffer::ImageBuffer(const IntSize& size, ColorSpace, RenderingMode renderingMode, DeferralMode deferralMode, bool& success)
     127ImageBuffer::ImageBuffer(const IntSize& size, float /* resolutionScale */, ColorSpace, RenderingMode renderingMode, DeferralMode deferralMode, bool& success)
    128128    : m_data(size)
    129129    , m_size(size)
     130    , m_logicalSize(size)
    130131    , m_resolutionScale(1)
    131132{
  • trunk/Source/WebCore/platform/graphics/wince/ImageBufferWinCE.cpp

    r112680 r113457  
    7272}
    7373
    74 ImageBuffer::ImageBuffer(const IntSize& size, ColorSpace colorSpace, RenderingMode, DeferralMode, bool& success)
     74ImageBuffer::ImageBuffer(const IntSize& size, float resolutionScale, ColorSpace colorSpace, RenderingMode, DeferralMode, bool& success)
    7575    : m_data(size)
    7676    , m_size(size)
    77 {
     77    , m_logicalSize(size)
     78{
     79    // FIXME: Respect resoutionScale to support high-DPI canvas.
     80    UNUSED_PARAM(resolutionScale);
    7881    // FIXME: colorSpace is not used
    7982    UNUSED_PARAM(colorSpace);
  • trunk/Source/WebCore/platform/graphics/wx/ImageBufferWx.cpp

    r112670 r113457  
    9696}
    9797
    98 ImageBuffer::ImageBuffer(const IntSize& size, ColorSpace colorSpace, RenderingMode, DeferralMode, bool& success)
     98ImageBuffer::ImageBuffer(const IntSize& size, float resolutionScale, ColorSpace colorSpace, RenderingMode, DeferralMode, bool& success)
    9999    : m_data(size)
    100100    , m_size(size)
     101    , m_logicalSize(size)
    101102{
     103    // FIXME: Respect resoutionScale to support high-DPI canvas.
     104    UNUSED_PARAM(resolutionScale);
    102105    // FIXME: colorSpace is not used
    103106    UNUSED_PARAM(colorSpace);
Note: See TracChangeset for help on using the changeset viewer.