/* static */ bool HwcUtils::PrepareLayerRects(nsIntRect aVisible, const gfxMatrix& aTransform, nsIntRect aClip, nsIntRect aBufferRect, hwc_rect_t* aSourceCrop, hwc_rect_t* aVisibleRegionScreen) { gfxRect visibleRect(aVisible); gfxRect clip(aClip); gfxRect visibleRectScreen = aTransform.TransformBounds(visibleRect); // |clip| is guaranteed to be integer visibleRectScreen.IntersectRect(visibleRectScreen, clip); if (visibleRectScreen.IsEmpty()) { LOGD("Skip layer"); return false; } gfxMatrix inverse(aTransform); inverse.Invert(); gfxRect crop = inverse.TransformBounds(visibleRectScreen); //clip to buffer size crop.IntersectRect(crop, aBufferRect); crop.Round(); if (crop.IsEmpty()) { LOGD("Skip layer"); return false; } //propagate buffer clipping back to visible rect visibleRectScreen = aTransform.TransformBounds(crop); visibleRectScreen.Round(); // Map from layer space to buffer space crop -= aBufferRect.TopLeft(); aSourceCrop->left = crop.x; aSourceCrop->top = crop.y; aSourceCrop->right = crop.x + crop.width; aSourceCrop->bottom = crop.y + crop.height; aVisibleRegionScreen->left = visibleRectScreen.x; aVisibleRegionScreen->top = visibleRectScreen.y; aVisibleRegionScreen->right = visibleRectScreen.x + visibleRectScreen.width; aVisibleRegionScreen->bottom = visibleRectScreen.y + visibleRectScreen.height; return true; }
/* static */ bool HwcUtils::PrepareVisibleRegion(const nsIntRegion& aVisible, const gfxMatrix& aTransform, nsIntRect aClip, nsIntRect aBufferRect, RectVector* aVisibleRegionScreen) { nsIntRegionRectIterator rect(aVisible); bool isVisible = false; while (const nsIntRect* visibleRect = rect.Next()) { hwc_rect_t visibleRectScreen; gfxRect screenRect; screenRect.IntersectRect(gfxRect(*visibleRect), aBufferRect); screenRect = aTransform.TransformBounds(screenRect); screenRect.IntersectRect(screenRect, aClip); screenRect.Round(); if (screenRect.IsEmpty()) { continue; } visibleRectScreen.left = screenRect.x; visibleRectScreen.top = screenRect.y; visibleRectScreen.right = screenRect.XMost(); visibleRectScreen.bottom = screenRect.YMost(); aVisibleRegionScreen->push_back(visibleRectScreen); isVisible = true; } return isVisible; }
/* static */ bool HwcUtils::CalculateClipRect(const gfxMatrix& aTransform, const nsIntRect* aLayerClip, nsIntRect aParentClip, nsIntRect* aRenderClip) { *aRenderClip = aParentClip; if (!aLayerClip) { return true; } if (aLayerClip->IsEmpty()) { return false; } nsIntRect clip = *aLayerClip; gfxRect r(clip); gfxRect trClip = aTransform.TransformBounds(r); trClip.Round(); gfxUtils::GfxRectToIntRect(trClip, &clip); aRenderClip->IntersectRect(*aRenderClip, clip); return true; }
/** * Returns the app unit canvas bounds of a userspace rect. * * @param aToCanvas Transform from userspace to canvas device space. */ static nsRect ToCanvasBounds(const gfxRect &aUserspaceRect, const gfxMatrix &aToCanvas, const nsPresContext *presContext) { return nsLayoutUtils::RoundGfxRectToAppRect( aToCanvas.TransformBounds(aUserspaceRect), presContext->AppUnitsPerDevPixel()); }
// EXTEND_PAD won't help us here; we have to create a temporary surface to hold // the subimage of pixels we're allowed to sample. static already_AddRefed<gfxDrawable> CreateSamplingRestrictedDrawable(gfxDrawable* aDrawable, gfxContext* aContext, const gfxMatrix& aUserSpaceToImageSpace, const gfxRect& aSourceRect, const gfxRect& aSubimage, const gfxImageFormat aFormat) { PROFILER_LABEL("gfxUtils", "CreateSamplingRestricedDrawable"); gfxRect userSpaceClipExtents = aContext->GetClipExtents(); // This isn't optimal --- if aContext has a rotation then GetClipExtents // will have to do a bounding-box computation, and TransformBounds might // too, so we could get a better result if we computed image space clip // extents in one go --- but it doesn't really matter and this is easier // to understand. gfxRect imageSpaceClipExtents = aUserSpaceToImageSpace.TransformBounds(userSpaceClipExtents); // Inflate by one pixel because bilinear filtering will sample at most // one pixel beyond the computed image pixel coordinate. imageSpaceClipExtents.Inflate(1.0); gfxRect needed = imageSpaceClipExtents.Intersect(aSourceRect); needed = needed.Intersect(aSubimage); needed.RoundOut(); // if 'needed' is empty, nothing will be drawn since aFill // must be entirely outside the clip region, so it doesn't // matter what we do here, but we should avoid trying to // create a zero-size surface. if (needed.IsEmpty()) return nullptr; nsRefPtr<gfxDrawable> drawable; gfxIntSize size(int32_t(needed.Width()), int32_t(needed.Height())); nsRefPtr<gfxImageSurface> image = aDrawable->GetAsImageSurface(); if (image && gfxRect(0, 0, image->GetSize().width, image->GetSize().height).Contains(needed)) { nsRefPtr<gfxASurface> temp = image->GetSubimage(needed); drawable = new gfxSurfaceDrawable(temp, size, gfxMatrix().Translate(-needed.TopLeft())); } else { mozilla::RefPtr<mozilla::gfx::DrawTarget> target = gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(ToIntSize(size), ImageFormatToSurfaceFormat(aFormat)); if (!target) { return nullptr; } nsRefPtr<gfxContext> tmpCtx = new gfxContext(target); tmpCtx->SetOperator(OptimalFillOperator()); aDrawable->Draw(tmpCtx, needed - needed.TopLeft(), true, GraphicsFilter::FILTER_FAST, gfxMatrix().Translate(needed.TopLeft())); drawable = new gfxSurfaceDrawable(target, size, gfxMatrix().Translate(-needed.TopLeft())); } return drawable.forget(); }
// EXTEND_PAD won't help us here; we have to create a temporary surface to hold // the subimage of pixels we're allowed to sample. static already_AddRefed<gfxDrawable> CreateSamplingRestrictedDrawable(gfxDrawable* aDrawable, gfxContext* aContext, const gfxMatrix& aUserSpaceToImageSpace, const gfxRect& aSourceRect, const gfxRect& aSubimage, const gfxImageSurface::gfxImageFormat aFormat) { SAMPLE_LABEL("gfxUtils", "CreateSamplingRestricedDrawable"); gfxRect userSpaceClipExtents = aContext->GetClipExtents(); // This isn't optimal --- if aContext has a rotation then GetClipExtents // will have to do a bounding-box computation, and TransformBounds might // too, so we could get a better result if we computed image space clip // extents in one go --- but it doesn't really matter and this is easier // to understand. gfxRect imageSpaceClipExtents = aUserSpaceToImageSpace.TransformBounds(userSpaceClipExtents); // Inflate by one pixel because bilinear filtering will sample at most // one pixel beyond the computed image pixel coordinate. imageSpaceClipExtents.Inflate(1.0); gfxRect needed = imageSpaceClipExtents.Intersect(aSourceRect); needed = needed.Intersect(aSubimage); needed.RoundOut(); // if 'needed' is empty, nothing will be drawn since aFill // must be entirely outside the clip region, so it doesn't // matter what we do here, but we should avoid trying to // create a zero-size surface. if (needed.IsEmpty()) return nullptr; gfxIntSize size(PRInt32(needed.Width()), PRInt32(needed.Height())); nsRefPtr<gfxASurface> temp = gfxPlatform::GetPlatform()->CreateOffscreenSurface(size, gfxASurface::ContentFromFormat(aFormat)); if (!temp || temp->CairoStatus()) return nullptr; nsRefPtr<gfxContext> tmpCtx = new gfxContext(temp); tmpCtx->SetOperator(OptimalFillOperator()); aDrawable->Draw(tmpCtx, needed - needed.TopLeft(), true, gfxPattern::FILTER_FAST, gfxMatrix().Translate(needed.TopLeft())); nsRefPtr<gfxPattern> resultPattern = new gfxPattern(temp); if (!resultPattern) return nullptr; nsRefPtr<gfxDrawable> drawable = new gfxSurfaceDrawable(temp, size, gfxMatrix().Translate(-needed.TopLeft())); return drawable.forget(); }
static nsIntRect MapDeviceRectToFilterSpace(const gfxMatrix& aMatrix, const gfxIntSize& aFilterSize, const nsIntRect* aDeviceRect) { nsIntRect rect(0, 0, aFilterSize.width, aFilterSize.height); if (aDeviceRect) { gfxRect r = aMatrix.TransformBounds(gfxRect(aDeviceRect->x, aDeviceRect->y, aDeviceRect->width, aDeviceRect->height)); r.RoundOut(); nsIntRect intRect; if (gfxUtils::GfxRectToIntRect(r, &intRect)) { rect = intRect; } } return rect; }
SVGBBox nsSVGForeignObjectFrame::GetBBoxContribution(const gfxMatrix &aToBBoxUserspace, PRUint32 aFlags) { nsSVGForeignObjectElement *content = static_cast<nsSVGForeignObjectElement*>(mContent); float x, y, w, h; content->GetAnimatedLengthValues(&x, &y, &w, &h, nsnull); if (w < 0.0f) w = 0.0f; if (h < 0.0f) h = 0.0f; if (aToBBoxUserspace.IsSingular()) { // XXX ReportToConsole return SVGBBox(); } return aToBBoxUserspace.TransformBounds(gfxRect(0.0, 0.0, w, h)); }
NS_IMETHODIMP DynamicImage::Draw(gfxContext* aContext, GraphicsFilter aFilter, const gfxMatrix& aUserSpaceToImageSpace, const gfxRect& aFill, const nsIntRect& aSubimage, const nsIntSize& aViewportSize, const SVGImageContext* aSVGContext, uint32_t aWhichFrame, uint32_t aFlags) { gfxIntSize drawableSize(mDrawable->Size()); gfxRect imageRect(0, 0, drawableSize.width, drawableSize.height); gfxRect sourceRect = aUserSpaceToImageSpace.TransformBounds(aFill); gfxUtils::DrawPixelSnapped(aContext, mDrawable, aUserSpaceToImageSpace, aSubimage, sourceRect, imageRect, aFill, SurfaceFormat::B8G8R8A8, aFilter, aFlags); return NS_OK; }
gfxRect nsSVGForeignObjectFrame::GetBBoxContribution(const gfxMatrix &aToBBoxUserspace) { NS_ASSERTION(!(GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD), "Should not be calling this on a non-display child"); nsSVGForeignObjectElement *content = static_cast<nsSVGForeignObjectElement*>(mContent); float x, y, w, h; content->GetAnimatedLengthValues(&x, &y, &w, &h, nsnull); if (w < 0.0f) w = 0.0f; if (h < 0.0f) h = 0.0f; if (aToBBoxUserspace.IsSingular()) { // XXX ReportToConsole return gfxRect(0.0, 0.0, 0.0, 0.0); } return aToBBoxUserspace.TransformBounds(gfxRect(0.0, 0.0, w, h)); }
/** * Converts an nsRect that is relative to a filtered frame's origin (i.e. the * top-left corner of its border box) into filter space. * Returns the entire filter region (a rect the width/height of aFilterRes) if * aFrameRect is null, or if the result is too large to be stored in an * nsIntRect. */ static nsIntRect MapFrameRectToFilterSpace(const nsRect* aRect, int32_t aAppUnitsPerCSSPx, const gfxMatrix& aFrameSpaceInCSSPxToFilterSpace, const gfxIntSize& aFilterRes) { nsIntRect rect(0, 0, aFilterRes.width, aFilterRes.height); if (aRect) { if (aRect->IsEmpty()) { return nsIntRect(); } gfxRect rectInCSSPx = nsLayoutUtils::RectToGfxRect(*aRect, aAppUnitsPerCSSPx); gfxRect rectInFilterSpace = aFrameSpaceInCSSPxToFilterSpace.TransformBounds(rectInCSSPx); rectInFilterSpace.RoundOut(); nsIntRect intRect; if (gfxUtils::GfxRectToIntRect(rectInFilterSpace, &intRect)) { rect = intRect; } } return rect; }
void CompositorOGL::BeginFrame(const Rect *aClipRectIn, const gfxMatrix& aTransform, const Rect& aRenderBounds, Rect *aClipRectOut, Rect *aRenderBoundsOut) { MOZ_ASSERT(!mFrameInProgress, "frame still in progress (should have called EndFrame or AbortFrame"); mVBOs.Reset(); mFrameInProgress = true; gfxRect rect; if (mUseExternalSurfaceSize) { rect = gfxRect(0, 0, mSurfaceSize.width, mSurfaceSize.height); } else { rect = gfxRect(aRenderBounds.x, aRenderBounds.y, aRenderBounds.width, aRenderBounds.height); // If render bounds is not updated explicitly, try to infer it from widget if (rect.width == 0 || rect.height == 0) { // FIXME/bug XXXXXX this races with rotation changes on the main // thread, and undoes all the care we take with layers txns being // sent atomically with rotation changes nsIntRect intRect; mWidget->GetClientBounds(intRect); rect = gfxRect(0, 0, intRect.width, intRect.height); } } rect = aTransform.TransformBounds(rect); if (aRenderBoundsOut) { *aRenderBoundsOut = Rect(rect.x, rect.y, rect.width, rect.height); } GLint width = rect.width; GLint height = rect.height; // We can't draw anything to something with no area // so just return if (width == 0 || height == 0) return; // If the widget size changed, we have to force a MakeCurrent // to make sure that GL sees the updated widget size. if (mWidgetSize.width != width || mWidgetSize.height != height) { MakeCurrent(ForceMakeCurrent); mWidgetSize.width = width; mWidgetSize.height = height; } else { MakeCurrent(); } #if MOZ_ANDROID_OMTC TexturePoolOGL::Fill(gl()); #endif mCurrentRenderTarget = CompositingRenderTargetOGL::RenderTargetForWindow(this, IntSize(width, height), aTransform); mCurrentRenderTarget->BindRenderTarget(); #ifdef DEBUG mWindowRenderTarget = mCurrentRenderTarget; #endif // Default blend function implements "OVER" mGLContext->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA, LOCAL_GL_ONE, LOCAL_GL_ONE); mGLContext->fEnable(LOCAL_GL_BLEND); if (!aClipRectIn) { mGLContext->fScissor(0, 0, width, height); if (aClipRectOut) { aClipRectOut->SetRect(0, 0, width, height); } } else { mGLContext->fScissor(aClipRectIn->x, aClipRectIn->y, aClipRectIn->width, aClipRectIn->height); } mGLContext->fEnable(LOCAL_GL_SCISSOR_TEST); // If the Android compositor is being used, this clear will be done in // DrawWindowUnderlay. Make sure the bits used here match up with those used // in mobile/android/base/gfx/LayerRenderer.java #ifndef MOZ_ANDROID_OMTC mGLContext->fClearColor(0.0, 0.0, 0.0, 0.0); mGLContext->fClear(LOCAL_GL_COLOR_BUFFER_BIT | LOCAL_GL_DEPTH_BUFFER_BIT); #endif }