void nsShmImage::Put(Display* aDisplay, Drawable aWindow, const LayoutDeviceIntRegion& aRegion) { GC gc = XCreateGC(aDisplay, aWindow, 0, nullptr); LayoutDeviceIntRegion bounded; bounded.And(aRegion, LayoutDeviceIntRect(0, 0, mImage->width, mImage->height)); LayoutDeviceIntRegion::RectIterator iter(bounded); for (const LayoutDeviceIntRect *r = iter.Next(); r; r = iter.Next()) { XShmPutImage(aDisplay, aWindow, gc, mImage, r->x, r->y, r->x, r->y, r->width, r->height, False); } XFreeGC(aDisplay, gc); // FIXME/bug 597336: we need to ensure that the shm image isn't // scribbled over before all its pending XShmPutImage()s complete. // However, XSync() is an unnecessarily heavyweight // synchronization mechanism; other options are possible. If this // XSync is shown to hurt responsiveness, we need to explore the // other options. XSync(aDisplay, False); }
nsresult PuppetWidget::Paint() { MOZ_ASSERT(!mDirtyRegion.IsEmpty(), "paint event logic messed up"); if (!GetCurrentWidgetListener()) return NS_OK; LayoutDeviceIntRegion region = mDirtyRegion; // reset repaint tracking mDirtyRegion.SetEmpty(); mPaintTask.Revoke(); RefPtr<PuppetWidget> strongThis(this); GetCurrentWidgetListener()->WillPaintWindow(this); if (GetCurrentWidgetListener()) { #ifdef DEBUG debug_DumpPaintEvent(stderr, this, region.ToUnknownRegion(), "PuppetWidget", 0); #endif if (mozilla::layers::LayersBackend::LAYERS_CLIENT == mLayerManager->GetBackendType()) { // Do nothing, the compositor will handle drawing if (mTabChild) { mTabChild->NotifyPainted(); } } else if (mozilla::layers::LayersBackend::LAYERS_BASIC == mLayerManager->GetBackendType()) { RefPtr<gfxContext> ctx = gfxContext::CreateOrNull(mDrawTarget); if (!ctx) { gfxDevCrash(LogReason::InvalidContext) << "PuppetWidget context problem " << gfx::hexa(mDrawTarget); return NS_ERROR_FAILURE; } ctx->Rectangle(gfxRect(0,0,0,0)); ctx->Clip(); AutoLayerManagerSetup setupLayerManager(this, ctx, BufferMode::BUFFER_NONE); GetCurrentWidgetListener()->PaintWindow(this, region); if (mTabChild) { mTabChild->NotifyPainted(); } } } if (GetCurrentWidgetListener()) { GetCurrentWidgetListener()->DidPaintWindow(); } return NS_OK; }
static void CalculatePluginClip(const LayoutDeviceIntRect& aBounds, const nsTArray<LayoutDeviceIntRect>& aPluginClipRects, const LayoutDeviceIntPoint& aContentOffset, const LayoutDeviceIntRegion& aParentLayerVisibleRegion, nsTArray<LayoutDeviceIntRect>& aResult, LayoutDeviceIntRect& aVisibleBounds, bool& aPluginIsVisible) { aPluginIsVisible = true; LayoutDeviceIntRegion contentVisibleRegion; // aPluginClipRects (plugin widget origin) - contains *visible* rects for (uint32_t idx = 0; idx < aPluginClipRects.Length(); idx++) { LayoutDeviceIntRect rect = aPluginClipRects[idx]; // shift to content origin rect.MoveBy(aBounds.x, aBounds.y); // accumulate visible rects contentVisibleRegion.OrWith(rect); } // apply layers clip (window origin) LayoutDeviceIntRegion region = aParentLayerVisibleRegion; region.MoveBy(-aContentOffset.x, -aContentOffset.y); contentVisibleRegion.AndWith(region); if (contentVisibleRegion.IsEmpty()) { aPluginIsVisible = false; return; } // shift to plugin widget origin contentVisibleRegion.MoveBy(-aBounds.x, -aBounds.y); for (auto iter = contentVisibleRegion.RectIter(); !iter.Done(); iter.Next()) { const LayoutDeviceIntRect& rect = iter.Get(); aResult.AppendElement(rect); aVisibleBounds.UnionRect(aVisibleBounds, rect); } }
static void InvalidateRegion(nsIWidget* aWidget, const LayoutDeviceIntRegion& aRegion) { for (auto iter = aRegion.RectIter(); !iter.Done(); iter.Next()) { aWidget->Invalidate(iter.Get()); } }
nsresult PuppetWidget::Paint() { MOZ_ASSERT(!mDirtyRegion.IsEmpty(), "paint event logic messed up"); if (!GetCurrentWidgetListener()) return NS_OK; LayoutDeviceIntRegion region = mDirtyRegion; // reset repaint tracking mDirtyRegion.SetEmpty(); mPaintTask.Revoke(); GetCurrentWidgetListener()->WillPaintWindow(this); if (GetCurrentWidgetListener()) { #ifdef DEBUG debug_DumpPaintEvent(stderr, this, region.ToUnknownRegion(), nsAutoCString("PuppetWidget"), 0); #endif if (mozilla::layers::LayersBackend::LAYERS_CLIENT == mLayerManager->GetBackendType()) { // Do nothing, the compositor will handle drawing if (mTabChild) { mTabChild->NotifyPainted(); } } else { RefPtr<gfxContext> ctx = new gfxContext(mDrawTarget); ctx->Rectangle(gfxRect(0,0,0,0)); ctx->Clip(); AutoLayerManagerSetup setupLayerManager(this, ctx, BufferMode::BUFFER_NONE); GetCurrentWidgetListener()->PaintWindow(this, region); if (mTabChild) { mTabChild->NotifyPainted(); } } } if (GetCurrentWidgetListener()) { GetCurrentWidgetListener()->DidPaintWindow(); } return NS_OK; }
bool nsViewManager::PaintWindow(nsIWidget* aWidget, LayoutDeviceIntRegion aRegion) { if (!aWidget || !mContext) return false; NS_ASSERTION(IsPaintingAllowed(), "shouldn't be receiving paint events while painting is disallowed!"); // Get the view pointer here since NS_WILL_PAINT might have // destroyed it during CallWillPaintOnObservers (bug 378273). nsView* view = nsView::GetViewFor(aWidget); if (view && !aRegion.IsEmpty()) { Refresh(view, aRegion); } return true; }
/** aRegion is given in device coordinates!! aContext may be null, in which case layers should be used for rendering. */ void nsViewManager::Refresh(nsView* aView, const LayoutDeviceIntRegion& aRegion) { NS_ASSERTION(aView->GetViewManager() == this, "wrong view manager"); if (mPresShell && mPresShell->IsNeverPainting()) { return; } // damageRegion is the damaged area, in twips, relative to the view origin nsRegion damageRegion = aRegion.ToAppUnits(AppUnitsPerDevPixel()); // move region from widget coordinates into view coordinates damageRegion.MoveBy(-aView->ViewToWidgetOffset()); if (damageRegion.IsEmpty()) { #ifdef DEBUG_roc nsRect viewRect = aView->GetDimensions(); nsRect damageRect = damageRegion.GetBounds(); printf_stderr("XXX Damage rectangle (%d,%d,%d,%d) does not intersect the widget's view (%d,%d,%d,%d)!\n", damageRect.x, damageRect.y, damageRect.width, damageRect.height, viewRect.x, viewRect.y, viewRect.width, viewRect.height); #endif return; } nsIWidget *widget = aView->GetWidget(); if (!widget) { return; } NS_ASSERTION(!IsPainting(), "recursive painting not permitted"); if (IsPainting()) { RootViewManager()->mRecursiveRefreshPending = true; return; } { nsAutoScriptBlocker scriptBlocker; SetPainting(true); NS_ASSERTION(GetDisplayRootFor(aView) == aView, "Widgets that we paint must all be display roots"); if (mPresShell) { #ifdef MOZ_DUMP_PAINTING if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) { printf_stderr("--COMPOSITE-- %p\n", mPresShell); } #endif uint32_t paintFlags = nsIPresShell::PAINT_COMPOSITE; LayerManager *manager = widget->GetLayerManager(); if (!manager->NeedsWidgetInvalidation()) { manager->FlushRendering(); } else { mPresShell->Paint(aView, damageRegion, paintFlags); } #ifdef MOZ_DUMP_PAINTING if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) { printf_stderr("--ENDCOMPOSITE--\n"); } #endif mozilla::StartupTimeline::RecordOnce(mozilla::StartupTimeline::FIRST_PAINT); } SetPainting(false); } if (RootViewManager()->mRecursiveRefreshPending) { RootViewManager()->mRecursiveRefreshPending = false; InvalidateAllViews(); } }
void BasicCompositor::BeginFrame(const nsIntRegion& aInvalidRegion, const gfx::Rect *aClipRectIn, const gfx::Rect& aRenderBounds, gfx::Rect *aClipRectOut /* = nullptr */, gfx::Rect *aRenderBoundsOut /* = nullptr */) { LayoutDeviceIntRect intRect(LayoutDeviceIntPoint(), mWidget->GetClientSize()); Rect rect = Rect(0, 0, intRect.width, intRect.height); LayoutDeviceIntRegion invalidRegionSafe; if (mDidExternalComposition) { // We do not know rendered region during external composition, just redraw // whole widget. invalidRegionSafe = intRect; mDidExternalComposition = false; } else { // Sometimes the invalid region is larger than we want to draw. invalidRegionSafe.And( LayoutDeviceIntRegion::FromUnknownRegion(aInvalidRegion), intRect); } mInvalidRegion = invalidRegionSafe; mInvalidRect = mInvalidRegion.GetBounds(); if (aRenderBoundsOut) { *aRenderBoundsOut = Rect(); } BufferMode bufferMode = BufferMode::BUFFERED; if (mTarget) { // If we have a copy target, then we don't have a widget-provided mDrawTarget (currently). Use a dummy // placeholder so that CreateRenderTarget() works. mDrawTarget = gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget(); } else { // StartRemoteDrawingInRegion can mutate mInvalidRegion. mDrawTarget = mWidget->StartRemoteDrawingInRegion(mInvalidRegion, &bufferMode); if (!mDrawTarget) { return; } mInvalidRect = mInvalidRegion.GetBounds(); if (mInvalidRect.IsEmpty()) { mWidget->EndRemoteDrawingInRegion(mDrawTarget, mInvalidRegion); return; } } if (!mDrawTarget || mInvalidRect.IsEmpty()) { return; } // Setup an intermediate render target to buffer all compositing. We will // copy this into mDrawTarget (the widget), and/or mTarget in EndFrame() RefPtr<CompositingRenderTarget> target = CreateRenderTargetForWindow(mInvalidRect.ToUnknownRect(), INIT_MODE_CLEAR, bufferMode); if (!target) { if (!mTarget) { mWidget->EndRemoteDrawingInRegion(mDrawTarget, mInvalidRegion); } return; } SetRenderTarget(target); // We only allocate a surface sized to the invalidated region, so we need to // translate future coordinates. mRenderTarget->mDrawTarget->SetTransform(Matrix::Translation(-mRenderTarget->GetOrigin())); gfxUtils::ClipToRegion(mRenderTarget->mDrawTarget, mInvalidRegion.ToUnknownRegion()); if (aRenderBoundsOut) { *aRenderBoundsOut = rect; } if (aClipRectIn) { mRenderTarget->mDrawTarget->PushClipRect(*aClipRectIn); } else { mRenderTarget->mDrawTarget->PushClipRect(rect); if (aClipRectOut) { *aClipRectOut = rect; } } }