зеркало из https://github.com/mozilla/gecko-dev.git
Don't expand displayports beyond the maximum texture size. (bug 1135907, r=kats)
--HG-- extra : rebase_source : 95178166bfb1aac79836808e4e5ebaa123145d9f
This commit is contained in:
Родитель
df118d4a47
Коммит
9215e781e3
|
@ -825,6 +825,33 @@ ApplyRectMultiplier(nsRect aRect, float aMultiplier)
|
|||
return nsRect(ceil(newX), ceil(newY), floor(newWidth), floor(newHeight));
|
||||
}
|
||||
|
||||
// Return the maximum displayport size, based on the LayerManager's maximum
|
||||
// supported texture size. The result is in app units.
|
||||
static nscoord
|
||||
GetMaxDisplayPortSize(nsIContent* aContent)
|
||||
{
|
||||
MOZ_ASSERT(!gfxPrefs::LayersTilesEnabled(), "Do not clamp displayports if tiling is enabled");
|
||||
|
||||
nsIFrame* frame = aContent->GetPrimaryFrame();
|
||||
if (!frame) {
|
||||
return nscoord_MAX;
|
||||
}
|
||||
frame = nsLayoutUtils::GetDisplayRootFrame(frame);
|
||||
|
||||
nsIWidget* widget = frame->GetNearestWidget();
|
||||
if (!widget) {
|
||||
return nscoord_MAX;
|
||||
}
|
||||
LayerManager* lm = widget->GetLayerManager();
|
||||
if (!lm) {
|
||||
return nscoord_MAX;
|
||||
}
|
||||
nsPresContext* presContext = frame->PresContext();
|
||||
|
||||
uint32_t maxSizeInDevPixels = lm->GetMaxTextureSize();
|
||||
return presContext->DevPixelsToAppUnits(maxSizeInDevPixels);
|
||||
}
|
||||
|
||||
static nsRect
|
||||
GetDisplayPortFromRectData(nsIContent* aContent,
|
||||
DisplayPortPropertyData* aRectData,
|
||||
|
@ -900,24 +927,23 @@ GetDisplayPortFromMarginsData(nsIContent* aContent,
|
|||
ScreenRect screenRect = LayoutDeviceRect::FromAppUnits(base, auPerDevPixel)
|
||||
* parentRes;
|
||||
|
||||
// Expand the rect by the margins
|
||||
screenRect.Inflate(aMarginsData->mMargins);
|
||||
if (gfxPrefs::LayersTilesEnabled()) {
|
||||
// Note on the correctness of applying the alignment in Screen space:
|
||||
// The correct space to apply the alignment in would be Layer space, but
|
||||
// we don't necessarily know the scale to convert to Layer space at this
|
||||
// point because Layout may not yet have chosen the resolution at which to
|
||||
// render (it chooses that in FrameLayerBuilder, but this can be called
|
||||
// during display list building). Therefore, we perform the alignment in
|
||||
// Screen space, which basically assumes that Layout chose to render at
|
||||
// screen resolution; since this is what Layout does most of the time,
|
||||
// this is a good approximation. A proper solution would involve moving
|
||||
// the choosing of the resolution to display-list building time.
|
||||
int alignmentX = gfxPlatform::GetPlatform()->GetTileWidth();
|
||||
int alignmentY = gfxPlatform::GetPlatform()->GetTileHeight();
|
||||
|
||||
int alignmentX = gfxPlatform::GetPlatform()->GetTileWidth();
|
||||
int alignmentY = gfxPlatform::GetPlatform()->GetTileHeight();
|
||||
// Expand the rect by the margins
|
||||
screenRect.Inflate(aMarginsData->mMargins);
|
||||
|
||||
// And then align it to the requested alignment.
|
||||
// Note on the correctness of applying the alignment in Screen space:
|
||||
// The correct space to apply the alignment in would be Layer space, but
|
||||
// we don't necessarily know the scale to convert to Layer space at this
|
||||
// point because Layout may not yet have chosen the resolution at which to
|
||||
// render (it chooses that in FrameLayerBuilder, but this can be called
|
||||
// during display list building). Therefore, we perform the alignment in
|
||||
// Screen space, which basically assumes that Layout chose to render at
|
||||
// screen resolution; since this is what Layout does most of the time,
|
||||
// this is a good approximation. A proper solution would involve moving the
|
||||
// choosing of the resolution to display-list building time.
|
||||
if (gfxPrefs::LayersTilesEnabled() && (alignmentX > 0 && alignmentY > 0)) {
|
||||
// Inflate the rectangle by 1 so that we always push to the next tile
|
||||
// boundary. This is desirable to stop from having a rectangle with a
|
||||
// moving origin occasionally being smaller when it coincidentally lines
|
||||
|
@ -942,9 +968,38 @@ GetDisplayPortFromMarginsData(nsIContent* aContent,
|
|||
float h = alignmentY * ceil(screenRect.YMost() / alignmentY) - y;
|
||||
screenRect = ScreenRect(x, y, w, h);
|
||||
screenRect -= scrollPosScreen;
|
||||
} else {
|
||||
nscoord maxSizeInAppUnits = GetMaxDisplayPortSize(aContent);
|
||||
if (maxSizeInAppUnits == nscoord_MAX) {
|
||||
// Pick a safe maximum displayport size for sanity purposes. This is the
|
||||
// lowest maximum texture size on tileless-platforms (Windows, D3D10).
|
||||
maxSizeInAppUnits = presContext->DevPixelsToAppUnits(8192);
|
||||
}
|
||||
|
||||
// Find the maximum size in screen pixels.
|
||||
int32_t maxSizeInDevPixels = presContext->AppUnitsToDevPixels(maxSizeInAppUnits);
|
||||
int32_t maxWidthInScreenPixels = floor(double(maxSizeInDevPixels) * res.xScale);
|
||||
int32_t maxHeightInScreenPixels = floor(double(maxSizeInDevPixels) * res.yScale);
|
||||
|
||||
// For each axis, inflate the margins up to the maximum size.
|
||||
const ScreenMargin& margins = aMarginsData->mMargins;
|
||||
if (screenRect.height < maxHeightInScreenPixels) {
|
||||
int32_t budget = maxHeightInScreenPixels - screenRect.height;
|
||||
|
||||
int32_t top = std::min(int32_t(margins.top), budget);
|
||||
screenRect.y -= top;
|
||||
screenRect.height += top + std::min(int32_t(margins.bottom), budget - top);
|
||||
}
|
||||
if (screenRect.width < maxWidthInScreenPixels) {
|
||||
int32_t budget = maxWidthInScreenPixels - screenRect.width;
|
||||
|
||||
int32_t left = std::min(int32_t(margins.left), budget);
|
||||
screenRect.x -= left;
|
||||
screenRect.width += left + std::min(int32_t(margins.right), budget - left);
|
||||
}
|
||||
}
|
||||
|
||||
// Convert the aligned rect back into app units
|
||||
// Convert the aligned rect back into app units.
|
||||
nsRect result = LayoutDeviceRect::ToAppUnits(screenRect / res, auPerDevPixel);
|
||||
|
||||
// Expand it for the low-res buffer if needed
|
||||
|
@ -988,11 +1043,25 @@ GetDisplayPortImpl(nsIContent* aContent, nsRect *aResult, float aMultiplier)
|
|||
NS_ASSERTION((rectData == nullptr) != (marginsData == nullptr),
|
||||
"Only one of rectData or marginsData should be set!");
|
||||
|
||||
nsRect result;
|
||||
if (rectData) {
|
||||
*aResult = GetDisplayPortFromRectData(aContent, rectData, aMultiplier);
|
||||
result = GetDisplayPortFromRectData(aContent, rectData, aMultiplier);
|
||||
} else {
|
||||
*aResult = GetDisplayPortFromMarginsData(aContent, marginsData, aMultiplier);
|
||||
result = GetDisplayPortFromMarginsData(aContent, marginsData, aMultiplier);
|
||||
}
|
||||
|
||||
if (!gfxPrefs::LayersTilesEnabled()) {
|
||||
// Either we should have gotten a valid rect directly from the displayport
|
||||
// base, or we should have computed a valid rect from the margins.
|
||||
NS_ASSERTION(GetMaxDisplayPortSize(aContent) <= 0 ||
|
||||
result.width < GetMaxDisplayPortSize(aContent),
|
||||
"Displayport must be a valid texture size");
|
||||
NS_ASSERTION(GetMaxDisplayPortSize(aContent) <= 0 ||
|
||||
result.height < GetMaxDisplayPortSize(aContent),
|
||||
"Displayport must be a valid texture size");
|
||||
}
|
||||
|
||||
*aResult = result;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче