diff --git a/Frameworks/include/CGIWICBitmap.h b/Frameworks/include/CGIWICBitmap.h index c04d6f8569..10d2ce907b 100644 --- a/Frameworks/include/CGIWICBitmap.h +++ b/Frameworks/include/CGIWICBitmap.h @@ -152,7 +152,7 @@ class CGIWICBitmap : public Microsoft::WRL::RuntimeClass lock; - RETURN_IF_FAILED(Lock(copyRect, 0, &lock)); + // TODO #1379: Support sub-regional locking. + RETURN_IF_FAILED(Lock(&fullRect, 0, &lock)); + + if (!copyRect) { + copyRect = &fullRect; + } - UINT sourceDataSize; - BYTE* sourceData; - RETURN_IF_FAILED(lock->GetDataPointer(&sourceDataSize, &sourceData)); + RETURN_HR_IF(E_INVALIDARG, copyRect->Width == 0 || copyRect->Height == 0 || copyRect->X < 0 || copyRect->Y < 0); - RETURN_HR_IF(E_INVALIDARG, sourceDataSize > bufferSize); + unsigned int srcStride; + unsigned int srcSize; + uint8_t* srcData; + RETURN_IF_FAILED(lock->GetStride(&srcStride)); + RETURN_IF_FAILED(lock->GetDataPointer(&srcSize, &srcData)); - // TODO #1379 - should support regional copying. - RETURN_HR_IF(E_UNEXPECTED, memcpy_s(buffer, bufferSize, sourceData, sourceDataSize) != 0); + if (copyRect->X == 0 && copyRect->Y == 0 && copyRect->Width == m_width && copyRect->Height == m_height) { + RETURN_HR_IF(E_INVALIDARG, srcSize > bufferSize); + RETURN_HR_IF(E_UNEXPECTED, memcpy_s(buffer, bufferSize, srcData, srcSize) != 0); + } else { + // Once we support sub-regional locking we can fix this stride copier. + + // Invalid state: Source stride is less than the width of the image. + // We can't copy regions from sub-8bpp images. + RETURN_HR_IF(E_NOTIMPL, srcStride < fullRect.Width); + + size_t bytesPerPixel = srcStride / fullRect.Width; + ptrdiff_t srcOffset = (copyRect->X * bytesPerPixel) + (copyRect->Y * srcStride); + const uint8_t* end = buffer + (stride * copyRect->Height); + for (uint8_t *src = srcData + srcOffset, *dest = buffer; + dest < end; + src += srcStride, dest += stride) { + RETURN_HR_IF(E_UNEXPECTED, + memcpy_s(dest, + end - dest, // Total remaining bytes available in the destination buffer. + src, + stride) + ); + } + } return S_OK; }