static bool _get_rectangular_clip (cairo_t *cr, const nsIntRect& bounds, bool *need_clip, nsIntRect *rectangles, int max_rectangles, int *num_rectangles) { cairo_rectangle_list_t *cliplist; cairo_rectangle_t *clips; int i; bool retval = true; cliplist = cairo_copy_clip_rectangle_list (cr); if (cliplist->status != CAIRO_STATUS_SUCCESS) { retval = false; NATIVE_DRAWING_NOTE("FALLBACK: non-rectangular clip"); goto FINISH; } /* the clip is always in surface backend coordinates (i.e. native backend coords) */ clips = cliplist->rectangles; for (i = 0; i < cliplist->num_rectangles; ++i) { nsIntRect rect; if (!_convert_coord_to_int (clips[i].x, &rect.x) || !_convert_coord_to_int (clips[i].y, &rect.y) || !_convert_coord_to_int (clips[i].width, &rect.width) || !_convert_coord_to_int (clips[i].height, &rect.height)) { retval = false; NATIVE_DRAWING_NOTE("FALLBACK: non-integer clip"); goto FINISH; } if (rect.IsEqualInterior(bounds)) { /* the bounds are entirely inside the clip region so we don't need to clip. */ *need_clip = false; goto FINISH; } NS_ASSERTION(bounds.Contains(rect), "Was expecting to be clipped to bounds"); if (i >= max_rectangles) { retval = false; NATIVE_DRAWING_NOTE("FALLBACK: unsupported clip rectangle count"); goto FINISH; } rectangles[i] = rect; } *need_clip = true; *num_rectangles = cliplist->num_rectangles; FINISH: cairo_rectangle_list_destroy (cliplist); return retval; }
void gfxImageSurface::MovePixels(const nsIntRect& aSourceRect, const nsIntPoint& aDestTopLeft) { const nsIntRect bounds(0, 0, mSize.width, mSize.height); nsIntPoint offset = aDestTopLeft - aSourceRect.TopLeft(); nsIntRect clippedSource = aSourceRect; clippedSource.IntersectRect(clippedSource, bounds); nsIntRect clippedDest = clippedSource + offset; clippedDest.IntersectRect(clippedDest, bounds); const nsIntRect dest = clippedDest; const nsIntRect source = dest - offset; // NB: this relies on IntersectRect() and operator+/- preserving // x/y for empty rectangles NS_ABORT_IF_FALSE(bounds.Contains(dest) && bounds.Contains(source) && aSourceRect.Contains(source) && nsIntRect(aDestTopLeft, aSourceRect.Size()).Contains(dest) && source.Size() == dest.Size() && offset == (dest.TopLeft() - source.TopLeft()), "Messed up clipping, crash or corruption will follow"); if (source.IsEmpty() || source.IsEqualInterior(dest)) { return; } long naturalStride = ComputeStride(mSize, mFormat); if (mStride == naturalStride && dest.width == bounds.width) { // Fast path: this is a vertical shift of some rows in a // "normal" image surface. We can directly memmove and // hopefully stay in SIMD land. unsigned char* dst = mData + dest.y * mStride; const unsigned char* src = mData + source.y * mStride; size_t nBytes = dest.height * mStride; memmove(dst, src, nBytes); return; } // Slow(er) path: have to move row-by-row. const int32_t bpp = BytePerPixelFromFormat(mFormat); const size_t nRowBytes = dest.width * bpp; // dstRow points at the first pixel within the current destination // row, and similarly for srcRow. endSrcRow is one row beyond the // last row we need to copy. stride is either +mStride or // -mStride, depending on which direction we're copying. unsigned char* dstRow; unsigned char* srcRow; unsigned char* endSrcRow; // NB: this may point outside the image long stride; if (dest.y > source.y) { // We're copying down from source to dest, so walk backwards // starting from the last rows to avoid stomping pixels we // need. stride = -mStride; dstRow = mData + dest.x * bpp + (dest.YMost() - 1) * mStride; srcRow = mData + source.x * bpp + (source.YMost() - 1) * mStride; endSrcRow = mData + source.x * bpp + (source.y - 1) * mStride; } else { stride = mStride; dstRow = mData + dest.x * bpp + dest.y * mStride; srcRow = mData + source.x * bpp + source.y * mStride; endSrcRow = mData + source.x * bpp + source.YMost() * mStride; } for (; srcRow != endSrcRow; dstRow += stride, srcRow += stride) { memmove(dstRow, srcRow, nRowBytes); } }