зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1254030 - Scale drag image by APZ zoom. r=botond
When rasterizing the drag image, we pick up the resolution from ancestor presShells and ensure that the drag image is rasterized at that resolution, with appropriate limits for memory usage. Differential Revision: https://phabricator.services.mozilla.com/D77435
This commit is contained in:
Родитель
f474d273b1
Коммит
d807edde6f
|
@ -231,6 +231,11 @@ struct RangePaintInfo {
|
|||
// offset of builder's reference frame to the root frame
|
||||
nsPoint mRootOffset;
|
||||
|
||||
// Resolution at which the items are normally painted. So if we're painting
|
||||
// these items in a range separately from the "full display list", we may want
|
||||
// to paint them at this resolution.
|
||||
float mResolution = 1.0;
|
||||
|
||||
RangePaintInfo(nsRange* aRange, nsIFrame* aFrame)
|
||||
: mRange(aRange),
|
||||
mBuilder(aFrame, nsDisplayListBuilderMode::Painting, false) {
|
||||
|
@ -4777,6 +4782,32 @@ UniquePtr<RangePaintInfo> PresShell::CreateRangePaintInfo(
|
|||
BuildDisplayListForNode(endContainer);
|
||||
}
|
||||
|
||||
// If one of the ancestor presShells (including this one) has a resolution
|
||||
// set, we may have some APZ zoom applied. That means we may want to rasterize
|
||||
// the nodes at that zoom level. Populate `info` with the relevant information
|
||||
// so that the caller can decide what to do. Also wrap the display list in
|
||||
// appropriate nsDisplayAsyncZoom display items. This code handles the general
|
||||
// case with nested async zooms (even though that never actually happens),
|
||||
// because it fell out of the implementation for free.
|
||||
for (nsPresContext* ctx = GetPresContext(); ctx;
|
||||
ctx = ctx->GetParentPresContext()) {
|
||||
PresShell* shell = ctx->PresShell();
|
||||
float resolution = shell->GetResolution();
|
||||
if (resolution == 1.0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
info->mResolution *= resolution;
|
||||
nsIFrame* rootScrollFrame = shell->GetRootScrollFrame();
|
||||
ViewID zoomedId =
|
||||
nsLayoutUtils::FindOrCreateIDFor(rootScrollFrame->GetContent());
|
||||
|
||||
nsDisplayList wrapped;
|
||||
wrapped.AppendNewToTop<nsDisplayAsyncZoom>(&info->mBuilder, rootScrollFrame,
|
||||
&info->mList, nullptr, zoomedId);
|
||||
info->mList.AppendToTop(&wrapped);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
if (gDumpRangePaintList) {
|
||||
fprintf(stderr, "CreateRangePaintInfo --- before ClipListToRange:\n");
|
||||
|
@ -4832,8 +4863,8 @@ already_AddRefed<SourceSurface> PresShell::PaintRangePaintInfo(
|
|||
// check if image-resizing-algorithm should be used
|
||||
if (aFlags & RenderImageFlags::IsImage) {
|
||||
// get max screensize
|
||||
nscoord maxWidth = pc->AppUnitsToDevPixels(maxSize.width);
|
||||
nscoord maxHeight = pc->AppUnitsToDevPixels(maxSize.height);
|
||||
int32_t maxWidth = pc->AppUnitsToDevPixels(maxSize.width);
|
||||
int32_t maxHeight = pc->AppUnitsToDevPixels(maxSize.height);
|
||||
// resize image relative to the screensize
|
||||
// get best height/width relative to screensize
|
||||
float bestHeight = float(maxHeight) * RELATIVE_SCALEFACTOR;
|
||||
|
@ -4852,8 +4883,8 @@ already_AddRefed<SourceSurface> PresShell::PaintRangePaintInfo(
|
|||
scale = std::min(scale, adjustedScale);
|
||||
} else {
|
||||
// get half of max screensize
|
||||
nscoord maxWidth = pc->AppUnitsToDevPixels(maxSize.width >> 1);
|
||||
nscoord maxHeight = pc->AppUnitsToDevPixels(maxSize.height >> 1);
|
||||
int32_t maxWidth = pc->AppUnitsToDevPixels(maxSize.width >> 1);
|
||||
int32_t maxHeight = pc->AppUnitsToDevPixels(maxSize.height >> 1);
|
||||
if (pixelArea.width > maxWidth || pixelArea.height > maxHeight) {
|
||||
// divide the maximum size by the image size in both directions.
|
||||
// Whichever direction produces the smallest result determines how much
|
||||
|
@ -4865,15 +4896,39 @@ already_AddRefed<SourceSurface> PresShell::PaintRangePaintInfo(
|
|||
}
|
||||
}
|
||||
|
||||
pixelArea.width = NSToIntFloor(float(pixelArea.width) * scale);
|
||||
pixelArea.height = NSToIntFloor(float(pixelArea.height) * scale);
|
||||
if (!pixelArea.width || !pixelArea.height) return nullptr;
|
||||
// Pick a resolution scale factor that is the highest we need for any of
|
||||
// the items. This means some items may get rendered at a higher-than-needed
|
||||
// resolution but at least nothing will be avoidably blurry.
|
||||
float resolutionScale = 1.0;
|
||||
for (const UniquePtr<RangePaintInfo>& rangeInfo : aItems) {
|
||||
resolutionScale = std::max(resolutionScale, rangeInfo->mResolution);
|
||||
}
|
||||
// Clamp the resolution scale so that `pixelArea` when scaled by `scale` and
|
||||
// `resolutionScale` isn't bigger than `maxSize`. This prevents creating
|
||||
// giant/unbounded images.
|
||||
resolutionScale =
|
||||
std::min(resolutionScale, maxSize.width / (scale * pixelArea.width));
|
||||
resolutionScale =
|
||||
std::min(resolutionScale, maxSize.height / (scale * pixelArea.height));
|
||||
// The following assert should only get hit if pixelArea scaled by `scale`
|
||||
// alone would already have been bigger than `maxSize`, which should never
|
||||
// be the case. For release builds we handle gracefully by reverting
|
||||
// resolutionScale to 1.0 to avoid unexpected consequences.
|
||||
MOZ_ASSERT(resolutionScale >= 1.0);
|
||||
resolutionScale = std::max(1.0f, resolutionScale);
|
||||
|
||||
// adjust the screen position based on the rescaled size
|
||||
nscoord left = rootScreenRect.x + pixelArea.x;
|
||||
nscoord top = rootScreenRect.y + pixelArea.y;
|
||||
aScreenRect->x = NSToIntFloor(aPoint.x - float(aPoint.x - left) * scale);
|
||||
aScreenRect->y = NSToIntFloor(aPoint.y - float(aPoint.y - top) * scale);
|
||||
|
||||
scale *= resolutionScale;
|
||||
pixelArea.width = NSToIntFloor(float(pixelArea.width) * scale);
|
||||
pixelArea.height = NSToIntFloor(float(pixelArea.height) * scale);
|
||||
if (!pixelArea.width || !pixelArea.height) {
|
||||
return nullptr;
|
||||
}
|
||||
} else {
|
||||
// move aScreenRect to the position of the surface in screen coordinates
|
||||
aScreenRect->MoveTo(rootScreenRect.x + pixelArea.x,
|
||||
|
@ -4914,7 +4969,9 @@ already_AddRefed<SourceSurface> PresShell::PaintRangePaintInfo(
|
|||
|
||||
gfxMatrix initialTM = ctx->CurrentMatrixDouble();
|
||||
|
||||
if (resize) initialTM.PreScale(scale, scale);
|
||||
if (resize) {
|
||||
initialTM.PreScale(scale, scale);
|
||||
}
|
||||
|
||||
// translate so that points are relative to the surface area
|
||||
gfxPoint surfaceOffset = nsLayoutUtils::PointToGfxPoint(
|
||||
|
|
Загрузка…
Ссылка в новой задаче