Bug 957668. Add and implement plumbing for a display port margins api. r=kats

This commit is contained in:
Timothy Nikkel 2014-03-26 21:46:23 -04:00
parent 90ca2854ab
commit 8ccbcd870e
5 changed files with 246 additions and 4 deletions

View File

@ -2022,6 +2022,8 @@ GK_ATOM(DeleteTxnName, "Deleting")
GK_ATOM(Remote, "remote")
GK_ATOM(RemoteId, "_remote_id")
GK_ATOM(DisplayPort, "_displayport")
GK_ATOM(DisplayPortMargins, "_displayportmargins")
GK_ATOM(DisplayPortBase, "_displayportbase")
GK_ATOM(CriticalDisplayPort, "_critical_displayport")
// Names for system metrics

View File

@ -452,6 +452,109 @@ nsDOMWindowUtils::SetDisplayPortForElement(float aXPx, float aYPx,
return NS_OK;
}
NS_IMETHODIMP
nsDOMWindowUtils::SetDisplayPortMarginsForElement(float aLeftMargin,
float aTopMargin,
float aRightMargin,
float aBottomMargin,
uint32_t aAlignment,
nsIDOMElement* aElement,
uint32_t aPriority)
{
if (!nsContentUtils::IsCallerChrome()) {
return NS_ERROR_DOM_SECURITY_ERR;
}
nsIPresShell* presShell = GetPresShell();
if (!presShell) {
return NS_ERROR_FAILURE;
}
// Note order change of arguments between our function signature and
// LayerMargin constructor.
LayerMargin displayportMargins(aTopMargin,
aRightMargin,
aBottomMargin,
aLeftMargin);
if (!aElement) {
return NS_ERROR_INVALID_ARG;
}
nsCOMPtr<nsIContent> content = do_QueryInterface(aElement);
if (!content) {
return NS_ERROR_INVALID_ARG;
}
if (content->GetCurrentDoc() != presShell->GetDocument()) {
return NS_ERROR_INVALID_ARG;
}
DisplayPortMarginsPropertyData* currentData =
static_cast<DisplayPortMarginsPropertyData*>(content->GetProperty(nsGkAtoms::DisplayPortMargins));
if (currentData && currentData->mPriority > aPriority) {
return NS_OK;
}
content->SetProperty(nsGkAtoms::DisplayPortMargins,
new DisplayPortMarginsPropertyData(displayportMargins, aAlignment, aPriority),
nsINode::DeleteProperty<DisplayPortMarginsPropertyData>);
nsIFrame* rootScrollFrame = presShell->GetRootScrollFrame();
if (rootScrollFrame) {
if (content == rootScrollFrame->GetContent()) {
// We are setting a root displayport for a document.
// The pres shell needs a special flag set.
presShell->SetIgnoreViewportScrolling(true);
}
}
nsIFrame* rootFrame = presShell->FrameManager()->GetRootFrame();
if (rootFrame) {
rootFrame->SchedulePaint();
}
return NS_OK;
}
NS_IMETHODIMP
nsDOMWindowUtils::SetDisplayPortBaseForElement(int32_t aX,
int32_t aY,
int32_t aWidth,
int32_t aHeight,
nsIDOMElement* aElement)
{
if (!nsContentUtils::IsCallerChrome()) {
return NS_ERROR_DOM_SECURITY_ERR;
}
nsIPresShell* presShell = GetPresShell();
if (!presShell) {
return NS_ERROR_FAILURE;
}
if (!aElement) {
return NS_ERROR_INVALID_ARG;
}
nsCOMPtr<nsIContent> content = do_QueryInterface(aElement);
if (!content) {
return NS_ERROR_INVALID_ARG;
}
if (content->GetCurrentDoc() != presShell->GetDocument()) {
return NS_ERROR_INVALID_ARG;
}
content->SetProperty(nsGkAtoms::DisplayPortBase, new nsRect(aX, aY, aWidth, aHeight),
nsINode::DeleteProperty<nsRect>);
return NS_OK;
}
NS_IMETHODIMP
nsDOMWindowUtils::SetCriticalDisplayPortForElement(float aXPx, float aYPx,
float aWidthPx, float aHeightPx,

View File

@ -43,7 +43,7 @@ interface nsIDOMEventTarget;
interface nsIRunnable;
interface nsICompositionStringSynthesizer;
[scriptable, uuid(ef70a299-033c-4adc-b214-6649aed9d828)]
[scriptable, uuid(f3148b3e-6db8-4a49-aa5c-de726449054d)]
interface nsIDOMWindowUtils : nsISupports {
/**
@ -152,6 +152,38 @@ interface nsIDOMWindowUtils : nsISupports {
in float aWidthPx, in float aHeightPx,
in nsIDOMElement aElement,
in uint32_t aPriority);
/**
* An alternate way to represent a displayport rect as a set of margins and a
* base rect to apply those margins to. A consumer of pixels may ask for as
* many extra pixels as it would like in each direction. Layout then sets
* the base rect to the "visible rect" of the element, which is just the
* subrect of the element that is drawn (it does not take in account content
* covering the element).
*
* If both a displayport rect and displayport margins with corresponding base
* rect are set with the same priority then the margins will take precendence.
*
* Specifying an alignment value will ensure that after the base rect has
* been expanded by the displayport margins, it will be further expanded so
* that each edge is located at a multiple of the "alignment" value.
*
* Note that both the margin values and alignment are treated as values in
* LayerPixels. Refer to layout/base/Units.h for a description of this unit.
* The base rect values are in app units.
*/
void setDisplayPortMarginsForElement(in float aLeftMargin,
in float aTopMargin,
in float aRightMargin,
in float aBottomMargin,
in uint32_t aAlignment,
in nsIDOMElement aElement,
in uint32_t aPriority);
void setDisplayPortBaseForElement(in int32_t aX,
in int32_t aY,
in int32_t aWidth,
in int32_t aHeight,
in nsIDOMElement aElement);
/**
* When a display port is set, this allows a sub-section of that

View File

@ -656,14 +656,107 @@ nsLayoutUtils::FindScrollableFrameFor(ViewID aId)
bool
nsLayoutUtils::GetDisplayPort(nsIContent* aContent, nsRect *aResult)
{
void* property = aContent->GetProperty(nsGkAtoms::DisplayPort);
if (!property) {
DisplayPortPropertyData* rectData =
static_cast<DisplayPortPropertyData*>(aContent->GetProperty(nsGkAtoms::DisplayPort));
DisplayPortMarginsPropertyData* marginsData =
static_cast<DisplayPortMarginsPropertyData*>(aContent->GetProperty(nsGkAtoms::DisplayPortMargins));
if (!rectData && !marginsData) {
return false;
}
if (aResult) {
*aResult = (static_cast<DisplayPortPropertyData*>(property))->mRect;
if (rectData && marginsData) {
// choose margins if equal priority
if (rectData->mPriority > marginsData->mPriority) {
marginsData = nullptr;
} else {
rectData = nullptr;
}
}
if (rectData) {
*aResult = rectData->mRect;
} else {
nsRect* baseData =
static_cast<nsRect*>(aContent->GetProperty(nsGkAtoms::DisplayPortBase));
nsRect base;
if (baseData) {
base = *baseData;
}
nsIFrame* frame = aContent->GetPrimaryFrame();
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;
}
if (frame) {
// 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) {
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);
nsIScrollableFrame* scrollableFrame = frame->GetScrollTargetFrame();
nsPoint scrollPos(
scrollableFrame ? scrollableFrame->GetScrollPosition() : nsPoint(0,0));
if (marginsData->mAlignment > 0) {
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->mAlignment * floor(rect.x / marginsData->mAlignment);
float top =
marginsData->mAlignment * floor(rect.y / marginsData->mAlignment);
float right =
marginsData->mAlignment * ceil(rect.XMost() / marginsData->mAlignment);
float bottom =
marginsData->mAlignment * ceil(rect.YMost() / marginsData->mAlignment);
rect = LayerRect(left, top, right - left, bottom - top);
rect -= scrollPosLayer;
}
nsRect result;
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);
// Finally, clamp the display port to the expanded scrollable rect.
nsRect expandedScrollableRect = CalculateExpandedScrollableRect(frame);
result = expandedScrollableRect.Intersect(result + scrollPos) - scrollPos;
*aResult = result;
}
}
}
return true;
}

View File

@ -85,6 +85,18 @@ struct DisplayPortPropertyData {
uint32_t mPriority;
};
struct DisplayPortMarginsPropertyData {
DisplayPortMarginsPropertyData(const LayerMargin& aMargins,
uint32_t aAlignment, uint32_t aPriority)
: mMargins(aMargins)
, mAlignment(aAlignment)
, mPriority(aPriority)
{}
LayerMargin mMargins;
uint32_t mAlignment;
uint32_t mPriority;
};
template <class AnimationsOrTransitions>
extern AnimationsOrTransitions* HasAnimationOrTransition(nsIContent* aContent,
nsIAtom* aAnimationProperty,