Changeset 160121 in webkit
- Timestamp:
- Dec 4, 2013, 1:35:38 PM (13 years ago)
- Location:
- trunk
- Files:
-
- 10 edited
-
LayoutTests/ChangeLog (modified) (1 diff)
-
LayoutTests/fast/canvas/script-tests/canvas-fillPath-shadow.js (modified) (1 diff)
-
LayoutTests/fast/canvas/script-tests/canvas-scale-shadowBlur.js (modified) (4 diffs)
-
LayoutTests/fast/canvas/script-tests/canvas-scale-strokePath-shadow.js (modified) (4 diffs)
-
LayoutTests/platform/mac/fast/canvas/canvas-scale-shadowBlur-expected.txt (modified) (4 diffs)
-
Source/WebCore/ChangeLog (modified) (1 diff)
-
Source/WebCore/platform/graphics/ImageBuffer.h (modified) (2 diffs)
-
Source/WebCore/platform/graphics/cg/ImageBufferCG.cpp (modified) (12 diffs)
-
Source/WebCore/platform/graphics/cg/ImageBufferDataCG.cpp (modified) (3 diffs)
-
Source/WebCore/platform/graphics/cg/ImageBufferDataCG.h (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r160119 r160121 1 2013-12-04 Myles C. Maxfield <mmaxfield@apple.com> 2 3 Allow ImageBuffer to use an IOSurface that is larger than necessary 4 https://bugs.webkit.org/show_bug.cgi?id=124626 5 6 Reviewed by Simon Fraser. 7 8 Update tests to be more robust with respect to accelerated vs 9 non-accelerated ImageBuffers. 10 11 * fast/canvas/script-tests/canvas-fillPath-shadow.js: Don't sample a canvas at exactly 12 the corner of a drawn shape (because the corner might be antialiased). Instead, sample 13 a single pixel inside the shape 14 * fast/canvas/script-tests/canvas-scale-shadowBlur.js: Don't sample a canvas at exactly 15 the edge of the blur radius. Instead, sample a single pixel past the blur radius. 16 * fast/canvas/script-tests/canvas-scale-strokePath-shadow.js: 17 (shouldBeAround): Allow this test to be less strict when sampling inside a blurred region 18 * platform/mac/fast/canvas/canvas-scale-shadowBlur-expected.txt: Matching update w/r/t 19 canvas-scale-shadowBlur.js 20 1 21 2013-12-03 Dean Jackson <dino@apple.com> 2 22 -
trunk/LayoutTests/fast/canvas/script-tests/canvas-fillPath-shadow.js
r98407 r160121 71 71 shouldBe('data[2]', '0'); 72 72 73 imageData = ctx.getImageData(38 0, 30, 1, 1);73 imageData = ctx.getImageData(381, 31, 1, 1); 74 74 data = imageData.data; 75 75 shouldBe('data[0]', '255'); -
trunk/LayoutTests/fast/canvas/script-tests/canvas-scale-shadowBlur.js
r98407 r160121 68 68 shouldBeAround('d[3]', '255'); 69 69 70 d = ctx.getImageData(250, 17 5, 1, 1).data;70 d = ctx.getImageData(250, 174, 1, 1).data; 71 71 shouldBe('d[0]', '0'); 72 72 shouldBe('d[1]', '0'); … … 80 80 shouldBe('d[3]', '0'); 81 81 82 d = ctx.getImageData(17 5, 250, 1, 1).data;82 d = ctx.getImageData(174, 250, 1, 1).data; 83 83 shouldBe('d[0]', '0'); 84 84 shouldBe('d[1]', '0'); … … 136 136 shouldBeAround('d[3]', '255'); 137 137 138 d = ctx.getImageData(450, 17 5, 1, 1).data;138 d = ctx.getImageData(450, 174, 1, 1).data; 139 139 shouldBe('d[0]', '0'); 140 140 shouldBe('d[1]', '0'); … … 148 148 shouldBe('d[3]', '0'); 149 149 150 d = ctx.getImageData(37 5, 250, 1, 1).data;150 d = ctx.getImageData(374, 250, 1, 1).data; 151 151 shouldBe('d[0]', '0'); 152 152 shouldBe('d[1]', '0'); -
trunk/LayoutTests/fast/canvas/script-tests/canvas-scale-strokePath-shadow.js
r98407 r160121 11 11 } 12 12 13 function shouldBeAround(a, b )13 function shouldBeAround(a, b, argdelta) 14 14 { 15 15 var evalA; … … 20 20 } 21 21 22 if (Math.abs(evalA - b) < 20) 22 var delta = 20; 23 if (typeof argdelta != "undefined") 24 delta = argdelta; 25 26 if (Math.abs(evalA - b) < delta) 23 27 print("PASS " + a + " is around " + b , "green") 24 28 else … … 120 124 shouldBe('d[1]', '0'); 121 125 shouldBe('d[2]', '0'); 122 shouldBeAround('d[3]', '200' );126 shouldBeAround('d[3]', '200', 25); 123 127 124 128 d = ctx.getImageData(508, 250, 1, 1).data; … … 132 136 shouldBe('d[1]', '0'); 133 137 shouldBe('d[2]', '0'); 134 shouldBeAround('d[3]', '199' );138 shouldBeAround('d[3]', '199', 25); 135 139 136 140 // Verify blurry alpha shadow. -
trunk/LayoutTests/platform/mac/fast/canvas/canvas-scale-shadowBlur-expected.txt
r126203 r160121 11 11 PASS d[1] is 0 12 12 PASS d[2] is 0 13 FAIL d[3] should be 0. Was 6.13 FAIL d[3] should be 0. Was 5. 14 14 FAIL d[0] should be 0. Was 255. 15 15 PASS d[1] is 0 … … 19 19 PASS d[1] is 0 20 20 PASS d[2] is 0 21 FAIL d[3] should be 0. Was 6.21 FAIL d[3] should be 0. Was 5. 22 22 FAIL d[0] should be 0. Was 255. 23 23 PASS d[1] is 0 … … 55 55 PASS d[1] is 0 56 56 PASS d[2] is 0 57 FAIL d[3] should be 0. Was 6.57 FAIL d[3] should be 0. Was 5. 58 58 FAIL d[0] should be 0. Was 255. 59 59 PASS d[1] is 0 … … 63 63 PASS d[1] is 0 64 64 PASS d[2] is 0 65 FAIL d[3] should be 0. Was 6.65 FAIL d[3] should be 0. Was 5. 66 66 FAIL d[0] should be 0. Was 255. 67 67 PASS d[1] is 0 -
trunk/Source/WebCore/ChangeLog
r160119 r160121 1 2013-12-04 Myles C. Maxfield <mmaxfield@apple.com> 2 3 Allow ImageBuffer to use an IOSurface that is larger than necessary 4 https://bugs.webkit.org/show_bug.cgi?id=124626 5 6 Reviewed by Simon Fraser. 7 8 Because creating ImageBuffer's backing store can be so expensive, it 9 would be beneficial to have a pool of pre-created backing stores 10 available. However, this means that ImageBuffer might have to use a 11 backing store that is larger than the exact dimensions that it needs. 12 This patch adds a field, m_backingStoreSize, to CG's ImageBufferData 13 class, and uses this new field when performing ImageBuffer operations 14 to allow for larger-than-necessary backing stores. Content is always 15 drawn in the top left corner of the backing store. 16 17 No new tests are necessary because there is no behavior change. 18 19 * platform/graphics/ImageBuffer.h: 20 (WebCore::ImageBuffer::baseTransform): The base transform has to put 21 content at the top left corner instead of bottom left 22 * platform/graphics/cg/ImageBufferCG.cpp: 23 (WebCore::createCroppedImageIfNecessary): Convenience function to figure out 24 the dimensions of the backing texture in user space 25 (WebCore::ImageBuffer::ImageBuffer): Set up new m_backingStoreSize member 26 (WebCore::maybeCropToBounds): Some ImageBuffer API functions require 27 outputting an image with logical size. This function performs the cropping 28 (WebCore::ImageBuffer::copyImage): Updated for larger-than-necessary 29 backing stores 30 (WebCore::ImageBuffer::copyNativeImage): Ditto 31 (WebCore::ImageBuffer::draw): Ditto 32 (WebCore::ImageBuffer::clip): Ditto 33 (WebCore::ImageBuffer::putByteArray): Ditto 34 (WebCore::ImageBuffer::toDataURL): Ditto 35 * platform/graphics/cg/ImageBufferDataCG.cpp: 36 (WebCore::ImageBufferData::getData): Ditto 37 (WebCore::ImageBufferData::putData): Ditto 38 * platform/graphics/cg/ImageBufferDataCG.h: New m_backingStoreSize field 39 1 40 2013-12-03 Dean Jackson <dino@apple.com> 2 41 -
trunk/Source/WebCore/platform/graphics/ImageBuffer.h
r159791 r160121 118 118 void platformTransformColorSpace(const Vector<int>&); 119 119 #else 120 AffineTransform baseTransform() const { return AffineTransform(1, 0, 0, -1, 0, internalSize().height()); }120 AffineTransform baseTransform() const { return AffineTransform(1, 0, 0, -1, 0, m_data.m_backingStoreSize.height()); } 121 121 #endif 122 122 #if USE(ACCELERATED_COMPOSITING) … … 136 136 private: 137 137 #if USE(CG) 138 // The returned image might be larger than the internalSize(). If you want the smaller 139 // image, crop the result. 138 140 RetainPtr<CGImageRef> copyNativeImage(BackingStoreCopy = CopyBackingStore) const; 139 141 void flushContext() const; -
trunk/Source/WebCore/platform/graphics/cg/ImageBufferCG.cpp
r160021 r160121 99 99 } 100 100 101 static FloatSize scaleSizeToUserSpace(const FloatSize& logicalSize, const IntSize& backingStoreSize, const IntSize& internalSize) 102 { 103 float xMagnification = static_cast<float>(backingStoreSize.width()) / internalSize.width(); 104 float yMagnification = static_cast<float>(backingStoreSize.height()) / internalSize.height(); 105 return FloatSize(logicalSize.width() * xMagnification, logicalSize.height() * yMagnification); 106 } 107 101 108 ImageBuffer::ImageBuffer(const IntSize& size, float resolutionScale, ColorSpace imageColorSpace, RenderingMode renderingMode, bool& success) 102 109 : m_data(size) // NOTE: The input here isn't important as ImageBufferDataCG's constructor just ignores it. … … 112 119 113 120 m_size = IntSize(scaledWidth, scaledHeight); 121 m_data.m_backingStoreSize = m_size; 114 122 115 123 success = false; // Make early return mean failure. … … 122 130 123 131 // Prevent integer overflows 124 m_data.m_bytesPerRow = 4 * width;125 Checked<size_t, RecordOverflow> numBytes = height* m_data.m_bytesPerRow;132 m_data.m_bytesPerRow = 4 * Checked<unsigned, RecordOverflow>(m_data.m_backingStoreSize.width()); 133 Checked<size_t, RecordOverflow> numBytes = Checked<unsigned, RecordOverflow>(m_data.m_backingStoreSize.height()) * m_data.m_bytesPerRow; 126 134 if (numBytes.hasOverflowed()) 127 135 return; … … 149 157 if (accelerateRendering) { 150 158 #if USE(IOSURFACE_CANVAS_BACKING_STORE) 151 m_data.m_surface = createIOSurface(m_size); 152 cgContext = adoptCF(wkIOSurfaceContextCreate(m_data.m_surface.get(), width.unsafeGet(), height.unsafeGet(), m_data.m_colorSpace)); 159 m_data.m_surface = createIOSurface(m_data.m_backingStoreSize); 160 FloatSize userBounds = scaleSizeToUserSpace(FloatSize(width.unsafeGet(), height.unsafeGet()), m_data.m_backingStoreSize, m_size); 161 cgContext = adoptCF(wkIOSurfaceContextCreate(m_data.m_surface.get(), userBounds.width(), userBounds.height(), m_data.m_colorSpace)); 153 162 #endif 154 163 if (!cgContext) … … 157 166 158 167 if (!accelerateRendering) { 159 if (!tryFastCalloc( height.unsafeGet(), m_data.m_bytesPerRow.unsafeGet()).getValue(m_data.m_data))168 if (!tryFastCalloc(m_data.m_backingStoreSize.height(), m_data.m_bytesPerRow.unsafeGet()).getValue(m_data.m_data)) 160 169 return; 161 170 ASSERT(!(reinterpret_cast<intptr_t>(m_data.m_data) & 3)); 162 171 163 172 m_data.m_bitmapInfo = kCGImageAlphaPremultipliedLast; 164 cgContext = adoptCF(CGBitmapContextCreate(m_data.m_data, width.unsafeGet(), height.unsafeGet(), 8, m_data.m_bytesPerRow.unsafeGet(), m_data.m_colorSpace, m_data.m_bitmapInfo));173 cgContext = adoptCF(CGBitmapContextCreate(m_data.m_data, m_data.m_backingStoreSize.width(), m_data.m_backingStoreSize.height(), 8, m_data.m_bytesPerRow.unsafeGet(), m_data.m_colorSpace, m_data.m_bitmapInfo)); 165 174 // Create a live image that wraps the data. 166 175 m_data.m_dataProvider = adoptCF(CGDataProviderCreateWithData(0, m_data.m_data, numBytes.unsafeGet(), releaseImageData)); … … 171 180 172 181 m_context = adoptPtr(new GraphicsContext(cgContext.get())); 182 m_context->scale(FloatSize(1, -1)); 183 m_context->translate(0, -m_data.m_backingStoreSize.height()); 173 184 m_context->applyDeviceScaleFactor(m_resolutionScale); 174 m_context->scale(FloatSize(1, -1));175 m_context->translate(0, -size.height());176 185 m_context->setIsAcceleratedContext(accelerateRendering); 177 186 success = true; … … 190 199 { 191 200 CGContextFlush(m_context->platformContext()); 201 } 202 203 static RetainPtr<CGImageRef> createCroppedImageIfNecessary(CGImageRef image, const IntSize& bounds) 204 { 205 if (image && (CGImageGetWidth(image) != static_cast<size_t>(bounds.width()) 206 || CGImageGetHeight(image) != static_cast<size_t>(bounds.height()))) { 207 return adoptCF(CGImageCreateWithImageInRect(image, CGRectMake(0, static_cast<int>(CGImageGetHeight(image)) - bounds.height(), bounds.width(), bounds.height()))); 208 } 209 return image; 192 210 } 193 211 … … 201 219 RetainPtr<CGContextRef> context = adoptCF(CGBitmapContextCreate(0, logicalSize().width(), logicalSize().height(), 8, 4 * logicalSize().width(), deviceRGBColorSpaceRef(), kCGImageAlphaPremultipliedLast)); 202 220 CGContextSetBlendMode(context.get(), kCGBlendModeCopy); 203 CGContextDrawImage(context.get(), CGRectMake(0, 0, logicalSize().width(), logicalSize().height()), image.get());221 CGContextDrawImage(context.get(), CGRectMake(0, 0, m_data.m_backingStoreSize.width(), m_data.m_backingStoreSize.height()), image.get()); 204 222 image = adoptCF(CGBitmapContextCreateImage(context.get())); 205 223 } 224 225 image = createCroppedImageIfNecessary(image.get(), internalSize()); 206 226 207 227 if (!image) 208 228 return 0; 229 230 ASSERT(CGImageGetWidth(image.get()) == static_cast<size_t>(m_logicalSize.width())); 231 ASSERT(CGImageGetHeight(image.get()) == static_cast<size_t>(m_logicalSize.height())); 209 232 210 233 RefPtr<BitmapImage> bitmapImage = BitmapImage::create(image.get()); … … 225 248 switch (copyBehavior) { 226 249 case DontCopyBackingStore: 227 image = CGImageCreate( internalSize().width(), internalSize().height(), 8, 32, m_data.m_bytesPerRow.unsafeGet(), m_data.m_colorSpace, m_data.m_bitmapInfo, m_data.m_dataProvider.get(), 0, true, kCGRenderingIntentDefault);250 image = CGImageCreate(m_data.m_backingStoreSize.width(), m_data.m_backingStoreSize.height(), 8, 32, m_data.m_bytesPerRow.unsafeGet(), m_data.m_colorSpace, m_data.m_bitmapInfo, m_data.m_dataProvider.get(), 0, true, kCGRenderingIntentDefault); 228 251 break; 229 252 case CopyBackingStore: … … 280 303 void ImageBuffer::clip(GraphicsContext* contextToClip, const FloatRect& rect) const 281 304 { 305 FloatSize backingStoreSizeInUserSpace = scaleSizeToUserSpace(rect.size(), m_data.m_backingStoreSize, internalSize()); 306 282 307 CGContextRef platformContextToClip = contextToClip->platformContext(); 283 308 // FIXME: This image needs to be grayscale to be used as an alpha mask here. 284 309 RetainPtr<CGImageRef> image = copyNativeImage(DontCopyBackingStore); 285 CGContextTranslateCTM(platformContextToClip, rect.x(), rect.y() + rect.height());310 CGContextTranslateCTM(platformContextToClip, rect.x(), rect.y() + backingStoreSizeInUserSpace.height()); 286 311 CGContextScaleCTM(platformContextToClip, 1, -1); 287 CGContextClipToMask(platformContextToClip, FloatRect(FloatPoint(), rect.size()), image.get()); 312 CGContextClipToRect(platformContextToClip, FloatRect(FloatPoint(0, backingStoreSizeInUserSpace.height() - rect.height()), rect.size())); 313 CGContextClipToMask(platformContextToClip, FloatRect(FloatPoint(), backingStoreSizeInUserSpace), image.get()); 288 314 CGContextScaleCTM(platformContextToClip, 1, -1); 289 315 CGContextTranslateCTM(platformContextToClip, -rect.x(), -rect.y() - rect.height()); … … 336 362 337 363 // Draw the image in CG coordinate space 338 IntPoint destPointInCGCoords(destPoint.x() + sourceRect.x(), (coordinateSystem == LogicalCoordinateSystem ? logicalSize() : internalSize()).height() - (destPoint.y() + sourceRect.y()) - sourceRect.height()); 364 FloatSize scaledDestSize = scaleSizeToUserSpace(coordinateSystem == LogicalCoordinateSystem ? logicalSize() : internalSize(), m_data.m_backingStoreSize, internalSize()); 365 IntPoint destPointInCGCoords(destPoint.x() + sourceRect.x(), scaledDestSize.height() - (destPoint.y() + sourceRect.y()) - sourceRect.height()); 339 366 IntRect destRectInCGCoords(destPointInCGCoords, sourceCopySize); 367 CGContextClipToRect(destContext, destRectInCGCoords); 368 340 369 RetainPtr<CGImageRef> sourceCopyImage = sourceCopy->copyNativeImage(); 341 CGContextDrawImage(destContext, destRectInCGCoords, sourceCopyImage.get()); 370 FloatRect backingStoreInDestRect = FloatRect(FloatPoint(destPointInCGCoords.x(), destPointInCGCoords.y() + sourceCopySize.height() - (int)CGImageGetHeight(sourceCopyImage.get())), FloatSize(CGImageGetWidth(sourceCopyImage.get()), CGImageGetHeight(sourceCopyImage.get()))); 371 CGContextDrawImage(destContext, backingStoreInDestRect, sourceCopyImage.get()); 342 372 CGContextRestoreGState(destContext); 343 373 #endif … … 443 473 deviceRGBColorSpaceRef(), kCGBitmapByteOrderDefault | kCGImageAlphaNoneSkipLast, 444 474 dataProvider.get(), 0, false, kCGRenderingIntentDefault)); 445 } else if (m_resolutionScale == 1) 475 } else if (m_resolutionScale == 1) { 446 476 image = copyNativeImage(CopyBackingStore); 447 else { 477 image = createCroppedImageIfNecessary(image.get(), internalSize()); 478 } else { 448 479 image = copyNativeImage(DontCopyBackingStore); 449 480 RetainPtr<CGContextRef> context = adoptCF(CGBitmapContextCreate(0, logicalSize().width(), logicalSize().height(), 8, 4 * logicalSize().width(), deviceRGBColorSpaceRef(), kCGImageAlphaPremultipliedLast)); 450 481 CGContextSetBlendMode(context.get(), kCGBlendModeCopy); 451 CGContextDrawImage(context.get(), CGRectMake(0, 0, logicalSize().width(), logicalSize().height()), image.get()); 482 CGContextClipToRect(context.get(), CGRectMake(0, 0, logicalSize().width(), logicalSize().height())); 483 FloatSize imageRectInUserBounds = scaleSizeToUserSpace(logicalSize(), m_data.m_backingStoreSize, internalSize()); 484 CGContextDrawImage(context.get(), CGRectMake(0, 0, imageRectInUserBounds.width(), imageRectInUserBounds.height()), image.get()); 452 485 image = adoptCF(CGBitmapContextCreateImage(context.get())); 453 486 } -
trunk/Source/WebCore/platform/graphics/cg/ImageBufferDataCG.cpp
r159027 r160121 159 159 160 160 if (!accelerateRendering) { 161 srcBytesPerRow = 4 * size.width();161 srcBytesPerRow = m_bytesPerRow.unsafeGet(); 162 162 srcRows = reinterpret_cast<unsigned char*>(m_data) + originy * srcBytesPerRow + originx * 4; 163 163 … … 340 340 void ImageBufferData::putData(Uint8ClampedArray*& source, const IntSize& sourceSize, const IntRect& sourceRect, const IntPoint& destPoint, const IntSize& size, bool accelerateRendering, bool unmultiplied, float resolutionScale) 341 341 { 342 #if ASSERT_DISABLED 343 UNUSED_PARAM(size); 344 #endif 345 342 346 ASSERT(sourceRect.width() > 0); 343 347 ASSERT(sourceRect.height() > 0); … … 382 386 383 387 if (!accelerateRendering) { 384 destBytesPerRow = 4 * size.width();388 destBytesPerRow = m_bytesPerRow.unsafeGet(); 385 389 destRows = reinterpret_cast<unsigned char*>(m_data) + (desty * destBytesPerRow + destx * 4).unsafeGet(); 386 390 -
trunk/Source/WebCore/platform/graphics/cg/ImageBufferDataCG.h
r158330 r160121 55 55 CGColorSpaceRef m_colorSpace; 56 56 RetainPtr<IOSurfaceRef> m_surface; 57 IntSize m_backingStoreSize; 57 58 58 59 PassRefPtr<Uint8ClampedArray> getData(const IntRect&, const IntSize&, bool accelerateRendering, bool unmultiplied, float resolutionScale) const;
Note:
See TracChangeset
for help on using the changeset viewer.