void nsShmImage::Put(const mozilla::LayoutDeviceIntRegion& aRegion) { AutoTArray<xcb_rectangle_t, 32> xrects; xrects.SetCapacity(aRegion.GetNumRects()); for (auto iter = aRegion.RectIter(); !iter.Done(); iter.Next()) { const mozilla::LayoutDeviceIntRect &r = iter.Get(); xcb_rectangle_t xrect = { (short)r.x, (short)r.y, (unsigned short)r.width, (unsigned short)r.height }; xrects.AppendElement(xrect); } if (!mGC) { mGC = xcb_generate_id(mConnection); xcb_create_gc(mConnection, mGC, mWindow, 0, nullptr); } xcb_set_clip_rectangles(mConnection, XCB_CLIP_ORDERING_YX_BANDED, mGC, 0, 0, xrects.Length(), xrects.Elements()); if (mPixmap != XCB_NONE) { mLastRequest = xcb_copy_area_checked(mConnection, mPixmap, mWindow, mGC, 0, 0, 0, 0, mSize.width, mSize.height); } else { mLastRequest = xcb_shm_put_image_checked(mConnection, mWindow, mGC, mSize.width, mSize.height, 0, 0, mSize.width, mSize.height, 0, 0, mDepth, XCB_IMAGE_FORMAT_Z_PIXMAP, 0, mShmSeg, 0); } xcb_flush(mConnection); }
already_AddRefed<DrawTarget> nsShmImage::CreateDrawTarget(const mozilla::LayoutDeviceIntRegion& aRegion) { // Wait for any in-flight requests to complete. // Typically X clients would wait for a XShmCompletionEvent to be received, // but this works as it's sent immediately after the request is processed. xcb_generic_error_t* error; if (mLastRequest.sequence != XCB_NONE && (error = xcb_request_check(mConnection, mLastRequest))) { gShmAvailable = false; free(error); return nullptr; } // Due to bug 1205045, we must avoid making GTK calls off the main thread to query window size. // Instead we just track the largest offset within the image we are drawing to and grow the image // to accomodate it. Since usually the entire window is invalidated on the first paint to it, // this should grow the image to the necessary size quickly without many intermediate reallocations. IntRect bounds = aRegion.GetBounds().ToUnknownRect(); IntSize size(bounds.XMost(), bounds.YMost()); if (size.width > mSize.width || size.height > mSize.height) { DestroyImage(); if (!CreateImage(size)) { return nullptr; } } return gfxPlatform::GetPlatform()->CreateDrawTargetForData( reinterpret_cast<unsigned char*>(mShmAddr) + BytesPerPixel(mFormat) * (bounds.y * mSize.width + bounds.x), bounds.Size(), BytesPerPixel(mFormat) * mSize.width, mFormat); }
void nsShmImage::Put(const mozilla::LayoutDeviceIntRegion& aRegion) { AutoTArray<xcb_rectangle_t, 32> xrects; xrects.SetCapacity(aRegion.GetNumRects()); for (auto iter = aRegion.RectIter(); !iter.Done(); iter.Next()) { const mozilla::LayoutDeviceIntRect &r = iter.Get(); xcb_rectangle_t xrect = { (short)r.x, (short)r.y, (unsigned short)r.width, (unsigned short)r.height }; xrects.AppendElement(xrect); } if (!mGC) { mGC = xcb_generate_id(mConnection); xcb_create_gc(mConnection, mGC, mWindow, 0, nullptr); } xcb_set_clip_rectangles(mConnection, XCB_CLIP_ORDERING_YX_BANDED, mGC, 0, 0, xrects.Length(), xrects.Elements()); if (mPixmap != XCB_NONE) { mPutRequest = xcb_copy_area_checked(mConnection, mPixmap, mWindow, mGC, 0, 0, 0, 0, mSize.width, mSize.height); } else { mPutRequest = xcb_shm_put_image_checked(mConnection, mWindow, mGC, mSize.width, mSize.height, 0, 0, mSize.width, mSize.height, 0, 0, mDepth, XCB_IMAGE_FORMAT_Z_PIXMAP, 0, mShmSeg, 0); } // Send a request that returns a response so that we don't have to start a // sync in nsShmImage::CreateDrawTarget to retrieve the result of mPutRequest. mSyncRequest = xcb_get_input_focus(mConnection); mRequestPending = true; xcb_flush(mConnection); }