/** * aSrcRect: Rect relative to the aSrc surface * aDestPoint: Point inside aDest surface */ void CopyRect(DataSourceSurface* aSrc, DataSourceSurface* aDest, IntRect aSrcRect, IntPoint aDestPoint) { if (aSrcRect.Overflows() || IntRect(aDestPoint, aSrcRect.Size()).Overflows()) { MOZ_CRASH("we should never be getting invalid rects at this point"); } MOZ_RELEASE_ASSERT(aSrc->GetFormat() == aDest->GetFormat(), "different surface formats"); MOZ_RELEASE_ASSERT(IntRect(IntPoint(), aSrc->GetSize()).Contains(aSrcRect), "source rect too big for source surface"); MOZ_RELEASE_ASSERT(IntRect(IntPoint(), aDest->GetSize()).Contains(IntRect(aDestPoint, aSrcRect.Size())), "dest surface too small"); if (aSrcRect.IsEmpty()) { return; } DataSourceSurface::ScopedMap srcMap(aSrc, DataSourceSurface::READ); DataSourceSurface::ScopedMap destMap(aDest, DataSourceSurface::WRITE); if (MOZ2D_WARN_IF(!srcMap.IsMapped() || !destMap.IsMapped())) { return; } uint8_t* sourceData = DataAtOffset(aSrc, srcMap.GetMappedSurface(), aSrcRect.TopLeft()); uint32_t sourceStride = srcMap.GetStride(); uint8_t* destData = DataAtOffset(aDest, destMap.GetMappedSurface(), aDestPoint); uint32_t destStride = destMap.GetStride(); if (BytesPerPixel(aSrc->GetFormat()) == 4) { for (int32_t y = 0; y < aSrcRect.height; y++) { PodCopy((int32_t*)destData, (int32_t*)sourceData, aSrcRect.width); sourceData += sourceStride; destData += destStride; } } else if (BytesPerPixel(aSrc->GetFormat()) == 1) { for (int32_t y = 0; y < aSrcRect.height; y++) { PodCopy(destData, sourceData, aSrcRect.width); sourceData += sourceStride; destData += destStride; } } }
/*static*/ bool TexUnpackSurface::ConvertSurface(WebGLContext* webgl, const webgl::DriverUnpackInfo* dui, gfx::DataSourceSurface* surf, bool isSurfAlphaPremult, UniqueBuffer* const out_convertedBuffer, uint8_t* const out_convertedAlignment, bool* const out_outOfMemory) { *out_outOfMemory = false; const size_t width = surf->GetSize().width; const size_t height = surf->GetSize().height; // Source args: // After we call this, on OSX, our GLContext will no longer be current. gfx::DataSourceSurface::ScopedMap srcMap(surf, gfx::DataSourceSurface::MapType::READ); if (!srcMap.IsMapped()) return false; const void* const srcBegin = srcMap.GetData(); const size_t srcStride = srcMap.GetStride(); WebGLTexelFormat srcFormat; if (!GetFormatForSurf(surf, &srcFormat)) return false; const bool srcPremultiplied = isSurfAlphaPremult; // Dest args: WebGLTexelFormat dstFormat; if (!GetFormatForPackingTuple(dui->unpackFormat, dui->unpackType, &dstFormat)) return false; const auto bytesPerPixel = webgl::BytesPerPixel({dui->unpackFormat, dui->unpackType}); const size_t dstRowBytes = bytesPerPixel * width; const size_t dstAlignment = 8; // Just use the max! const size_t dstStride = RoundUpToMultipleOf(dstRowBytes, dstAlignment); CheckedUint32 checkedDstSize = dstStride; checkedDstSize *= height; if (!checkedDstSize.isValid()) { *out_outOfMemory = true; return false; } const size_t dstSize = checkedDstSize.value(); UniqueBuffer dstBuffer = malloc(dstSize); if (!dstBuffer) { *out_outOfMemory = true; return false; } void* const dstBegin = dstBuffer.get(); gl::OriginPos srcOrigin, dstOrigin; OriginsForDOM(webgl, &srcOrigin, &dstOrigin); const bool dstPremultiplied = webgl->mPixelStore_PremultiplyAlpha; // And go!: if (!ConvertImage(width, height, srcBegin, srcStride, srcOrigin, srcFormat, srcPremultiplied, dstBegin, dstStride, dstOrigin, dstFormat, dstPremultiplied)) { MOZ_ASSERT(false, "ConvertImage failed unexpectedly."); NS_ERROR("ConvertImage failed unexpectedly."); *out_outOfMemory = true; return false; } *out_convertedBuffer = Move(dstBuffer); *out_convertedAlignment = dstAlignment; return true; }