Commit 7967e9ae authored by Lee Salzman's avatar Lee Salzman
Browse files

Bug 1767365 - Clip image data transfers. r=aosmond, a=RyanVM

parent 8f84602c
Loading
Loading
Loading
Loading
+17 −11
Original line number Diff line number Diff line
@@ -5044,6 +5044,16 @@ already_AddRefed<ImageData> CanvasRenderingContext2D::GetImageData(
  return MakeAndAddRef<ImageData>(w, h, *array);
}

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, int32_t aY, uint32_t aWidth, uint32_t aHeight,
    nsIPrincipal& aSubjectPrincipal, JSObject** aRetval) {
@@ -5073,9 +5083,9 @@ nsresult CanvasRenderingContext2D::GetImageDataArray(
    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));
  if (srcReadRect.IsEmpty()) {
    *aRetval = darray;
    return NS_OK;
@@ -5100,9 +5110,6 @@ nsresult CanvasRenderingContext2D::GetImageDataArray(
    return NS_ERROR_OUT_OF_MEMORY;
  }

  IntRect dstWriteRect = srcReadRect;
  dstWriteRect.MoveBy(-aX, -aY);

  // Check for site-specific permission.  This check is not needed if the
  // canvas was created with a docshell (that is only done for special
  // internal uses).
@@ -5253,10 +5260,10 @@ void CanvasRenderingContext2D::PutImageData_explicit(
    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;
  }

@@ -5311,7 +5318,6 @@ void CanvasRenderingContext2D::PutImageData_explicit(
    dstFormat = sourceSurface->GetFormat();
  }

  IntRect srcRect = dirtyRect - IntPoint(aX, aY);
  uint8_t* srcData = arr.Data() + srcRect.y * (width * 4) + srcRect.x * 4;

  PremultiplyData(
+33 −0
Original line number Diff line number Diff line
@@ -313,6 +313,39 @@ struct BaseRect {
    height = aSize.height;
  }

  // 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 Inflate(T aD) { Inflate(aD, aD); }
  void Inflate(T aDx, T aDy) {
    x -= aDx;