Bug 69787. Implement MouseEvent.offsetX/Y. r=mats,smaug

--HG--
extra : rebase_source : 0120fa29fb94c1c2f992b4e3bae63c5120b90f4b
This commit is contained in:
Robert O'Callahan 2015-03-14 00:50:10 +13:00
Родитель b84e0849ec
Коммит 843379803a
9 изменённых файлов: 139 добавлений и 3 удалений

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

@ -959,7 +959,6 @@ Event::GetClientCoords(nsPresContext* aPresContext,
if (!shell) { if (!shell) {
return CSSIntPoint(0, 0); return CSSIntPoint(0, 0);
} }
nsIFrame* rootFrame = shell->GetRootFrame(); nsIFrame* rootFrame = shell->GetRootFrame();
if (!rootFrame) { if (!rootFrame) {
return CSSIntPoint(0, 0); return CSSIntPoint(0, 0);
@ -970,6 +969,44 @@ Event::GetClientCoords(nsPresContext* aPresContext,
return CSSIntPoint::FromAppUnitsRounded(pt); return CSSIntPoint::FromAppUnitsRounded(pt);
} }
// static
CSSIntPoint
Event::GetOffsetCoords(nsPresContext* aPresContext,
WidgetEvent* aEvent,
LayoutDeviceIntPoint aPoint,
CSSIntPoint aDefaultPoint)
{
if (!aEvent->mFlags.mIsBeingDispatched) {
return GetPageCoords(aPresContext, aEvent, aPoint, aDefaultPoint);
}
nsCOMPtr<nsIContent> content = do_QueryInterface(aEvent->target);
if (!content) {
return CSSIntPoint(0, 0);
}
nsCOMPtr<nsIPresShell> shell = aPresContext->GetPresShell();
if (!shell) {
return CSSIntPoint(0, 0);
}
shell->FlushPendingNotifications(Flush_Layout);
nsIFrame* frame = content->GetPrimaryFrame();
if (!frame) {
return CSSIntPoint(0, 0);
}
nsIFrame* rootFrame = shell->GetRootFrame();
if (!rootFrame) {
return CSSIntPoint(0, 0);
}
CSSIntPoint clientCoords =
GetClientCoords(aPresContext, aEvent, aPoint, aDefaultPoint);
nsPoint pt = CSSPixel::ToAppUnits(clientCoords);
if (nsLayoutUtils::TransformPoint(rootFrame, frame, pt) ==
nsLayoutUtils::TRANSFORM_SUCCEEDED) {
pt -= frame->GetPaddingRectRelativeToSelf().TopLeft();
return CSSPixel::FromAppUnitsRounded(pt);
}
return CSSIntPoint(0, 0);
}
// To be called ONLY by Event::GetType (which has the additional // To be called ONLY by Event::GetType (which has the additional
// logic for handling user-defined events). // logic for handling user-defined events).
// static // static

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

@ -141,6 +141,10 @@ public:
static LayoutDeviceIntPoint GetScreenCoords(nsPresContext* aPresContext, static LayoutDeviceIntPoint GetScreenCoords(nsPresContext* aPresContext,
WidgetEvent* aEvent, WidgetEvent* aEvent,
LayoutDeviceIntPoint aPoint); LayoutDeviceIntPoint aPoint);
static CSSIntPoint GetOffsetCoords(nsPresContext* aPresContext,
WidgetEvent* aEvent,
LayoutDeviceIntPoint aPoint,
CSSIntPoint aDefaultPoint);
static already_AddRefed<Event> Constructor(const GlobalObject& aGlobal, static already_AddRefed<Event> Constructor(const GlobalObject& aGlobal,
const nsAString& aType, const nsAString& aType,

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

@ -386,6 +386,20 @@ MouseEvent::ClientY()
mClientPoint).y; mClientPoint).y;
} }
int32_t
MouseEvent::OffsetX()
{
return Event::GetOffsetCoords(mPresContext, mEvent, mEvent->refPoint,
mClientPoint).x;
}
int32_t
MouseEvent::OffsetY()
{
return Event::GetOffsetCoords(mPresContext, mEvent, mEvent->refPoint,
mClientPoint).y;
}
bool bool
MouseEvent::AltKey() MouseEvent::AltKey()
{ {

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

@ -45,6 +45,8 @@ public:
int32_t ScreenY(); int32_t ScreenY();
int32_t ClientX(); int32_t ClientX();
int32_t ClientY(); int32_t ClientY();
int32_t OffsetX();
int32_t OffsetY();
bool CtrlKey(); bool CtrlKey();
bool ShiftKey(); bool ShiftKey();
bool AltKey(); bool AltKey();

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

@ -182,3 +182,4 @@ skip-if = buildapp == 'b2g' || e10s
[test_bug1096146.html] [test_bug1096146.html]
support-files = support-files =
bug1096146_embedded.html bug1096146_embedded.html
[test_offsetxy.html]

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

@ -0,0 +1,73 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test for DOM MouseEvent offsetX/Y</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<div id="d" style="position:absolute; top:100px; left:100px; width:100px; border:5px dotted black; height:100px"></div>
<div id="d2" style="position:absolute; top:100px; left:100px; width:100px; border:5px dotted black; height:100px; transform:translateX(100px)"></div>
<div id="d3" style="display:none; position:absolute; top:100px; left:100px; width:100px; border:5px dotted black; height:100px"></div>
<div id="d4" style="transform:scale(0); position:absolute; top:100px; left:100px; width:100px; border:5px dotted black; height:100px"></div>
<pre id="test">
<script type="application/javascript">
var offsetX = -1, offsetY = -1;
var ev = new MouseEvent("click", {clientX:110, clientY:110});
d.addEventListener("click", function (event) {
is(ev, event, "Event objects must match");
offsetX = event.offsetX;
offsetY = event.offsetY;
});
d.dispatchEvent(ev);
is(offsetX, 5);
is(offsetY, 5);
is(ev.offsetX, ev.pageX);
is(ev.offsetY, ev.pageY);
var ev2 = new MouseEvent("click", {clientX:220, clientY:130});
d2.addEventListener("click", function (event) {
is(ev2, event, "Event objects must match");
offsetX = event.offsetX;
offsetY = event.offsetY;
});
d2.dispatchEvent(ev2);
is(offsetX, 15);
is(offsetY, 25);
is(ev2.offsetX, ev2.pageX);
is(ev2.offsetY, ev2.pageY);
var ev3 = new MouseEvent("click", {clientX:110, clientY:110});
d3.addEventListener("click", function (event) {
is(ev3, event, "Event objects must match");
offsetX = event.offsetX;
offsetY = event.offsetY;
});
d3.dispatchEvent(ev3);
is(offsetX, 0);
is(offsetY, 0);
is(ev3.offsetX, ev3.pageX);
is(ev3.offsetY, ev3.pageY);
var ev4 = new MouseEvent("click", {clientX:110, clientY:110});
d4.addEventListener("click", function (event) {
is(ev4, event, "Event objects must match");
offsetX = event.offsetX;
offsetY = event.offsetY;
});
d4.dispatchEvent(ev4);
is(offsetX, 0);
is(offsetY, 0);
is(ev4.offsetX, ev4.pageX);
is(ev4.offsetY, ev4.pageY);
</script>
</pre>
</body>
</html>

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

@ -15,6 +15,8 @@ interface MouseEvent : UIEvent {
readonly attribute long screenY; readonly attribute long screenY;
readonly attribute long clientX; readonly attribute long clientX;
readonly attribute long clientY; readonly attribute long clientY;
readonly attribute long offsetX;
readonly attribute long offsetY;
readonly attribute boolean ctrlKey; readonly attribute boolean ctrlKey;
readonly attribute boolean shiftKey; readonly attribute boolean shiftKey;
readonly attribute boolean altKey; readonly attribute boolean altKey;

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

@ -2403,8 +2403,8 @@ nsLayoutUtils::TransformPoint(nsIFrame* aFromFrame, nsIFrame* aToFrame,
// coordinate space. // coordinate space.
return NONINVERTIBLE_TRANSFORM; return NONINVERTIBLE_TRANSFORM;
} }
aPoint.x = toDevPixels.x / devPixelsPerAppUnitToFrame; aPoint.x = NSToCoordRound(toDevPixels.x / devPixelsPerAppUnitToFrame);
aPoint.y = toDevPixels.y / devPixelsPerAppUnitToFrame; aPoint.y = NSToCoordRound(toDevPixels.y / devPixelsPerAppUnitToFrame);
return TRANSFORM_SUCCEEDED; return TRANSFORM_SUCCEEDED;
} }

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

@ -593,6 +593,9 @@ function doTest(aTest)
is(gEvent[name], null, description + ": mismatch with fixed value (" + name + ")"); is(gEvent[name], null, description + ": mismatch with fixed value (" + name + ")");
} else if (aTest.todoMismatch.indexOf(name) >= 0) { } else if (aTest.todoMismatch.indexOf(name) >= 0) {
todo_is(gEvent[name], gCopiedEvent[i].value, description + ": mismatch (" + name + ")"); todo_is(gEvent[name], gCopiedEvent[i].value, description + ": mismatch (" + name + ")");
} else if (name == "offsetX" || name == "offsetY") {
// do nothing; these are defined to return different values during event dispatch
// vs not during event dispatch
} else { } else {
is(gEvent[name], gCopiedEvent[i].value, description + ": mismatch (" + name + ")"); is(gEvent[name], gCopiedEvent[i].value, description + ": mismatch (" + name + ")");
} }