diff --git a/dom/canvas/WebGLContext.cpp b/dom/canvas/WebGLContext.cpp index fbddb634228d..2233015de57f 100644 --- a/dom/canvas/WebGLContext.cpp +++ b/dom/canvas/WebGLContext.cpp @@ -2225,25 +2225,47 @@ ScopedLazyBind::UnwrapImpl() //////////////////////////////////////// -void -Intersect(uint32_t srcSize, int32_t dstStartInSrc, uint32_t dstSize, - uint32_t* const out_intStartInSrc, uint32_t* const out_intStartInDst, - uint32_t* const out_intSize) +bool +Intersect(const int32_t srcSize, const int32_t read0, const int32_t readSize, + int32_t* const out_intRead0, int32_t* const out_intWrite0, + int32_t* const out_intSize) { - // Only >0 if dstStartInSrc is >0: - // 0 3 // src coords - // | [========] // dst box - // ^--^ - *out_intStartInSrc = std::max(0, dstStartInSrc); + MOZ_ASSERT(srcSize >= 0); + MOZ_ASSERT(readSize >= 0); + const auto read1 = int64_t(read0) + readSize; - // Only >0 if dstStartInSrc is <0: - //-6 0 // src coords - // [=====|==] // dst box - // ^-----^ - *out_intStartInDst = std::max(0, 0 - dstStartInSrc); + int32_t intRead0 = read0; // Clearly doesn't need validation. + int64_t intWrite0 = 0; + int64_t intSize = readSize; - int32_t intEndInSrc = std::min(srcSize, dstStartInSrc + dstSize); - *out_intSize = std::max(0, intEndInSrc - *out_intStartInSrc); + if (read1 <= 0 || read0 >= srcSize) { + // Disjoint ranges. + intSize = 0; + } else { + if (read0 < 0) { + const auto diff = int64_t(0) - read0; + MOZ_ASSERT(diff >= 0); + intRead0 = 0; + intWrite0 = diff; + intSize -= diff; + } + if (read1 > srcSize) { + const auto diff = int64_t(read1) - srcSize; + MOZ_ASSERT(diff >= 0); + intSize -= diff; + } + + if (!CheckedInt(intWrite0).isValid() || + !CheckedInt(intSize).isValid()) + { + return false; + } + } + + *out_intRead0 = intRead0; + *out_intWrite0 = intWrite0; + *out_intSize = intSize; + return true; } //////////////////////////////////////////////////////////////////////////////// diff --git a/dom/canvas/WebGLContext.h b/dom/canvas/WebGLContext.h index ce0e5e544618..37ac2929bcd0 100644 --- a/dom/canvas/WebGLContext.h +++ b/dom/canvas/WebGLContext.h @@ -2164,10 +2164,9 @@ private: //// -void -Intersect(uint32_t srcSize, int32_t dstStartInSrc, uint32_t dstSize, - uint32_t* const out_intStartInSrc, uint32_t* const out_intStartInDst, - uint32_t* const out_intSize); +bool +Intersect(int32_t srcSize, int32_t read0, int32_t readSize, int32_t* out_intRead0, + int32_t* out_intWrite0, int32_t* out_intSize); //// diff --git a/dom/canvas/WebGLContextGL.cpp b/dom/canvas/WebGLContextGL.cpp index 0a9ac679d88f..91328e8f5ae4 100644 --- a/dom/canvas/WebGLContextGL.cpp +++ b/dom/canvas/WebGLContextGL.cpp @@ -1556,18 +1556,32 @@ WebGLContext::ReadPixelsImpl(GLint x, GLint y, GLsizei rawWidth, GLsizei rawHeig return; } + //// + + int32_t readX, readY; + int32_t writeX, writeY; + int32_t rwWidth, rwHeight; + if (!Intersect(srcWidth, x, width, &readX, &writeX, &rwWidth) || + !Intersect(srcHeight, y, height, &readY, &writeY, &rwHeight)) + { + ErrorOutOfMemory("readPixels: Bad subrect selection."); + return; + } + //////////////// // Now that the errors are out of the way, on to actually reading! OnBeforeReadCall(); - uint32_t readX, readY; - uint32_t writeX, writeY; - uint32_t rwWidth, rwHeight; - Intersect(srcWidth, x, width, &readX, &writeX, &rwWidth); - Intersect(srcHeight, y, height, &readY, &writeY, &rwHeight); + if (!rwWidth || !rwHeight) { + // Disjoint rects, so we're done already. + DummyReadFramebufferOperation("readPixels"); + return; + } - if (rwWidth == uint32_t(width) && rwHeight == uint32_t(height)) { + if (uint32_t(rwWidth) == width && + uint32_t(rwHeight) == height) + { DoReadPixelsAndConvert(srcFormat->format, x, y, width, height, packFormat, packType, dest, dataLen, rowStride); return; @@ -1586,12 +1600,6 @@ WebGLContext::ReadPixelsImpl(GLint x, GLint y, GLsizei rawWidth, GLsizei rawHeig //////////////////////////////////// // Read only the in-bounds pixels. - if (!rwWidth || !rwHeight) { - // There aren't any, so we're 'done'. - DummyReadFramebufferOperation("readPixels"); - return; - } - if (IsWebGL2()) { if (!mPixelStore_PackRowLength) { gl->fPixelStorei(LOCAL_GL_PACK_ROW_LENGTH, @@ -1611,7 +1619,7 @@ WebGLContext::ReadPixelsImpl(GLint x, GLint y, GLsizei rawWidth, GLsizei rawHeig uint8_t* row = (uint8_t*)dest + writeX * bytesPerPixel; row += writeY * rowStride; - for (uint32_t j = 0; j < rwHeight; j++) { + for (uint32_t j = 0; j < uint32_t(rwHeight); j++) { DoReadPixelsAndConvert(srcFormat->format, readX, readY+j, rwWidth, 1, packFormat, packType, row, dataLen, rowStride); row += rowStride; diff --git a/dom/canvas/WebGLTextureUpload.cpp b/dom/canvas/WebGLTextureUpload.cpp index b104f38a8200..1f98a06f553a 100644 --- a/dom/canvas/WebGLTextureUpload.cpp +++ b/dom/canvas/WebGLTextureUpload.cpp @@ -2011,11 +2011,15 @@ DoCopyTexOrSubImage(WebGLContext* webgl, const char* funcName, bool isSubImage, //// - uint32_t readX, readY; - uint32_t writeX, writeY; - uint32_t rwWidth, rwHeight; - Intersect(srcTotalWidth, xWithinSrc, dstWidth, &readX, &writeX, &rwWidth); - Intersect(srcTotalHeight, yWithinSrc, dstHeight, &readY, &writeY, &rwHeight); + int32_t readX, readY; + int32_t writeX, writeY; + int32_t rwWidth, rwHeight; + if (!Intersect(srcTotalWidth, xWithinSrc, dstWidth, &readX, &writeX, &rwWidth) || + !Intersect(srcTotalHeight, yWithinSrc, dstHeight, &readY, &writeY, &rwHeight)) + { + webgl->ErrorOutOfMemory("%s: Bad subrect selection.", funcName); + return false; + } writeX += xOffset; writeY += yOffset; @@ -2028,7 +2032,7 @@ DoCopyTexOrSubImage(WebGLContext* webgl, const char* funcName, bool isSubImage, if (!isSubImage) { UniqueBuffer buffer; - if (rwWidth != dstWidth || rwHeight != dstHeight) { + if (uint32_t(rwWidth) != dstWidth || uint32_t(rwHeight) != dstHeight) { const auto& pi = idealUnpack->ToPacking(); CheckedUint32 byteCount = BytesPerPixel(pi); byteCount *= dstWidth;