// Computes the smallest rectangle that contains both aRect1 and aRect2 and // fills 'this' with the result. Returns FALSE if both aRect1 and aRect2 are // empty and TRUE otherwise PRBool nsIntRect::UnionRect(const nsIntRect &aRect1, const nsIntRect &aRect2) { PRBool result = PR_TRUE; // Is aRect1 empty? if (aRect1.IsEmpty()) { if (aRect2.IsEmpty()) { // Both rectangles are empty which is an error Empty(); result = PR_FALSE; } else { // aRect1 is empty so set the result to aRect2 *this = aRect2; } } else if (aRect2.IsEmpty()) { // aRect2 is empty so set the result to aRect1 *this = aRect1; } else { PRInt32 xmost1 = aRect1.XMost(); PRInt32 xmost2 = aRect2.XMost(); PRInt32 ymost1 = aRect1.YMost(); PRInt32 ymost2 = aRect2.YMost(); // Compute the origin x = PR_MIN(aRect1.x, aRect2.x); y = PR_MIN(aRect1.y, aRect2.y); // Compute the size width = PR_MAX(xmost1, xmost2) - x; height = PR_MAX(ymost1, ymost2) - y; } return result; }
static inline void TilePixels(uint8_t *aTargetData, const uint8_t *aSourceData, const nsIntRect &targetRegion, const nsIntRect &aTile, uint32_t aStride) { if (targetRegion.IsEmpty()) { return; } uint32_t tileRowCopyMemSize = aTile.width * 4; uint32_t numTimesToCopyTileRows = targetRegion.width / aTile.width; uint8_t *targetFirstRowOffset = aTargetData + 4 * targetRegion.x; const uint8_t *tileFirstRowOffset = aSourceData + 4 * aTile.x; int32_t tileYOffset = 0; for (int32_t targetY = targetRegion.y; targetY < targetRegion.YMost(); ++targetY) { uint8_t *targetRowOffset = targetFirstRowOffset + aStride * targetY; const uint8_t *tileRowOffset = tileFirstRowOffset + aStride * (aTile.y + tileYOffset); for (uint32_t i = 0; i < numTimesToCopyTileRows; ++i) { memcpy(targetRowOffset + i * tileRowCopyMemSize, tileRowOffset, tileRowCopyMemSize); } tileYOffset = (tileYOffset + 1) % aTile.height; } }
/* static */ void ProgressTracker::SyncNotifyInternal(ObserverArray& aObservers, bool aHasImage, Progress aProgress, const nsIntRect& aDirtyRect) { MOZ_ASSERT(NS_IsMainThread()); typedef imgINotificationObserver I; if (aProgress & FLAG_SIZE_AVAILABLE) { NOTIFY_IMAGE_OBSERVERS(aObservers, Notify(I::SIZE_AVAILABLE)); } if (aProgress & FLAG_ONLOAD_BLOCKED) { NOTIFY_IMAGE_OBSERVERS(aObservers, BlockOnload()); } if (aHasImage) { // OnFrameUpdate // If there's any content in this frame at all (always true for // vector images, true for raster images that have decoded at // least one frame) then send OnFrameUpdate. if (!aDirtyRect.IsEmpty()) { NOTIFY_IMAGE_OBSERVERS(aObservers, Notify(I::FRAME_UPDATE, &aDirtyRect)); } if (aProgress & FLAG_FRAME_COMPLETE) { NOTIFY_IMAGE_OBSERVERS(aObservers, Notify(I::FRAME_COMPLETE)); } if (aProgress & FLAG_HAS_TRANSPARENCY) { NOTIFY_IMAGE_OBSERVERS(aObservers, Notify(I::HAS_TRANSPARENCY)); } if (aProgress & FLAG_IS_ANIMATED) { NOTIFY_IMAGE_OBSERVERS(aObservers, Notify(I::IS_ANIMATED)); } } // Send UnblockOnload before OnStopDecode and OnStopRequest. This allows // observers that can fire events when they receive those notifications to do // so then, instead of being forced to wait for UnblockOnload. if (aProgress & FLAG_ONLOAD_UNBLOCKED) { NOTIFY_IMAGE_OBSERVERS(aObservers, UnblockOnload()); } if (aProgress & FLAG_DECODE_COMPLETE) { MOZ_ASSERT(aHasImage, "Stopped decoding without ever having an image?"); NOTIFY_IMAGE_OBSERVERS(aObservers, Notify(I::DECODE_COMPLETE)); } if (aProgress & FLAG_LOAD_COMPLETE) { NOTIFY_IMAGE_OBSERVERS(aObservers, OnLoadComplete(aProgress & FLAG_LAST_PART_COMPLETE)); } }
/* static */ void ProgressTracker::SyncNotifyInternal(ProxyArray& aProxies, bool aHasImage, Progress aProgress, const nsIntRect& aDirtyRect) { MOZ_ASSERT(NS_IsMainThread()); // OnStartRequest if (aProgress & FLAG_REQUEST_STARTED) NOTIFY_IMAGE_OBSERVERS(aProxies, OnStartRequest()); // OnStartContainer if (aProgress & FLAG_HAS_SIZE) NOTIFY_IMAGE_OBSERVERS(aProxies, OnStartContainer()); // OnStartDecode if (aProgress & FLAG_DECODE_STARTED) NOTIFY_IMAGE_OBSERVERS(aProxies, OnStartDecode()); // BlockOnload if (aProgress & FLAG_ONLOAD_BLOCKED) NOTIFY_IMAGE_OBSERVERS(aProxies, BlockOnload()); if (aHasImage) { // OnFrameUpdate // If there's any content in this frame at all (always true for // vector images, true for raster images that have decoded at // least one frame) then send OnFrameUpdate. if (!aDirtyRect.IsEmpty()) NOTIFY_IMAGE_OBSERVERS(aProxies, OnFrameUpdate(&aDirtyRect)); if (aProgress & FLAG_FRAME_STOPPED) NOTIFY_IMAGE_OBSERVERS(aProxies, OnStopFrame()); // OnImageIsAnimated if (aProgress & FLAG_IS_ANIMATED) NOTIFY_IMAGE_OBSERVERS(aProxies, OnImageIsAnimated()); } // Send UnblockOnload before OnStopDecode and OnStopRequest. This allows // observers that can fire events when they receive those notifications to do // so then, instead of being forced to wait for UnblockOnload. if (aProgress & FLAG_ONLOAD_UNBLOCKED) { NOTIFY_IMAGE_OBSERVERS(aProxies, UnblockOnload()); } if (aProgress & FLAG_DECODE_STOPPED) { MOZ_ASSERT(aHasImage, "Stopped decoding without ever having an image?"); NOTIFY_IMAGE_OBSERVERS(aProxies, OnStopDecode()); } if (aProgress & FLAG_REQUEST_STOPPED) { NOTIFY_IMAGE_OBSERVERS(aProxies, OnStopRequest(aProgress & FLAG_MULTIPART_STOPPED)); } }
nsRect nsFilterInstance::FilterSpaceToFrameSpace(const nsIntRect& aRect) const { if (aRect.IsEmpty()) { return nsRect(); } gfxRect r(aRect.x, aRect.y, aRect.width, aRect.height); r = mFilterSpaceToFrameSpaceInCSSPxTransform.TransformBounds(r); return nsLayoutUtils::RoundGfxRectToAppRect(r, mAppUnitsPerCSSPx); }
bool imgFrame::Draw(gfxContext *aContext, GraphicsFilter aFilter, const gfxMatrix &aUserSpaceToImageSpace, const gfxRect& aFill, const nsIntMargin &aPadding, const nsIntRect &aSubimage, uint32_t aImageFlags) { PROFILER_LABEL("image", "imgFrame::Draw"); NS_ASSERTION(!aFill.IsEmpty(), "zero dest size --- fix caller"); NS_ASSERTION(!aSubimage.IsEmpty(), "zero source size --- fix caller"); NS_ASSERTION(!mPalettedImageData, "Directly drawing a paletted image!"); bool doPadding = aPadding != nsIntMargin(0,0,0,0); bool doPartialDecode = !ImageComplete(); if (mSinglePixel && !doPadding && !doPartialDecode) { DoSingleColorFastPath(aContext, mSinglePixelColor, aFill); return true; } gfxMatrix userSpaceToImageSpace = aUserSpaceToImageSpace; gfxRect sourceRect = userSpaceToImageSpace.TransformBounds(aFill); gfxRect imageRect(0, 0, mSize.width + aPadding.LeftRight(), mSize.height + aPadding.TopBottom()); gfxRect subimage(aSubimage.x, aSubimage.y, aSubimage.width, aSubimage.height); gfxRect fill = aFill; NS_ASSERTION(!sourceRect.Intersect(subimage).IsEmpty(), "We must be allowed to sample *some* source pixels!"); nsRefPtr<gfxASurface> surf; if (!mSinglePixel) { surf = ThebesSurface(); if (!surf) return false; } bool doTile = !imageRect.Contains(sourceRect) && !(aImageFlags & imgIContainer::FLAG_CLAMP); SurfaceWithFormat surfaceResult = SurfaceForDrawing(doPadding, doPartialDecode, doTile, aPadding, userSpaceToImageSpace, fill, subimage, sourceRect, imageRect, surf); if (surfaceResult.IsValid()) { gfxUtils::DrawPixelSnapped(aContext, surfaceResult.mDrawable, userSpaceToImageSpace, subimage, sourceRect, imageRect, fill, surfaceResult.mFormat, aFilter, aImageFlags); } return true; }
void GrallocTextureHostBasic::SetCropRect(nsIntRect aCropRect) { MOZ_ASSERT(aCropRect.TopLeft() == gfx::IntPoint(0, 0)); MOZ_ASSERT(!aCropRect.IsEmpty()); MOZ_ASSERT(aCropRect.width <= mSize.width); MOZ_ASSERT(aCropRect.height <= mSize.height); gfx::IntSize cropSize(aCropRect.width, aCropRect.height); if (mCropSize == cropSize) { return; } mCropSize = cropSize; ClearTextureSource(); }
static nsIntRect TransformRect(const nsIntRect& aRect, const gfx3DMatrix& aTransform) { if (aRect.IsEmpty()) { return nsIntRect(); } gfxRect rect(aRect.x, aRect.y, aRect.width, aRect.height); rect = aTransform.TransformBounds(rect); rect.RoundOut(); nsIntRect intRect; if (!gfxUtils::GfxRectToIntRect(rect, &intRect)) { return nsIntRect(); } return intRect; }
void imgFrame::Draw(gfxContext *aContext, gfxPattern::GraphicsFilter aFilter, const gfxMatrix &aUserSpaceToImageSpace, const gfxRect& aFill, const nsIntMargin &aPadding, const nsIntRect &aSubimage) { NS_ASSERTION(!aFill.IsEmpty(), "zero dest size --- fix caller"); NS_ASSERTION(!aSubimage.IsEmpty(), "zero source size --- fix caller"); NS_ASSERTION(!mPalettedImageData, "Directly drawing a paletted image!"); bool doPadding = aPadding != nsIntMargin(0,0,0,0); bool doPartialDecode = !ImageComplete(); if (mSinglePixel && !doPadding && !doPartialDecode) { DoSingleColorFastPath(aContext, mSinglePixelColor, aFill); return; } gfxMatrix userSpaceToImageSpace = aUserSpaceToImageSpace; gfxRect sourceRect = userSpaceToImageSpace.Transform(aFill); gfxRect imageRect(0, 0, mSize.width + aPadding.LeftRight(), mSize.height + aPadding.TopBottom()); gfxRect subimage(aSubimage.x, aSubimage.y, aSubimage.width, aSubimage.height); gfxRect fill = aFill; NS_ASSERTION(!sourceRect.Intersect(subimage).IsEmpty(), "We must be allowed to sample *some* source pixels!"); bool doTile = !imageRect.Contains(sourceRect); SurfaceWithFormat surfaceResult = SurfaceForDrawing(doPadding, doPartialDecode, doTile, aPadding, userSpaceToImageSpace, fill, subimage, sourceRect, imageRect); if (surfaceResult.IsValid()) { gfxUtils::DrawPixelSnapped(aContext, surfaceResult.mDrawable, userSpaceToImageSpace, subimage, sourceRect, imageRect, fill, surfaceResult.mFormat, aFilter); } }
void GLBlitTextureImageHelper::BlitTextureImage(TextureImage *aSrc, const nsIntRect& aSrcRect, TextureImage *aDst, const nsIntRect& aDstRect) { GLContext *gl = mCompositor->gl(); NS_ASSERTION(!aSrc->InUpdate(), "Source texture is in update!"); NS_ASSERTION(!aDst->InUpdate(), "Destination texture is in update!"); if (!aSrc || !aDst || aSrcRect.IsEmpty() || aDstRect.IsEmpty()) return; int savedFb = 0; gl->fGetIntegerv(LOCAL_GL_FRAMEBUFFER_BINDING, &savedFb); ScopedGLState scopedScissorTestState(gl, LOCAL_GL_SCISSOR_TEST, false); ScopedGLState scopedBlendState(gl, LOCAL_GL_BLEND, false); // 2.0 means scale up by two float blitScaleX = float(aDstRect.width) / float(aSrcRect.width); float blitScaleY = float(aDstRect.height) / float(aSrcRect.height); // We start iterating over all destination tiles aDst->BeginBigImageIteration(); do { // calculate portion of the tile that is going to be painted to nsIntRect dstSubRect; nsIntRect dstTextureRect = ThebesIntRect(aDst->GetTileRect()); dstSubRect.IntersectRect(aDstRect, dstTextureRect); // this tile is not part of the destination rectangle aDstRect if (dstSubRect.IsEmpty()) continue; // (*) transform the rect of this tile into the rectangle defined by aSrcRect... nsIntRect dstInSrcRect(dstSubRect); dstInSrcRect.MoveBy(-aDstRect.TopLeft()); // ...which might be of different size, hence scale accordingly dstInSrcRect.ScaleRoundOut(1.0f / blitScaleX, 1.0f / blitScaleY); dstInSrcRect.MoveBy(aSrcRect.TopLeft()); SetBlitFramebufferForDestTexture(aDst->GetTextureID()); UseBlitProgram(); aSrc->BeginBigImageIteration(); // now iterate over all tiles in the source Image... do { // calculate portion of the source tile that is in the source rect nsIntRect srcSubRect; nsIntRect srcTextureRect = ThebesIntRect(aSrc->GetTileRect()); srcSubRect.IntersectRect(aSrcRect, srcTextureRect); // this tile is not part of the source rect if (srcSubRect.IsEmpty()) { continue; } // calculate intersection of source rect with destination rect srcSubRect.IntersectRect(srcSubRect, dstInSrcRect); // this tile does not overlap the current destination tile if (srcSubRect.IsEmpty()) { continue; } // We now have the intersection of // the current source tile // and the desired source rectangle // and the destination tile // and the desired destination rectange // in destination space. // We need to transform this back into destination space, inverting the transform from (*) nsIntRect srcSubInDstRect(srcSubRect); srcSubInDstRect.MoveBy(-aSrcRect.TopLeft()); srcSubInDstRect.ScaleRoundOut(blitScaleX, blitScaleY); srcSubInDstRect.MoveBy(aDstRect.TopLeft()); // we transform these rectangles to be relative to the current src and dst tiles, respectively nsIntSize srcSize = srcTextureRect.Size(); nsIntSize dstSize = dstTextureRect.Size(); srcSubRect.MoveBy(-srcTextureRect.x, -srcTextureRect.y); srcSubInDstRect.MoveBy(-dstTextureRect.x, -dstTextureRect.y); float dx0 = 2.0f * float(srcSubInDstRect.x) / float(dstSize.width) - 1.0f; float dy0 = 2.0f * float(srcSubInDstRect.y) / float(dstSize.height) - 1.0f; float dx1 = 2.0f * float(srcSubInDstRect.x + srcSubInDstRect.width) / float(dstSize.width) - 1.0f; float dy1 = 2.0f * float(srcSubInDstRect.y + srcSubInDstRect.height) / float(dstSize.height) - 1.0f; ScopedViewportRect autoViewportRect(gl, 0, 0, dstSize.width, dstSize.height); RectTriangles rects; nsIntSize realTexSize = srcSize; if (!CanUploadNonPowerOfTwo(gl)) { realTexSize = nsIntSize(gfx::NextPowerOfTwo(srcSize.width), gfx::NextPowerOfTwo(srcSize.height)); } if (aSrc->GetWrapMode() == LOCAL_GL_REPEAT) { rects.addRect(/* dest rectangle */ dx0, dy0, dx1, dy1, /* tex coords */ srcSubRect.x / float(realTexSize.width), srcSubRect.y / float(realTexSize.height), srcSubRect.XMost() / float(realTexSize.width), srcSubRect.YMost() / float(realTexSize.height)); } else { DecomposeIntoNoRepeatTriangles(srcSubRect, realTexSize, rects); // now put the coords into the d[xy]0 .. d[xy]1 coordinate space // from the 0..1 that it comes out of decompose InfallibleTArray<RectTriangles::coord>& coords = rects.vertCoords(); for (unsigned int i = 0; i < coords.Length(); ++i) { coords[i].x = (coords[i].x * (dx1 - dx0)) + dx0; coords[i].y = (coords[i].y * (dy1 - dy0)) + dy0; } } ScopedBindTextureUnit autoTexUnit(gl, LOCAL_GL_TEXTURE0); ScopedBindTexture autoTex(gl, aSrc->GetTextureID()); ScopedVertexAttribPointer autoAttrib0(gl, 0, 2, LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0, 0, rects.vertCoords().Elements()); ScopedVertexAttribPointer autoAttrib1(gl, 1, 2, LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0, 0, rects.texCoords().Elements()); gl->fDrawArrays(LOCAL_GL_TRIANGLES, 0, rects.elements()); } while (aSrc->NextTile()); } while (aDst->NextTile()); // unbind the previous texture from the framebuffer SetBlitFramebufferForDestTexture(0); gl->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, savedFb); }
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); } }
static bool ValidatePictureRect(const mozilla::gfx::IntSize& aSize, const nsIntRect& aPictureRect) { return nsIntRect(0, 0, aSize.width, aSize.height).Contains(aPictureRect) && !aPictureRect.IsEmpty(); }
bool imgFrame::Draw(gfxContext *aContext, GraphicsFilter aFilter, const gfxMatrix &aUserSpaceToImageSpace, const gfxRect& aFill, const nsIntMargin &aPadding, const nsIntRect &aSubimage, uint32_t aImageFlags) { PROFILER_LABEL("imgFrame", "Draw", js::ProfileEntry::Category::GRAPHICS); NS_ASSERTION(!aFill.IsEmpty(), "zero dest size --- fix caller"); NS_ASSERTION(!aSubimage.IsEmpty(), "zero source size --- fix caller"); NS_ASSERTION(!mPalettedImageData, "Directly drawing a paletted image!"); bool doPadding = aPadding != nsIntMargin(0,0,0,0); bool doPartialDecode = !ImageComplete(); if (mSinglePixel && !doPadding && !doPartialDecode) { DoSingleColorFastPath(aContext, mSinglePixelColor, aFill); return true; } gfxMatrix userSpaceToImageSpace = aUserSpaceToImageSpace; gfxRect sourceRect = userSpaceToImageSpace.TransformBounds(aFill); gfxRect imageRect(0, 0, mSize.width + aPadding.LeftRight(), mSize.height + aPadding.TopBottom()); gfxRect subimage(aSubimage.x, aSubimage.y, aSubimage.width, aSubimage.height); gfxRect fill = aFill; NS_ASSERTION(!sourceRect.Intersect(subimage).IsEmpty(), "We must be allowed to sample *some* source pixels!"); nsRefPtr<gfxASurface> surf = CachedThebesSurface(); VolatileBufferPtr<unsigned char> ref(mVBuf); if (!mSinglePixel && !surf) { if (ref.WasBufferPurged()) { return false; } surf = mDrawSurface; if (!surf) { long stride = gfxImageSurface::ComputeStride(mSize, mFormat); nsRefPtr<gfxImageSurface> imgSurf = new gfxImageSurface(ref, mSize, stride, mFormat); #if defined(XP_MACOSX) surf = mDrawSurface = new gfxQuartzImageSurface(imgSurf); #else surf = mDrawSurface = imgSurf; #endif } if (!surf || surf->CairoStatus()) { mDrawSurface = nullptr; return true; } } bool doTile = !imageRect.Contains(sourceRect) && !(aImageFlags & imgIContainer::FLAG_CLAMP); SurfaceWithFormat surfaceResult = SurfaceForDrawing(doPadding, doPartialDecode, doTile, aPadding, userSpaceToImageSpace, fill, subimage, sourceRect, imageRect, surf); if (surfaceResult.IsValid()) { gfxUtils::DrawPixelSnapped(aContext, surfaceResult.mDrawable, userSpaceToImageSpace, subimage, sourceRect, imageRect, fill, surfaceResult.mFormat, aFilter, aImageFlags); } return true; }