/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// There's nothing special about this alignment, other than that it's what // cairo_format_stride_for_width uses. staticconst int32_t alignment = sizeof(int32_t);
const int32_t bpp = BytesPerPixel(aFormat);
if (aWidth >= (INT32_MAX - alignment) / bpp) { return -1; // too big
}
if (!srcSurface || !destSurface) { return nullptr;
}
if (CopyRect(srcSurface, destSurface,
IntRect(IntPoint(), srcSurface->GetSize()), IntPoint())) { return destSurface.forget();
}
return nullptr;
}
uint8_t* DataAtOffset(DataSourceSurface* aSurface, const DataSourceSurface::MappedSurface* aMap,
IntPoint aPoint) { if (!SurfaceContainsPoint(aSurface, aPoint)) {
MOZ_CRASH("GFX: sample position needs to be inside surface!");
}
MOZ_ASSERT(Factory::CheckSurfaceSize(aSurface->GetSize()), "surface size overflows - this should have been prevented when " "the surface was created");
if (size_t(aSrcStride) == packedStride.value()) { // aSrc is already packed, so we can copy with a single memcpy.
memcpy(aDst, aSrc, totalSize.value());
} else { // memcpy one row at a time. for (int row = 0; row < aSrcSize.height; ++row) {
memcpy(aDst, aSrc, packedStride.value());
aSrc += aSrcStride;
aDst += packedStride.value();
}
}
}
UniquePtr<uint8_t[]> SurfaceToPackedBGRA(DataSourceSurface* aSurface) {
SurfaceFormat format = aSurface->GetFormat(); if (format != SurfaceFormat::B8G8R8A8 && format != SurfaceFormat::B8G8R8X8) { return nullptr;
}
if (format == SurfaceFormat::B8G8R8X8) { // Convert BGRX to BGRA by setting a to 255.
SwizzleData(imageBuffer.get(), stride, SurfaceFormat::X8R8G8B8_UINT32,
imageBuffer.get(), stride, SurfaceFormat::A8R8G8B8_UINT32,
size);
}
return imageBuffer;
}
uint8_t* SurfaceToPackedBGR(DataSourceSurface* aSurface) {
SurfaceFormat format = aSurface->GetFormat();
MOZ_ASSERT(format == SurfaceFormat::B8G8R8X8, "Format not supported");
if (format != SurfaceFormat::B8G8R8X8) { // To support B8G8R8A8 we'd need to un-pre-multiply alpha return nullptr;
}
void ClearDataSourceSurface(DataSourceSurface* aSurface) {
DataSourceSurface::MappedSurface map; if (!aSurface->Map(DataSourceSurface::MapType::WRITE, &map)) {
MOZ_ASSERT(false, "Failed to map DataSourceSurface"); return;
}
// We avoid writing into the gaps between the rows here since we can't be // sure that some drivers don't use those bytes.
uint32_t width = aSurface->GetSize().width;
uint32_t bytesPerRow = width * BytesPerPixel(aSurface->GetFormat());
uint8_t* row = map.mData; // converting to size_t here because otherwise the temporaries can overflow // and we can end up with |end| being a bad address!
uint8_t* end = row + size_t(map.mStride) * size_t(aSurface->GetSize().height);
// We limit the length returned to values that can be represented by int32_t // because we don't want to allocate buffers any bigger than that. This // allows for a buffer size of over 2 GiB which is already rediculously // large and will make the process janky. (Note the choice of the signed type // is deliberate because we specifically don't want the returned value to // overflow if someone stores the buffer length in an int32_t variable.)
/** * aSrcRect: Rect relative to the aSrc surface * aDestPoint: Point inside aDest surface * * aSrcRect and aDestPoint are in internal local coordinates. * i.e. locations of pixels and not in the same coordinate space * as aSrc->GetRect()
*/ bool CopyRect(DataSourceSurface* aSrc, DataSourceSurface* aDest,
IntRect aSrcRect, IntPoint aDestPoint) { if (aSrcRect.Overflows() ||
IntRect(aDestPoint, aSrcRect.Size()).Overflows()) {
MOZ_CRASH("GFX: we should never be getting invalid rects at this point");
}
MOZ_RELEASE_ASSERT(aSrc->GetFormat() == aDest->GetFormat(), "GFX: different surface formats");
MOZ_RELEASE_ASSERT(IntRect(IntPoint(), aSrc->GetSize()).Contains(aSrcRect), "GFX: source rect too big for source surface");
MOZ_RELEASE_ASSERT(IntRect(IntPoint(), aDest->GetSize())
.Contains(IntRect(aDestPoint, aSrcRect.Size())), "GFX: dest surface too small");