mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-08-15 08:53:07 +09:00
[DOM] Clip image data transfers.
This commit is contained in:
parent
7b3f9fb7c0
commit
9fa9622d5b
2 changed files with 79 additions and 10 deletions
|
|
@ -5754,6 +5754,18 @@ inline uint8_t PoisonValue(uint8_t v)
|
|||
return v + rand() %3 -1;
|
||||
}
|
||||
|
||||
static IntRect ClipImageDataTransfer(IntRect& aSrc,
|
||||
const IntPoint& aDestOffset,
|
||||
const IntSize& aDestBounds)
|
||||
{
|
||||
IntRect dest = aSrc;
|
||||
dest.SafeMoveBy(aDestOffset);
|
||||
dest = IntRect(IntPoint(0, 0), aDestBounds).SafeIntersect(dest);
|
||||
|
||||
aSrc = aSrc.SafeIntersect(dest - aDestOffset);
|
||||
return aSrc + aDestOffset;
|
||||
}
|
||||
|
||||
nsresult
|
||||
CanvasRenderingContext2D::GetImageDataArray(JSContext* aCx,
|
||||
int32_t aX,
|
||||
|
|
@ -5794,9 +5806,11 @@ CanvasRenderingContext2D::GetImageDataArray(JSContext* aCx,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
IntRect srcRect(0, 0, mWidth, mHeight);
|
||||
IntRect destRect(aX, aY, aWidth, aHeight);
|
||||
IntRect srcReadRect = srcRect.Intersect(destRect);
|
||||
IntRect dstWriteRect(0, 0, aWidth, aHeight);
|
||||
IntRect srcReadRect = ClipImageDataTransfer(dstWriteRect,
|
||||
IntPoint(aX, aY),
|
||||
IntSize(mWidth, mHeight));
|
||||
|
||||
RefPtr<DataSourceSurface> readback;
|
||||
DataSourceSurface::MappedSurface rawData;
|
||||
if (!srcReadRect.IsEmpty()) {
|
||||
|
|
@ -5824,9 +5838,6 @@ CanvasRenderingContext2D::GetImageDataArray(JSContext* aCx,
|
|||
}
|
||||
}
|
||||
|
||||
IntRect dstWriteRect = srcReadRect;
|
||||
dstWriteRect.MoveBy(-aX, -aY);
|
||||
|
||||
JS::AutoCheckCannotGC nogc;
|
||||
bool isShared;
|
||||
uint8_t* data = JS_GetUint8ClampedArrayData(darray, &isShared, nogc);
|
||||
|
|
@ -6027,10 +6038,10 @@ CanvasRenderingContext2D::PutImageData_explicit(int32_t aX, int32_t aY, uint32_t
|
|||
dirtyRect = imageDataRect;
|
||||
}
|
||||
|
||||
dirtyRect.MoveBy(IntPoint(aX, aY));
|
||||
dirtyRect = IntRect(0, 0, mWidth, mHeight).Intersect(dirtyRect);
|
||||
|
||||
if (dirtyRect.Width() <= 0 || dirtyRect.Height() <= 0) {
|
||||
IntRect srcRect = dirtyRect;
|
||||
dirtyRect = ClipImageDataTransfer(srcRect, IntPoint(aX, aY),
|
||||
IntSize(mWidth, mHeight));
|
||||
if (dirtyRect.IsEmpty()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -107,6 +107,10 @@ struct BaseRect {
|
|||
// (including edges) of *this and aRect. If there are no points in that
|
||||
// intersection, returns an empty rectangle with x/y set to the std::max of the x/y
|
||||
// of *this and aRect.
|
||||
//
|
||||
// Intersection with an empty Rect may not produce an empty Rect if overflow
|
||||
// occurs. e.g. {INT_MIN, 0, 0, 20} Intersect { 5000, 0, 500, 20 } gives:
|
||||
// the non-emtpy {5000, 0, 500, 20 } instead of {5000, 0, 0, 0}
|
||||
MOZ_MUST_USE Sub Intersect(const Sub& aRect) const
|
||||
{
|
||||
Sub result;
|
||||
|
|
@ -119,6 +123,26 @@ struct BaseRect {
|
|||
}
|
||||
return result;
|
||||
}
|
||||
// Gives the same results as Intersect() but handles integer overflow
|
||||
// better. This comes at a tiny cost in performance.
|
||||
// e.g. {INT_MIN, 0, 0, 20} Intersect { 5000, 0, 500, 20 } gives:
|
||||
// {5000, 0, 0, 0}
|
||||
MOZ_MUST_USE Sub SafeIntersect(const Sub& aRect) const
|
||||
{
|
||||
Sub result;
|
||||
result.x = std::max<T>(x, aRect.x);
|
||||
result.y = std::max<T>(y, aRect.y);
|
||||
T right = std::min<T>(x + width, aRect.x + aRect.width);
|
||||
T bottom = std::min<T>(y + height, aRect.y + aRect.height);
|
||||
if (right < result.x || bottom < result.y) {
|
||||
result.width = 0;
|
||||
result.height = 0;
|
||||
} else {
|
||||
result.width = right - result.x;
|
||||
result.height = bottom - result.y;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
// Sets *this to be the rectangle containing the intersection of the points
|
||||
// (including edges) of *this and aRect. If there are no points in that
|
||||
// intersection, sets *this to be an empty rectangle with x/y set to the std::max
|
||||
|
|
@ -211,6 +235,40 @@ struct BaseRect {
|
|||
void MoveTo(const Point& aPoint) { x = aPoint.x; y = aPoint.y; }
|
||||
void MoveBy(T aDx, T aDy) { x += aDx; y += aDy; }
|
||||
void MoveBy(const Point& aPoint) { x += aPoint.x; y += aPoint.y; }
|
||||
|
||||
// Variant of MoveBy that ensures that even after translation by a point that
|
||||
// the rectangle coordinates will still fit within numeric limits. The origin
|
||||
// and size will be clipped within numeric limits to ensure this.
|
||||
void SafeMoveByX(T aDx) {
|
||||
T x2 = XMost();
|
||||
if (aDx >= T(0)) {
|
||||
T limit = std::numeric_limits<T>::max();
|
||||
x = limit - aDx < x ? limit : x + aDx;
|
||||
width = (limit - aDx < x2 ? limit : x2 + aDx) - x;
|
||||
} else {
|
||||
T limit = std::numeric_limits<T>::min();
|
||||
x = limit - aDx > x ? limit : x + aDx;
|
||||
width = (limit - aDx > x2 ? limit : x2 + aDx) - x;
|
||||
}
|
||||
}
|
||||
void SafeMoveByY(T aDy) {
|
||||
T y2 = YMost();
|
||||
if (aDy >= T(0)) {
|
||||
T limit = std::numeric_limits<T>::max();
|
||||
y = limit - aDy < y ? limit : y + aDy;
|
||||
height = (limit - aDy < y2 ? limit : y2 + aDy) - y;
|
||||
} else {
|
||||
T limit = std::numeric_limits<T>::min();
|
||||
y = limit - aDy > y ? limit : y + aDy;
|
||||
height = (limit - aDy > y2 ? limit : y2 + aDy) - y;
|
||||
}
|
||||
}
|
||||
void SafeMoveBy(T aDx, T aDy) {
|
||||
SafeMoveByX(aDx);
|
||||
SafeMoveByY(aDy);
|
||||
}
|
||||
void SafeMoveBy(const Point& aPoint) { SafeMoveBy(aPoint.x, aPoint.y); }
|
||||
|
||||
void SizeTo(T aWidth, T aHeight) { width = aWidth; height = aHeight; }
|
||||
void SizeTo(const SizeT& aSize) { width = aSize.width; height = aSize.height; }
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue