Bug 1001438 - Refactor the GetDisplayPortImpl code for readability. r=tn

This commit is contained in:
Kartikaya Gupta 2014-05-21 12:06:03 -04:00
Родитель 252dbea774
Коммит 5068cf8dde
1 изменённых файлов: 128 добавлений и 105 удалений

Просмотреть файл

@ -685,22 +685,139 @@ ApplyRectMultiplier(nsRect aRect, float aMultiplier)
return nsRect(ceil(newX), ceil(newY), floor(newWidth), floor(newHeight));
}
static nsRect
GetDisplayPortFromRectData(nsIContent* aContent,
DisplayPortPropertyData* aRectData,
float aMultiplier)
{
// In the case where the displayport is set as a rect, we assume it is
// already aligned and clamped as necessary. The burden to do that is
// on the setter of the displayport. In practice very few places set the
// displayport directly as a rect (mostly tests). We still do need to
// expand it by the multiplier though.
return ApplyRectMultiplier(aRectData->mRect, aMultiplier);
}
static nsRect
GetDisplayPortFromMarginsData(nsIContent* aContent,
DisplayPortMarginsPropertyData* aMarginsData,
float aMultiplier)
{
// In the case where the displayport is set via margins, we apply the margins
// to a base rect. Then we align the expanded rect based on the alignment
// requested, further expand the rect by the multiplier, and finally, clamp it
// to the size of the scrollable rect.
nsRect base;
if (nsRect* baseData = static_cast<nsRect*>(aContent->GetProperty(nsGkAtoms::DisplayPortBase))) {
base = *baseData;
} else {
NS_WARNING("Attempting to get a margins-based displayport with no base data!");
}
nsIFrame* frame = aContent->GetPrimaryFrame();
if (!frame) {
// Turns out we can't really compute it. Oops. We still should return
// something sane. Note that although we can apply the multiplier on the
// base rect here, we can't tile-align or clamp the rect without a frame.
NS_WARNING("Attempting to get a displayport from a content with no primary frame!");
return ApplyRectMultiplier(base, aMultiplier);
}
bool isRoot = false;
if (aContent->OwnerDoc()->GetRootElement() == aContent) {
// We want the scroll frame, the root scroll frame differs from all
// others in that the primary frame is not the scroll frame.
frame = frame->PresContext()->PresShell()->GetRootScrollFrame();
isRoot = true;
}
nsPoint scrollPos;
if (nsIScrollableFrame* scrollableFrame = frame->GetScrollTargetFrame()) {
scrollPos = scrollableFrame->GetScrollPosition();
}
nsPresContext* presContext = frame->PresContext();
int32_t auPerDevPixel = presContext->AppUnitsPerDevPixel();
gfxSize res = presContext->PresShell()->GetCumulativeResolution();
// First convert the base rect to layer pixels
gfxSize parentRes = res;
if (isRoot) {
// the base rect for root scroll frames is specified in the parent document
// coordinate space, so it doesn't include the local resolution.
gfxSize localRes = presContext->PresShell()->GetResolution();
parentRes.width /= localRes.width;
parentRes.height /= localRes.height;
}
LayerRect layerRect(NSAppUnitsToFloatPixels(base.x, auPerDevPixel) * parentRes.width,
NSAppUnitsToFloatPixels(base.y, auPerDevPixel) * parentRes.height,
NSAppUnitsToFloatPixels(base.width, auPerDevPixel) * parentRes.width,
NSAppUnitsToFloatPixels(base.height, auPerDevPixel) * parentRes.height);
// Expand the rect by the margins
layerRect.Inflate(aMarginsData->mMargins);
// And then align it to the requested alignment
if (aMarginsData->mAlignmentX > 0 || aMarginsData->mAlignmentY > 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
// up to tile boundaries.
layerRect.Inflate(1);
// Avoid division by zero.
if (aMarginsData->mAlignmentX == 0) {
aMarginsData->mAlignmentX = 1;
}
if (aMarginsData->mAlignmentY == 0) {
aMarginsData->mAlignmentY = 1;
}
LayerPoint scrollPosLayer(NSAppUnitsToFloatPixels(scrollPos.x, auPerDevPixel) * res.width,
NSAppUnitsToFloatPixels(scrollPos.y, auPerDevPixel) * res.height);
layerRect += scrollPosLayer;
float x = aMarginsData->mAlignmentX * floor(layerRect.x / aMarginsData->mAlignmentX);
float y = aMarginsData->mAlignmentY * floor(layerRect.y / aMarginsData->mAlignmentY);
float w = aMarginsData->mAlignmentX * ceil(layerRect.XMost() / aMarginsData->mAlignmentX) - x;
float h = aMarginsData->mAlignmentY * ceil(layerRect.YMost() / aMarginsData->mAlignmentY) - y;
layerRect = LayerRect(x, y, w, h);
layerRect -= scrollPosLayer;
}
// Convert the aligned rect back into app units
nsRect result(NSFloatPixelsToAppUnits(layerRect.x / res.width, auPerDevPixel),
NSFloatPixelsToAppUnits(layerRect.y / res.height, auPerDevPixel),
NSFloatPixelsToAppUnits(layerRect.width / res.width, auPerDevPixel),
NSFloatPixelsToAppUnits(layerRect.height / res.height, auPerDevPixel));
// Expand it for the low-res buffer if needed
result = ApplyRectMultiplier(result, aMultiplier);
// Finally, clamp it to the expanded scrollable rect.
nsRect expandedScrollableRect = nsLayoutUtils::CalculateExpandedScrollableRect(frame);
result = expandedScrollableRect.Intersect(result + scrollPos) - scrollPos;
return result;
}
static bool
GetDisplayPortImpl(nsIContent* aContent, nsRect *aResult, float aMultiplier = 1.0f)
GetDisplayPortImpl(nsIContent* aContent, nsRect *aResult, float aMultiplier)
{
DisplayPortPropertyData* rectData =
static_cast<DisplayPortPropertyData*>(aContent->GetProperty(nsGkAtoms::DisplayPort));
DisplayPortMarginsPropertyData* marginsData =
static_cast<DisplayPortMarginsPropertyData*>(aContent->GetProperty(nsGkAtoms::DisplayPortMargins));
nsRect* baseData =
static_cast<nsRect*>(aContent->GetProperty(nsGkAtoms::DisplayPortBase));
if (!rectData && !marginsData) {
// This content element has no displayport data at all
return false;
}
if (!aResult) {
// We have displayport data, but no need to compute it because the
// caller doesn't want it
// We have displayport data, but the caller doesn't want the actual
// rect, so we don't need to actually compute it.
return true;
}
@ -713,108 +830,14 @@ GetDisplayPortImpl(nsIContent* aContent, nsRect *aResult, float aMultiplier = 1.
}
}
nsIFrame* frame = aContent->GetPrimaryFrame();
if (!frame) {
if (rectData) {
*aResult = rectData->mRect;
} else {
// Turns out we can't really compute it. Oops. We still should
// return true and set aResult to something sane.
NS_WARNING("Attempting to get a displayport from a content with no primary frame!");
if (baseData) {
*aResult = *baseData;
} else {
*aResult = nsRect();
}
}
*aResult = ApplyRectMultiplier(*aResult, aMultiplier);
return true;
}
NS_ASSERTION((rectData == nullptr) != (marginsData == nullptr),
"Only one of rectData or marginsData should be set!");
bool isRoot = false;
if (aContent->OwnerDoc()->GetRootElement() == aContent) {
// We want the scroll frame, the root scroll frame differs from all
// others in that the primary frame is not the scroll frame.
frame = frame->PresContext()->PresShell()->GetRootScrollFrame();
isRoot = true;
}
nsIScrollableFrame* scrollableFrame = frame->GetScrollTargetFrame();
nsPoint scrollPos(scrollableFrame ? scrollableFrame->GetScrollPosition() : nsPoint(0,0));
nsRect result;
if (rectData) {
// We have it as a straight-up rect
result = rectData->mRect;
*aResult = GetDisplayPortFromRectData(aContent, rectData, aMultiplier);
} else {
// We need to compute it from the margins + base rect
nsRect base;
if (baseData) {
base = *baseData;
}
// first convert the base rect to layer pixels
nsPresContext* presContext = frame->PresContext();
int32_t auPerDevPixel = presContext->AppUnitsPerDevPixel();
gfxSize res = presContext->PresShell()->GetCumulativeResolution();
gfxSize parentRes = res;
if (isRoot) {
// the base rect for root scroll frames is specified in the parent document
// coordinate space, so it doesn't include the local resolution.
gfxSize localRes = presContext->PresShell()->GetResolution();
parentRes.width /= localRes.width;
parentRes.height /= localRes.height;
}
LayerRect rect;
rect.x = parentRes.width * NSAppUnitsToFloatPixels(base.x, auPerDevPixel);
rect.y = parentRes.height * NSAppUnitsToFloatPixels(base.y, auPerDevPixel);
rect.width = parentRes.width * NSAppUnitsToFloatPixels(base.width, auPerDevPixel);
rect.height = parentRes.height * NSAppUnitsToFloatPixels(base.height, auPerDevPixel);
rect.Inflate(marginsData->mMargins);
if (marginsData->mAlignmentX > 0 || marginsData->mAlignmentY > 0) {
// Avoid division by zero.
if (marginsData->mAlignmentX == 0) {
marginsData->mAlignmentX = 1;
}
if (marginsData->mAlignmentY == 0) {
marginsData->mAlignmentY = 1;
}
LayerPoint scrollPosLayer(
res.width * NSAppUnitsToFloatPixels(scrollPos.x, auPerDevPixel),
res.height * NSAppUnitsToFloatPixels(scrollPos.y, auPerDevPixel));
rect += scrollPosLayer;
// 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
// up to tile boundaries.
rect.Inflate(1);
float left = marginsData->mAlignmentX * floor(rect.x / marginsData->mAlignmentX);
float top = marginsData->mAlignmentY * floor(rect.y / marginsData->mAlignmentY);
float right = marginsData->mAlignmentX * ceil(rect.XMost() / marginsData->mAlignmentX);
float bottom = marginsData->mAlignmentY * ceil(rect.YMost() / marginsData->mAlignmentY);
rect = LayerRect(left, top, right - left, bottom - top);
rect -= scrollPosLayer;
}
result.x = NSFloatPixelsToAppUnits(rect.x / res.width, auPerDevPixel);
result.y = NSFloatPixelsToAppUnits(rect.y / res.height, auPerDevPixel);
result.width = NSFloatPixelsToAppUnits(rect.width / res.width, auPerDevPixel);
result.height = NSFloatPixelsToAppUnits(rect.height / res.height, auPerDevPixel);
*aResult = GetDisplayPortFromMarginsData(aContent, marginsData, aMultiplier);
}
result = ApplyRectMultiplier(result, aMultiplier);
if (marginsData) {
// Finally, if the displayport was set via margins, clamp it to the expanded scrollable rect.
nsRect expandedScrollableRect = nsLayoutUtils::CalculateExpandedScrollableRect(frame);
result = expandedScrollableRect.Intersect(result + scrollPos) - scrollPos;
}
*aResult = result;
return true;
}
@ -824,7 +847,7 @@ nsLayoutUtils::GetDisplayPort(nsIContent* aContent, nsRect *aResult)
if (gfxPrefs::UseLowPrecisionBuffer()) {
return GetDisplayPortImpl(aContent, aResult, 1.0f / gfxPrefs::LowPrecisionResolution());
}
return GetDisplayPortImpl(aContent, aResult);
return GetDisplayPortImpl(aContent, aResult, 1.0f);
}
void
@ -881,7 +904,7 @@ bool
nsLayoutUtils::GetCriticalDisplayPort(nsIContent* aContent, nsRect* aResult)
{
if (gfxPrefs::UseLowPrecisionBuffer()) {
return GetDisplayPortImpl(aContent, aResult);
return GetDisplayPortImpl(aContent, aResult, 1.0f);
}
return false;
}