Index: Source/core/platform/graphics/GraphicsContext3D.cpp |
diff --git a/Source/core/platform/graphics/GraphicsContext3D.cpp b/Source/core/platform/graphics/GraphicsContext3D.cpp |
index 2ff862ed02a5668a21123dbe66b68a5b73d8ec0e..a5deef4c28c874c3b214dc2e70fac0d9ff7f8a8b 100644 |
--- a/Source/core/platform/graphics/GraphicsContext3D.cpp |
+++ b/Source/core/platform/graphics/GraphicsContext3D.cpp |
@@ -87,6 +87,7 @@ GraphicsContext3D::GraphicsContext3D(PassOwnPtr<WebKit::WebGraphicsContext3D> we |
, m_initializedAvailableExtensions(false) |
, m_layerComposited(false) |
, m_preserveDrawingBuffer(preserveDrawingBuffer) |
+ , m_packAlignment(4) |
, m_resourceSafety(ResourceSafetyUnknown) |
, m_grContext(0) |
{ |
@@ -98,6 +99,7 @@ GraphicsContext3D::GraphicsContext3D(PassOwnPtr<WebKit::WebGraphicsContext3DProv |
, m_initializedAvailableExtensions(false) |
, m_layerComposited(false) |
, m_preserveDrawingBuffer(preserveDrawingBuffer) |
+ , m_packAlignment(4) |
, m_resourceSafety(ResourceSafetyUnknown) |
, m_grContext(m_provider->grContext()) |
{ |
@@ -500,7 +502,14 @@ DELEGATE_TO_WEBCONTEXT_1R(isShader, Platform3DObject, GC3Dboolean) |
DELEGATE_TO_WEBCONTEXT_1R(isTexture, Platform3DObject, GC3Dboolean) |
DELEGATE_TO_WEBCONTEXT_1(lineWidth, GC3Dfloat) |
DELEGATE_TO_WEBCONTEXT_1(linkProgram, Platform3DObject) |
-DELEGATE_TO_WEBCONTEXT_2(pixelStorei, GC3Denum, GC3Dint) |
+ |
+void GraphicsContext3D::pixelStorei(GC3Denum pname, GC3Dint param) |
+{ |
+ if (pname == PACK_ALIGNMENT) |
+ m_packAlignment = param; |
+ m_impl->pixelStorei(pname, param); |
+} |
+ |
DELEGATE_TO_WEBCONTEXT_2(polygonOffset, GC3Dfloat, GC3Dfloat) |
DELEGATE_TO_WEBCONTEXT_7(readPixels, GC3Dint, GC3Dint, GC3Dsizei, GC3Dsizei, GC3Denum, GC3Denum, void*) |
@@ -604,17 +613,43 @@ PassRefPtr<ImageData> GraphicsContext3D::paintRenderingResultsToImageData(Drawin |
RefPtr<ImageData> imageData = ImageData::create(IntSize(width, height)); |
unsigned char* pixels = imageData->data()->data(); |
- size_t bufferSize = 4 * width * height; |
- m_impl->readBackFramebuffer(pixels, bufferSize, framebufferId, width, height); |
+ m_impl->bindFramebuffer(FRAMEBUFFER, framebufferId); |
+ readBackFramebuffer(pixels, width, height, ReadbackRGBA, AlphaDoNothing); |
+ flipVertically(pixels, width, height); |
+ return imageData.release(); |
+} |
+ |
+void GraphicsContext3D::readBackFramebuffer(unsigned char* pixels, int width, int height, ReadbackOrder readbackOrder, AlphaOp op) |
+{ |
+ if (m_packAlignment > 4) |
+ m_impl->pixelStorei(PACK_ALIGNMENT, 1); |
+ m_impl->readPixels(0, 0, width, height, RGBA, UNSIGNED_BYTE, pixels); |
+ if (m_packAlignment > 4) |
+ m_impl->pixelStorei(PACK_ALIGNMENT, m_packAlignment); |
+ |
+ size_t bufferSize = 4 * width * height; |
+ |
+ if (readbackOrder == ReadbackSkia) { |
#if (SK_R32_SHIFT == 16) && !SK_B32_SHIFT |
- // If the implementation swapped the red and blue channels, un-swap them. |
- for (size_t i = 0; i < bufferSize; i += 4) |
- std::swap(pixels[i], pixels[i + 2]); |
+ // Swizzle red and blue channels to match SkBitmap's byte ordering. |
+ // TODO(kbr): expose GL_BGRA as extension. |
+ for (size_t i = 0; i < bufferSize; i += 4) { |
+ std::swap(pixels[i], pixels[i + 2]); |
+ } |
#endif |
+ } |
- return imageData.release(); |
+ if (op == AlphaDoPremultiply) { |
+ for (size_t i = 0; i < bufferSize; i += 4) { |
+ pixels[i + 0] = std::min(255, pixels[i + 0] * pixels[i + 3] / 255); |
+ pixels[i + 1] = std::min(255, pixels[i + 1] * pixels[i + 3] / 255); |
+ pixels[i + 2] = std::min(255, pixels[i + 2] * pixels[i + 3] / 255); |
+ } |
+ } else if (op != AlphaDoNothing) { |
+ ASSERT_NOT_REACHED(); |
+ } |
} |
DELEGATE_TO_WEBCONTEXT_R(createBuffer, Platform3DObject) |
@@ -890,7 +925,6 @@ unsigned GraphicsContext3D::getChannelBitsByFormat(GC3Denum format) |
void GraphicsContext3D::paintFramebufferToCanvas(int framebuffer, int width, int height, bool premultiplyAlpha, ImageBuffer* imageBuffer) |
{ |
unsigned char* pixels = 0; |
- size_t bufferSize = 4 * width * height; |
const SkBitmap* canvasBitmap = imageBuffer->context()->bitmap(); |
const SkBitmap* readbackBitmap = 0; |
@@ -916,15 +950,9 @@ void GraphicsContext3D::paintFramebufferToCanvas(int framebuffer, int width, int |
SkAutoLockPixels bitmapLock(*readbackBitmap); |
pixels = static_cast<unsigned char*>(readbackBitmap->getPixels()); |
- m_impl->readBackFramebuffer(pixels, 4 * width * height, framebuffer, width, height); |
- |
- if (premultiplyAlpha) { |
- for (size_t i = 0; i < bufferSize; i += 4) { |
- pixels[i + 0] = std::min(255, pixels[i + 0] * pixels[i + 3] / 255); |
- pixels[i + 1] = std::min(255, pixels[i + 1] * pixels[i + 3] / 255); |
- pixels[i + 2] = std::min(255, pixels[i + 2] * pixels[i + 3] / 255); |
- } |
- } |
+ m_impl->bindFramebuffer(FRAMEBUFFER, framebuffer); |
+ readBackFramebuffer(pixels, width, height, ReadbackSkia, premultiplyAlpha ? AlphaDoPremultiply : AlphaDoNothing); |
+ flipVertically(pixels, width, height); |
readbackBitmap->notifyPixelsChanged(); |
if (m_resizingBitmap.readyToDraw()) { |
@@ -1009,4 +1037,19 @@ bool GraphicsContext3D::isExtensionEnabled(const String& name) |
return m_enabledExtensions.contains(mappedName); |
} |
+void GraphicsContext3D::flipVertically(uint8_t* framebuffer, int width, int height) |
+{ |
+ m_scanline.resize(width * 4); |
+ uint8* scanline = &m_scanline[0]; |
+ unsigned rowBytes = width * 4; |
+ unsigned count = height / 2; |
+ for (unsigned i = 0; i < count; i++) { |
+ uint8* rowA = framebuffer + i * rowBytes; |
+ uint8* rowB = framebuffer + (height - i - 1) * rowBytes; |
+ memcpy(scanline, rowB, rowBytes); |
+ memcpy(rowB, rowA, rowBytes); |
+ memcpy(rowA, scanline, rowBytes); |
+ } |
+} |
+ |
} // namespace WebCore |