зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1565904. Move the blob metadata from image space to an absolute space. r=nical
This is a follow up to bug 1564655. It removes the offset from ToDeviceSpace and thus moves item rects into absolute space which is now the same coordinate space as the recordings are in. We also adjust item bounds for fallback blobs. Some additional changes that need happen to: 1. In Moz2DImageRenderer we can reunify the origin because the recording and the recording metadata return to using the same coordinate space. 2. The calls to PushLayer can return to using the item bounds which are now in the same coordinate space. 3. This dirty rect which remains in images space is adjusted during merging. Differential Revision: https://phabricator.services.mozilla.com/D38015 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
fb2fb2496b
Коммит
81db073a18
|
@ -305,8 +305,7 @@ struct DIGroup {
|
|||
ScrollableLayerGuid::ViewID mScrollId;
|
||||
LayerPoint mResidualOffset;
|
||||
LayerIntRect mLayerBounds;
|
||||
// The current bounds of the blob image, relative to
|
||||
// the top-left of the mLayerBounds.
|
||||
// The current bounds of the blob image
|
||||
IntRect mImageBounds;
|
||||
// mImageBounds clipped to the container/parent of the
|
||||
// current item being processed.
|
||||
|
@ -348,16 +347,14 @@ struct DIGroup {
|
|||
}
|
||||
|
||||
static IntRect ToDeviceSpace(nsRect aBounds, Matrix& aMatrix,
|
||||
int32_t aAppUnitsPerDevPixel,
|
||||
LayerIntPoint aOffset) {
|
||||
int32_t aAppUnitsPerDevPixel) {
|
||||
// RoundedOut can convert empty rectangles to non-empty ones
|
||||
// so special case them here
|
||||
if (aBounds.IsEmpty()) {
|
||||
return IntRect();
|
||||
}
|
||||
return RoundedOut(aMatrix.TransformBounds(ToRect(
|
||||
nsLayoutUtils::RectToGfxRect(aBounds, aAppUnitsPerDevPixel)))) -
|
||||
aOffset.ToUnknownPoint();
|
||||
return RoundedOut(aMatrix.TransformBounds(
|
||||
ToRect(nsLayoutUtils::RectToGfxRect(aBounds, aAppUnitsPerDevPixel))));
|
||||
}
|
||||
|
||||
void ComputeGeometryChange(nsDisplayItem* aItem, BlobItemData* aData,
|
||||
|
@ -372,14 +369,12 @@ struct DIGroup {
|
|||
int32_t appUnitsPerDevPixel =
|
||||
aItem->Frame()->PresContext()->AppUnitsPerDevPixel();
|
||||
MOZ_RELEASE_ASSERT(mAppUnitsPerDevPixel == appUnitsPerDevPixel);
|
||||
LayoutDeviceRect bounds =
|
||||
LayoutDeviceRect::FromAppUnits(mGroupBounds, appUnitsPerDevPixel);
|
||||
LayoutDeviceIntPoint offset = RoundedToInt(bounds.TopLeft());
|
||||
GP("\n");
|
||||
GP("CGC offset %d %d\n", offset.x, offset.y);
|
||||
GP("clippedImageRect %d %d %d %d\n", mClippedImageBounds.x,
|
||||
mClippedImageBounds.y, mClippedImageBounds.width,
|
||||
mClippedImageBounds.height);
|
||||
LayerIntSize size = mLayerBounds.Size();
|
||||
GP("imageSize: %d %d\n", size.width, size.height);
|
||||
/*if (aItem->IsReused() && aData->mGeometry) {
|
||||
return;
|
||||
}*/
|
||||
|
@ -397,12 +392,12 @@ struct DIGroup {
|
|||
geometry->ComputeInvalidationRegion());
|
||||
aData->mGeometry = std::move(geometry);
|
||||
|
||||
IntRect transformedRect = ToDeviceSpace(
|
||||
clippedBounds, aMatrix, appUnitsPerDevPixel, mLayerBounds.TopLeft());
|
||||
IntRect transformedRect =
|
||||
ToDeviceSpace(clippedBounds, aMatrix, appUnitsPerDevPixel);
|
||||
aData->mRect = transformedRect.Intersect(mClippedImageBounds);
|
||||
GP("CGC %s %d %d %d %d\n", aItem->Name(), clippedBounds.x,
|
||||
clippedBounds.y, clippedBounds.width, clippedBounds.height);
|
||||
GP("%d %d, %f %f\n", mLayerBounds.TopLeft().x, mLayerBounds.TopLeft().y,
|
||||
GP("%d %d, %f %f\n", mPaintRect.TopLeft().x, mPaintRect.TopLeft().y,
|
||||
aMatrix._11, aMatrix._22);
|
||||
GP("mRect %d %d %d %d\n", aData->mRect.x, aData->mRect.y,
|
||||
aData->mRect.width, aData->mRect.height);
|
||||
|
@ -411,7 +406,6 @@ struct DIGroup {
|
|||
} else if (aData->mInvalid ||
|
||||
/* XXX: handle image load invalidation */ (
|
||||
aItem->IsInvalid(invalid) && invalid.IsEmpty())) {
|
||||
MOZ_RELEASE_ASSERT(mLayerBounds.TopLeft() == aData->mGroupOffset);
|
||||
UniquePtr<nsDisplayItemGeometry> geometry(
|
||||
aItem->AllocateGeometry(aBuilder));
|
||||
nsRect clippedBounds = clip.ApplyNonRoundedIntersection(
|
||||
|
@ -427,15 +421,14 @@ struct DIGroup {
|
|||
// matrix?
|
||||
// XXX: TransformBounds is expensive. We should avoid doing it if we have
|
||||
// no transform
|
||||
IntRect transformedRect = ToDeviceSpace(
|
||||
clippedBounds, aMatrix, appUnitsPerDevPixel, mLayerBounds.TopLeft());
|
||||
IntRect transformedRect =
|
||||
ToDeviceSpace(clippedBounds, aMatrix, appUnitsPerDevPixel);
|
||||
aData->mRect = transformedRect.Intersect(mClippedImageBounds);
|
||||
InvalidateRect(aData->mRect);
|
||||
GP("new rect: %d %d %d %d\n", aData->mRect.x, aData->mRect.y,
|
||||
aData->mRect.width, aData->mRect.height);
|
||||
aData->mInvalid = true;
|
||||
} else {
|
||||
MOZ_RELEASE_ASSERT(mLayerBounds.TopLeft() == aData->mGroupOffset);
|
||||
GP("else invalidate: %s\n", aItem->Name());
|
||||
nsRegion combined;
|
||||
// this includes situations like reflow changing the position
|
||||
|
@ -456,8 +449,7 @@ struct DIGroup {
|
|||
nsRect clippedBounds = clip.ApplyNonRoundedIntersection(
|
||||
aData->mGeometry->ComputeInvalidationRegion());
|
||||
IntRect transformedRect =
|
||||
ToDeviceSpace(clippedBounds, aMatrix, appUnitsPerDevPixel,
|
||||
mLayerBounds.TopLeft());
|
||||
ToDeviceSpace(clippedBounds, aMatrix, appUnitsPerDevPixel);
|
||||
aData->mRect = transformedRect.Intersect(mClippedImageBounds);
|
||||
InvalidateRect(aData->mRect);
|
||||
|
||||
|
@ -487,8 +479,7 @@ struct DIGroup {
|
|||
nsRect clippedBounds = clip.ApplyNonRoundedIntersection(
|
||||
aData->mGeometry->ComputeInvalidationRegion());
|
||||
IntRect transformedRect =
|
||||
ToDeviceSpace(clippedBounds, aMatrix, appUnitsPerDevPixel,
|
||||
mLayerBounds.TopLeft());
|
||||
ToDeviceSpace(clippedBounds, aMatrix, appUnitsPerDevPixel);
|
||||
InvalidateRect(aData->mRect.Intersect(mImageBounds));
|
||||
aData->mRect = transformedRect.Intersect(mClippedImageBounds);
|
||||
InvalidateRect(aData->mRect);
|
||||
|
@ -517,8 +508,7 @@ struct DIGroup {
|
|||
nsRect clippedBounds = clip.ApplyNonRoundedIntersection(
|
||||
aData->mGeometry->ComputeInvalidationRegion());
|
||||
IntRect transformedRect =
|
||||
ToDeviceSpace(clippedBounds, aMatrix, appUnitsPerDevPixel,
|
||||
mLayerBounds.TopLeft());
|
||||
ToDeviceSpace(clippedBounds, aMatrix, appUnitsPerDevPixel);
|
||||
InvalidateRect(aData->mRect.Intersect(mImageBounds));
|
||||
aData->mRect = transformedRect.Intersect(mClippedImageBounds);
|
||||
InvalidateRect(aData->mRect);
|
||||
|
@ -536,8 +526,7 @@ struct DIGroup {
|
|||
geometry->ComputeInvalidationRegion());
|
||||
aData->mGeometry = std::move(geometry);
|
||||
IntRect transformedRect =
|
||||
ToDeviceSpace(clippedBounds, aMatrix, appUnitsPerDevPixel,
|
||||
mLayerBounds.TopLeft());
|
||||
ToDeviceSpace(clippedBounds, aMatrix, appUnitsPerDevPixel);
|
||||
InvalidateRect(aData->mRect.Intersect(mImageBounds));
|
||||
aData->mRect = transformedRect.Intersect(mClippedImageBounds);
|
||||
InvalidateRect(aData->mRect);
|
||||
|
@ -547,8 +536,7 @@ struct DIGroup {
|
|||
nsRect clippedBounds = clip.ApplyNonRoundedIntersection(
|
||||
geometry->ComputeInvalidationRegion());
|
||||
IntRect transformedRect =
|
||||
ToDeviceSpace(clippedBounds, aMatrix, appUnitsPerDevPixel,
|
||||
mLayerBounds.TopLeft());
|
||||
ToDeviceSpace(clippedBounds, aMatrix, appUnitsPerDevPixel);
|
||||
// The invalid rect should contain the old rect and the new rect
|
||||
// but may not because the parent may have been removed.
|
||||
InvalidateRect(aData->mRect);
|
||||
|
@ -560,8 +548,7 @@ struct DIGroup {
|
|||
nsRect clippedBounds = clip.ApplyNonRoundedIntersection(
|
||||
geometry->ComputeInvalidationRegion());
|
||||
IntRect transformedRect =
|
||||
ToDeviceSpace(clippedBounds, aMatrix, appUnitsPerDevPixel,
|
||||
mLayerBounds.TopLeft());
|
||||
ToDeviceSpace(clippedBounds, aMatrix, appUnitsPerDevPixel);
|
||||
auto rect = transformedRect.Intersect(mClippedImageBounds);
|
||||
GP("Layer NoChange: %s %d %d %d %d\n", aItem->Name(),
|
||||
aData->mRect.x, aData->mRect.y, aData->mRect.XMost(),
|
||||
|
@ -575,8 +562,7 @@ struct DIGroup {
|
|||
nsRect clippedBounds = clip.ApplyNonRoundedIntersection(
|
||||
geometry->ComputeInvalidationRegion());
|
||||
IntRect transformedRect =
|
||||
ToDeviceSpace(clippedBounds, aMatrix, appUnitsPerDevPixel,
|
||||
mLayerBounds.TopLeft());
|
||||
ToDeviceSpace(clippedBounds, aMatrix, appUnitsPerDevPixel);
|
||||
// The invalid rect should contain the old rect and the new rect
|
||||
// but may not because the parent may have been removed.
|
||||
InvalidateRect(aData->mRect);
|
||||
|
@ -590,18 +576,17 @@ struct DIGroup {
|
|||
nsRect clippedBounds = clip.ApplyNonRoundedIntersection(
|
||||
geometry->ComputeInvalidationRegion());
|
||||
IntRect transformedRect =
|
||||
ToDeviceSpace(clippedBounds, aMatrix, appUnitsPerDevPixel,
|
||||
mLayerBounds.TopLeft());
|
||||
ToDeviceSpace(clippedBounds, aMatrix, appUnitsPerDevPixel);
|
||||
auto rect = transformedRect.Intersect(mClippedImageBounds);
|
||||
GP("NoChange: %s %d %d %d %d\n", aItem->Name(), aData->mRect.x,
|
||||
aData->mRect.y, aData->mRect.XMost(), aData->mRect.YMost());
|
||||
GP("NoChange: %s %d %d %d %d vs %d %d %d %d\n", aItem->Name(), rect.x,
|
||||
rect.y, rect.XMost(), rect.YMost(), aData->mRect.x, aData->mRect.y,
|
||||
aData->mRect.XMost(), aData->mRect.YMost());
|
||||
MOZ_RELEASE_ASSERT(rect.IsEqualEdges(aData->mRect));
|
||||
}
|
||||
}
|
||||
}
|
||||
aData->mClip = clip;
|
||||
aData->mMatrix = aMatrix;
|
||||
aData->mGroupOffset = mLayerBounds.TopLeft();
|
||||
aData->mImageRect = mClippedImageBounds;
|
||||
GP("post mInvalidRect: %d %d %d %d\n", mInvalidRect.x, mInvalidRect.y,
|
||||
mInvalidRect.width, mInvalidRect.height);
|
||||
|
@ -630,22 +615,25 @@ struct DIGroup {
|
|||
}
|
||||
}
|
||||
|
||||
IntSize dtSize = mLayerBounds.Size().ToUnknownSize();
|
||||
// The actual display item's size shouldn't have the scale factored in
|
||||
// Round the bounds out to leave space for unsnapped content
|
||||
LayoutDeviceToLayerScale2D scale(mScale.width, mScale.height);
|
||||
LayerIntRect layerBounds = mLayerBounds;
|
||||
IntSize dtSize = layerBounds.Size().ToUnknownSize();
|
||||
LayoutDeviceRect bounds =
|
||||
(LayerRect(layerBounds) - mResidualOffset) / scale;
|
||||
LayoutDeviceRect itemBounds =
|
||||
(LayerRect(mLayerBounds) - mResidualOffset) / scale;
|
||||
|
||||
if (mInvalidRect.IsEmpty()) {
|
||||
GP("Not repainting group because it's empty\n");
|
||||
GP("End EndGroup\n");
|
||||
if (mKey) {
|
||||
// Although the contents haven't changed, the visible area *may* have,
|
||||
// so request it be updated unconditionally (wr should be able to easily
|
||||
// detect if this is a no-op on its side, if that matters)
|
||||
aResources.SetBlobImageVisibleArea(
|
||||
mKey.value().second(),
|
||||
ViewAs<ImagePixel>(mPaintRect,
|
||||
PixelCastJustification::LayerIsImage));
|
||||
PushImage(aBuilder, bounds);
|
||||
PushImage(aBuilder, itemBounds);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -681,7 +669,9 @@ struct DIGroup {
|
|||
recorder, dummyDt, mLayerBounds.ToUnknownRect());
|
||||
// Setup the gfxContext
|
||||
RefPtr<gfxContext> context = gfxContext::CreateOrNull(dt);
|
||||
context->SetMatrix(Matrix::Scaling(mScale.width, mScale.height).PostTranslate(mResidualOffset.x, mResidualOffset.y));
|
||||
context->SetMatrix(
|
||||
Matrix::Scaling(mScale.width, mScale.height)
|
||||
.PostTranslate(mResidualOffset.x, mResidualOffset.y));
|
||||
|
||||
GP("mInvalidRect: %d %d %d %d\n", mInvalidRect.x, mInvalidRect.y,
|
||||
mInvalidRect.width, mInvalidRect.height);
|
||||
|
@ -728,7 +718,13 @@ struct DIGroup {
|
|||
mKey = Some(MakePair(aBuilder.GetRenderRoot(), key));
|
||||
} else {
|
||||
wr::ImageDescriptor descriptor(dtSize, 0, dt->GetFormat(), opacity);
|
||||
auto bottomRight = mInvalidRect.BottomRight();
|
||||
|
||||
// Convert mInvalidRect to image space by subtracting the corner of the
|
||||
// image bounds
|
||||
auto dirtyRect = ViewAs<ImagePixel>(
|
||||
mInvalidRect - mLayerBounds.ToUnknownRect().TopLeft());
|
||||
|
||||
auto bottomRight = dirtyRect.BottomRight();
|
||||
GP("check invalid %d %d - %d %d\n", bottomRight.x, bottomRight.y,
|
||||
dtSize.width, dtSize.height);
|
||||
MOZ_RELEASE_ASSERT(bottomRight.x <= dtSize.width &&
|
||||
|
@ -739,7 +735,7 @@ struct DIGroup {
|
|||
mKey.value().second(), descriptor, bytes,
|
||||
ViewAs<ImagePixel>(mPaintRect,
|
||||
PixelCastJustification::LayerIsImage),
|
||||
ViewAs<ImagePixel>(mInvalidRect))) {
|
||||
dirtyRect)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -748,7 +744,7 @@ struct DIGroup {
|
|||
aResources.SetBlobImageVisibleArea(
|
||||
mKey.value().second(),
|
||||
ViewAs<ImagePixel>(mPaintRect, PixelCastJustification::LayerIsImage));
|
||||
PushImage(aBuilder, bounds);
|
||||
PushImage(aBuilder, itemBounds);
|
||||
GP("End EndGroup\n\n");
|
||||
}
|
||||
|
||||
|
@ -965,7 +961,7 @@ void Grouper::PaintContainerItem(DIGroup* aGroup, nsDisplayItem* aItem,
|
|||
|
||||
aContext->GetDrawTarget()->PushLayer(false, opacityItem->GetOpacity(),
|
||||
nullptr, mozilla::gfx::Matrix(),
|
||||
aItemBounds + aGroup->mLayerBounds.ToUnknownRect().TopLeft());
|
||||
aItemBounds);
|
||||
GP("beginGroup %s %p-%d\n", aItem->Name(), aItem->Frame(),
|
||||
aItem->GetPerFrameKey());
|
||||
aContext->GetDrawTarget()->FlushItem(aItemBounds);
|
||||
|
@ -981,7 +977,7 @@ void Grouper::PaintContainerItem(DIGroup* aGroup, nsDisplayItem* aItem,
|
|||
auto blendItem = static_cast<nsDisplayBlendMode*>(aItem);
|
||||
auto blendMode = blendItem->BlendMode();
|
||||
aContext->GetDrawTarget()->PushLayerWithBlend(
|
||||
false, 1.0, nullptr, mozilla::gfx::Matrix(), aItemBounds + aGroup->mLayerBounds.ToUnknownRect().TopLeft(), false,
|
||||
false, 1.0, nullptr, mozilla::gfx::Matrix(), aItemBounds, false,
|
||||
blendMode);
|
||||
GP("beginGroup %s %p-%d\n", aItem->Name(), aItem->Frame(),
|
||||
aItem->GetPerFrameKey());
|
||||
|
@ -996,7 +992,7 @@ void Grouper::PaintContainerItem(DIGroup* aGroup, nsDisplayItem* aItem,
|
|||
}
|
||||
case DisplayItemType::TYPE_BLEND_CONTAINER: {
|
||||
aContext->GetDrawTarget()->PushLayer(false, 1.0, nullptr,
|
||||
mozilla::gfx::Matrix(), aItemBounds + aGroup->mLayerBounds.ToUnknownRect().TopLeft());
|
||||
mozilla::gfx::Matrix(), aItemBounds);
|
||||
GP("beginGroup %s %p-%d\n", aItem->Name(), aItem->Frame(),
|
||||
aItem->GetPerFrameKey());
|
||||
aContext->GetDrawTarget()->FlushItem(aItemBounds);
|
||||
|
@ -1518,8 +1514,7 @@ void WebRenderCommandBuilder::DoGroupingForDisplayList(
|
|||
group.mLayerBounds = LayerIntRect::FromUnknownRect(
|
||||
ScaleToOutsidePixelsOffset(group.mGroupBounds, scale.width, scale.height,
|
||||
group.mAppUnitsPerDevPixel, residualOffset));
|
||||
group.mImageBounds =
|
||||
IntRect(0, 0, group.mLayerBounds.width, group.mLayerBounds.height);
|
||||
group.mImageBounds = group.mLayerBounds.ToUnknownRect();
|
||||
group.mClippedImageBounds = group.mImageBounds;
|
||||
|
||||
const nsRect& untransformedPaintRect =
|
||||
|
@ -1530,10 +1525,7 @@ void WebRenderCommandBuilder::DoGroupingForDisplayList(
|
|||
untransformedPaintRect, scale.width, scale.height,
|
||||
group.mAppUnitsPerDevPixel, residualOffset))
|
||||
.Intersect(group.mLayerBounds);
|
||||
// XXX: Make the paint rect relative to the layer bounds. After we include
|
||||
// mLayerBounds.TopLeft() in the blob image we want to stop doing this
|
||||
// adjustment.
|
||||
group.mPaintRect = group.mPaintRect - group.mLayerBounds.TopLeft();
|
||||
|
||||
g.mTransform = Matrix::Scaling(scale.width, scale.height)
|
||||
.PostTranslate(residualOffset.x, residualOffset.y);
|
||||
group.mScale = scale;
|
||||
|
@ -2292,7 +2284,7 @@ WebRenderCommandBuilder::GenerateFallbackData(
|
|||
isInvalidated = true;
|
||||
}
|
||||
}
|
||||
recorder->FlushItem(IntRect({0, 0}, dtSize.ToUnknownSize()));
|
||||
recorder->FlushItem(dtRect.ToUnknownRect());
|
||||
recorder->Finish();
|
||||
|
||||
if (!validFonts) {
|
||||
|
|
|
@ -369,10 +369,9 @@ static bool Moz2DRenderCallback(const Range<const uint8_t> aBlob,
|
|||
// them because of CompositorHitTestInfo and merging.
|
||||
size_t footerSize = sizeof(size_t) + sizeof(IntPoint);
|
||||
MOZ_RELEASE_ASSERT(aBlob.length() >= footerSize);
|
||||
size_t indexOffset =
|
||||
ConvertFromBytes<size_t>(aBlob.end().get() - footerSize);
|
||||
IntPoint recordingOrigin =
|
||||
ConvertFromBytes<IntPoint>(aBlob.end().get() - footerSize + sizeof(size_t));
|
||||
size_t indexOffset = ConvertFromBytes<size_t>(aBlob.end().get() - footerSize);
|
||||
IntPoint origin = ConvertFromBytes<IntPoint>(aBlob.end().get() - footerSize +
|
||||
sizeof(size_t));
|
||||
// Apply the visibleRect's offset to make (0, 0) in the DT correspond to (0,
|
||||
// 0) in the texture
|
||||
|
||||
|
@ -380,20 +379,17 @@ static bool Moz2DRenderCallback(const Range<const uint8_t> aBlob,
|
|||
Reader reader(aBlob.begin().get() + indexOffset,
|
||||
aBlob.length() - footerSize - indexOffset);
|
||||
|
||||
IntPoint origin;
|
||||
if (aTileOffset) {
|
||||
origin +=
|
||||
gfx::IntPoint(aTileOffset->x * *aTileSize, aTileOffset->y * *aTileSize);
|
||||
}
|
||||
dt = gfx::Factory::CreateOffsetDrawTarget(dt, recordingOrigin + origin);
|
||||
dt = gfx::Factory::CreateOffsetDrawTarget(dt, origin);
|
||||
|
||||
auto bounds = gfx::IntRect(origin, aSize);
|
||||
|
||||
if (aDirtyRect) {
|
||||
Rect dirty(aDirtyRect->origin.x + recordingOrigin.x,
|
||||
aDirtyRect->origin.y + recordingOrigin.y,
|
||||
aDirtyRect->size.width,
|
||||
aDirtyRect->size.height);
|
||||
Rect dirty(aDirtyRect->origin.x, aDirtyRect->origin.y,
|
||||
aDirtyRect->size.width, aDirtyRect->size.height);
|
||||
dt->PushClipRect(dirty);
|
||||
bounds = bounds.Intersect(
|
||||
IntRect(aDirtyRect->origin.x, aDirtyRect->origin.y,
|
||||
|
|
|
@ -380,7 +380,7 @@ impl<'a> CachedReader<'a> {
|
|||
/// the first not-yet-copied item with those bounds in the old list and copy that.
|
||||
/// Any items found in the old list but not the new one can be safely assumed to
|
||||
/// have been deleted.
|
||||
fn merge_blob_images(old_buf: &[u8], new_buf: &[u8], dirty_rect: Box2d) -> Vec<u8> {
|
||||
fn merge_blob_images(old_buf: &[u8], new_buf: &[u8], mut dirty_rect: Box2d) -> Vec<u8> {
|
||||
|
||||
let mut result = BlobWriter::new();
|
||||
dlog!("dirty rect: {:?}", dirty_rect);
|
||||
|
@ -395,6 +395,11 @@ fn merge_blob_images(old_buf: &[u8], new_buf: &[u8], dirty_rect: Box2d) -> Vec<u
|
|||
// we currently only support merging blobs that have the same origin
|
||||
assert_eq!(old_reader.reader.origin, new_reader.origin);
|
||||
|
||||
dirty_rect.x1 += new_reader.origin.x;
|
||||
dirty_rect.y1 += new_reader.origin.y;
|
||||
dirty_rect.x2 += new_reader.origin.x;
|
||||
dirty_rect.y2 += new_reader.origin.y;
|
||||
|
||||
// Loop over both new and old entries merging them.
|
||||
// Both new and old must have the same number of entries that
|
||||
// overlap but are not contained by the dirty rect, and they
|
||||
|
|
Загрузка…
Ссылка в новой задаче