зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-inbound to mozilla-central a=merge
This commit is contained in:
Коммит
cef33be47c
|
@ -2553,6 +2553,56 @@ int32_t nsContentUtils::ComparePoints(nsINode* aParent1, int32_t aOffset1,
|
||||||
return child1index < aOffset2 ? -1 : 1;
|
return child1index < aOffset2 ? -1 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
nsINode*
|
||||||
|
nsContentUtils::GetCommonAncestorUnderInteractiveContent(nsINode* aNode1,
|
||||||
|
nsINode* aNode2)
|
||||||
|
{
|
||||||
|
if (!aNode1 || !aNode2) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (aNode1 == aNode2) {
|
||||||
|
return aNode1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build the chain of parents
|
||||||
|
AutoTArray<nsINode*, 30> parents1;
|
||||||
|
do {
|
||||||
|
parents1.AppendElement(aNode1);
|
||||||
|
if (aNode1->IsElement() &&
|
||||||
|
aNode1->AsElement()->IsInteractiveHTMLContent(true)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
aNode1 = aNode1->GetFlattenedTreeParentNode();
|
||||||
|
} while (aNode1);
|
||||||
|
|
||||||
|
AutoTArray<nsINode*, 30> parents2;
|
||||||
|
do {
|
||||||
|
parents2.AppendElement(aNode2);
|
||||||
|
if (aNode2->IsElement() &&
|
||||||
|
aNode2->AsElement()->IsInteractiveHTMLContent(true)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
aNode2 = aNode2->GetFlattenedTreeParentNode();
|
||||||
|
} while (aNode2);
|
||||||
|
|
||||||
|
// Find where the parent chain differs
|
||||||
|
uint32_t pos1 = parents1.Length();
|
||||||
|
uint32_t pos2 = parents2.Length();
|
||||||
|
nsINode* parent = nullptr;
|
||||||
|
for (uint32_t len = std::min(pos1, pos2); len > 0; --len) {
|
||||||
|
nsINode* child1 = parents1.ElementAt(--pos1);
|
||||||
|
nsINode* child2 = parents2.ElementAt(--pos2);
|
||||||
|
if (child1 != child2) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
parent = child1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return parent;
|
||||||
|
}
|
||||||
|
|
||||||
/* static */
|
/* static */
|
||||||
int32_t nsContentUtils::ComparePoints(const RawRangeBoundary& aFirst,
|
int32_t nsContentUtils::ComparePoints(const RawRangeBoundary& aFirst,
|
||||||
const RawRangeBoundary& aSecond,
|
const RawRangeBoundary& aSecond,
|
||||||
|
|
|
@ -439,6 +439,15 @@ class nsContentUtils {
|
||||||
static Element* GetCommonFlattenedTreeAncestorForStyle(Element* aElement1,
|
static Element* GetCommonFlattenedTreeAncestorForStyle(Element* aElement1,
|
||||||
Element* aElement2);
|
Element* aElement2);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the common ancestor under interactive content, if any.
|
||||||
|
* If neither one has interactive content as ancestor, common ancestor will be
|
||||||
|
* returned. If only one has interactive content as ancestor, null will be
|
||||||
|
* returned. If the nodes are the same, that node is returned.
|
||||||
|
*/
|
||||||
|
static nsINode* GetCommonAncestorUnderInteractiveContent(nsINode* aNode1,
|
||||||
|
nsINode* aNode2);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if aNode1 is before aNode2 in the same connected
|
* Returns true if aNode1 is before aNode2 in the same connected
|
||||||
* tree.
|
* tree.
|
||||||
|
|
|
@ -162,6 +162,10 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Event)
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (WidgetMouseEvent* mouseEvent = tmp->mEvent->AsMouseEvent()) {
|
||||||
|
mouseEvent->mClickTarget = nullptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mPresContext);
|
NS_IMPL_CYCLE_COLLECTION_UNLINK(mPresContext);
|
||||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mExplicitOriginalTarget);
|
NS_IMPL_CYCLE_COLLECTION_UNLINK(mExplicitOriginalTarget);
|
||||||
|
@ -194,6 +198,11 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Event)
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (WidgetMouseEvent* mouseEvent = tmp->mEvent->AsMouseEvent()) {
|
||||||
|
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mEvent->mClickTarget");
|
||||||
|
cb.NoteXPCOMChild(mouseEvent->mClickTarget);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPresContext)
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPresContext)
|
||||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mExplicitOriginalTarget)
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mExplicitOriginalTarget)
|
||||||
|
|
|
@ -347,11 +347,9 @@ NS_IMPL_CYCLE_COLLECTING_RELEASE(EventStateManager)
|
||||||
NS_IMPL_CYCLE_COLLECTION(
|
NS_IMPL_CYCLE_COLLECTION(
|
||||||
EventStateManager, mCurrentTargetContent, mGestureDownContent,
|
EventStateManager, mCurrentTargetContent, mGestureDownContent,
|
||||||
mGestureDownFrameOwner, mLastLeftMouseDownContent,
|
mGestureDownFrameOwner, mLastLeftMouseDownContent,
|
||||||
mLastLeftMouseDownContentParent, mLastMiddleMouseDownContent,
|
mLastMiddleMouseDownContent, mLastRightMouseDownContent, mActiveContent,
|
||||||
mLastMiddleMouseDownContentParent, mLastRightMouseDownContent,
|
mHoverContent, mURLTargetContent, mMouseEnterLeaveHelper,
|
||||||
mLastRightMouseDownContentParent, mActiveContent, mHoverContent,
|
mPointersEnterLeaveHelper, mDocument, mIMEContentObserver, mAccessKeys)
|
||||||
mURLTargetContent, mMouseEnterLeaveHelper, mPointersEnterLeaveHelper,
|
|
||||||
mDocument, mIMEContentObserver, mAccessKeys)
|
|
||||||
|
|
||||||
void EventStateManager::ReleaseCurrentIMEContentObserver() {
|
void EventStateManager::ReleaseCurrentIMEContentObserver() {
|
||||||
if (mIMEContentObserver) {
|
if (mIMEContentObserver) {
|
||||||
|
@ -4594,16 +4592,13 @@ nsresult EventStateManager::SetClickCount(WidgetMouseEvent* aEvent,
|
||||||
nsEventStatus* aStatus,
|
nsEventStatus* aStatus,
|
||||||
nsIContent* aOverrideClickTarget) {
|
nsIContent* aOverrideClickTarget) {
|
||||||
nsCOMPtr<nsIContent> mouseContent = aOverrideClickTarget;
|
nsCOMPtr<nsIContent> mouseContent = aOverrideClickTarget;
|
||||||
nsIContent* mouseContentParent = nullptr;
|
|
||||||
if (!mouseContent && mCurrentTarget) {
|
if (!mouseContent && mCurrentTarget) {
|
||||||
mCurrentTarget->GetContentForEvent(aEvent, getter_AddRefs(mouseContent));
|
mCurrentTarget->GetContentForEvent(aEvent, getter_AddRefs(mouseContent));
|
||||||
}
|
}
|
||||||
if (mouseContent) {
|
if (mouseContent && mouseContent->IsText()) {
|
||||||
if (mouseContent->IsText()) {
|
nsINode* parent = mouseContent->GetFlattenedTreeParentNode();
|
||||||
mouseContent = mouseContent->GetFlattenedTreeParent();
|
if (parent && parent->IsContent()) {
|
||||||
}
|
mouseContent = parent->AsContent();
|
||||||
if (mouseContent && mouseContent->IsRootOfNativeAnonymousSubtree()) {
|
|
||||||
mouseContentParent = mouseContent->GetParent();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4611,54 +4606,51 @@ nsresult EventStateManager::SetClickCount(WidgetMouseEvent* aEvent,
|
||||||
case WidgetMouseEvent::eLeftButton:
|
case WidgetMouseEvent::eLeftButton:
|
||||||
if (aEvent->mMessage == eMouseDown) {
|
if (aEvent->mMessage == eMouseDown) {
|
||||||
mLastLeftMouseDownContent = mouseContent;
|
mLastLeftMouseDownContent = mouseContent;
|
||||||
mLastLeftMouseDownContentParent = mouseContentParent;
|
|
||||||
} else if (aEvent->mMessage == eMouseUp) {
|
} else if (aEvent->mMessage == eMouseUp) {
|
||||||
if (mLastLeftMouseDownContent == mouseContent ||
|
aEvent->mClickTarget =
|
||||||
mLastLeftMouseDownContentParent == mouseContent ||
|
nsContentUtils::GetCommonAncestorUnderInteractiveContent(
|
||||||
mLastLeftMouseDownContent == mouseContentParent) {
|
mouseContent, mLastLeftMouseDownContent);
|
||||||
|
if (aEvent->mClickTarget) {
|
||||||
aEvent->mClickCount = mLClickCount;
|
aEvent->mClickCount = mLClickCount;
|
||||||
mLClickCount = 0;
|
mLClickCount = 0;
|
||||||
} else {
|
} else {
|
||||||
aEvent->mClickCount = 0;
|
aEvent->mClickCount = 0;
|
||||||
}
|
}
|
||||||
mLastLeftMouseDownContent = nullptr;
|
mLastLeftMouseDownContent = nullptr;
|
||||||
mLastLeftMouseDownContentParent = nullptr;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WidgetMouseEvent::eMiddleButton:
|
case WidgetMouseEvent::eMiddleButton:
|
||||||
if (aEvent->mMessage == eMouseDown) {
|
if (aEvent->mMessage == eMouseDown) {
|
||||||
mLastMiddleMouseDownContent = mouseContent;
|
mLastMiddleMouseDownContent = mouseContent;
|
||||||
mLastMiddleMouseDownContentParent = mouseContentParent;
|
|
||||||
} else if (aEvent->mMessage == eMouseUp) {
|
} else if (aEvent->mMessage == eMouseUp) {
|
||||||
if (mLastMiddleMouseDownContent == mouseContent ||
|
aEvent->mClickTarget =
|
||||||
mLastMiddleMouseDownContentParent == mouseContent ||
|
nsContentUtils::GetCommonAncestorUnderInteractiveContent(
|
||||||
mLastMiddleMouseDownContent == mouseContentParent) {
|
mouseContent, mLastMiddleMouseDownContent);
|
||||||
|
if (aEvent->mClickTarget) {
|
||||||
aEvent->mClickCount = mMClickCount;
|
aEvent->mClickCount = mMClickCount;
|
||||||
mMClickCount = 0;
|
mMClickCount = 0;
|
||||||
} else {
|
} else {
|
||||||
aEvent->mClickCount = 0;
|
aEvent->mClickCount = 0;
|
||||||
}
|
}
|
||||||
mLastMiddleMouseDownContent = nullptr;
|
mLastMiddleMouseDownContent = nullptr;
|
||||||
mLastMiddleMouseDownContentParent = nullptr;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WidgetMouseEvent::eRightButton:
|
case WidgetMouseEvent::eRightButton:
|
||||||
if (aEvent->mMessage == eMouseDown) {
|
if (aEvent->mMessage == eMouseDown) {
|
||||||
mLastRightMouseDownContent = mouseContent;
|
mLastRightMouseDownContent = mouseContent;
|
||||||
mLastRightMouseDownContentParent = mouseContentParent;
|
|
||||||
} else if (aEvent->mMessage == eMouseUp) {
|
} else if (aEvent->mMessage == eMouseUp) {
|
||||||
if (mLastRightMouseDownContent == mouseContent ||
|
aEvent->mClickTarget =
|
||||||
mLastRightMouseDownContentParent == mouseContent ||
|
nsContentUtils::GetCommonAncestorUnderInteractiveContent(
|
||||||
mLastRightMouseDownContent == mouseContentParent) {
|
mouseContent, mLastRightMouseDownContent);
|
||||||
|
if (aEvent->mClickTarget) {
|
||||||
aEvent->mClickCount = mRClickCount;
|
aEvent->mClickCount = mRClickCount;
|
||||||
mRClickCount = 0;
|
mRClickCount = 0;
|
||||||
} else {
|
} else {
|
||||||
aEvent->mClickCount = 0;
|
aEvent->mClickCount = 0;
|
||||||
}
|
}
|
||||||
mLastRightMouseDownContent = nullptr;
|
mLastRightMouseDownContent = nullptr;
|
||||||
mLastRightMouseDownContentParent = nullptr;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -4679,7 +4671,7 @@ bool EventStateManager::EventCausesClickEvents(
|
||||||
}
|
}
|
||||||
// If mouse is still over same element, clickcount will be > 1.
|
// If mouse is still over same element, clickcount will be > 1.
|
||||||
// If it has moved it will be zero, so no click.
|
// If it has moved it will be zero, so no click.
|
||||||
if (!aMouseEvent.mClickCount) {
|
if (!aMouseEvent.mClickCount || !aMouseEvent.mClickTarget) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Check that the window isn't disabled before firing a click
|
// Check that the window isn't disabled before firing a click
|
||||||
|
@ -4716,6 +4708,10 @@ nsresult EventStateManager::InitAndDispatchClickEvent(
|
||||||
targetFrame = aOverrideClickTarget->GetPrimaryFrame();
|
targetFrame = aOverrideClickTarget->GetPrimaryFrame();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!target->IsInComposedDoc()) {
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
// Use local event status for each click event dispatching since it'll be
|
// Use local event status for each click event dispatching since it'll be
|
||||||
// cleared by EventStateManager::PreHandleEvent(). Therefore, dispatching
|
// cleared by EventStateManager::PreHandleEvent(). Therefore, dispatching
|
||||||
// an event means that previous event status will be ignored.
|
// an event means that previous event status will be ignored.
|
||||||
|
@ -4756,25 +4752,16 @@ nsresult EventStateManager::PostHandleMouseUp(
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsCOMPtr<nsIContent> mouseUpContent = GetEventTargetContent(aMouseUpEvent);
|
nsCOMPtr<nsIContent> clickTarget =
|
||||||
// Click events apply to *elements* not nodes. At this point the target
|
do_QueryInterface(aMouseUpEvent->mClickTarget);
|
||||||
// content may have been reset to some non-element content, and so we need
|
NS_ENSURE_STATE(clickTarget);
|
||||||
// to walk up the closest ancestor element, just like we do in
|
|
||||||
// nsPresShell::HandleEvent.
|
|
||||||
while (mouseUpContent && !mouseUpContent->IsElement()) {
|
|
||||||
mouseUpContent = mouseUpContent->GetFlattenedTreeParent();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!mouseUpContent && !mCurrentTarget && !aOverrideClickTarget) {
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fire click events if the event target is still available.
|
// Fire click events if the event target is still available.
|
||||||
// Note that do not include the eMouseUp event's status since we ignore it
|
// Note that do not include the eMouseUp event's status since we ignore it
|
||||||
// for compatibility with the other browsers.
|
// for compatibility with the other browsers.
|
||||||
nsEventStatus status = nsEventStatus_eIgnore;
|
nsEventStatus status = nsEventStatus_eIgnore;
|
||||||
nsresult rv = DispatchClickEvents(presShell, aMouseUpEvent, &status,
|
nsresult rv = DispatchClickEvents(presShell, aMouseUpEvent, &status,
|
||||||
mouseUpContent, aOverrideClickTarget);
|
clickTarget, aOverrideClickTarget);
|
||||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
@ -4815,13 +4802,13 @@ nsresult EventStateManager::PostHandleMouseUp(
|
||||||
|
|
||||||
nsresult EventStateManager::DispatchClickEvents(
|
nsresult EventStateManager::DispatchClickEvents(
|
||||||
nsIPresShell* aPresShell, WidgetMouseEvent* aMouseUpEvent,
|
nsIPresShell* aPresShell, WidgetMouseEvent* aMouseUpEvent,
|
||||||
nsEventStatus* aStatus, nsIContent* aMouseUpContent,
|
nsEventStatus* aStatus, nsIContent* aClickTarget,
|
||||||
nsIContent* aOverrideClickTarget) {
|
nsIContent* aOverrideClickTarget) {
|
||||||
MOZ_ASSERT(aPresShell);
|
MOZ_ASSERT(aPresShell);
|
||||||
MOZ_ASSERT(aMouseUpEvent);
|
MOZ_ASSERT(aMouseUpEvent);
|
||||||
MOZ_ASSERT(EventCausesClickEvents(*aMouseUpEvent));
|
MOZ_ASSERT(EventCausesClickEvents(*aMouseUpEvent));
|
||||||
MOZ_ASSERT(aStatus);
|
MOZ_ASSERT(aStatus);
|
||||||
MOZ_ASSERT(aMouseUpContent || mCurrentTarget || aOverrideClickTarget);
|
MOZ_ASSERT(aClickTarget || aOverrideClickTarget);
|
||||||
|
|
||||||
bool notDispatchToContents =
|
bool notDispatchToContents =
|
||||||
(aMouseUpEvent->button == WidgetMouseEvent::eMiddleButton ||
|
(aMouseUpEvent->button == WidgetMouseEvent::eMiddleButton ||
|
||||||
|
@ -4829,20 +4816,19 @@ nsresult EventStateManager::DispatchClickEvents(
|
||||||
|
|
||||||
bool fireAuxClick = notDispatchToContents;
|
bool fireAuxClick = notDispatchToContents;
|
||||||
|
|
||||||
// HandleEvent clears out mCurrentTarget which we might need again
|
AutoWeakFrame currentTarget = aClickTarget->GetPrimaryFrame();
|
||||||
AutoWeakFrame currentTarget = mCurrentTarget;
|
|
||||||
nsresult rv = InitAndDispatchClickEvent(
|
nsresult rv = InitAndDispatchClickEvent(
|
||||||
aMouseUpEvent, aStatus, eMouseClick, aPresShell, aMouseUpContent,
|
aMouseUpEvent, aStatus, eMouseClick, aPresShell, aClickTarget,
|
||||||
currentTarget, notDispatchToContents, aOverrideClickTarget);
|
currentTarget, notDispatchToContents, aOverrideClickTarget);
|
||||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fire double click event if click count is 2.
|
// Fire double click event if click count is 2.
|
||||||
if (aMouseUpEvent->mClickCount == 2 && aMouseUpContent &&
|
if (aMouseUpEvent->mClickCount == 2 && aClickTarget &&
|
||||||
aMouseUpContent->IsInComposedDoc()) {
|
aClickTarget->IsInComposedDoc()) {
|
||||||
rv = InitAndDispatchClickEvent(aMouseUpEvent, aStatus, eMouseDoubleClick,
|
rv = InitAndDispatchClickEvent(aMouseUpEvent, aStatus, eMouseDoubleClick,
|
||||||
aPresShell, aMouseUpContent, currentTarget,
|
aPresShell, aClickTarget, currentTarget,
|
||||||
notDispatchToContents, aOverrideClickTarget);
|
notDispatchToContents, aOverrideClickTarget);
|
||||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
return rv;
|
return rv;
|
||||||
|
@ -4850,9 +4836,9 @@ nsresult EventStateManager::DispatchClickEvents(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fire auxclick even if necessary.
|
// Fire auxclick even if necessary.
|
||||||
if (fireAuxClick && aMouseUpContent && aMouseUpContent->IsInComposedDoc()) {
|
if (fireAuxClick && aClickTarget && aClickTarget->IsInComposedDoc()) {
|
||||||
rv = InitAndDispatchClickEvent(aMouseUpEvent, aStatus, eMouseAuxClick,
|
rv = InitAndDispatchClickEvent(aMouseUpEvent, aStatus, eMouseAuxClick,
|
||||||
aPresShell, aMouseUpContent, currentTarget,
|
aPresShell, aClickTarget, currentTarget,
|
||||||
false, aOverrideClickTarget);
|
false, aOverrideClickTarget);
|
||||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed to dispatch eMouseAuxClick");
|
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed to dispatch eMouseAuxClick");
|
||||||
}
|
}
|
||||||
|
|
|
@ -1210,11 +1210,8 @@ class EventStateManager : public nsSupportsWeakReference, public nsIObserver {
|
||||||
uint16_t mGestureDownButtons;
|
uint16_t mGestureDownButtons;
|
||||||
|
|
||||||
nsCOMPtr<nsIContent> mLastLeftMouseDownContent;
|
nsCOMPtr<nsIContent> mLastLeftMouseDownContent;
|
||||||
nsCOMPtr<nsIContent> mLastLeftMouseDownContentParent;
|
|
||||||
nsCOMPtr<nsIContent> mLastMiddleMouseDownContent;
|
nsCOMPtr<nsIContent> mLastMiddleMouseDownContent;
|
||||||
nsCOMPtr<nsIContent> mLastMiddleMouseDownContentParent;
|
|
||||||
nsCOMPtr<nsIContent> mLastRightMouseDownContent;
|
nsCOMPtr<nsIContent> mLastRightMouseDownContent;
|
||||||
nsCOMPtr<nsIContent> mLastRightMouseDownContentParent;
|
|
||||||
|
|
||||||
nsCOMPtr<nsIContent> mActiveContent;
|
nsCOMPtr<nsIContent> mActiveContent;
|
||||||
nsCOMPtr<nsIContent> mHoverContent;
|
nsCOMPtr<nsIContent> mHoverContent;
|
||||||
|
|
|
@ -58,7 +58,7 @@ function runTest() {
|
||||||
|
|
||||||
is(downCount, 3, "Wrong mousedown event count!");
|
is(downCount, 3, "Wrong mousedown event count!");
|
||||||
is(upCount, 3, "Wrong mouseup event count!");
|
is(upCount, 3, "Wrong mouseup event count!");
|
||||||
is(clickCount, 2, "Wrong click event count!");
|
is(clickCount, 3, "Wrong click event count!");
|
||||||
|
|
||||||
SimpleTest.finish();
|
SimpleTest.finish();
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,8 +22,27 @@ function runTests()
|
||||||
synthesizeMouse(document.getElementById("display"), 5, 5, { clickCount: 2 });
|
synthesizeMouse(document.getElementById("display"), 5, 5, { clickCount: 2 });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
window.onmousedown = function(event) {
|
||||||
|
is(event.explicitOriginalTarget.nodeType, Node.TEXT_NODE,
|
||||||
|
"explicitOriginalTarget is a text node");
|
||||||
|
is(event.explicitOriginalTarget, document.getElementById("display").firstChild,
|
||||||
|
"explicitOriginalTarget should point to the child node of the click target");
|
||||||
|
}
|
||||||
|
|
||||||
|
window.onmouseup = function(event) {
|
||||||
|
is(event.explicitOriginalTarget.nodeType, Node.TEXT_NODE,
|
||||||
|
"explicitOriginalTarget is a text node");
|
||||||
|
is(event.explicitOriginalTarget, document.getElementById("display").firstChild,
|
||||||
|
"explicitOriginalTarget should point to the child node of the click target");
|
||||||
|
}
|
||||||
|
|
||||||
|
// The old versions of Gecko had explicitOriginalTarget pointing to a Text node
|
||||||
|
// when handling *click events, newer versions target Elements.
|
||||||
window.ondblclick = function(event) {
|
window.ondblclick = function(event) {
|
||||||
is(event.explicitOriginalTarget.nodeType, Node.TEXT_NODE, "explicitOriginalTarget is a text node");
|
is(event.explicitOriginalTarget.nodeType, Node.ELEMENT_NODE,
|
||||||
|
"explicitOriginalTarget is an element node");
|
||||||
|
is(event.explicitOriginalTarget, document.getElementById("display"),
|
||||||
|
"explicitOriginalTarget should point to the click target");
|
||||||
SimpleTest.finish();
|
SimpleTest.finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -171,11 +171,14 @@ void HTMLButtonElement::GetEventTargetParent(EventChainPreVisitor& aVisitor) {
|
||||||
WidgetMouseEvent* mouseEvent = aVisitor.mEvent->AsMouseEvent();
|
WidgetMouseEvent* mouseEvent = aVisitor.mEvent->AsMouseEvent();
|
||||||
bool outerActivateEvent = ((mouseEvent && mouseEvent->IsLeftClickEvent()) ||
|
bool outerActivateEvent = ((mouseEvent && mouseEvent->IsLeftClickEvent()) ||
|
||||||
(aVisitor.mEvent->mMessage == eLegacyDOMActivate &&
|
(aVisitor.mEvent->mMessage == eLegacyDOMActivate &&
|
||||||
!mInInternalActivate));
|
!mInInternalActivate &&
|
||||||
|
aVisitor.mEvent->mOriginalTarget == this));
|
||||||
|
|
||||||
if (outerActivateEvent) {
|
if (outerActivateEvent) {
|
||||||
aVisitor.mItemFlags |= NS_OUTER_ACTIVATE_EVENT;
|
aVisitor.mItemFlags |= NS_OUTER_ACTIVATE_EVENT;
|
||||||
if (mType == NS_FORM_BUTTON_SUBMIT && mForm) {
|
if (mType == NS_FORM_BUTTON_SUBMIT && mForm &&
|
||||||
|
!aVisitor.mEvent->mFlags.mMultiplePreActionsPrevented) {
|
||||||
|
aVisitor.mEvent->mFlags.mMultiplePreActionsPrevented = true;
|
||||||
aVisitor.mItemFlags |= NS_IN_SUBMIT_CLICK;
|
aVisitor.mItemFlags |= NS_IN_SUBMIT_CLICK;
|
||||||
// tell the form that we are about to enter a click handler.
|
// tell the form that we are about to enter a click handler.
|
||||||
// that means that if there are scripted submissions, the
|
// that means that if there are scripted submissions, the
|
||||||
|
|
|
@ -132,11 +132,14 @@ namespace dom {
|
||||||
#define NS_ORIGINAL_CHECKED_VALUE (1 << 10)
|
#define NS_ORIGINAL_CHECKED_VALUE (1 << 10)
|
||||||
#define NS_NO_CONTENT_DISPATCH (1 << 11)
|
#define NS_NO_CONTENT_DISPATCH (1 << 11)
|
||||||
#define NS_ORIGINAL_INDETERMINATE_VALUE (1 << 12)
|
#define NS_ORIGINAL_INDETERMINATE_VALUE (1 << 12)
|
||||||
#define NS_CONTROL_TYPE(bits) \
|
|
||||||
((bits) & ~(NS_OUTER_ACTIVATE_EVENT | NS_ORIGINAL_CHECKED_VALUE | \
|
|
||||||
NS_NO_CONTENT_DISPATCH | NS_ORIGINAL_INDETERMINATE_VALUE))
|
|
||||||
#define NS_PRE_HANDLE_BLUR_EVENT (1 << 13)
|
#define NS_PRE_HANDLE_BLUR_EVENT (1 << 13)
|
||||||
#define NS_PRE_HANDLE_INPUT_EVENT (1 << 14)
|
#define NS_PRE_HANDLE_INPUT_EVENT (1 << 14)
|
||||||
|
#define NS_IN_SUBMIT_CLICK (1 << 15)
|
||||||
|
#define NS_CONTROL_TYPE(bits) \
|
||||||
|
((bits) & ~(NS_OUTER_ACTIVATE_EVENT | NS_ORIGINAL_CHECKED_VALUE | \
|
||||||
|
NS_NO_CONTENT_DISPATCH | NS_ORIGINAL_INDETERMINATE_VALUE | \
|
||||||
|
NS_PRE_HANDLE_BLUR_EVENT | NS_PRE_HANDLE_INPUT_EVENT | \
|
||||||
|
NS_IN_SUBMIT_CLICK))
|
||||||
|
|
||||||
// whether textfields should be selected once focused:
|
// whether textfields should be selected once focused:
|
||||||
// -1: no, 1: yes, 0: uninitialized
|
// -1: no, 1: yes, 0: uninitialized
|
||||||
|
@ -3180,7 +3183,10 @@ void HTMLInputElement::GetEventTargetParent(EventChainPreVisitor& aVisitor) {
|
||||||
|
|
||||||
case NS_FORM_INPUT_SUBMIT:
|
case NS_FORM_INPUT_SUBMIT:
|
||||||
case NS_FORM_INPUT_IMAGE:
|
case NS_FORM_INPUT_IMAGE:
|
||||||
if (mForm) {
|
if (mForm && !aVisitor.mEvent->mFlags.mMultiplePreActionsPrevented) {
|
||||||
|
// Make sure other submit elements don't try to trigger submission.
|
||||||
|
aVisitor.mEvent->mFlags.mMultiplePreActionsPrevented = true;
|
||||||
|
aVisitor.mItemFlags |= NS_IN_SUBMIT_CLICK;
|
||||||
// tell the form that we are about to enter a click handler.
|
// tell the form that we are about to enter a click handler.
|
||||||
// that means that if there are scripted submissions, the
|
// that means that if there are scripted submissions, the
|
||||||
// latest one will be deferred until after the exit point of the
|
// latest one will be deferred until after the exit point of the
|
||||||
|
@ -3736,17 +3742,15 @@ nsresult HTMLInputElement::PostHandleEvent(EventChainPostVisitor& aVisitor) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (outerActivateEvent) {
|
if ((aVisitor.mItemFlags & NS_IN_SUBMIT_CLICK) && mForm) {
|
||||||
switch (oldType) {
|
switch (oldType) {
|
||||||
case NS_FORM_INPUT_SUBMIT:
|
case NS_FORM_INPUT_SUBMIT:
|
||||||
case NS_FORM_INPUT_IMAGE:
|
case NS_FORM_INPUT_IMAGE:
|
||||||
if (mForm) {
|
// tell the form that we are about to exit a click handler
|
||||||
// tell the form that we are about to exit a click handler
|
// so the form knows not to defer subsequent submissions
|
||||||
// so the form knows not to defer subsequent submissions
|
// the pending ones that were created during the handler
|
||||||
// the pending ones that were created during the handler
|
// will be flushed or forgoten.
|
||||||
// will be flushed or forgoten.
|
mForm->OnSubmitClickEnd();
|
||||||
mForm->OnSubmitClickEnd();
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
@ -4112,7 +4116,8 @@ nsresult HTMLInputElement::PostHandleEvent(EventChainPostVisitor& aVisitor) {
|
||||||
if (outerActivateEvent) {
|
if (outerActivateEvent) {
|
||||||
if (mForm && (oldType == NS_FORM_INPUT_SUBMIT ||
|
if (mForm && (oldType == NS_FORM_INPUT_SUBMIT ||
|
||||||
oldType == NS_FORM_INPUT_IMAGE)) {
|
oldType == NS_FORM_INPUT_IMAGE)) {
|
||||||
if (mType != NS_FORM_INPUT_SUBMIT && mType != NS_FORM_INPUT_IMAGE) {
|
if (mType != NS_FORM_INPUT_SUBMIT && mType != NS_FORM_INPUT_IMAGE &&
|
||||||
|
aVisitor.mItemFlags & NS_IN_SUBMIT_CLICK) {
|
||||||
// If the type has changed to a non-submit type, then we want to
|
// If the type has changed to a non-submit type, then we want to
|
||||||
// flush the stored submission if there is one (as if the submit()
|
// flush the stored submission if there is one (as if the submit()
|
||||||
// was allowed to succeed)
|
// was allowed to succeed)
|
||||||
|
@ -4152,7 +4157,7 @@ nsresult HTMLInputElement::PostHandleEvent(EventChainPostVisitor& aVisitor) {
|
||||||
break;
|
break;
|
||||||
} // switch
|
} // switch
|
||||||
} // click or outer activate event
|
} // click or outer activate event
|
||||||
} else if (outerActivateEvent &&
|
} else if ((aVisitor.mItemFlags & NS_IN_SUBMIT_CLICK) &&
|
||||||
(oldType == NS_FORM_INPUT_SUBMIT ||
|
(oldType == NS_FORM_INPUT_SUBMIT ||
|
||||||
oldType == NS_FORM_INPUT_IMAGE) &&
|
oldType == NS_FORM_INPUT_IMAGE) &&
|
||||||
mForm) {
|
mForm) {
|
||||||
|
|
|
@ -417,6 +417,7 @@ support-files =
|
||||||
[test_bug982039.html]
|
[test_bug982039.html]
|
||||||
[test_bug1003539.html]
|
[test_bug1003539.html]
|
||||||
[test_bug1045270.html]
|
[test_bug1045270.html]
|
||||||
|
[test_bug1089326.html]
|
||||||
[test_bug1146116.html]
|
[test_bug1146116.html]
|
||||||
[test_bug1264157.html]
|
[test_bug1264157.html]
|
||||||
[test_bug1287321.html]
|
[test_bug1287321.html]
|
||||||
|
|
|
@ -0,0 +1,108 @@
|
||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html>
|
||||||
|
<!--
|
||||||
|
https://bugzilla.mozilla.org/show_bug.cgi?id=1089326
|
||||||
|
-->
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>Test for Bug 1089326</title>
|
||||||
|
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||||
|
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
|
||||||
|
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||||
|
<script type="application/javascript">
|
||||||
|
|
||||||
|
/** Test for Bug 1089326 **/
|
||||||
|
function test() {
|
||||||
|
var b = document.getElementById("button");
|
||||||
|
var b_rect = b.getBoundingClientRect();
|
||||||
|
var a = document.getElementById("anchor");
|
||||||
|
var a_rect = a.getBoundingClientRect();
|
||||||
|
|
||||||
|
is(document.elementFromPoint(b_rect.x + 1, b_rect.y + 1), b,
|
||||||
|
"Should find button when doing hit test on top of it.");
|
||||||
|
is(document.elementFromPoint(a_rect.x + 1, a_rect.y + 1), a,
|
||||||
|
"Should find anchor when doing hit test on top of it.");
|
||||||
|
|
||||||
|
var expectedTarget;
|
||||||
|
var clickCount = 0;
|
||||||
|
var container = document.getElementById("interactiveContentContainer");
|
||||||
|
container.addEventListener("click", function(event) {
|
||||||
|
is(event.target, expectedTarget, "Got expected click event target.");
|
||||||
|
++clickCount;
|
||||||
|
}, true);
|
||||||
|
var i1 = document.getElementById("interactiveContent1");
|
||||||
|
var s11 = document.getElementById("s11");
|
||||||
|
var s12 = document.getElementById("s12");
|
||||||
|
|
||||||
|
var i2 = document.getElementById("interactiveContent2");
|
||||||
|
var s21 = document.getElementById("s21");
|
||||||
|
|
||||||
|
expectedTarget = i1;
|
||||||
|
synthesizeMouseAtCenter(s11, { type: "mousedown" });
|
||||||
|
synthesizeMouseAtCenter(s12, { type: "mouseup" });
|
||||||
|
is(clickCount, 1, "Should have got a click event.");
|
||||||
|
|
||||||
|
expectedTarget = null;
|
||||||
|
synthesizeMouseAtCenter(s11, { type: "mousedown" });
|
||||||
|
synthesizeMouseAtCenter(s21, { type: "mouseup" });
|
||||||
|
is(clickCount, 1, "Should not have got a click event.");
|
||||||
|
|
||||||
|
expectedTarget = null;
|
||||||
|
synthesizeMouseAtCenter(s21, { type: "mousedown" });
|
||||||
|
synthesizeMouseAtCenter(s11, { type: "mouseup" });
|
||||||
|
is(clickCount, 1, "Should not have got a click event.");
|
||||||
|
|
||||||
|
var span1 = document.getElementById("span1");
|
||||||
|
var span2 = document.getElementById("span2");
|
||||||
|
expectedTarget = container;
|
||||||
|
synthesizeMouseAtCenter(span1, { type: "mousedown" });
|
||||||
|
synthesizeMouseAtCenter(span2, { type: "mouseup" });
|
||||||
|
is(clickCount, 2, "Should not have got a click event.");
|
||||||
|
|
||||||
|
button.addEventListener("click", function(event) {
|
||||||
|
is(event.target, expectedTarget, "Got expected click event target.");
|
||||||
|
++clickCount;
|
||||||
|
}, true);
|
||||||
|
|
||||||
|
expectedTarget = a;
|
||||||
|
synthesizeMouseAtCenter(a, { type: "mousedown" });
|
||||||
|
synthesizeMouseAtCenter(a, { type: "mouseup" });
|
||||||
|
is(clickCount, 3, "Should have got a click event.");
|
||||||
|
|
||||||
|
expectedTarget = a;
|
||||||
|
synthesizeMouseAtCenter(b, { type: "mousedown" });
|
||||||
|
synthesizeMouseAtCenter(b, { type: "mouseup" });
|
||||||
|
is(clickCount, 4, "Should have got a click event.");
|
||||||
|
|
||||||
|
SimpleTest.finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
SimpleTest.waitForExplicitFinish();
|
||||||
|
SimpleTest.waitForFocus(test);
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1089326">Mozilla Bug 1089326</a>
|
||||||
|
<p id="display"></p>
|
||||||
|
<button id="button">button <a id="anchor" href="#">anchor</a>button</button>
|
||||||
|
|
||||||
|
<div id="interactiveContentContainer">
|
||||||
|
<a id="interactiveContent1" href="#">foo <span id="s11">s11</span><span id="s12">s12</span> bar</a>
|
||||||
|
<a id="interactiveContent2" href="#">foo <span id="s21">s21</span><span id="s22">s22</span> bar</a>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<span>
|
||||||
|
<span id="span1">span1</span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<span>
|
||||||
|
<span id="span2">span2</span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -60,9 +60,16 @@ function InitDetectorTests()
|
||||||
|
|
||||||
function SetDetectorPref(aPrefValue)
|
function SetDetectorPref(aPrefValue)
|
||||||
{
|
{
|
||||||
|
var fallback = "";
|
||||||
|
if (aPrefValue == "ja_parallel_state_machine") {
|
||||||
|
fallback = "Shift_JIS";
|
||||||
|
} else if (aPrefValue == "ruprob" || aPrefValue == "ukprob") {
|
||||||
|
fallback = "windows-1251";
|
||||||
|
}
|
||||||
var prefService = Cc["@mozilla.org/preferences-service;1"]
|
var prefService = Cc["@mozilla.org/preferences-service;1"]
|
||||||
.getService(Ci.nsIPrefBranch);
|
.getService(Ci.nsIPrefBranch);
|
||||||
prefService.setStringPref("intl.charset.detector", aPrefValue);
|
prefService.setStringPref("intl.charset.detector", aPrefValue);
|
||||||
|
prefService.setStringPref("intl.charset.fallback.override", fallback);
|
||||||
gCurrentDetector = aPrefValue;
|
gCurrentDetector = aPrefValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=811363
|
||||||
<script class="testbody" type="text/javascript">
|
<script class="testbody" type="text/javascript">
|
||||||
/** Test for Bug 811363 **/
|
/** Test for Bug 811363 **/
|
||||||
CharsetDetectionTests("bug811363-invalid-1.text",
|
CharsetDetectionTests("bug811363-invalid-1.text",
|
||||||
"windows-1252",
|
"Shift_JIS",
|
||||||
new Array("ja_parallel_state_machine"));
|
new Array("ja_parallel_state_machine"));
|
||||||
</script>
|
</script>
|
||||||
</pre>
|
</pre>
|
||||||
|
|
|
@ -22,7 +22,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=811363
|
||||||
<script class="testbody" type="text/javascript">
|
<script class="testbody" type="text/javascript">
|
||||||
/** Test for Bug 811363 **/
|
/** Test for Bug 811363 **/
|
||||||
CharsetDetectionTests("bug811363-invalid-5.text",
|
CharsetDetectionTests("bug811363-invalid-5.text",
|
||||||
"windows-1252",
|
"Shift_JIS",
|
||||||
new Array("ja_parallel_state_machine"));
|
new Array("ja_parallel_state_machine"));
|
||||||
</script>
|
</script>
|
||||||
</pre>
|
</pre>
|
||||||
|
|
|
@ -1738,7 +1738,8 @@ bool WebRenderCommandBuilder::PushImage(
|
||||||
nsDisplayItem* aItem, ImageContainer* aContainer,
|
nsDisplayItem* aItem, ImageContainer* aContainer,
|
||||||
mozilla::wr::DisplayListBuilder& aBuilder,
|
mozilla::wr::DisplayListBuilder& aBuilder,
|
||||||
mozilla::wr::IpcResourceUpdateQueue& aResources,
|
mozilla::wr::IpcResourceUpdateQueue& aResources,
|
||||||
const StackingContextHelper& aSc, const LayoutDeviceRect& aRect) {
|
const StackingContextHelper& aSc, const LayoutDeviceRect& aRect,
|
||||||
|
const LayoutDeviceRect& aClip) {
|
||||||
mozilla::wr::ImageRendering rendering = wr::ToImageRendering(
|
mozilla::wr::ImageRendering rendering = wr::ToImageRendering(
|
||||||
nsLayoutUtils::GetSamplingFilterForFrame(aItem->Frame()));
|
nsLayoutUtils::GetSamplingFilterForFrame(aItem->Frame()));
|
||||||
gfx::IntSize size;
|
gfx::IntSize size;
|
||||||
|
@ -1755,7 +1756,8 @@ bool WebRenderCommandBuilder::PushImage(
|
||||||
}
|
}
|
||||||
|
|
||||||
auto r = wr::ToRoundedLayoutRect(aRect);
|
auto r = wr::ToRoundedLayoutRect(aRect);
|
||||||
aBuilder.PushImage(r, r, !aItem->BackfaceIsHidden(), rendering, key.value());
|
auto c = wr::ToRoundedLayoutRect(aClip);
|
||||||
|
aBuilder.PushImage(r, c, !aItem->BackfaceIsHidden(), rendering, key.value());
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,7 +77,7 @@ class WebRenderCommandBuilder {
|
||||||
mozilla::wr::DisplayListBuilder& aBuilder,
|
mozilla::wr::DisplayListBuilder& aBuilder,
|
||||||
mozilla::wr::IpcResourceUpdateQueue& aResources,
|
mozilla::wr::IpcResourceUpdateQueue& aResources,
|
||||||
const StackingContextHelper& aSc,
|
const StackingContextHelper& aSc,
|
||||||
const LayoutDeviceRect& aRect);
|
const LayoutDeviceRect& aRect, const LayoutDeviceRect& aClip);
|
||||||
|
|
||||||
Maybe<wr::WrImageMask> BuildWrMaskImage(
|
Maybe<wr::WrImageMask> BuildWrMaskImage(
|
||||||
nsDisplayItem* aItem, wr::DisplayListBuilder& aBuilder,
|
nsDisplayItem* aItem, wr::DisplayListBuilder& aBuilder,
|
||||||
|
|
|
@ -459,7 +459,47 @@ void CodeGeneratorARM64::modICommon(MMod* mir, Register lhs, Register rhs,
|
||||||
MOZ_CRASH("CodeGeneratorARM64::modICommon");
|
MOZ_CRASH("CodeGeneratorARM64::modICommon");
|
||||||
}
|
}
|
||||||
|
|
||||||
void CodeGenerator::visitModI(LModI* ins) { MOZ_CRASH("visitModI"); }
|
void CodeGenerator::visitModI(LModI* ins) {
|
||||||
|
if (gen->compilingWasm()) {
|
||||||
|
MOZ_CRASH("visitModI while compilingWasm");
|
||||||
|
}
|
||||||
|
|
||||||
|
MMod* mir = ins->mir();
|
||||||
|
ARMRegister lhs = toWRegister(ins->lhs());
|
||||||
|
ARMRegister rhs = toWRegister(ins->rhs());
|
||||||
|
ARMRegister output = toWRegister(ins->output());
|
||||||
|
Label done;
|
||||||
|
|
||||||
|
if (mir->canBeDivideByZero() && !mir->isTruncated()) {
|
||||||
|
// Non-truncated division by zero produces a non-integer.
|
||||||
|
masm.Cmp(rhs, Operand(0));
|
||||||
|
bailoutIf(Assembler::Equal, ins->snapshot());
|
||||||
|
} else if (mir->canBeDivideByZero()) {
|
||||||
|
// Truncated division by zero yields integer zero.
|
||||||
|
masm.Mov(output, rhs);
|
||||||
|
masm.Cbz(rhs, &done);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Signed division.
|
||||||
|
masm.Sdiv(output, lhs, rhs);
|
||||||
|
|
||||||
|
// Compute the remainder: output = lhs - (output * rhs).
|
||||||
|
masm.Msub(output, output, rhs, lhs);
|
||||||
|
|
||||||
|
if (mir->canBeNegativeDividend() && !mir->isTruncated()) {
|
||||||
|
// If output == 0 and lhs < 0, then the result should be double -0.0.
|
||||||
|
// Note that this guard handles lhs == INT_MIN and rhs == -1:
|
||||||
|
// output = INT_MIN - (INT_MIN / -1) * -1
|
||||||
|
// = INT_MIN - INT_MIN
|
||||||
|
// = 0
|
||||||
|
masm.Cbnz(output, &done);
|
||||||
|
bailoutCmp32(Assembler::LessThan, lhs, Imm32(0), ins->snapshot());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (done.used()) {
|
||||||
|
masm.bind(&done);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void CodeGenerator::visitModPowTwoI(LModPowTwoI* ins) {
|
void CodeGenerator::visitModPowTwoI(LModPowTwoI* ins) {
|
||||||
Register lhs = ToRegister(ins->getOperand(0));
|
Register lhs = ToRegister(ins->getOperand(0));
|
||||||
|
@ -502,7 +542,97 @@ void CodeGenerator::visitModPowTwoI(LModPowTwoI* ins) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void CodeGenerator::visitModMaskI(LModMaskI* ins) {
|
void CodeGenerator::visitModMaskI(LModMaskI* ins) {
|
||||||
MOZ_CRASH("CodeGenerator::visitModMaskI");
|
MMod* mir = ins->mir();
|
||||||
|
int32_t shift = ins->shift();
|
||||||
|
|
||||||
|
const Register src = ToRegister(ins->getOperand(0));
|
||||||
|
const Register dest = ToRegister(ins->getDef(0));
|
||||||
|
const Register hold = ToRegister(ins->getTemp(0));
|
||||||
|
const Register remain = ToRegister(ins->getTemp(1));
|
||||||
|
|
||||||
|
const ARMRegister src32 = ARMRegister(src, 32);
|
||||||
|
const ARMRegister dest32 = ARMRegister(dest, 32);
|
||||||
|
const ARMRegister remain32 = ARMRegister(remain, 32);
|
||||||
|
|
||||||
|
vixl::UseScratchRegisterScope temps(&masm.asVIXL());
|
||||||
|
const ARMRegister scratch32 = temps.AcquireW();
|
||||||
|
const Register scratch = scratch32.asUnsized();
|
||||||
|
|
||||||
|
// We wish to compute x % (1<<y) - 1 for a known constant, y.
|
||||||
|
//
|
||||||
|
// 1. Let b = (1<<y) and C = (1<<y)-1, then think of the 32 bit dividend as
|
||||||
|
// a number in base b, namely c_0*1 + c_1*b + c_2*b^2 ... c_n*b^n
|
||||||
|
//
|
||||||
|
// 2. Since both addition and multiplication commute with modulus:
|
||||||
|
// x % C == (c_0 + c_1*b + ... + c_n*b^n) % C ==
|
||||||
|
// (c_0 % C) + (c_1%C) * (b % C) + (c_2 % C) * (b^2 % C)...
|
||||||
|
//
|
||||||
|
// 3. Since b == C + 1, b % C == 1, and b^n % C == 1 the whole thing
|
||||||
|
// simplifies to: c_0 + c_1 + c_2 ... c_n % C
|
||||||
|
//
|
||||||
|
// Each c_n can easily be computed by a shift/bitextract, and the modulus
|
||||||
|
// can be maintained by simply subtracting by C whenever the number gets
|
||||||
|
// over C.
|
||||||
|
int32_t mask = (1 << shift) - 1;
|
||||||
|
Label loop;
|
||||||
|
|
||||||
|
// Register 'hold' holds -1 if the value was negative, 1 otherwise.
|
||||||
|
// The remain reg holds the remaining bits that have not been processed.
|
||||||
|
// The scratch reg serves as a temporary location to store extracted bits.
|
||||||
|
// The dest reg is the accumulator, becoming final result.
|
||||||
|
//
|
||||||
|
// Move the whole value into the remain.
|
||||||
|
masm.Mov(remain32, src32);
|
||||||
|
// Zero out the dest.
|
||||||
|
masm.Mov(dest32, wzr);
|
||||||
|
// Set the hold appropriately.
|
||||||
|
{
|
||||||
|
Label negative;
|
||||||
|
masm.branch32(Assembler::Signed, remain, Imm32(0), &negative);
|
||||||
|
masm.move32(Imm32(1), hold);
|
||||||
|
masm.jump(&loop);
|
||||||
|
|
||||||
|
masm.bind(&negative);
|
||||||
|
masm.move32(Imm32(-1), hold);
|
||||||
|
masm.neg32(remain);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Begin the main loop.
|
||||||
|
masm.bind(&loop);
|
||||||
|
{
|
||||||
|
// Extract the bottom bits into scratch.
|
||||||
|
masm.And(scratch32, remain32, Operand(mask));
|
||||||
|
// Add those bits to the accumulator.
|
||||||
|
masm.Add(dest32, dest32, scratch32);
|
||||||
|
// Do a trial subtraction. This functions as a cmp but remembers the result.
|
||||||
|
masm.Subs(scratch32, dest32, Operand(mask));
|
||||||
|
// If (sum - C) > 0, store sum - C back into sum, thus performing a modulus.
|
||||||
|
{
|
||||||
|
Label sumSigned;
|
||||||
|
masm.branch32(Assembler::Signed, scratch, scratch, &sumSigned);
|
||||||
|
masm.Mov(dest32, scratch32);
|
||||||
|
masm.bind(&sumSigned);
|
||||||
|
}
|
||||||
|
// Get rid of the bits that we extracted before.
|
||||||
|
masm.Lsr(remain32, remain32, shift);
|
||||||
|
// If the shift produced zero, finish, otherwise, continue in the loop.
|
||||||
|
masm.branchTest32(Assembler::NonZero, remain, remain, &loop);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check the hold to see if we need to negate the result.
|
||||||
|
{
|
||||||
|
Label done;
|
||||||
|
|
||||||
|
// If the hold was non-zero, negate the result to match JS expectations.
|
||||||
|
masm.branchTest32(Assembler::NotSigned, hold, hold, &done);
|
||||||
|
if (mir->canBeNegativeDividend() && !mir->isTruncated()) {
|
||||||
|
// Bail in case of negative zero hold.
|
||||||
|
bailoutTest32(Assembler::Zero, hold, hold, ins->snapshot());
|
||||||
|
}
|
||||||
|
|
||||||
|
masm.neg32(dest);
|
||||||
|
masm.bind(&done);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CodeGenerator::visitBitNotI(LBitNotI* ins) {
|
void CodeGenerator::visitBitNotI(LBitNotI* ins) {
|
||||||
|
@ -1144,7 +1274,41 @@ void CodeGenerator::visitWasmStackArg(LWasmStackArg* ins) {
|
||||||
|
|
||||||
void CodeGenerator::visitUDiv(LUDiv* ins) { MOZ_CRASH("visitUDiv"); }
|
void CodeGenerator::visitUDiv(LUDiv* ins) { MOZ_CRASH("visitUDiv"); }
|
||||||
|
|
||||||
void CodeGenerator::visitUMod(LUMod* ins) { MOZ_CRASH("visitUMod"); }
|
void CodeGenerator::visitUMod(LUMod* ins) {
|
||||||
|
MMod* mir = ins->mir();
|
||||||
|
ARMRegister lhs = toWRegister(ins->lhs());
|
||||||
|
ARMRegister rhs = toWRegister(ins->rhs());
|
||||||
|
ARMRegister output = toWRegister(ins->output());
|
||||||
|
Label done;
|
||||||
|
|
||||||
|
if (mir->canBeDivideByZero() && !mir->isTruncated()) {
|
||||||
|
// Non-truncated division by zero produces a non-integer.
|
||||||
|
masm.Cmp(rhs, Operand(0));
|
||||||
|
bailoutIf(Assembler::Equal, ins->snapshot());
|
||||||
|
} else if (mir->canBeDivideByZero()) {
|
||||||
|
// Truncated division by zero yields integer zero.
|
||||||
|
masm.Mov(output, rhs);
|
||||||
|
masm.Cbz(rhs, &done);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unsigned division.
|
||||||
|
masm.Udiv(output, lhs, rhs);
|
||||||
|
|
||||||
|
// Compute the remainder: output = lhs - (output * rhs).
|
||||||
|
masm.Msub(output, output, rhs, lhs);
|
||||||
|
|
||||||
|
if (!mir->isTruncated()) {
|
||||||
|
// Bail if the output would be negative.
|
||||||
|
//
|
||||||
|
// LUMod inputs may be Uint32, so care is taken to ensure the result
|
||||||
|
// is not unexpectedly signed.
|
||||||
|
bailoutCmp32(Assembler::LessThan, output, Imm32(0), ins->snapshot());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (done.used()) {
|
||||||
|
masm.bind(&done);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void CodeGenerator::visitEffectiveAddress(LEffectiveAddress* ins) {
|
void CodeGenerator::visitEffectiveAddress(LEffectiveAddress* ins) {
|
||||||
const MEffectiveAddress* mir = ins->mir();
|
const MEffectiveAddress* mir = ins->mir();
|
||||||
|
@ -1241,10 +1405,6 @@ void CodeGenerator::visitBitOpI64(LBitOpI64*) { MOZ_CRASH("NYI"); }
|
||||||
|
|
||||||
void CodeGenerator::visitShiftI64(LShiftI64*) { MOZ_CRASH("NYI"); }
|
void CodeGenerator::visitShiftI64(LShiftI64*) { MOZ_CRASH("NYI"); }
|
||||||
|
|
||||||
void CodeGenerator::visitSoftDivI(LSoftDivI*) { MOZ_CRASH("NYI"); }
|
|
||||||
|
|
||||||
void CodeGenerator::visitSoftModI(LSoftModI*) { MOZ_CRASH("NYI"); }
|
|
||||||
|
|
||||||
void CodeGenerator::visitWasmLoad(LWasmLoad*) { MOZ_CRASH("NYI"); }
|
void CodeGenerator::visitWasmLoad(LWasmLoad*) { MOZ_CRASH("NYI"); }
|
||||||
|
|
||||||
void CodeGenerator::visitCopySignD(LCopySignD*) { MOZ_CRASH("NYI"); }
|
void CodeGenerator::visitCopySignD(LCopySignD*) { MOZ_CRASH("NYI"); }
|
||||||
|
@ -1271,8 +1431,6 @@ void CodeGenerator::visitWasmStoreI64(LWasmStoreI64*) { MOZ_CRASH("NYI"); }
|
||||||
|
|
||||||
void CodeGenerator::visitMemoryBarrier(LMemoryBarrier*) { MOZ_CRASH("NYI"); }
|
void CodeGenerator::visitMemoryBarrier(LMemoryBarrier*) { MOZ_CRASH("NYI"); }
|
||||||
|
|
||||||
void CodeGenerator::visitSoftUDivOrMod(LSoftUDivOrMod*) { MOZ_CRASH("NYI"); }
|
|
||||||
|
|
||||||
void CodeGenerator::visitWasmAddOffset(LWasmAddOffset*) { MOZ_CRASH("NYI"); }
|
void CodeGenerator::visitWasmAddOffset(LWasmAddOffset*) { MOZ_CRASH("NYI"); }
|
||||||
|
|
||||||
void CodeGenerator::visitWasmSelectI64(LWasmSelectI64*) { MOZ_CRASH("NYI"); }
|
void CodeGenerator::visitWasmSelectI64(LWasmSelectI64*) { MOZ_CRASH("NYI"); }
|
||||||
|
|
|
@ -80,36 +80,6 @@ class LDivI : public LBinaryMath<1> {
|
||||||
MDiv* mir() const { return mir_->toDiv(); }
|
MDiv* mir() const { return mir_->toDiv(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
// LSoftDivI is a software divide for ARM cores that don't support a hardware
|
|
||||||
// divide instruction.
|
|
||||||
//
|
|
||||||
// It is implemented as a proper C function so it trashes r0, r1, r2 and r3.
|
|
||||||
// The call also trashes lr, and has the ability to trash ip. The function also
|
|
||||||
// takes two arguments (dividend in r0, divisor in r1). The LInstruction gets
|
|
||||||
// encoded such that the divisor and dividend are passed in their apropriate
|
|
||||||
// registers and end their life at the start of the instruction by the use of
|
|
||||||
// useFixedAtStart. The result is returned in r0 and the other three registers
|
|
||||||
// that can be trashed are marked as temps. For the time being, the link
|
|
||||||
// register is not marked as trashed because we never allocate to the link
|
|
||||||
// register. The FP registers are not trashed.
|
|
||||||
class LSoftDivI : public LBinaryMath<3> {
|
|
||||||
public:
|
|
||||||
LIR_HEADER(SoftDivI);
|
|
||||||
|
|
||||||
LSoftDivI(const LAllocation& lhs, const LAllocation& rhs,
|
|
||||||
const LDefinition& temp1, const LDefinition& temp2,
|
|
||||||
const LDefinition& temp3)
|
|
||||||
: LBinaryMath(classOpcode) {
|
|
||||||
setOperand(0, lhs);
|
|
||||||
setOperand(1, rhs);
|
|
||||||
setTemp(0, temp1);
|
|
||||||
setTemp(1, temp2);
|
|
||||||
setTemp(2, temp3);
|
|
||||||
}
|
|
||||||
|
|
||||||
MDiv* mir() const { return mir_->toDiv(); }
|
|
||||||
};
|
|
||||||
|
|
||||||
class LDivPowTwoI : public LInstructionHelper<1, 1, 0> {
|
class LDivPowTwoI : public LInstructionHelper<1, 1, 0> {
|
||||||
const int32_t shift_;
|
const int32_t shift_;
|
||||||
|
|
||||||
|
@ -145,27 +115,6 @@ class LModI : public LBinaryMath<1> {
|
||||||
MMod* mir() const { return mir_->toMod(); }
|
MMod* mir() const { return mir_->toMod(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
class LSoftModI : public LBinaryMath<4> {
|
|
||||||
public:
|
|
||||||
LIR_HEADER(SoftModI);
|
|
||||||
|
|
||||||
LSoftModI(const LAllocation& lhs, const LAllocation& rhs,
|
|
||||||
const LDefinition& temp1, const LDefinition& temp2,
|
|
||||||
const LDefinition& temp3, const LDefinition& callTemp)
|
|
||||||
: LBinaryMath(classOpcode) {
|
|
||||||
setOperand(0, lhs);
|
|
||||||
setOperand(1, rhs);
|
|
||||||
setTemp(0, temp1);
|
|
||||||
setTemp(1, temp2);
|
|
||||||
setTemp(2, temp3);
|
|
||||||
setTemp(3, callTemp);
|
|
||||||
}
|
|
||||||
|
|
||||||
const LDefinition* callTemp() { return getTemp(3); }
|
|
||||||
|
|
||||||
MMod* mir() const { return mir_->toMod(); }
|
|
||||||
};
|
|
||||||
|
|
||||||
class LModPowTwoI : public LInstructionHelper<1, 1, 0> {
|
class LModPowTwoI : public LInstructionHelper<1, 1, 0> {
|
||||||
const int32_t shift_;
|
const int32_t shift_;
|
||||||
|
|
||||||
|
@ -181,16 +130,18 @@ class LModPowTwoI : public LInstructionHelper<1, 1, 0> {
|
||||||
MMod* mir() const { return mir_->toMod(); }
|
MMod* mir() const { return mir_->toMod(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
class LModMaskI : public LInstructionHelper<1, 1, 1> {
|
class LModMaskI : public LInstructionHelper<1, 1, 2> {
|
||||||
const int32_t shift_;
|
const int32_t shift_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
LIR_HEADER(ModMaskI);
|
LIR_HEADER(ModMaskI);
|
||||||
|
|
||||||
LModMaskI(const LAllocation& lhs, const LDefinition& temp1, int32_t shift)
|
LModMaskI(const LAllocation& lhs, const LDefinition& temp1,
|
||||||
|
const LDefinition& temp2, int32_t shift)
|
||||||
: LInstructionHelper(classOpcode), shift_(shift) {
|
: LInstructionHelper(classOpcode), shift_(shift) {
|
||||||
setOperand(0, lhs);
|
setOperand(0, lhs);
|
||||||
setTemp(0, temp1);
|
setTemp(0, temp1);
|
||||||
|
setTemp(1, temp2);
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t shift() const { return shift_; }
|
int32_t shift() const { return shift_; }
|
||||||
|
@ -262,26 +213,13 @@ class LUMod : public LBinaryMath<0> {
|
||||||
public:
|
public:
|
||||||
LIR_HEADER(UMod);
|
LIR_HEADER(UMod);
|
||||||
|
|
||||||
MMod* mir() { return mir_->toMod(); }
|
LUMod(const LAllocation& lhs, const LAllocation& rhs)
|
||||||
};
|
|
||||||
|
|
||||||
// This class performs a simple x86 'div', yielding either a quotient or
|
|
||||||
// remainder depending on whether this instruction is defined to output eax
|
|
||||||
// (quotient) or edx (remainder).
|
|
||||||
class LSoftUDivOrMod : public LBinaryMath<3> {
|
|
||||||
public:
|
|
||||||
LIR_HEADER(SoftUDivOrMod);
|
|
||||||
|
|
||||||
LSoftUDivOrMod(const LAllocation& lhs, const LAllocation& rhs,
|
|
||||||
const LDefinition& temp1, const LDefinition& temp2,
|
|
||||||
const LDefinition& temp3)
|
|
||||||
: LBinaryMath(classOpcode) {
|
: LBinaryMath(classOpcode) {
|
||||||
setOperand(0, lhs);
|
setOperand(0, lhs);
|
||||||
setOperand(1, rhs);
|
setOperand(1, rhs);
|
||||||
setTemp(0, temp1);
|
|
||||||
setTemp(1, temp2);
|
|
||||||
setTemp(2, temp3);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MMod* mir() { return mir_->toMod(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace jit
|
} // namespace jit
|
||||||
|
|
|
@ -222,7 +222,41 @@ void LIRGeneratorARM64::lowerMulI(MMul* mul, MDefinition* lhs,
|
||||||
lowerForALU(lir, mul, lhs, rhs);
|
lowerForALU(lir, mul, lhs, rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LIRGeneratorARM64::lowerModI(MMod* mod) { MOZ_CRASH("lowerModI"); }
|
void LIRGeneratorARM64::lowerModI(MMod* mod) {
|
||||||
|
if (mod->isUnsigned()) {
|
||||||
|
lowerUMod(mod);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mod->rhs()->isConstant()) {
|
||||||
|
int32_t rhs = mod->rhs()->toConstant()->toInt32();
|
||||||
|
int32_t shift = FloorLog2(rhs);
|
||||||
|
if (rhs > 0 && 1 << shift == rhs) {
|
||||||
|
LModPowTwoI* lir = new(alloc()) LModPowTwoI(useRegister(mod->lhs()), shift);
|
||||||
|
if (mod->fallible()) {
|
||||||
|
assignSnapshot(lir, Bailout_DoubleOutput);
|
||||||
|
}
|
||||||
|
define(lir, mod);
|
||||||
|
return;
|
||||||
|
} else if (shift < 31 && (1 << (shift + 1)) - 1 == rhs) {
|
||||||
|
LModMaskI* lir = new(alloc()) LModMaskI(useRegister(mod->lhs()),
|
||||||
|
temp(),
|
||||||
|
temp(),
|
||||||
|
shift + 1);
|
||||||
|
if (mod->fallible()) {
|
||||||
|
assignSnapshot(lir, Bailout_DoubleOutput);
|
||||||
|
}
|
||||||
|
define(lir, mod);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LModI* lir = new(alloc()) LModI(useRegister(mod->lhs()),
|
||||||
|
useRegister(mod->rhs()), temp());
|
||||||
|
if (mod->fallible()) {
|
||||||
|
assignSnapshot(lir, Bailout_DoubleOutput);
|
||||||
|
}
|
||||||
|
define(lir, mod);
|
||||||
|
}
|
||||||
|
|
||||||
void LIRGeneratorARM64::lowerDivI64(MDiv* div) { MOZ_CRASH("NYI"); }
|
void LIRGeneratorARM64::lowerDivI64(MDiv* div) { MOZ_CRASH("NYI"); }
|
||||||
|
|
||||||
|
@ -279,7 +313,14 @@ void LIRGenerator::visitWasmSelect(MWasmSelect* ins) {
|
||||||
|
|
||||||
void LIRGeneratorARM64::lowerUDiv(MDiv* div) { MOZ_CRASH("lowerUDiv"); }
|
void LIRGeneratorARM64::lowerUDiv(MDiv* div) { MOZ_CRASH("lowerUDiv"); }
|
||||||
|
|
||||||
void LIRGeneratorARM64::lowerUMod(MMod* mod) { MOZ_CRASH("lowerUMod"); }
|
void LIRGeneratorARM64::lowerUMod(MMod* mod) {
|
||||||
|
LUMod* lir = new(alloc()) LUMod(useRegister(mod->getOperand(0)),
|
||||||
|
useRegister(mod->getOperand(1)));
|
||||||
|
if (mod->fallible()) {
|
||||||
|
assignSnapshot(lir, Bailout_DoubleOutput);
|
||||||
|
}
|
||||||
|
define(lir, mod);
|
||||||
|
}
|
||||||
|
|
||||||
void LIRGenerator::visitWasmUnsignedToDouble(MWasmUnsignedToDouble* ins) {
|
void LIRGenerator::visitWasmUnsignedToDouble(MWasmUnsignedToDouble* ins) {
|
||||||
MOZ_CRASH("visitWasmUnsignedToDouble");
|
MOZ_CRASH("visitWasmUnsignedToDouble");
|
||||||
|
|
|
@ -96,8 +96,10 @@ void nsHTMLButtonControlFrame::BuildDisplayList(
|
||||||
|
|
||||||
nsDisplayListCollection set(aBuilder);
|
nsDisplayListCollection set(aBuilder);
|
||||||
|
|
||||||
// Do not allow the child subtree to receive events.
|
// Do not allow the child subtree to receive events,
|
||||||
if (!isForEventDelivery || aBuilder->HitTestIsForVisibility()) {
|
// except in case of <button>.
|
||||||
|
if (!isForEventDelivery || mContent->IsHTMLElement(nsGkAtoms::button) ||
|
||||||
|
aBuilder->HitTestIsForVisibility()) {
|
||||||
DisplayListClipState::AutoSaveRestore clipState(aBuilder);
|
DisplayListClipState::AutoSaveRestore clipState(aBuilder);
|
||||||
|
|
||||||
if (ShouldClipPaintingToBorderBox()) {
|
if (ShouldClipPaintingToBorderBox()) {
|
||||||
|
|
|
@ -53,8 +53,9 @@ class TextDrawTarget : public DrawTarget {
|
||||||
wr::IpcResourceUpdateQueue& aResources,
|
wr::IpcResourceUpdateQueue& aResources,
|
||||||
const layers::StackingContextHelper& aSc,
|
const layers::StackingContextHelper& aSc,
|
||||||
layers::WebRenderLayerManager* aManager,
|
layers::WebRenderLayerManager* aManager,
|
||||||
nsDisplayItem* aItem, nsRect& aBounds)
|
nsDisplayItem* aItem, nsRect& aBounds,
|
||||||
: mBuilder(aBuilder) {
|
bool aCallerDoesSaveRestore = false)
|
||||||
|
: mCallerDoesSaveRestore(aCallerDoesSaveRestore), mBuilder(aBuilder) {
|
||||||
Reinitialize(aResources, aSc, aManager, aItem, aBounds);
|
Reinitialize(aResources, aSc, aManager, aItem, aBounds);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,7 +63,7 @@ class TextDrawTarget : public DrawTarget {
|
||||||
TextDrawTarget(const TextDrawTarget& src) = delete;
|
TextDrawTarget(const TextDrawTarget& src) = delete;
|
||||||
TextDrawTarget& operator=(const TextDrawTarget&) = delete;
|
TextDrawTarget& operator=(const TextDrawTarget&) = delete;
|
||||||
|
|
||||||
~TextDrawTarget() {}
|
~TextDrawTarget() { MOZ_ASSERT(mFinished); }
|
||||||
|
|
||||||
void Reinitialize(wr::IpcResourceUpdateQueue& aResources,
|
void Reinitialize(wr::IpcResourceUpdateQueue& aResources,
|
||||||
const layers::StackingContextHelper& aSc,
|
const layers::StackingContextHelper& aSc,
|
||||||
|
@ -93,12 +94,26 @@ class TextDrawTarget : public DrawTarget {
|
||||||
|
|
||||||
mBackfaceVisible = !aItem->BackfaceIsHidden();
|
mBackfaceVisible = !aItem->BackfaceIsHidden();
|
||||||
|
|
||||||
mBuilder.Save();
|
if (!mCallerDoesSaveRestore) {
|
||||||
|
mBuilder.Save();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FoundUnsupportedFeature() { mHasUnsupportedFeatures = true; }
|
void FoundUnsupportedFeature() { mHasUnsupportedFeatures = true; }
|
||||||
|
bool CheckHasUnsupportedFeatures() {
|
||||||
|
MOZ_ASSERT(mCallerDoesSaveRestore);
|
||||||
|
#ifdef DEBUG
|
||||||
|
MOZ_ASSERT(!mFinished);
|
||||||
|
mFinished = true;
|
||||||
|
#endif
|
||||||
|
return mHasUnsupportedFeatures;
|
||||||
|
}
|
||||||
|
|
||||||
bool Finish() {
|
bool Finish() {
|
||||||
|
MOZ_ASSERT(!mCallerDoesSaveRestore);
|
||||||
|
#ifdef DEBUG
|
||||||
|
mFinished = true;
|
||||||
|
#endif
|
||||||
if (mHasUnsupportedFeatures) {
|
if (mHasUnsupportedFeatures) {
|
||||||
mBuilder.Restore();
|
mBuilder.Restore();
|
||||||
return false;
|
return false;
|
||||||
|
@ -336,6 +351,12 @@ class TextDrawTarget : public DrawTarget {
|
||||||
// * Text stroke
|
// * Text stroke
|
||||||
bool mHasUnsupportedFeatures = false;
|
bool mHasUnsupportedFeatures = false;
|
||||||
|
|
||||||
|
// The caller promises to call Save/Restore on the builder as needed.
|
||||||
|
bool mCallerDoesSaveRestore = false;
|
||||||
|
#ifdef DEBUG
|
||||||
|
bool mFinished = false;
|
||||||
|
#endif
|
||||||
|
|
||||||
// Whether PopAllShadows needs to be called
|
// Whether PopAllShadows needs to be called
|
||||||
bool mHasShadows = false;
|
bool mHasShadows = false;
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
#include "nsImageFrame.h"
|
#include "nsImageFrame.h"
|
||||||
|
|
||||||
|
#include "TextDrawTarget.h"
|
||||||
#include "gfx2DGlue.h"
|
#include "gfx2DGlue.h"
|
||||||
#include "gfxContext.h"
|
#include "gfxContext.h"
|
||||||
#include "gfxUtils.h"
|
#include "gfxUtils.h"
|
||||||
|
@ -1316,6 +1317,21 @@ class nsDisplayAltFeedback final : public nsDisplayItem {
|
||||||
nsDisplayItemGenericImageGeometry::UpdateDrawResult(this, result);
|
nsDisplayItemGenericImageGeometry::UpdateDrawResult(this, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CreateWebRenderCommands(
|
||||||
|
mozilla::wr::DisplayListBuilder& aBuilder,
|
||||||
|
mozilla::wr::IpcResourceUpdateQueue& aResources,
|
||||||
|
const StackingContextHelper& aSc,
|
||||||
|
mozilla::layers::WebRenderLayerManager* aManager,
|
||||||
|
nsDisplayListBuilder* aDisplayListBuilder) override {
|
||||||
|
uint32_t flags = imgIContainer::FLAG_ASYNC_NOTIFY;
|
||||||
|
nsImageFrame* f = static_cast<nsImageFrame*>(mFrame);
|
||||||
|
ImgDrawResult result = f->DisplayAltFeedbackWithoutLayer(
|
||||||
|
this, aBuilder, aResources, aSc, aManager, aDisplayListBuilder,
|
||||||
|
ToReferenceFrame(), flags);
|
||||||
|
|
||||||
|
return result == ImgDrawResult::SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
NS_DISPLAY_DECL_NAME("AltFeedback", TYPE_ALT_FEEDBACK)
|
NS_DISPLAY_DECL_NAME("AltFeedback", TYPE_ALT_FEEDBACK)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1473,6 +1489,226 @@ ImgDrawResult nsImageFrame::DisplayAltFeedback(gfxContext& aRenderingContext,
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ImgDrawResult nsImageFrame::DisplayAltFeedbackWithoutLayer(
|
||||||
|
nsDisplayItem* aItem, mozilla::wr::DisplayListBuilder& aBuilder,
|
||||||
|
mozilla::wr::IpcResourceUpdateQueue& aResources,
|
||||||
|
const StackingContextHelper& aSc,
|
||||||
|
mozilla::layers::WebRenderLayerManager* aManager,
|
||||||
|
nsDisplayListBuilder* aDisplayListBuilder, nsPoint aPt, uint32_t aFlags) {
|
||||||
|
// We should definitely have a gIconLoad here.
|
||||||
|
MOZ_ASSERT(gIconLoad, "How did we succeed in Init then?");
|
||||||
|
|
||||||
|
// Whether we draw the broken or loading icon.
|
||||||
|
bool isLoading = IMAGE_OK(GetContent()->AsElement()->State(), true);
|
||||||
|
|
||||||
|
// Calculate the inner area
|
||||||
|
nsRect inner = GetInnerArea() + aPt;
|
||||||
|
|
||||||
|
// Display a recessed one pixel border
|
||||||
|
nscoord borderEdgeWidth =
|
||||||
|
nsPresContext::CSSPixelsToAppUnits(ALT_BORDER_WIDTH);
|
||||||
|
|
||||||
|
// if inner area is empty, then make it big enough for at least the icon
|
||||||
|
if (inner.IsEmpty()) {
|
||||||
|
inner.SizeTo(2 * (nsPresContext::CSSPixelsToAppUnits(
|
||||||
|
ICON_SIZE + ICON_PADDING + ALT_BORDER_WIDTH)),
|
||||||
|
2 * (nsPresContext::CSSPixelsToAppUnits(
|
||||||
|
ICON_SIZE + ICON_PADDING + ALT_BORDER_WIDTH)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure we have enough room to actually render the border within
|
||||||
|
// our frame bounds
|
||||||
|
if ((inner.width < 2 * borderEdgeWidth) ||
|
||||||
|
(inner.height < 2 * borderEdgeWidth)) {
|
||||||
|
return ImgDrawResult::SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the TextDrawTarget requires fallback we need to rollback everything we
|
||||||
|
// may have added to the display list, but we don't find that out until the
|
||||||
|
// end.
|
||||||
|
bool textDrawResult = true;
|
||||||
|
class AutoSaveRestore {
|
||||||
|
public:
|
||||||
|
explicit AutoSaveRestore(mozilla::wr::DisplayListBuilder& aBuilder,
|
||||||
|
bool& aTextDrawResult)
|
||||||
|
: mBuilder(aBuilder), mTextDrawResult(aTextDrawResult) {
|
||||||
|
mBuilder.Save();
|
||||||
|
}
|
||||||
|
~AutoSaveRestore() {
|
||||||
|
// If we have to use fallback for the text restore the builder and remove
|
||||||
|
// anything else we added to the display list, we need to use fallback.
|
||||||
|
if (mTextDrawResult) {
|
||||||
|
mBuilder.ClearSave();
|
||||||
|
} else {
|
||||||
|
mBuilder.Restore();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
mozilla::wr::DisplayListBuilder& mBuilder;
|
||||||
|
bool& mTextDrawResult;
|
||||||
|
};
|
||||||
|
|
||||||
|
AutoSaveRestore autoSaveRestore(aBuilder, textDrawResult);
|
||||||
|
|
||||||
|
// Paint the border
|
||||||
|
if (!isLoading || gIconLoad->mPrefShowLoadingPlaceholder) {
|
||||||
|
nsRecessedBorder recessedBorder(borderEdgeWidth, PresContext());
|
||||||
|
// Assert that we're not drawing a border-image here; if we were, we
|
||||||
|
// couldn't ignore the ImgDrawResult that PaintBorderWithStyleBorder
|
||||||
|
// returns.
|
||||||
|
MOZ_ASSERT(recessedBorder.mBorderImageSource.GetType() ==
|
||||||
|
eStyleImageType_Null);
|
||||||
|
|
||||||
|
nsRect rect = nsRect(aPt, GetSize());
|
||||||
|
Unused << nsCSSRendering::CreateWebRenderCommandsForBorderWithStyleBorder(
|
||||||
|
aItem, this, rect, aBuilder, aResources, aSc, aManager,
|
||||||
|
aDisplayListBuilder, recessedBorder);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adjust the inner rect to account for the one pixel recessed border,
|
||||||
|
// and a six pixel padding on each edge
|
||||||
|
inner.Deflate(
|
||||||
|
nsPresContext::CSSPixelsToAppUnits(ICON_PADDING + ALT_BORDER_WIDTH),
|
||||||
|
nsPresContext::CSSPixelsToAppUnits(ICON_PADDING + ALT_BORDER_WIDTH));
|
||||||
|
if (inner.IsEmpty()) {
|
||||||
|
return ImgDrawResult::SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clip to this rect so we don't render outside the inner rect
|
||||||
|
LayoutDeviceRect bounds = LayoutDeviceRect::FromAppUnits(
|
||||||
|
inner, PresContext()->AppUnitsPerDevPixel());
|
||||||
|
auto wrBounds = wr::ToRoundedLayoutRect(bounds);
|
||||||
|
|
||||||
|
// Draw image
|
||||||
|
ImgDrawResult result = ImgDrawResult::NOT_READY;
|
||||||
|
|
||||||
|
// Check if we should display image placeholders
|
||||||
|
if (!ShouldShowBrokenImageIcon() || !gIconLoad->mPrefShowPlaceholders ||
|
||||||
|
(isLoading && !gIconLoad->mPrefShowLoadingPlaceholder)) {
|
||||||
|
result = ImgDrawResult::SUCCESS;
|
||||||
|
} else {
|
||||||
|
nscoord size = nsPresContext::CSSPixelsToAppUnits(ICON_SIZE);
|
||||||
|
imgIRequest* request = isLoading ? nsImageFrame::gIconLoad->mLoadingImage
|
||||||
|
: nsImageFrame::gIconLoad->mBrokenImage;
|
||||||
|
|
||||||
|
// If we weren't previously displaying an icon, register ourselves
|
||||||
|
// as an observer for load and animation updates and flag that we're
|
||||||
|
// doing so now.
|
||||||
|
if (request && !mDisplayingIcon) {
|
||||||
|
gIconLoad->AddIconObserver(this);
|
||||||
|
mDisplayingIcon = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
WritingMode wm = GetWritingMode();
|
||||||
|
bool flushRight =
|
||||||
|
(!wm.IsVertical() && !wm.IsBidiLTR()) || wm.IsVerticalRL();
|
||||||
|
|
||||||
|
// If the icon in question is loaded, draw it.
|
||||||
|
uint32_t imageStatus = 0;
|
||||||
|
if (request) request->GetImageStatus(&imageStatus);
|
||||||
|
if (imageStatus & imgIRequest::STATUS_LOAD_COMPLETE &&
|
||||||
|
!(imageStatus & imgIRequest::STATUS_ERROR)) {
|
||||||
|
nsCOMPtr<imgIContainer> imgCon;
|
||||||
|
request->GetImage(getter_AddRefs(imgCon));
|
||||||
|
MOZ_ASSERT(imgCon, "Load complete, but no image container?");
|
||||||
|
|
||||||
|
nsRect dest(flushRight ? inner.XMost() - size : inner.x, inner.y, size,
|
||||||
|
size);
|
||||||
|
|
||||||
|
const int32_t factor = PresContext()->AppUnitsPerDevPixel();
|
||||||
|
const LayoutDeviceRect destRect(
|
||||||
|
LayoutDeviceRect::FromAppUnits(dest, factor));
|
||||||
|
Maybe<SVGImageContext> svgContext;
|
||||||
|
IntSize decodeSize =
|
||||||
|
nsLayoutUtils::ComputeImageContainerDrawingParameters(
|
||||||
|
imgCon, this, destRect, aSc, aFlags, svgContext);
|
||||||
|
RefPtr<ImageContainer> container;
|
||||||
|
result = imgCon->GetImageContainerAtSize(
|
||||||
|
aManager, decodeSize, svgContext, aFlags, getter_AddRefs(container));
|
||||||
|
if (container) {
|
||||||
|
bool wrResult = aManager->CommandBuilder().PushImage(
|
||||||
|
aItem, container, aBuilder, aResources, aSc, destRect, bounds);
|
||||||
|
result &= wrResult ? ImgDrawResult::SUCCESS : ImgDrawResult::NOT_READY;
|
||||||
|
} else {
|
||||||
|
// We don't use &= here because we want the result to be NOT_READY so
|
||||||
|
// the next block executes.
|
||||||
|
result = ImgDrawResult::NOT_READY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we could not draw the icon, just draw some graffiti in the mean time.
|
||||||
|
if (result == ImgDrawResult::NOT_READY) {
|
||||||
|
auto color = wr::ColorF{1.0f, 0.0f, 0.0f, 1.0f};
|
||||||
|
bool isBackfaceVisible = !aItem->BackfaceIsHidden();
|
||||||
|
|
||||||
|
nscoord iconXPos = flushRight ? inner.XMost() - size : inner.x;
|
||||||
|
|
||||||
|
// stroked rect:
|
||||||
|
nsRect rect(iconXPos, inner.y, size, size);
|
||||||
|
auto devPxRect = LayoutDeviceRect::FromAppUnits(
|
||||||
|
rect, PresContext()->AppUnitsPerDevPixel());
|
||||||
|
auto dest = wr::ToRoundedLayoutRect(devPxRect);
|
||||||
|
|
||||||
|
auto borderWidths = wr::ToBorderWidths(1.0, 1.0, 1.0, 1.0);
|
||||||
|
wr::BorderSide side = {color, wr::BorderStyle::Solid};
|
||||||
|
wr::BorderSide sides[4] = {side, side, side, side};
|
||||||
|
Range<const wr::BorderSide> sidesRange(sides, 4);
|
||||||
|
aBuilder.PushBorder(dest, wrBounds, isBackfaceVisible, borderWidths,
|
||||||
|
sidesRange, wr::EmptyBorderRadius());
|
||||||
|
|
||||||
|
// filled circle in bottom right quadrant of stroked rect:
|
||||||
|
nscoord twoPX = nsPresContext::CSSPixelsToAppUnits(2);
|
||||||
|
rect = nsRect(iconXPos + size / 2, inner.y + size / 2, size / 2 - twoPX,
|
||||||
|
size / 2 - twoPX);
|
||||||
|
devPxRect = LayoutDeviceRect::FromAppUnits(
|
||||||
|
rect, PresContext()->AppUnitsPerDevPixel());
|
||||||
|
dest = wr::ToRoundedLayoutRect(devPxRect);
|
||||||
|
|
||||||
|
AutoTArray<wr::ComplexClipRegion, 1> clips;
|
||||||
|
clips.AppendElement(wr::SimpleRadii(dest, dest.size.width / 2));
|
||||||
|
auto clipId = aBuilder.DefineClip(Nothing(), dest, &clips, nullptr);
|
||||||
|
aBuilder.PushClip(clipId);
|
||||||
|
aBuilder.PushRect(dest, wrBounds, isBackfaceVisible, color);
|
||||||
|
aBuilder.PopClip();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reduce the inner rect by the width of the icon, and leave an
|
||||||
|
// additional ICON_PADDING pixels for padding
|
||||||
|
int32_t paddedIconSize =
|
||||||
|
nsPresContext::CSSPixelsToAppUnits(ICON_SIZE + ICON_PADDING);
|
||||||
|
if (wm.IsVertical()) {
|
||||||
|
inner.y += paddedIconSize;
|
||||||
|
inner.height -= paddedIconSize;
|
||||||
|
} else {
|
||||||
|
if (!flushRight) {
|
||||||
|
inner.x += paddedIconSize;
|
||||||
|
}
|
||||||
|
inner.width -= paddedIconSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw text
|
||||||
|
if (!inner.IsEmpty()) {
|
||||||
|
RefPtr<TextDrawTarget> textDrawer =
|
||||||
|
new TextDrawTarget(aBuilder, aResources, aSc, aManager, aItem, inner,
|
||||||
|
/* aCallerDoesSaveRestore = */ true);
|
||||||
|
RefPtr<gfxContext> captureCtx = gfxContext::CreateOrNull(textDrawer);
|
||||||
|
|
||||||
|
nsAutoString altText;
|
||||||
|
nsCSSFrameConstructor::GetAlternateTextFor(
|
||||||
|
mContent->AsElement(), mContent->NodeInfo()->NameAtom(), altText);
|
||||||
|
DisplayAltText(PresContext(), *captureCtx.get(), altText, inner);
|
||||||
|
|
||||||
|
textDrawer->TerminateShadows();
|
||||||
|
textDrawResult = !textDrawer->CheckHasUnsupportedFeatures();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Purposely ignore local DrawResult because we handled it not being success
|
||||||
|
// already.
|
||||||
|
return textDrawResult ? ImgDrawResult::SUCCESS : ImgDrawResult::NOT_READY;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
static void PaintDebugImageMap(nsIFrame* aFrame, DrawTarget* aDrawTarget,
|
static void PaintDebugImageMap(nsIFrame* aFrame, DrawTarget* aDrawTarget,
|
||||||
const nsRect& aDirtyRect, nsPoint aPt) {
|
const nsRect& aDirtyRect, nsPoint aPt) {
|
||||||
|
@ -1716,7 +1952,7 @@ bool nsDisplayImage::CreateWebRenderCommands(
|
||||||
// help us. Hence we can ignore the return value from PushImage.
|
// help us. Hence we can ignore the return value from PushImage.
|
||||||
if (container) {
|
if (container) {
|
||||||
aManager->CommandBuilder().PushImage(this, container, aBuilder, aResources,
|
aManager->CommandBuilder().PushImage(this, container, aBuilder, aResources,
|
||||||
aSc, destRect);
|
aSc, destRect, destRect);
|
||||||
}
|
}
|
||||||
|
|
||||||
nsDisplayItemGenericImageGeometry::UpdateDrawResult(this, drawResult);
|
nsDisplayItemGenericImageGeometry::UpdateDrawResult(this, drawResult);
|
||||||
|
|
|
@ -150,6 +150,13 @@ class nsImageFrame : public nsAtomicContainerFrame, public nsIReflowCallback {
|
||||||
const nsRect& aDirtyRect, nsPoint aPt,
|
const nsRect& aDirtyRect, nsPoint aPt,
|
||||||
uint32_t aFlags);
|
uint32_t aFlags);
|
||||||
|
|
||||||
|
ImgDrawResult DisplayAltFeedbackWithoutLayer(
|
||||||
|
nsDisplayItem* aItem, mozilla::wr::DisplayListBuilder& aBuilder,
|
||||||
|
mozilla::wr::IpcResourceUpdateQueue& aResources,
|
||||||
|
const mozilla::layers::StackingContextHelper& aSc,
|
||||||
|
mozilla::layers::WebRenderLayerManager* aManager,
|
||||||
|
nsDisplayListBuilder* aDisplayListBuilder, nsPoint aPt, uint32_t aFlags);
|
||||||
|
|
||||||
nsRect GetInnerArea() const;
|
nsRect GetInnerArea() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1340,7 +1340,7 @@ bool nsPluginFrame::CreateWebRenderCommands(
|
||||||
// help us. Hence we can ignore the return value from PushImage.
|
// help us. Hence we can ignore the return value from PushImage.
|
||||||
LayoutDeviceRect dest(r.x, r.y, size.width, size.height);
|
LayoutDeviceRect dest(r.x, r.y, size.width, size.height);
|
||||||
aManager->CommandBuilder().PushImage(aItem, container, aBuilder, aResources,
|
aManager->CommandBuilder().PushImage(aItem, container, aBuilder, aResources,
|
||||||
aSc, dest);
|
aSc, dest, dest);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -499,7 +499,7 @@ class nsDisplayVideo : public nsDisplayItem {
|
||||||
LayoutDeviceRect rect(destGFXRect.x, destGFXRect.y, destGFXRect.width,
|
LayoutDeviceRect rect(destGFXRect.x, destGFXRect.y, destGFXRect.width,
|
||||||
destGFXRect.height);
|
destGFXRect.height);
|
||||||
aManager->CommandBuilder().PushImage(this, container, aBuilder, aResources,
|
aManager->CommandBuilder().PushImage(this, container, aBuilder, aResources,
|
||||||
aSc, rect);
|
aSc, rect, rect);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -670,12 +670,28 @@ ImgDrawResult nsCSSRendering::CreateWebRenderCommandsForBorder(
|
||||||
const mozilla::layers::StackingContextHelper& aSc,
|
const mozilla::layers::StackingContextHelper& aSc,
|
||||||
mozilla::layers::WebRenderLayerManager* aManager,
|
mozilla::layers::WebRenderLayerManager* aManager,
|
||||||
nsDisplayListBuilder* aDisplayListBuilder) {
|
nsDisplayListBuilder* aDisplayListBuilder) {
|
||||||
|
const nsStyleBorder* styleBorder = aForFrame->Style()->StyleBorder();
|
||||||
|
return nsCSSRendering::CreateWebRenderCommandsForBorderWithStyleBorder(
|
||||||
|
aItem, aForFrame, aBorderArea, aBuilder, aResources, aSc, aManager,
|
||||||
|
aDisplayListBuilder, *styleBorder);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImgDrawResult nsCSSRendering::CreateWebRenderCommandsForBorderWithStyleBorder(
|
||||||
|
nsDisplayItem* aItem, nsIFrame* aForFrame, const nsRect& aBorderArea,
|
||||||
|
mozilla::wr::DisplayListBuilder& aBuilder,
|
||||||
|
mozilla::wr::IpcResourceUpdateQueue& aResources,
|
||||||
|
const mozilla::layers::StackingContextHelper& aSc,
|
||||||
|
mozilla::layers::WebRenderLayerManager* aManager,
|
||||||
|
nsDisplayListBuilder* aDisplayListBuilder,
|
||||||
|
const nsStyleBorder& aStyleBorder) {
|
||||||
// First try to draw a normal border
|
// First try to draw a normal border
|
||||||
{
|
{
|
||||||
bool borderIsEmpty = false;
|
bool borderIsEmpty = false;
|
||||||
Maybe<nsCSSBorderRenderer> br = nsCSSRendering::CreateBorderRenderer(
|
Maybe<nsCSSBorderRenderer> br =
|
||||||
aForFrame->PresContext(), nullptr, aForFrame, nsRect(), aBorderArea,
|
nsCSSRendering::CreateBorderRendererWithStyleBorder(
|
||||||
aForFrame->Style(), &borderIsEmpty, aForFrame->GetSkipSides());
|
aForFrame->PresContext(), nullptr, aForFrame, nsRect(), aBorderArea,
|
||||||
|
aStyleBorder, aForFrame->Style(), &borderIsEmpty,
|
||||||
|
aForFrame->GetSkipSides());
|
||||||
if (borderIsEmpty) {
|
if (borderIsEmpty) {
|
||||||
return ImgDrawResult::SUCCESS;
|
return ImgDrawResult::SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -687,8 +703,7 @@ ImgDrawResult nsCSSRendering::CreateWebRenderCommandsForBorder(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Next try to draw an image border
|
// Next try to draw an image border
|
||||||
const nsStyleBorder* styleBorder = aForFrame->Style()->StyleBorder();
|
const nsStyleImage* image = &aStyleBorder.mBorderImageSource;
|
||||||
const nsStyleImage* image = &styleBorder->mBorderImageSource;
|
|
||||||
|
|
||||||
// Filter out unsupported image/border types
|
// Filter out unsupported image/border types
|
||||||
if (!image) {
|
if (!image) {
|
||||||
|
@ -704,10 +719,10 @@ ImgDrawResult nsCSSRendering::CreateWebRenderCommandsForBorder(
|
||||||
return ImgDrawResult::NOT_SUPPORTED;
|
return ImgDrawResult::NOT_SUPPORTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (styleBorder->mBorderImageRepeatH == StyleBorderImageRepeat::Round ||
|
if (aStyleBorder.mBorderImageRepeatH == StyleBorderImageRepeat::Round ||
|
||||||
styleBorder->mBorderImageRepeatH == StyleBorderImageRepeat::Space ||
|
aStyleBorder.mBorderImageRepeatH == StyleBorderImageRepeat::Space ||
|
||||||
styleBorder->mBorderImageRepeatV == StyleBorderImageRepeat::Round ||
|
aStyleBorder.mBorderImageRepeatV == StyleBorderImageRepeat::Round ||
|
||||||
styleBorder->mBorderImageRepeatV == StyleBorderImageRepeat::Space) {
|
aStyleBorder.mBorderImageRepeatV == StyleBorderImageRepeat::Space) {
|
||||||
return ImgDrawResult::NOT_SUPPORTED;
|
return ImgDrawResult::NOT_SUPPORTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -719,7 +734,7 @@ ImgDrawResult nsCSSRendering::CreateWebRenderCommandsForBorder(
|
||||||
image::ImgDrawResult result;
|
image::ImgDrawResult result;
|
||||||
Maybe<nsCSSBorderImageRenderer> bir =
|
Maybe<nsCSSBorderImageRenderer> bir =
|
||||||
nsCSSBorderImageRenderer::CreateBorderImageRenderer(
|
nsCSSBorderImageRenderer::CreateBorderImageRenderer(
|
||||||
aForFrame->PresContext(), aForFrame, aBorderArea, *styleBorder,
|
aForFrame->PresContext(), aForFrame, aBorderArea, aStyleBorder,
|
||||||
aItem->GetPaintRect(), aForFrame->GetSkipSides(), flags, &result);
|
aItem->GetPaintRect(), aForFrame->GetSkipSides(), flags, &result);
|
||||||
|
|
||||||
if (!bir) {
|
if (!bir) {
|
||||||
|
|
|
@ -205,6 +205,15 @@ struct nsCSSRendering {
|
||||||
mozilla::layers::WebRenderLayerManager* aManager,
|
mozilla::layers::WebRenderLayerManager* aManager,
|
||||||
nsDisplayListBuilder* aDisplayListBuilder);
|
nsDisplayListBuilder* aDisplayListBuilder);
|
||||||
|
|
||||||
|
static ImgDrawResult CreateWebRenderCommandsForBorderWithStyleBorder(
|
||||||
|
nsDisplayItem* aItem, nsIFrame* aForFrame, const nsRect& aBorderArea,
|
||||||
|
mozilla::wr::DisplayListBuilder& aBuilder,
|
||||||
|
mozilla::wr::IpcResourceUpdateQueue& aResources,
|
||||||
|
const mozilla::layers::StackingContextHelper& aSc,
|
||||||
|
mozilla::layers::WebRenderLayerManager* aManager,
|
||||||
|
nsDisplayListBuilder* aDisplayListBuilder,
|
||||||
|
const nsStyleBorder& aStyleBorder);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render the outline for an element using css rendering rules
|
* Render the outline for an element using css rendering rules
|
||||||
* for borders.
|
* for borders.
|
||||||
|
|
|
@ -141,6 +141,7 @@ nsHtml5StreamParser::nsHtml5StreamParser(nsHtml5TreeOpExecutor* aExecutor,
|
||||||
mBomState(eBomState::BOM_SNIFFING_NOT_STARTED),
|
mBomState(eBomState::BOM_SNIFFING_NOT_STARTED),
|
||||||
mCharsetSource(kCharsetUninitialized),
|
mCharsetSource(kCharsetUninitialized),
|
||||||
mEncoding(WINDOWS_1252_ENCODING),
|
mEncoding(WINDOWS_1252_ENCODING),
|
||||||
|
mFeedChardetIfEncoding(nullptr),
|
||||||
mReparseForbidden(false),
|
mReparseForbidden(false),
|
||||||
mLastBuffer(nullptr), // Will be filled when starting
|
mLastBuffer(nullptr), // Will be filled when starting
|
||||||
mExecutor(aExecutor),
|
mExecutor(aExecutor),
|
||||||
|
@ -165,7 +166,6 @@ nsHtml5StreamParser::nsHtml5StreamParser(nsHtml5TreeOpExecutor* aExecutor,
|
||||||
mEventTarget(nsHtml5Module::GetStreamParserThread()->SerialEventTarget()),
|
mEventTarget(nsHtml5Module::GetStreamParserThread()->SerialEventTarget()),
|
||||||
mExecutorFlusher(new nsHtml5ExecutorFlusher(aExecutor)),
|
mExecutorFlusher(new nsHtml5ExecutorFlusher(aExecutor)),
|
||||||
mLoadFlusher(new nsHtml5LoadFlusher(aExecutor)),
|
mLoadFlusher(new nsHtml5LoadFlusher(aExecutor)),
|
||||||
mFeedChardet(false),
|
|
||||||
mInitialEncodingWasFromParentFrame(false),
|
mInitialEncodingWasFromParentFrame(false),
|
||||||
mHasHadErrors(false),
|
mHasHadErrors(false),
|
||||||
mDecodingLocalFileAsUTF8(false),
|
mDecodingLocalFileAsUTF8(false),
|
||||||
|
@ -198,16 +198,16 @@ nsHtml5StreamParser::nsHtml5StreamParser(nsHtml5TreeOpExecutor* aExecutor,
|
||||||
// We recognize one of the three magic strings for the following languages.
|
// We recognize one of the three magic strings for the following languages.
|
||||||
if (detectorName.EqualsLiteral("ruprob")) {
|
if (detectorName.EqualsLiteral("ruprob")) {
|
||||||
mChardet = new nsRUProbDetector();
|
mChardet = new nsRUProbDetector();
|
||||||
|
mFeedChardetIfEncoding = WINDOWS_1251_ENCODING;
|
||||||
} else if (detectorName.EqualsLiteral("ukprob")) {
|
} else if (detectorName.EqualsLiteral("ukprob")) {
|
||||||
mChardet = new nsUKProbDetector();
|
mChardet = new nsUKProbDetector();
|
||||||
|
mFeedChardetIfEncoding = WINDOWS_1251_ENCODING;
|
||||||
} else if (detectorName.EqualsLiteral("ja_parallel_state_machine")) {
|
} else if (detectorName.EqualsLiteral("ja_parallel_state_machine")) {
|
||||||
mChardet = new nsJAPSMDetector();
|
mChardet = new nsJAPSMDetector();
|
||||||
} else {
|
mFeedChardetIfEncoding = SHIFT_JIS_ENCODING;
|
||||||
mChardet = nullptr;
|
|
||||||
}
|
}
|
||||||
if (mChardet) {
|
if (mChardet) {
|
||||||
(void)mChardet->Init(this);
|
(void)mChardet->Init(this);
|
||||||
mFeedChardet = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -248,7 +248,7 @@ NS_IMETHODIMP
|
||||||
nsHtml5StreamParser::Notify(const char* aCharset, nsDetectionConfident aConf) {
|
nsHtml5StreamParser::Notify(const char* aCharset, nsDetectionConfident aConf) {
|
||||||
NS_ASSERTION(IsParserThread(), "Wrong thread!");
|
NS_ASSERTION(IsParserThread(), "Wrong thread!");
|
||||||
if (aConf == eBestAnswer || aConf == eSureAnswer) {
|
if (aConf == eBestAnswer || aConf == eSureAnswer) {
|
||||||
mFeedChardet = false; // just in case
|
mFeedChardetIfEncoding = nullptr; // just in case
|
||||||
auto encoding =
|
auto encoding =
|
||||||
Encoding::ForLabelNoReplacement(nsDependentCString(aCharset));
|
Encoding::ForLabelNoReplacement(nsDependentCString(aCharset));
|
||||||
if (!encoding) {
|
if (!encoding) {
|
||||||
|
@ -339,7 +339,7 @@ nsresult nsHtml5StreamParser::SetupDecodingFromBom(
|
||||||
mDecodingLocalFileAsUTF8 = false;
|
mDecodingLocalFileAsUTF8 = false;
|
||||||
mUnicodeDecoder = mEncoding->NewDecoderWithoutBOMHandling();
|
mUnicodeDecoder = mEncoding->NewDecoderWithoutBOMHandling();
|
||||||
mCharsetSource = kCharsetFromByteOrderMark;
|
mCharsetSource = kCharsetFromByteOrderMark;
|
||||||
mFeedChardet = false;
|
mFeedChardetIfEncoding = nullptr;
|
||||||
mTreeBuilder->SetDocumentCharset(mEncoding, mCharsetSource);
|
mTreeBuilder->SetDocumentCharset(mEncoding, mCharsetSource);
|
||||||
mSniffingBuffer = nullptr;
|
mSniffingBuffer = nullptr;
|
||||||
mMetaScanner = nullptr;
|
mMetaScanner = nullptr;
|
||||||
|
@ -397,7 +397,7 @@ void nsHtml5StreamParser::SniffBOMlessUTF16BasicLatin(
|
||||||
}
|
}
|
||||||
mCharsetSource = kCharsetFromIrreversibleAutoDetection;
|
mCharsetSource = kCharsetFromIrreversibleAutoDetection;
|
||||||
mTreeBuilder->SetDocumentCharset(mEncoding, mCharsetSource);
|
mTreeBuilder->SetDocumentCharset(mEncoding, mCharsetSource);
|
||||||
mFeedChardet = false;
|
mFeedChardetIfEncoding = nullptr;
|
||||||
mTreeBuilder->MaybeComplainAboutCharset("EncBomlessUtf16", true, 0);
|
mTreeBuilder->MaybeComplainAboutCharset("EncBomlessUtf16", true, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -533,7 +533,7 @@ nsresult nsHtml5StreamParser::FinalizeSniffing(Span<const uint8_t> aFromSegment,
|
||||||
|
|
||||||
// meta scan failed.
|
// meta scan failed.
|
||||||
if (mCharsetSource >= kCharsetFromHintPrevDoc) {
|
if (mCharsetSource >= kCharsetFromHintPrevDoc) {
|
||||||
mFeedChardet = false;
|
mFeedChardetIfEncoding = nullptr;
|
||||||
return SetupDecodingAndWriteSniffingBufferAndCurrentSegment(aFromSegment);
|
return SetupDecodingAndWriteSniffingBufferAndCurrentSegment(aFromSegment);
|
||||||
}
|
}
|
||||||
// Check for BOMless UTF-16 with Basic
|
// Check for BOMless UTF-16 with Basic
|
||||||
|
@ -541,16 +541,18 @@ nsresult nsHtml5StreamParser::FinalizeSniffing(Span<const uint8_t> aFromSegment,
|
||||||
SniffBOMlessUTF16BasicLatin(aFromSegment.To(aCountToSniffingLimit));
|
SniffBOMlessUTF16BasicLatin(aFromSegment.To(aCountToSniffingLimit));
|
||||||
// the charset may have been set now
|
// the charset may have been set now
|
||||||
// maybe try chardet now;
|
// maybe try chardet now;
|
||||||
if (mFeedChardet && !mDecodingLocalFileAsUTF8) {
|
if ((mFeedChardetIfEncoding == mEncoding) && !mDecodingLocalFileAsUTF8) {
|
||||||
bool dontFeed;
|
bool dontFeed;
|
||||||
nsresult rv;
|
nsresult rv;
|
||||||
if (mSniffingBuffer) {
|
if (mSniffingBuffer) {
|
||||||
rv = mChardet->DoIt((const char*)mSniffingBuffer.get(), mSniffingLength,
|
rv = mChardet->DoIt((const char*)mSniffingBuffer.get(), mSniffingLength,
|
||||||
&dontFeed);
|
&dontFeed);
|
||||||
mFeedChardet = !dontFeed;
|
if (dontFeed) {
|
||||||
|
mFeedChardetIfEncoding = nullptr;
|
||||||
|
}
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
}
|
}
|
||||||
if (mFeedChardet && !aFromSegment.IsEmpty()) {
|
if ((mFeedChardetIfEncoding == mEncoding) && !aFromSegment.IsEmpty()) {
|
||||||
rv = mChardet->DoIt(
|
rv = mChardet->DoIt(
|
||||||
(const char*)aFromSegment.Elements(),
|
(const char*)aFromSegment.Elements(),
|
||||||
// Avoid buffer boundary-dependent behavior when
|
// Avoid buffer boundary-dependent behavior when
|
||||||
|
@ -561,14 +563,16 @@ nsresult nsHtml5StreamParser::FinalizeSniffing(Span<const uint8_t> aFromSegment,
|
||||||
// once or twice. :-(
|
// once or twice. :-(
|
||||||
mReparseForbidden ? aCountToSniffingLimit : aFromSegment.Length(),
|
mReparseForbidden ? aCountToSniffingLimit : aFromSegment.Length(),
|
||||||
&dontFeed);
|
&dontFeed);
|
||||||
mFeedChardet = !dontFeed;
|
if (dontFeed) {
|
||||||
|
mFeedChardetIfEncoding = nullptr;
|
||||||
|
}
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
}
|
}
|
||||||
if (mFeedChardet && (aEof || mReparseForbidden)) {
|
if ((mFeedChardetIfEncoding == mEncoding) && (aEof || mReparseForbidden)) {
|
||||||
// mReparseForbidden is checked so that we get to use the sniffing
|
// mReparseForbidden is checked so that we get to use the sniffing
|
||||||
// buffer with the best guess so far if we aren't allowed to guess
|
// buffer with the best guess so far if we aren't allowed to guess
|
||||||
// better later.
|
// better later.
|
||||||
mFeedChardet = false;
|
mFeedChardetIfEncoding = nullptr;
|
||||||
rv = mChardet->Done();
|
rv = mChardet->Done();
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
}
|
}
|
||||||
|
@ -581,7 +585,7 @@ nsresult nsHtml5StreamParser::FinalizeSniffing(Span<const uint8_t> aFromSegment,
|
||||||
mTreeBuilder->SetDocumentCharset(mEncoding, mCharsetSource);
|
mTreeBuilder->SetDocumentCharset(mEncoding, mCharsetSource);
|
||||||
} else if (mMode == LOAD_AS_DATA && mCharsetSource == kCharsetFromFallback) {
|
} else if (mMode == LOAD_AS_DATA && mCharsetSource == kCharsetFromFallback) {
|
||||||
NS_ASSERTION(mReparseForbidden, "Reparse should be forbidden for XHR");
|
NS_ASSERTION(mReparseForbidden, "Reparse should be forbidden for XHR");
|
||||||
NS_ASSERTION(!mFeedChardet, "Should not feed chardet for XHR");
|
NS_ASSERTION(!mFeedChardetIfEncoding, "Should not feed chardet for XHR");
|
||||||
NS_ASSERTION(mEncoding == UTF_8_ENCODING, "XHR should default to UTF-8");
|
NS_ASSERTION(mEncoding == UTF_8_ENCODING, "XHR should default to UTF-8");
|
||||||
// Now mark charset source as non-weak to signal that we have a decision
|
// Now mark charset source as non-weak to signal that we have a decision
|
||||||
mCharsetSource = kCharsetFromDocTypeDefault;
|
mCharsetSource = kCharsetFromDocTypeDefault;
|
||||||
|
@ -668,7 +672,7 @@ nsresult nsHtml5StreamParser::SniffStreamBytes(
|
||||||
// earlier call to SetDocumentCharset(), since we didn't find a BOM and
|
// earlier call to SetDocumentCharset(), since we didn't find a BOM and
|
||||||
// overwrite mEncoding. (Note that if the user has overridden the charset,
|
// overwrite mEncoding. (Note that if the user has overridden the charset,
|
||||||
// we don't come here but check <meta> for XSS-dangerous charsets first.)
|
// we don't come here but check <meta> for XSS-dangerous charsets first.)
|
||||||
mFeedChardet = false;
|
mFeedChardetIfEncoding = nullptr;
|
||||||
mTreeBuilder->SetDocumentCharset(mEncoding, mCharsetSource);
|
mTreeBuilder->SetDocumentCharset(mEncoding, mCharsetSource);
|
||||||
return SetupDecodingAndWriteSniffingBufferAndCurrentSegment(aFromSegment);
|
return SetupDecodingAndWriteSniffingBufferAndCurrentSegment(aFromSegment);
|
||||||
}
|
}
|
||||||
|
@ -707,7 +711,7 @@ nsresult nsHtml5StreamParser::SniffStreamBytes(
|
||||||
}
|
}
|
||||||
mEncoding = WrapNotNull(encoding);
|
mEncoding = WrapNotNull(encoding);
|
||||||
mCharsetSource = kCharsetFromMetaPrescan;
|
mCharsetSource = kCharsetFromMetaPrescan;
|
||||||
mFeedChardet = false;
|
mFeedChardetIfEncoding = nullptr;
|
||||||
mTreeBuilder->SetDocumentCharset(mEncoding, mCharsetSource);
|
mTreeBuilder->SetDocumentCharset(mEncoding, mCharsetSource);
|
||||||
return SetupDecodingAndWriteSniffingBufferAndCurrentSegment(
|
return SetupDecodingAndWriteSniffingBufferAndCurrentSegment(
|
||||||
aFromSegment);
|
aFromSegment);
|
||||||
|
@ -744,7 +748,7 @@ nsresult nsHtml5StreamParser::SniffStreamBytes(
|
||||||
}
|
}
|
||||||
mEncoding = WrapNotNull(encoding);
|
mEncoding = WrapNotNull(encoding);
|
||||||
mCharsetSource = kCharsetFromMetaPrescan;
|
mCharsetSource = kCharsetFromMetaPrescan;
|
||||||
mFeedChardet = false;
|
mFeedChardetIfEncoding = nullptr;
|
||||||
mTreeBuilder->SetDocumentCharset(mEncoding, mCharsetSource);
|
mTreeBuilder->SetDocumentCharset(mEncoding, mCharsetSource);
|
||||||
return SetupDecodingAndWriteSniffingBufferAndCurrentSegment(aFromSegment);
|
return SetupDecodingAndWriteSniffingBufferAndCurrentSegment(aFromSegment);
|
||||||
}
|
}
|
||||||
|
@ -841,7 +845,7 @@ void nsHtml5StreamParser::CommitLocalFileToUTF8()
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(mDecodingLocalFileAsUTF8);
|
MOZ_ASSERT(mDecodingLocalFileAsUTF8);
|
||||||
mDecodingLocalFileAsUTF8 = false;
|
mDecodingLocalFileAsUTF8 = false;
|
||||||
mFeedChardet = false;
|
mFeedChardetIfEncoding = nullptr;
|
||||||
mEncoding = UTF_8_ENCODING;
|
mEncoding = UTF_8_ENCODING;
|
||||||
mCharsetSource = kCharsetFromFileURLGuess;
|
mCharsetSource = kCharsetFromFileURLGuess;
|
||||||
mTreeBuilder->SetDocumentCharset(mEncoding, mCharsetSource);
|
mTreeBuilder->SetDocumentCharset(mEncoding, mCharsetSource);
|
||||||
|
@ -987,7 +991,7 @@ nsresult nsHtml5StreamParser::OnStartRequest(nsIRequest* aRequest,
|
||||||
// This is the old Gecko behavior but the HTML5 spec disagrees.
|
// This is the old Gecko behavior but the HTML5 spec disagrees.
|
||||||
// Don't reparse on POST.
|
// Don't reparse on POST.
|
||||||
mReparseForbidden = true;
|
mReparseForbidden = true;
|
||||||
mFeedChardet = false; // can't restart anyway
|
mFeedChardetIfEncoding = nullptr; // can't restart anyway
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1019,7 +1023,7 @@ nsresult nsHtml5StreamParser::OnStartRequest(nsIRequest* aRequest,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mCharsetSource >= kCharsetFromAutoDetection) {
|
if (mCharsetSource >= kCharsetFromAutoDetection) {
|
||||||
mFeedChardet = false;
|
mFeedChardetIfEncoding = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsCOMPtr<nsIWyciwygChannel> wyciwygChannel(do_QueryInterface(mRequest));
|
nsCOMPtr<nsIWyciwygChannel> wyciwygChannel(do_QueryInterface(mRequest));
|
||||||
|
@ -1033,7 +1037,7 @@ nsresult nsHtml5StreamParser::OnStartRequest(nsIRequest* aRequest,
|
||||||
// a browsing context. In the latter case, there's no need to remove the
|
// a browsing context. In the latter case, there's no need to remove the
|
||||||
// BOM manually here, because the UTF-8 decoder removes it.
|
// BOM manually here, because the UTF-8 decoder removes it.
|
||||||
mReparseForbidden = true;
|
mReparseForbidden = true;
|
||||||
mFeedChardet = false;
|
mFeedChardetIfEncoding = nullptr;
|
||||||
|
|
||||||
// Instantiate the converter here to avoid BOM sniffing.
|
// Instantiate the converter here to avoid BOM sniffing.
|
||||||
mDecodingLocalFileAsUTF8 = false;
|
mDecodingLocalFileAsUTF8 = false;
|
||||||
|
@ -1073,7 +1077,7 @@ void nsHtml5StreamParser::DoStopRequest() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (mFeedChardet && !mDecodingLocalFileAsUTF8) {
|
if ((mFeedChardetIfEncoding == mEncoding) && !mDecodingLocalFileAsUTF8) {
|
||||||
mChardet->Done();
|
mChardet->Done();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1231,10 +1235,12 @@ void nsHtml5StreamParser::DoDataAvailable(Span<const uint8_t> aBuffer) {
|
||||||
|
|
||||||
nsresult rv;
|
nsresult rv;
|
||||||
if (HasDecoder()) {
|
if (HasDecoder()) {
|
||||||
if (mFeedChardet && !mDecodingLocalFileAsUTF8) {
|
if ((mFeedChardetIfEncoding == mEncoding) && !mDecodingLocalFileAsUTF8) {
|
||||||
bool dontFeed;
|
bool dontFeed;
|
||||||
mChardet->DoIt((const char*)aBuffer.Elements(), aBuffer.Length(), &dontFeed);
|
mChardet->DoIt((const char*)aBuffer.Elements(), aBuffer.Length(), &dontFeed);
|
||||||
mFeedChardet = !dontFeed;
|
if (dontFeed) {
|
||||||
|
mFeedChardetIfEncoding = nullptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
rv = WriteStreamBytes(aBuffer);
|
rv = WriteStreamBytes(aBuffer);
|
||||||
} else {
|
} else {
|
||||||
|
@ -1393,7 +1399,7 @@ const Encoding* nsHtml5StreamParser::PreferredForInternalEncodingDecl(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mCharsetSource = kCharsetFromMetaTag; // become confident
|
mCharsetSource = kCharsetFromMetaTag; // become confident
|
||||||
mFeedChardet = false; // don't feed chardet when confident
|
mFeedChardetIfEncoding = nullptr; // don't feed chardet when confident
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1432,7 +1438,7 @@ bool nsHtml5StreamParser::internalEncodingDeclaration(nsHtml5String aEncoding) {
|
||||||
|
|
||||||
// Avoid having the chardet ask for another restart after this restart
|
// Avoid having the chardet ask for another restart after this restart
|
||||||
// request.
|
// request.
|
||||||
mFeedChardet = false;
|
mFeedChardetIfEncoding = nullptr;
|
||||||
mTreeBuilder->NeedsCharsetSwitchTo(WrapNotNull(encoding), kCharsetFromMetaTag,
|
mTreeBuilder->NeedsCharsetSwitchTo(WrapNotNull(encoding), kCharsetFromMetaTag,
|
||||||
mTokenizer->getLineNumber());
|
mTokenizer->getLineNumber());
|
||||||
FlushTreeOpsAndDisarmTimer();
|
FlushTreeOpsAndDisarmTimer();
|
||||||
|
|
|
@ -412,6 +412,11 @@ class nsHtml5StreamParser final : public nsICharsetDetectionObserver {
|
||||||
*/
|
*/
|
||||||
NotNull<const Encoding*> mEncoding;
|
NotNull<const Encoding*> mEncoding;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The character encoding that is the base expectation for detection.
|
||||||
|
*/
|
||||||
|
const Encoding* mFeedChardetIfEncoding;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether reparse is forbidden
|
* Whether reparse is forbidden
|
||||||
*/
|
*/
|
||||||
|
@ -530,11 +535,6 @@ class nsHtml5StreamParser final : public nsICharsetDetectionObserver {
|
||||||
*/
|
*/
|
||||||
nsCOMPtr<nsICharsetDetector> mChardet;
|
nsCOMPtr<nsICharsetDetector> mChardet;
|
||||||
|
|
||||||
/**
|
|
||||||
* If false, don't push data to chardet.
|
|
||||||
*/
|
|
||||||
bool mFeedChardet;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether the initial charset source was kCharsetFromParentFrame
|
* Whether the initial charset source was kCharsetFromParentFrame
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1035,9 +1035,7 @@ element.getContainer = function(el) {
|
||||||
return element.findClosest(el, "datalist,select") || el;
|
return element.findClosest(el, "datalist,select") || el;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Child nodes of button will not be part of the element tree for
|
return el;
|
||||||
// elementsFromPoint until bug 1089326 is fixed.
|
|
||||||
return element.findClosest(el, "button") || el;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,4 +1,2 @@
|
||||||
[ecdh_keys.https.any.html]
|
[ecdh_keys.https.any.html]
|
||||||
expected: TIMEOUT
|
expected: TIMEOUT
|
||||||
|
|
||||||
[ecdh_keys.https.any.worker.html]
|
|
||||||
|
|
|
@ -4865,11 +4865,3 @@
|
||||||
[Derived key of type name: AES-CTR length: 128 using empty derivedKey, normal salt, SHA-256, with empty info with missing deriveKey usage]
|
[Derived key of type name: AES-CTR length: 128 using empty derivedKey, normal salt, SHA-256, with empty info with missing deriveKey usage]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
|
||||||
[hkdf.https.any.worker.html?2001-3000]
|
|
||||||
|
|
||||||
[hkdf.https.any.worker.html?3001-last]
|
|
||||||
|
|
||||||
[hkdf.https.any.worker.html?1001-2000]
|
|
||||||
|
|
||||||
[hkdf.https.any.worker.html?1-1000]
|
|
||||||
|
|
|
@ -6,7 +6,5 @@
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[Test that the child iframe navigation is not allowed]
|
[Test that the child iframe navigation is not allowed]
|
||||||
expected:
|
expected: FAIL
|
||||||
if not debug and not webrender and not e10s and (os == "android") and (version == "Ubuntu 16.04") and (processor == "x86") and (bits == 32): NOTRUN
|
|
||||||
FAIL
|
|
||||||
|
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
[adopted-callback.html]
|
|
||||||
expected: ERROR
|
|
|
@ -1,5 +1,4 @@
|
||||||
[parser-uses-registry-of-owner-document.html]
|
[parser-uses-registry-of-owner-document.html]
|
||||||
expected: ERROR
|
|
||||||
[HTML parser must use the registry of window.document in a document created by document.implementation.createHTMLDocument()]
|
[HTML parser must use the registry of window.document in a document created by document.implementation.createHTMLDocument()]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -1,7 +0,0 @@
|
||||||
[Attr.html]
|
|
||||||
[value on Attr must not enqueue an attributeChanged reaction when replacing an existing unobserved attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[value on Attr must enqueue an attributeChanged reaction when replacing an existing attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -1,91 +0,0 @@
|
||||||
[CSSStyleDeclaration.html]
|
|
||||||
[A dashed property (border-width) on CSSStyleDeclaration must enqueue an attributeChanged reaction when it adds the observed style attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[cssText on CSSStyleDeclaration must not enqueue an attributeChanged reaction when it mutates the style attribute but the style attribute is not observed]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[setProperty on CSSStyleDeclaration must enqueue an attributeChanged reaction when it mutates the observed style attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[A webkit prefixed dashed property (-webkit-filter) on CSSStyleDeclaration must not enqueue an attributeChanged reaction when it mutates the style attribute but the style attribute is not observed]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[cssFloat on CSSStyleDeclaration must enqueue an attributeChanged reaction when it adds the observed style attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[cssText on CSSStyleDeclaration must not enqueue an attributeChanged reaction when it adds the style attribute but the style attribute is not observed]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[A camel case attribute (borderWidth) on CSSStyleDeclaration must not enqueue an attributeChanged reaction when it mutates the style attribute but the style attribute is not observed]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[cssFloat on CSSStyleDeclaration must not enqueue an attributeChanged reaction when it adds the style attribute but the style attribute is not observed]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[A webkit prefixed dashed property (-webkit-filter) on CSSStyleDeclaration must not enqueue an attributeChanged reaction when it adds the style attribute but the style attribute is not observed]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[setProperty on CSSStyleDeclaration must not enqueue an attributeChanged reaction when it adds the style attribute but the style attribute is not observed]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[setProperty on CSSStyleDeclaration must enqueue an attributeChanged reaction when it makes a property important but the style attribute is not observed]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[setProperty on CSSStyleDeclaration must enqueue an attributeChanged reaction when it makes a property important and the style attribute is observed]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[A webkit prefixed dashed property (-webkit-filter) on CSSStyleDeclaration must enqueue an attributeChanged reaction when it adds the observed style attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[A webkit prefixed dashed property (-webkit-filter) on CSSStyleDeclaration must enqueue an attributeChanged reaction when it mutates the observed style attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[A dashed property (border-width) on CSSStyleDeclaration must enqueue an attributeChanged reaction when it mutates the observed style attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[A camel case attribute (borderWidth) on CSSStyleDeclaration must enqueue an attributeChanged reaction when it adds the observed style attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[setProperty on CSSStyleDeclaration must enqueue an attributeChanged reaction when it adds the observed style attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[A webkit prefixed camel case attribute (webkitFilter) on CSSStyleDeclaration must enqueue an attributeChanged reaction when it adds the observed style attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[A webkit prefixed camel case attribute (webkitFilter) on CSSStyleDeclaration must not enqueue an attributeChanged reaction when it mutates the style attribute but the style attribute is not observed]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[removeProperty on CSSStyleDeclaration must enqueue an attributeChanged reaction when it removes a property from the observed style attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[cssText on CSSStyleDeclaration must enqueue an attributeChanged reaction when it mutates the observed style attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[A camel case attribute (borderWidth) on CSSStyleDeclaration must not enqueue an attributeChanged reaction when it adds the style attribute but the style attribute is not observed]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[A dashed property (border-width) on CSSStyleDeclaration must not enqueue an attributeChanged reaction when it adds the style attribute but the style attribute is not observed]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[A webkit prefixed camel case attribute (webkitFilter) on CSSStyleDeclaration must not enqueue an attributeChanged reaction when it adds the style attribute but the style attribute is not observed]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[A webkit prefixed camel case attribute (webkitFilter) on CSSStyleDeclaration must enqueue an attributeChanged reaction when it mutates the observed style attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[setProperty on CSSStyleDeclaration must not enqueue an attributeChanged reaction when it mutates the style attribute but the style attribute is not observed]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[cssText on CSSStyleDeclaration must enqueue an attributeChanged reaction when it adds the observed style attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[removeProperty on CSSStyleDeclaration must not enqueue an attributeChanged reaction when it removes a property from the style attribute but the style attribute is not observed]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[A camel case attribute (borderWidth) on CSSStyleDeclaration must enqueue an attributeChanged reaction when it mutates the observed style attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[A dashed property (border-width) on CSSStyleDeclaration must not enqueue an attributeChanged reaction when it mutates the style attribute but the style attribute is not observed]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -1,22 +0,0 @@
|
||||||
[ChildNode.html]
|
|
||||||
[before on ChildNode must enqueue a connected reaction]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[replaceWith on ChildNode must enqueue a disconnected reaction, an adopted reaction, and a connected reaction when the custom element was in another document]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[before on ChildNode must enqueue a disconnected reaction, an adopted reaction, and a connected reaction when the custom element was in another document]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[after on ChildNode must enqueue a connected reaction]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[remove on ChildNode must enqueue a disconnected reaction]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[replaceWith on ChildNode must enqueue a connected reaction]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[after on ChildNode must enqueue a disconnected reaction, an adopted reaction, and a connected reaction when the custom element was in another document]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -1,25 +0,0 @@
|
||||||
[DOMStringMap.html]
|
|
||||||
[deleter on DOMStringMap must enqueue an attributeChanged reaction when removing an observed data attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[deleter on DOMStringMap must not enqueue an attributeChanged reaction when removing an unobserved data attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[setter on DOMStringMap must not enqueue an attributeChanged reaction when mutating the value of an unobserved data attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[setter on DOMStringMap must enqueue an attributeChanged reaction when adding an observed data attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[setter on DOMStringMap must not enqueue an attributeChanged reaction when adding an unobserved data attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[setter on DOMStringMap must enqueue an attributeChanged reaction when mutating the value of an observed data attribute to the same value]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[deleter on DOMStringMap must not enqueue an attributeChanged reaction when it does not remove a data attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[setter on DOMStringMap must enqueue an attributeChanged reaction when mutating the value of an observed data attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -1,58 +0,0 @@
|
||||||
[DOMTokenList.html]
|
|
||||||
[add on DOMTokenList must not enqueue an attributeChanged reaction when adding an unobserved attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[replace on DOMTokenList must not enqueue an attributeChanged reaction when the token to replace does not exist in the attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[replace on DOMTokenList must not enqueue an attributeChanged reaction when replacing a value in an unobserved attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[toggle on DOMTokenList must enqueue an attributeChanged reaction when removing a value from an attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[add on DOMTokenList must not enqueue an attributeChanged reaction when adding a value to an unobserved attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[add on DOMTokenList must enqueue exactly one attributeChanged reaction when adding multiple values to an attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[remove on DOMTokenList must enqueue an attributeChanged reaction when removing a value from an attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[the stringifier of DOMTokenList must not enqueue an attributeChanged reaction when adding an unobserved attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[the stringifier of DOMTokenList must enqueue an attributeChanged reaction when the setter is called with the original value of the attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[toggle on DOMTokenList must enqueue an attributeChanged reaction when adding a value to an attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[the stringifier of DOMTokenList must enqueue an attributeChanged reaction when adding an observed attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[add on DOMTokenList must enqueue an attributeChanged reaction when adding a value to an existing attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[remove on DOMTokenList must enqueue an attributeChanged reaction even when removing a non-existent value from an attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[remove on DOMTokenList must not enqueue an attributeChanged reaction when removing a value from an unobserved attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[remove on DOMTokenList must enqueue exactly one attributeChanged reaction when removing multiple values to an attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[the stringifier of DOMTokenList must enqueue an attributeChanged reaction when mutating the value of an observed attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[replace on DOMTokenList must enqueue an attributeChanged reaction when replacing a value in an attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[add on DOMTokenList must enqueue an attributeChanged reaction when adding an attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[the stringifier of DOMTokenList must not enqueue an attributeChanged reaction when mutating the value of an unobserved attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -14,126 +14,3 @@
|
||||||
[undefined must enqueue a disconnected reaction, an adopted reaction, and a connected reaction when the custom element was in another document]
|
[undefined must enqueue a disconnected reaction, an adopted reaction, and a connected reaction when the custom element was in another document]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[className on Element must enqueue an attributeChanged reaction when adding class content attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[id on Element must enqueue an attributeChanged reaction when adding id content attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[removeAttributeNS on Element must not enqueue an attributeChanged reaction when removing an unobserved attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[setAttributeNode on Element must not enqueue an attributeChanged reaction when adding an unobserved attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[slot on Element must enqueue an attributeChanged reaction when adding slot content attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[insertAdjacentHTML on Element must enqueue a attributeChanged reaction for a newly constructed custom element]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[removeAttribute on Element must enqueue an attributeChanged reaction when removing an existing attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[setAttributeNodeNS on Element must not enqueue an attributeChanged reaction when adding an unobserved attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[removeAttribute on Element must not enqueue an attributeChanged reaction when removing an existing unobserved attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[id on Element must enqueue an attributeChanged reaction when replacing an existing attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[insertAdjacentHTML on Element must enqueue a connected reaction for a newly constructed custom element]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[removeAttributeNode on Element must not enqueue an attributeChanged reaction when removing an unobserved attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[removeAttributeNode on Element must enqueue an attributeChanged reaction when removing an existing attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[slot on Element must enqueue an attributeChanged reaction when replacing an existing attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[outerHTML on Element must enqueue a attributeChanged reaction for a newly constructed custom element]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[innerHTML on Element must enqueue a disconnected reaction]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[setAttributeNS on Element must enqueue an attributeChanged reaction when replacing an existing attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[setAttribute on Element must not enqueue an attributeChanged reaction when adding an unobserved attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[outerHTML on Element must enqueue a disconnected reaction]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[removeAttributeNode on Element must not enqueue an attributeChanged reaction when removing an existing unobserved attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[outerHTML on Element must enqueue a connected reaction for a newly constructed custom element]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[innerHTML on Element must enqueue a attributeChanged reaction for a newly constructed custom element]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[setAttribute on Element must enqueue an attributeChanged reaction when replacing an existing attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[setAttributeNode on Element must enqueue an attributeChanged reaction when adding an attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[setAttributeNodeNS on Element must enqueue an attributeChanged reaction when replacing an existing attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[insertAdjacentElement on Element must enqueue a disconnected reaction, an adopted reaction, and a connected reaction when the custom element was in another document]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[removeAttribute on Element must not enqueue an attributeChanged reaction when removing an unobserved attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[setAttributeNodeNS on Element must enqueue an attributeChanged reaction when replacing an existing unobserved attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[className on Element must enqueue an attributeChanged reaction when replacing an existing attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[removeAttributeNS on Element must enqueue an attributeChanged reaction when removing an existing attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[innerHTML on Element must enqueue a connected reaction for a newly constructed custom element]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[setAttributeNodeNS on Element must enqueue an attributeChanged reaction when adding an attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[removeAttributeNS on Element must not enqueue an attributeChanged reaction when removing an existing unobserved attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[insertAdjacentElement on Element must enqueue a connected reaction]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[setAttributeNode on Element must enqueue an attributeChanged reaction when replacing an existing unobserved attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[setAttribute on Element must enqueue an attributeChanged reaction when replacing an existing unobserved attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[setAttributeNS on Element must enqueue an attributeChanged reaction when replacing an existing unobserved attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[setAttribute on Element must enqueue an attributeChanged reaction when adding an attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[setAttributeNode on Element must enqueue an attributeChanged reaction when replacing an existing attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[setAttributeNS on Element must not enqueue an attributeChanged reaction when adding an unobserved attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[setAttributeNS on Element must enqueue an attributeChanged reaction when adding an attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
|
|
|
@ -1,7 +0,0 @@
|
||||||
[ElementContentEditable.html]
|
|
||||||
[contentEditable on ElementContentEditable must enqueue an attributeChanged reaction when adding contenteditable content attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[contentEditable on ElementContentEditable must enqueue an attributeChanged reaction when replacing an existing attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -17,45 +17,3 @@
|
||||||
[formNoValidate on HTMLButtonElement must enqueue an attributeChanged reaction when replacing an existing attribute]
|
[formNoValidate on HTMLButtonElement must enqueue an attributeChanged reaction when replacing an existing attribute]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[formMethod on HTMLButtonElement must enqueue an attributeChanged reaction when replacing an existing attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[formMethod on HTMLButtonElement must enqueue an attributeChanged reaction when adding a new attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[formEnctype on HTMLButtonElement must enqueue an attributeChanged reaction when adding a new attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[formAction on HTMLButtonElement must enqueue an attributeChanged reaction when adding a new attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[value on HTMLButtonElement must enqueue an attributeChanged reaction when adding value content attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[type on HTMLButtonElement must enqueue an attributeChanged reaction when replacing an existing attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[formTarget on HTMLButtonElement must enqueue an attributeChanged reaction when replacing an existing attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[formTarget on HTMLButtonElement must enqueue an attributeChanged reaction when adding a new attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[formAction on HTMLButtonElement must enqueue an attributeChanged reaction when replacing an existing attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[name on HTMLButtonElement must enqueue an attributeChanged reaction when adding name content attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[value on HTMLButtonElement must enqueue an attributeChanged reaction when replacing an existing attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[formEnctype on HTMLButtonElement must enqueue an attributeChanged reaction when replacing an existing attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[name on HTMLButtonElement must enqueue an attributeChanged reaction when replacing an existing attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[type on HTMLButtonElement must enqueue an attributeChanged reaction when adding a new attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
|
|
|
@ -17,54 +17,3 @@
|
||||||
[contextMenu on HTMLElement must enqueue an attributeChanged reaction when replacing an existing attribute]
|
[contextMenu on HTMLElement must enqueue an attributeChanged reaction when replacing an existing attribute]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[hidden on HTMLElement must enqueue an attributeChanged reaction when adding hidden content attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[hidden on HTMLElement must enqueue an attributeChanged reaction when replacing an existing attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[tabIndex on HTMLElement must enqueue an attributeChanged reaction when replacing an existing attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[draggable on HTMLElement must enqueue an attributeChanged reaction when replacing an existing attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[accessKey on HTMLElement must enqueue an attributeChanged reaction when adding accesskey content attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[spellcheck on HTMLElement must enqueue an attributeChanged reaction when adding spellcheck content attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[lang on HTMLElement must enqueue an attributeChanged reaction when replacing an existing attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[accessKey on HTMLElement must enqueue an attributeChanged reaction when replacing an existing attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[draggable on HTMLElement must enqueue an attributeChanged reaction when adding draggable content attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[innerText on HTMLElement must enqueue a disconnected reaction]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[title on HTMLElement must enqueue an attributeChanged reaction when replacing an existing attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[spellcheck on HTMLElement must enqueue an attributeChanged reaction when replacing an existing attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[lang on HTMLElement must enqueue an attributeChanged reaction when adding lang content attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[dir on HTMLElement must enqueue an attributeChanged reaction when replacing an existing attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[title on HTMLElement must enqueue an attributeChanged reaction when adding title content attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[tabIndex on HTMLElement must enqueue an attributeChanged reaction when adding tabindex content attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[dir on HTMLElement must enqueue an attributeChanged reaction when adding dir content attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
|
|
|
@ -1,43 +0,0 @@
|
||||||
[NamedNodeMap.html]
|
|
||||||
[removeNamedItem on NamedNodeMap must not enqueue an attributeChanged reaction when removing an existing unobserved attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[removeNamedItemNS on NamedNodeMap must enqueue an attributeChanged reaction when removing an existing attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[setNamedItemNS on NamedNodeMap must enqueue an attributeChanged reaction when adding an attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[removeNamedItem on NamedNodeMap must enqueue an attributeChanged reaction when removing an existing attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[setNamedItemNS on NamedNodeMap must enqueue an attributeChanged reaction when replacing an existing unobserved attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[removeNamedItemNS on NamedNodeMap must not enqueue an attributeChanged reaction when removing an unobserved attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[setNamedItem on NamedNodeMap must enqueue an attributeChanged reaction when adding an attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[setNamedItem on NamedNodeMap must not enqueue an attributeChanged reaction when adding an unobserved attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[removeNamedItem on NamedNodeMap must not enqueue an attributeChanged reaction when removing an unobserved attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[setNamedItemNS on NamedNodeMap must enqueue an attributeChanged reaction when replacing an existing attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[setNamedItem on NamedNodeMap must enqueue an attributeChanged reaction when replacing an existing unobserved attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[removeNamedItemNS on NamedNodeMap must not enqueue an attributeChanged reaction when removing an existing unobserved attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[setNamedItemNS on NamedNodeMap must not enqueue an attributeChanged reaction when adding an unobserved attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[setNamedItem on NamedNodeMap must enqueue an attributeChanged reaction when replacing an existing attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -1,43 +0,0 @@
|
||||||
[Node.html]
|
|
||||||
[removeChild on ChildNode must enqueue a disconnected reaction]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[cloneNode on Node must enqueue an attributeChanged reaction when cloning an element with an observed attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[replaceChild on ChildNode must enqueue a connected reaction]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[nodeValue on Node must enqueue an attributeChanged reaction when replacing an existing attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[cloneNode on Node must not enqueue an attributeChanged reaction when cloning an element with an unobserved attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[cloneNode on Node must enqueue an attributeChanged reaction when cloning an element only for observed attributes]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[appendChild on ChildNode must enqueue a disconnected reaction, an adopted reaction, and a connected reaction when the custom element was in another document]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[insertBefore on ChildNode must enqueue a disconnected reaction, an adopted reaction, and a connected reaction when the custom element was in another document]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[insertBefore on ChildNode must enqueue a connected reaction]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[appendChild on ChildNode must enqueue a connected reaction]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[textContent on Node must not enqueue an attributeChanged reaction when replacing an existing unobserved attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[textContent on Node must enqueue an attributeChanged reaction when replacing an existing attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[replaceChild on ChildNode must enqueue a disconnected reaction, an adopted reaction, and a connected reaction when the custom element was in another document]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[nodeValue on Node must not enqueue an attributeChanged reaction when replacing an existing unobserved attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
[ParentNode.html]
|
|
||||||
[prepend on ParentNode must enqueue a connected reaction]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[prepend on ParentNode must enqueue a disconnected reaction, an adopted reaction, and a connected reaction when the custom element was in another document]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[append on ParentNode must enqueue a disconnected reaction, an adopted reaction, and a connected reaction when the custom element was in another document]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[append on ParentNode must enqueue a connected reaction]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -1,31 +0,0 @@
|
||||||
[Range.html]
|
|
||||||
[cloneContents on Range must enqueue an attributeChanged reaction when cloning an element only for observed attributes]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[cloneContents on Range must not enqueue an attributeChanged reaction when cloning an element with an unobserved attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[deleteContents on Range must enqueue a disconnected reaction]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[extractContents on Range must enqueue a disconnected reaction]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[insertNode on Range must enqueue a disconnected reaction, an adopted reaction, and a connected reaction when the custom element was in another document]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[cloneContents on Range must enqueue an attributeChanged reaction when cloning an element with an observed attribute]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[surroundContents on Range must enqueue a disconnected reaction, an adopted reaction, and a connected reaction when the custom element was in another document]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[surroundContents on Range must enqueue a connected reaction]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[insertNode on Range must enqueue a connected reaction]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[createContextualFragment on Range must construct a custom element]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
[Selection.html]
|
|
||||||
[deleteFromDocument on Selection must enqueue a disconnected reaction]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
[eucjp-decode-x-euc-jp.html?3001-4000]
|
||||||
|
|
||||||
|
[eucjp-decode-x-euc-jp.html?2001-3000]
|
||||||
|
|
||||||
|
[eucjp-decode-x-euc-jp.html?13001-last]
|
||||||
|
|
||||||
|
[eucjp-decode-x-euc-jp.html?10001-11000]
|
||||||
|
[x-euc-jp decoding]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
||||||
|
[eucjp-decode-x-euc-jp.html?1001-2000]
|
||||||
|
|
||||||
|
[eucjp-decode-x-euc-jp.html?7001-8000]
|
||||||
|
|
||||||
|
[eucjp-decode-x-euc-jp.html?12001-13000]
|
||||||
|
|
||||||
|
[eucjp-decode-x-euc-jp.html?6001-7000]
|
||||||
|
|
||||||
|
[eucjp-decode-x-euc-jp.html?9001-10000]
|
||||||
|
|
||||||
|
[eucjp-decode-x-euc-jp.html?11001-12000]
|
||||||
|
|
||||||
|
[eucjp-decode-x-euc-jp.html?8001-9000]
|
||||||
|
|
||||||
|
[eucjp-decode-x-euc-jp.html?5001-6000]
|
||||||
|
|
||||||
|
[eucjp-decode-x-euc-jp.html?1-1000]
|
||||||
|
|
||||||
|
[eucjp-decode-x-euc-jp.html?4001-5000]
|
|
@ -0,0 +1,18 @@
|
||||||
|
[sjis-encode-form-shift-jis.html?2001-3000]
|
||||||
|
|
||||||
|
[sjis-encode-form-shift-jis.html?1-1000]
|
||||||
|
|
||||||
|
[sjis-encode-form-shift-jis.html?3001-4000]
|
||||||
|
|
||||||
|
[sjis-encode-form-shift-jis.html?5001-6000]
|
||||||
|
[shift-jis encoding (form)]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
||||||
|
[sjis-encode-form-shift-jis.html?4001-5000]
|
||||||
|
|
||||||
|
[sjis-encode-form-shift-jis.html?6001-7000]
|
||||||
|
|
||||||
|
[sjis-encode-form-shift-jis.html?1001-2000]
|
||||||
|
|
||||||
|
[sjis-encode-form-shift-jis.html?7001-last]
|
|
@ -0,0 +1,4 @@
|
||||||
|
[event-timing-bufferbeforeonload.html]
|
||||||
|
[Event Timing: click, onload.]
|
||||||
|
expected: FAIL
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
[event-timing-crossiframe.html]
|
||||||
|
[Event Timing: entries should only be observable by its own frame.]
|
||||||
|
expected: FAIL
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
[event-timing-observethenonload.html]
|
||||||
|
expected: TIMEOUT
|
||||||
|
[Event Timing: click, observer, onload, click.]
|
||||||
|
expected: TIMEOUT
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
[event-timing-onloadthenobserve-firstInput.html]
|
||||||
|
expected: TIMEOUT
|
||||||
|
[Event Timing: check firstInput after onload, observer, click, click.]
|
||||||
|
expected: TIMEOUT
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
[event-timing-onloadthenobserve.html]
|
||||||
|
expected: TIMEOUT
|
||||||
|
[Event Timing: onload, click, observer, click.]
|
||||||
|
expected: TIMEOUT
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
[event-timing-only-observe-firstInput.html]
|
||||||
|
[Event Timing: check firstInput for a PerformanceObserver observing only firstInput.]
|
||||||
|
expected: FAIL
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
[event-timing-retrievability.html]
|
||||||
|
expected: ERROR
|
||||||
|
[Event Timing: make sure event-timing entries are retrievable by existing perf APIs.]
|
||||||
|
expected: TIMEOUT
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
[event-timing-timingconditions.html]
|
||||||
|
expected: TIMEOUT
|
||||||
|
[Event Timing only times certain types of trusted event.]
|
||||||
|
expected: TIMEOUT
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
[no_window_open_when_term_nesting_level_nonzero.window.html]
|
[no_window_open_when_term_nesting_level_nonzero.window.html]
|
||||||
expected: ERROR
|
expected:
|
||||||
|
if not debug and webrender and e10s and (os == "linux") and (version == "Ubuntu 16.04") and (processor == "x86_64") and (bits == 64): TIMEOUT
|
||||||
|
ERROR
|
||||||
[no popups from synchronously reachable window]
|
[no popups from synchronously reachable window]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -404,13 +404,3 @@
|
||||||
[<meta>: "-0"]
|
[<meta>: "-0"]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
|
||||||
[parsing.html?21-30]
|
|
||||||
|
|
||||||
[parsing.html?1-10]
|
|
||||||
|
|
||||||
[parsing.html?41-50]
|
|
||||||
|
|
||||||
[parsing.html?121-130]
|
|
||||||
|
|
||||||
[parsing.html?51-60]
|
|
||||||
|
|
|
@ -20,3 +20,6 @@
|
||||||
[Test that decodingInfo returns a valid MediaCapabilitiesDecodingInfo objects with encrypted media]
|
[Test that decodingInfo returns a valid MediaCapabilitiesDecodingInfo objects with encrypted media]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
[Test that random key systems are reported as non supported.]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
local: a6a52f144b7e00102574a5fe2b53feaa0d653264
|
local: 3df33cfe93b1d11a21ac3aacc1e63cae6f44609a
|
||||||
upstream: 7268cc55c89de22afe2823f20aa05b8cab6a66bd
|
upstream: 25f3222fcba6e642e2edfe4bb29a5793c8109dfc
|
||||||
|
|
|
@ -14,3 +14,4 @@
|
||||||
[embed]
|
[embed]
|
||||||
expected:
|
expected:
|
||||||
if not e10s: FAIL
|
if not e10s: FAIL
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,2 @@
|
||||||
[idlharness.https.any.serviceworker.html]
|
[idlharness.https.any.serviceworker.html]
|
||||||
expected: TIMEOUT
|
expected: TIMEOUT
|
||||||
|
|
||||||
[idlharness.any.worker.html]
|
|
||||||
|
|
||||||
[idlharness.any.sharedworker.html]
|
|
||||||
|
|
||||||
[idlharness.any.html]
|
|
||||||
|
|
|
@ -1,2 +1,5 @@
|
||||||
[pointerevent_setpointercapture_inactive_button_mouse.html]
|
[pointerevent_setpointercapture_inactive_button_mouse.html]
|
||||||
expected: TIMEOUT
|
expected: TIMEOUT
|
||||||
|
[setPointerCapture + inactive button state]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,3 @@
|
||||||
[WindowOrWorkerGlobalScope interface: self must inherit property "isSecureContext" with the proper type]
|
[WindowOrWorkerGlobalScope interface: self must inherit property "isSecureContext" with the proper type]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
|
||||||
[idlharness.any.worker.html]
|
|
||||||
|
|
||||||
[idlharness.any.sharedworker.html]
|
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
[unregister-then-register.https.html]
|
[unregister-then-register.https.html]
|
||||||
disabled:
|
disabled:
|
||||||
if os == "android": https://bugzilla.mozilla.org/show_bug.cgi?id=1499972
|
if os == "android": https://bugzilla.mozilla.org/show_bug.cgi?id=1499972
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
[shape-inside-valid.svg]
|
||||||
|
[e.style['shape-inside'\] = "url(\\"https://example.com/\\")" should set the property value]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[e.style['shape-inside'\] = "auto" should set the property value]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[e.style['shape-inside'\] = "circle(10px at 20px -30px) url(\\"https://example.com/\\") ellipse(10px 20px at -30px 40px)" should set the property value]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[e.style['shape-inside'\] = "ellipse(10px 20px at -30px 40px)" should set the property value]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[e.style['shape-inside'\] = "circle(10px at 20px -30px)" should set the property value]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[e.style['shape-inside'\] = "polygon(10px 20px, -30px 40px, 50px 60px)" should set the property value]
|
||||||
|
expected: FAIL
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
[shape-subtract-valid.svg]
|
||||||
|
[e.style['shape-subtract'\] = "circle(10px at 20px -30px)" should set the property value]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[e.style['shape-subtract'\] = "polygon(10px 20px, -30px 40px, 50px 60px)" should set the property value]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[e.style['shape-subtract'\] = "auto" should set the property value]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[e.style['shape-subtract'\] = "circle(10px at 20px -30px) url(\\"https://example.com/\\") ellipse(10px 20px at -30px 40px)" should set the property value]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[e.style['shape-subtract'\] = "ellipse(10px 20px at -30px 40px)" should set the property value]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[e.style['shape-subtract'\] = "url(\\"https://example.com/\\")" should set the property value]
|
||||||
|
expected: FAIL
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
[text-decoration-fill-valid.svg]
|
||||||
|
[e.style['text-decoration-fill'\] = "none" should set the property value]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[e.style['text-decoration-fill'\] = "url(\\"https://example.com/\\") none" should set the property value]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[e.style['text-decoration-fill'\] = "context-stroke" should set the property value]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[e.style['text-decoration-fill'\] = "url(\\"https://example.com/\\")" should set the property value]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[e.style['text-decoration-fill'\] = "url(\\"https://example.com/\\") rgb(12, 34, 56)" should set the property value]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[e.style['text-decoration-fill'\] = "context-fill" should set the property value]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[e.style['text-decoration-fill'\] = "rgb(12, 34, 56)" should set the property value]
|
||||||
|
expected: FAIL
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
[text-decoration-stroke-valid.svg]
|
||||||
|
[e.style['text-decoration-stroke'\] = "rgb(12, 34, 56)" should set the property value]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[e.style['text-decoration-stroke'\] = "context-fill" should set the property value]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[e.style['text-decoration-stroke'\] = "url(\\"https://example.com/\\") none" should set the property value]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[e.style['text-decoration-stroke'\] = "none" should set the property value]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[e.style['text-decoration-stroke'\] = "context-stroke" should set the property value]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[e.style['text-decoration-stroke'\] = "url(\\"https://example.com/\\") rgb(12, 34, 56)" should set the property value]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[e.style['text-decoration-stroke'\] = "url(\\"https://example.com/\\")" should set the property value]
|
||||||
|
expected: FAIL
|
||||||
|
|
|
@ -1,8 +1,2 @@
|
||||||
[idlharness.https.any.serviceworker.html]
|
[idlharness.https.any.serviceworker.html]
|
||||||
expected: TIMEOUT
|
expected: TIMEOUT
|
||||||
|
|
||||||
[idlharness.any.sharedworker.html]
|
|
||||||
|
|
||||||
[idlharness.any.html]
|
|
||||||
|
|
||||||
[idlharness.any.worker.html]
|
|
||||||
|
|
|
@ -0,0 +1,79 @@
|
||||||
|
[set.py]
|
||||||
|
[test_invalid_parameters[parameters0\]]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[test_invalid_parameters[parameters1\]]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[test_invalid_parameters[parameters2\]]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[test_invalid_parameters[parameters3\]]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[test_invalid_parameters[parameters4\]]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[test_invalid_parameters[parameters5\]]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[test_invalid_parameters[parameters6\]]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[test_invalid_parameters[parameters7\]]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[test_non_secure_context[granted\]]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[test_non_secure_context[denied\]]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[test_non_secure_context[prompt\]]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[test_set_to_state[realmSetting0-granted\]]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[test_set_to_state[realmSetting0-denied\]]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[test_set_to_state[realmSetting0-prompt\]]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[test_set_to_state[realmSetting1-granted\]]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[test_set_to_state[realmSetting1-denied\]]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[test_set_to_state[realmSetting1-prompt\]]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[test_set_to_state[realmSetting2-granted\]]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[test_set_to_state[realmSetting2-denied\]]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[test_set_to_state[realmSetting2-prompt\]]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[test_set_to_state_cross_realm[realmSetting0-granted\]]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[test_set_to_state_cross_realm[realmSetting0-denied\]]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[test_set_to_state_cross_realm[realmSetting0-prompt\]]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[test_set_to_state_cross_realm[realmSetting1-granted\]]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[test_set_to_state_cross_realm[realmSetting1-denied\]]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[test_set_to_state_cross_realm[realmSetting1-prompt\]]
|
||||||
|
expected: FAIL
|
||||||
|
|
|
@ -686,3 +686,72 @@
|
||||||
[XR must be primary interface of navigator.xr]
|
[XR must be primary interface of navigator.xr]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
[XRViewerPose interface object length]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[XR interface: calling supportsSession(XRSessionCreationOptions) on navigator.xr with too few arguments must throw TypeError]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[XRFrame interface: operation getInputPose(XRInputSource, XRFrameOfReference)]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[XR interface: operation requestSession(XRSessionCreationOptions)]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[XRViewerPose interface: attribute poseMatrix]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[XRViewerPose interface object name]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[XR interface: navigator.xr must inherit property "requestSession(XRSessionCreationOptions)" with the proper type]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[XRFrame interface: operation getViewerPose(XRFrameOfReference)]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[XRView interface: attribute viewMatrix]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[XRViewerPose interface: existence and properties of interface prototype object]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[XR interface: calling requestSession(XRSessionCreationOptions) on navigator.xr with too few arguments must throw TypeError]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[XRViewerPose interface: attribute views]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[XRViewerPose interface: existence and properties of interface object]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[XR interface: navigator.xr must inherit property "supportsSession(XRSessionCreationOptions)" with the proper type]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[WebGLRenderingContext interface: operation makeXRCompatible()]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[XRViewerPose interface: existence and properties of interface prototype object's "constructor" property]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[XRViewerPose interface: existence and properties of interface prototype object's @@unscopables property]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[XRSession interface: attribute oninputsourceschange]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[XR interface: operation supportsSession(XRSessionCreationOptions)]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[XR interface: navigator.xr must inherit property "supportsSessionMode(XRSessionMode)" with the proper type]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[XR interface: operation supportsSessionMode(XRSessionMode)]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[XRSession interface: attribute mode]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
[XR interface: calling supportsSessionMode(XRSessionMode) on navigator.xr with too few arguments must throw TypeError]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -61,7 +61,7 @@ tasks:
|
||||||
owner: ${event.pusher.email}
|
owner: ${event.pusher.email}
|
||||||
source: ${event.repository.url}
|
source: ${event.repository.url}
|
||||||
payload:
|
payload:
|
||||||
image: harjgam/web-platform-tests:0.22
|
image: hexcles/web-platform-tests:0.23
|
||||||
maxRunTime: 7200
|
maxRunTime: 7200
|
||||||
artifacts:
|
artifacts:
|
||||||
public/results:
|
public/results:
|
||||||
|
@ -125,7 +125,7 @@ tasks:
|
||||||
owner: ${event.pull_request.user.login}@users.noreply.github.com
|
owner: ${event.pull_request.user.login}@users.noreply.github.com
|
||||||
source: ${event.repository.url}
|
source: ${event.repository.url}
|
||||||
payload:
|
payload:
|
||||||
image: harjgam/web-platform-tests:0.22
|
image: hexcles/web-platform-tests:0.23
|
||||||
maxRunTime: 7200
|
maxRunTime: 7200
|
||||||
artifacts:
|
artifacts:
|
||||||
public/results:
|
public/results:
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
<meta name="help" content="https://html.spec.whatwg.org/multipage/dynamic-markup-insertion.html#throw-on-dynamic-markup-insertion-counter">
|
<meta name="help" content="https://html.spec.whatwg.org/multipage/dynamic-markup-insertion.html#throw-on-dynamic-markup-insertion-counter">
|
||||||
<script src="/resources/testharness.js"></script>
|
<script src="/resources/testharness.js"></script>
|
||||||
<script src="/resources/testharnessreport.js"></script>
|
<script src="/resources/testharnessreport.js"></script>
|
||||||
<script src="/resources/custom-elements-helpers.js"></script>
|
<script src="./resources/custom-elements-helpers.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="log"></div>
|
<div id="log"></div>
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
<meta name="help" content="https://html.spec.whatwg.org/multipage/dynamic-markup-insertion.html#throw-on-dynamic-markup-insertion-counter">
|
<meta name="help" content="https://html.spec.whatwg.org/multipage/dynamic-markup-insertion.html#throw-on-dynamic-markup-insertion-counter">
|
||||||
<script src="/resources/testharness.js"></script>
|
<script src="/resources/testharness.js"></script>
|
||||||
<script src="/resources/testharnessreport.js"></script>
|
<script src="/resources/testharnessreport.js"></script>
|
||||||
<script src="/resources/custom-elements-helpers.js"></script>
|
<script src="./resources/custom-elements-helpers.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="log"></div>
|
<div id="log"></div>
|
||||||
|
|
|
@ -0,0 +1,79 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<meta charset=utf-8 />
|
||||||
|
<title>Event Timing: buffer long-latency events before onload</title>
|
||||||
|
<button id='button' onclick='clickDelay()'>Generate a 'click' event</button>
|
||||||
|
<script src=/resources/testharness.js></script>
|
||||||
|
<script src=/resources/testharnessreport.js></script>
|
||||||
|
<script src=/resources/testdriver.js></script>
|
||||||
|
<script src=/resources/testdriver-vendor.js></script>
|
||||||
|
|
||||||
|
<script src=resources/event-timing-support.js></script>
|
||||||
|
<img src=resources/slow-image.py>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
let clickTimeMin;
|
||||||
|
let processingStartMin;
|
||||||
|
let onloadStart;
|
||||||
|
let firstClickStart = 0;
|
||||||
|
let firstClickEnd = 0;
|
||||||
|
function clickDelay() {
|
||||||
|
const onclickStart = performance.now();
|
||||||
|
if (firstClickStart === 0)
|
||||||
|
firstClickStart = onclickStart;
|
||||||
|
while(performance.now() < onclickStart + 60) {}
|
||||||
|
if (firstClickEnd === 0)
|
||||||
|
firstClickEnd = performance.now();
|
||||||
|
}
|
||||||
|
|
||||||
|
function validateEntries() {
|
||||||
|
const entries = performance.getEntriesByName('click', 'event');
|
||||||
|
|
||||||
|
const entriesBeforeOnload = entries.filter(
|
||||||
|
e => e.startTime < onloadStart);
|
||||||
|
assert_equals(entriesBeforeOnload.length, 1,
|
||||||
|
"Long latency events before onload should be buffered.");
|
||||||
|
const entry = entriesBeforeOnload[0];
|
||||||
|
verifyClickEvent(entry, true);
|
||||||
|
|
||||||
|
assert_greater_than_equal(entry.startTime, clickTimeMin,
|
||||||
|
"The entry's start time should be later than clickTimeMin.");
|
||||||
|
assert_greater_than_equal(entry.processingStart, processingStartMin,
|
||||||
|
"The entry should be processed later than processingStartMin.");
|
||||||
|
assert_less_than_equal(entry.processingStart, firstClickStart,
|
||||||
|
"The processingStart must be before firstClickStart.")
|
||||||
|
assert_greater_than_equal(entry.processingEnd, firstClickEnd,
|
||||||
|
"The processingEnd must be after firstClickEnd.");
|
||||||
|
|
||||||
|
const entriesAfterOnload = entries.filter(
|
||||||
|
e => e.startTime >= onloadStart);
|
||||||
|
assert_equals(entriesAfterOnload.length, 0,
|
||||||
|
"Events after onload shouldn't be buffered.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Timeline:
|
||||||
|
Begin Busy Loop
|
||||||
|
Click 1 arrives
|
||||||
|
End Busy Loop
|
||||||
|
(Dispatch and Process Click 1 - buffered)
|
||||||
|
Onload Event Fires
|
||||||
|
Begin Busy Loop
|
||||||
|
Click 2 arrives
|
||||||
|
End Busy Loop
|
||||||
|
(Dispatch and Process Click 2 - not buffered)
|
||||||
|
*/
|
||||||
|
async_test(function(t) {
|
||||||
|
clickTimeMin = performance.now();
|
||||||
|
clickAndBlockMain('button');
|
||||||
|
// Event handlers will be dispatched asynchronously, so this will be called
|
||||||
|
// before processing begins.
|
||||||
|
processingStartMin = performance.now();
|
||||||
|
on_event(window, 'load', e => {
|
||||||
|
onloadStart = performance.now();
|
||||||
|
clickAndBlockMain('button').then(wait).then(
|
||||||
|
t.step_func_done(validateEntries));
|
||||||
|
});
|
||||||
|
}, "Event Timing: click, onload.");
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</html>
|
|
@ -0,0 +1,89 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset=utf-8 />
|
||||||
|
<title>Event Timing: entries should be observable by its own frame.</title>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<button id='button' onclick='1'>Generate a 'click' event</button>
|
||||||
|
<script src=/resources/testharness.js></script>
|
||||||
|
<script src=/resources/testharnessreport.js></script>
|
||||||
|
<script src=/resources/testdriver.js></script>
|
||||||
|
<script src=/resources/testdriver-vendor.js></script>
|
||||||
|
|
||||||
|
<script src=resources/event-timing-support.js></script>
|
||||||
|
<img src=./resources/slow-image.py>
|
||||||
|
<iframe src=resources/event-timing-crossiframe-childframe.html></iframe>
|
||||||
|
<script>
|
||||||
|
let clickTimeMin;
|
||||||
|
let processingStartMin;
|
||||||
|
let onloadStart;
|
||||||
|
|
||||||
|
function validateEntries() {
|
||||||
|
const entries = performance.getEntriesByName('click', 'event');
|
||||||
|
|
||||||
|
assert_equals(entries.length, 1,
|
||||||
|
"Observer of main frames should only capture main-frame event-timing entries."
|
||||||
|
);
|
||||||
|
const entry = entries[0];
|
||||||
|
verifyClickEvent(entry, true);
|
||||||
|
|
||||||
|
assert_greater_than(entry.processingStart, processingStartMin,
|
||||||
|
"The entry's processing start should be later than processingStartMin.");
|
||||||
|
assert_greater_than(onloadStart, entry.processingStart,
|
||||||
|
"onload should occur later than the entry's procesisng start.");
|
||||||
|
assert_greater_than(entry.startTime, clickTimeMin,
|
||||||
|
"The entry's start time should be later than clickTimeMin.");
|
||||||
|
assert_greater_than(onloadStart, entry.startTime,
|
||||||
|
"onload should occur later than the entry's start time.");
|
||||||
|
}
|
||||||
|
|
||||||
|
function validateChildFrameEntries(childFrameData) {
|
||||||
|
assert_equals(childFrameData.bufferedEntries.length, 1,
|
||||||
|
"Event Timing of child frames should only capture child-frame event-timing entries."
|
||||||
|
);
|
||||||
|
const entry = entries[0];
|
||||||
|
verifyClickEvent(entry);
|
||||||
|
|
||||||
|
assert_greater_than(entry.processingStart, childFrameData.processingStartMin,
|
||||||
|
"The entry's processing start should be later than the child frame's processingStartMin.");
|
||||||
|
assert_greater_than(childFrameData.onloadStart, entry.processingStart,
|
||||||
|
"Child frame's onload should occur later than the entry's processing \
|
||||||
|
start.");
|
||||||
|
assert_greater_than(entry.startTime, childFrameData.clickTimeMin,
|
||||||
|
"The entry's start time should be later than the child frame's \
|
||||||
|
clickTimeMin.");
|
||||||
|
assert_greater_than(childFrameData.onloadStart, entry.startTime,
|
||||||
|
"Child frame's onload should be later than the entry's start time.");
|
||||||
|
|
||||||
|
assert_array_equals(childFrameData.observedEntries,
|
||||||
|
childFrameData.bufferedEntries,
|
||||||
|
"The child frame's observed entries should be buffered as well.");
|
||||||
|
}
|
||||||
|
|
||||||
|
async_test(function(t) {
|
||||||
|
clickTimeMin = performance.now();
|
||||||
|
clickAndBlockMain('button');
|
||||||
|
processingStartMin = performance.now();
|
||||||
|
const childFrameEntriesPromise = new Promise((resolve, reject) => {
|
||||||
|
window.addEventListener("message", (event) => {
|
||||||
|
resolve(event.data);
|
||||||
|
}, false);
|
||||||
|
});
|
||||||
|
on_event(window, 'load', e => {
|
||||||
|
onloadStart = performance.now();
|
||||||
|
childFrameEntriesPromise.then((entries) => {
|
||||||
|
t.step(() => {
|
||||||
|
validateChildFrameEntries(entries);
|
||||||
|
validateEntries();
|
||||||
|
});
|
||||||
|
t.done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}, "Event Timing: entries should only be observable by its own frame.");
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,79 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset=utf-8 />
|
||||||
|
<title>Event Timing: entries should be observable by its own frame.
|
||||||
|
</title>
|
||||||
|
<script src=./resources/event-timing-support.js></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h2>Description:</h2>
|
||||||
|
<p>
|
||||||
|
<div>
|
||||||
|
The goal of this manual test is to verify that observers that have
|
||||||
|
registered "event" entry type can observe the long-latency input events,
|
||||||
|
and verify the same behavior within iframe and in cross-frame scenario.
|
||||||
|
</div>
|
||||||
|
</p>
|
||||||
|
<h2>Manual test steps:</h2>
|
||||||
|
<p>
|
||||||
|
<div>
|
||||||
|
Step 1: Click the "make busy" button to make main-thread busy for 2 seconds.</span>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
Step 2: do several clicks on "click while busy" while busy to generate long-latency inputs.
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
Step 3: observe in the "timeline" section that the long-latency clicks are captured by the observer.
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
Step 4: do step 1 to step 3 for the iframe. Observe that the observers only observe input events within its frame.
|
||||||
|
</div>
|
||||||
|
</p>
|
||||||
|
<div>
|
||||||
|
<h2>Actions:</h2>
|
||||||
|
<button id='busy_button' onclick='onMakeBusy()'>make busy</button>
|
||||||
|
<button id='click_input_button' onclick='1'> click while busy </button>
|
||||||
|
</div>
|
||||||
|
<h2>iframe:</h2>
|
||||||
|
<div>
|
||||||
|
<iframe name='childframe' width="100%" height="30%" src=./resources/event-timing-observer-manual-childframe.html></iframe>
|
||||||
|
</div>
|
||||||
|
<h2>Timeline:</h2>
|
||||||
|
<p id='timeline'></p>
|
||||||
|
</body>
|
||||||
|
<script>
|
||||||
|
function log(message) {
|
||||||
|
const timestamp = performance.now();
|
||||||
|
const elem = document.createElement('div');
|
||||||
|
elem.innerHTML = `${timestamp.toFixed(1)}: ${message}`;
|
||||||
|
const timeline = document.getElementById('timeline');
|
||||||
|
timeline.appendChild(elem);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onMakeBusy() {
|
||||||
|
log("busy start");
|
||||||
|
step_timeout(()=>{
|
||||||
|
mainThreadBusy(2000);
|
||||||
|
log("busy end");
|
||||||
|
}, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
document.body.onload = () => {
|
||||||
|
new PerformanceObserver((entryList) => {
|
||||||
|
entryList.getEntries().forEach(e => {
|
||||||
|
log(`entry observed: ${JSON.stringify(e)}`);
|
||||||
|
});
|
||||||
|
}).observe({ entryTypes: ['event'] });
|
||||||
|
log("observer registered");
|
||||||
|
};
|
||||||
|
|
||||||
|
window.onmessage = (msg) => {
|
||||||
|
log("received msg: " + msg.data);
|
||||||
|
if (msg.data === 'CHILD_FRAME_IS_READY') {
|
||||||
|
// TODO(crbug/831729): automate clicks on iframe when testdriver support
|
||||||
|
// clicking in iframe.
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
</html>
|
|
@ -0,0 +1,103 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<meta charset=utf-8 />
|
||||||
|
<title>Event Timing: Performance observers can observe long-latency events
|
||||||
|
</title>
|
||||||
|
<button id='button' onclick='1'>Generate a 'click' event</button>
|
||||||
|
<script src=/resources/testharness.js></script>
|
||||||
|
<script src=/resources/testharnessreport.js></script>
|
||||||
|
<script src=/resources/testdriver.js></script>
|
||||||
|
<script src=/resources/testdriver-vendor.js></script>
|
||||||
|
|
||||||
|
<script src=resources/event-timing-support.js></script>
|
||||||
|
<img src=resources/slow-image.py>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
let timeBeforeFirstClick;
|
||||||
|
let timeAfterFirstClick;
|
||||||
|
let timeAfterSecondClick;
|
||||||
|
let onloadStart;
|
||||||
|
let observedEntries = [];
|
||||||
|
|
||||||
|
function verifyBuffer(bufferedEntries) {
|
||||||
|
assert_equals(bufferedEntries.length, 1,
|
||||||
|
"Only events before onload should be buffered.");
|
||||||
|
const entry = bufferedEntries[0];
|
||||||
|
assert_greater_than(onloadStart, entry.startTime,
|
||||||
|
"Onload should be later than entry's start time.");
|
||||||
|
assert_greater_than(entry.processingStart, timeBeforeFirstClick,
|
||||||
|
"The entry's processing start should be after timeBeforeFirstClick");
|
||||||
|
assert_less_than(entry.processingStart, timeAfterFirstClick,
|
||||||
|
"The entry's processing start should be before timeAfterFirstClick.");
|
||||||
|
verifyClickEvent(entry, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
function verifyObserverEntries(observedEntries) {
|
||||||
|
const entriesAfterFirstClick = observedEntries.filter(
|
||||||
|
e => e.startTime > timeAfterFirstClick);
|
||||||
|
assert_equals(entriesAfterFirstClick.length, 1,
|
||||||
|
'There should be one event after timeAfterFirstClick.');
|
||||||
|
const entry1 = entriesAfterFirstClick[0];
|
||||||
|
verifyClickEvent(entry1);
|
||||||
|
assert_greater_than(entry1.processingStart, timeAfterFirstClick,
|
||||||
|
"entry1's processing start should be after timeAfterFirstClick");
|
||||||
|
assert_less_than(entry1.processingStart, timeAfterSecondClick,
|
||||||
|
"entry1's processing start should be before timeAfterSecondClick.");
|
||||||
|
assert_greater_than(entry1.startTime, onloadStart,
|
||||||
|
"entry1's start time should be later than onloadStart.");
|
||||||
|
|
||||||
|
const entriesBeforeFirstClick =
|
||||||
|
observedEntries.filter(e => e.startTime < timeAfterFirstClick);
|
||||||
|
assert_equals(entriesBeforeFirstClick.length, 1,
|
||||||
|
'There should be one event before timeAfterFirstClick.'
|
||||||
|
);
|
||||||
|
const entry2 = entriesBeforeFirstClick[0];
|
||||||
|
verifyClickEvent(entry2);
|
||||||
|
assert_greater_than(entry2.processingStart, timeBeforeFirstClick,
|
||||||
|
"entry2's processing start should be after timeBeforeFirstClick");
|
||||||
|
assert_less_than(entry2.processingStart, timeAfterFirstClick,
|
||||||
|
"entry2's processing start should be berfore timeAfterFirstClick.");
|
||||||
|
assert_greater_than(timeAfterFirstClick, entry2.startTime,
|
||||||
|
"timeAfterFirstClick should be later than entry2's start time.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Timeline:
|
||||||
|
Observer starts
|
||||||
|
Begin Busy Loop
|
||||||
|
Click 1 arrives
|
||||||
|
End Busy Loop
|
||||||
|
(Dispatch and Process Click 1 (buffered, observed))
|
||||||
|
Onload Event Fires
|
||||||
|
Begin Busy Loop
|
||||||
|
Click 2 arrives
|
||||||
|
End Busy Loop
|
||||||
|
(Dispatch and Process Click 2 (buffered, observed))
|
||||||
|
observer callback start
|
||||||
|
*/
|
||||||
|
async_test(function(t) {
|
||||||
|
const observerPromise = new Promise((resolve, reject) => {
|
||||||
|
new PerformanceObserver(function(entryList) {
|
||||||
|
observedEntries = observedEntries.concat(entryList.getEntries());
|
||||||
|
if (observedEntries.length < 2) return;
|
||||||
|
resolve(observedEntries);
|
||||||
|
}).observe({ entryTypes: ['event'] });
|
||||||
|
});
|
||||||
|
timeBeforeFirstClick = performance.now();
|
||||||
|
clickAndBlockMain('button').then( () => {
|
||||||
|
timeAfterFirstClick = performance.now();
|
||||||
|
});
|
||||||
|
on_event(window, 'load', function(e) {
|
||||||
|
onloadStart = performance.now();
|
||||||
|
// After onload start and before registering observer.
|
||||||
|
const bufferPromise = clickAndBlockMain('button').then(wait);
|
||||||
|
Promise.all([observerPromise, bufferPromise]).then((results) => {
|
||||||
|
timeAfterSecondClick = performance.now();
|
||||||
|
t.step(verifyObserverEntries.bind(null, results[0]));
|
||||||
|
t.step(verifyBuffer.bind(null, performance.getEntriesByName('click', 'event')));
|
||||||
|
t.done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}, "Event Timing: click, observer, onload, click.");
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</html>
|
|
@ -0,0 +1,53 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<meta charset=utf-8 />
|
||||||
|
<title>Event Timing: buffer long-latency events before onload</title>
|
||||||
|
<button id='button' onclick='1'>Generate a 'click' event</button>
|
||||||
|
<script src=/resources/testharness.js></script>
|
||||||
|
<script src=/resources/testharnessreport.js></script>
|
||||||
|
<script src=/resources/testdriver.js></script>
|
||||||
|
<script src=/resources/testdriver-vendor.js></script>
|
||||||
|
|
||||||
|
<script src=resources/event-timing-support.js></script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
/* Timeline:
|
||||||
|
Onload
|
||||||
|
PerformanceObserver is registered
|
||||||
|
Click 1
|
||||||
|
Click 2
|
||||||
|
PerformanceObserver should observe only one firstInput entry.
|
||||||
|
(Dispatch and Process Click 2 - not buffered)
|
||||||
|
*/
|
||||||
|
async_test(function(t) {
|
||||||
|
let numFirstInputObserved = 0;
|
||||||
|
let numEventsObserved = 0;
|
||||||
|
new PerformanceObserver(t.step_func((entryList, obs) => {
|
||||||
|
const observedEntries = entryList.getEntries();
|
||||||
|
numEventsObserved += observedEntries.filter(entry =>
|
||||||
|
entry.entryType == 'event').length;
|
||||||
|
numFirstInputObserved += observedEntries.filter(entry =>
|
||||||
|
entry.entryType == 'firstInput').length;
|
||||||
|
if (numEventsObserved >= 2) {
|
||||||
|
assert_equals(performance.getEntriesByType('event').length, 0,
|
||||||
|
"There should be no buffered event entries.");
|
||||||
|
assert_equals(performance.getEntriesByType('firstInput').length, 0,
|
||||||
|
"There should be no buffered firstInput entries.");
|
||||||
|
// There should be 2 event entries and one firstInput entry.
|
||||||
|
assert_equals(numEventsObserved, 2,
|
||||||
|
"There should be 2 observed event entries.");
|
||||||
|
assert_equals(numFirstInputObserved, 1,
|
||||||
|
"There should be only 1 observed firstInput entry.");
|
||||||
|
t.done();
|
||||||
|
}
|
||||||
|
})).observe({ entryTypes: ['event', 'firstInput'] });
|
||||||
|
on_event(window, 'load', () => {
|
||||||
|
clickAndBlockMain('button').then(wait).then(() => {
|
||||||
|
clickAndBlockMain('button').then(wait);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
"Event Timing: check firstInput after onload, observer, click, click."
|
||||||
|
);
|
||||||
|
</script>
|
||||||
|
</html>
|
|
@ -0,0 +1,76 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<meta charset=utf-8 />
|
||||||
|
<title>Event Timing: long-latency events after onload and before observer
|
||||||
|
registration are lost
|
||||||
|
</title>
|
||||||
|
<button id='button' onclick='1'>Generate a 'click' event</button>
|
||||||
|
<script src=/resources/testharness.js></script>
|
||||||
|
<script src=/resources/testharnessreport.js></script>
|
||||||
|
<script src=/resources/testdriver.js></script>
|
||||||
|
<script src=/resources/testdriver-vendor.js></script>
|
||||||
|
|
||||||
|
<script src=resources/event-timing-support.js></script>
|
||||||
|
<script>
|
||||||
|
let callbackTime;
|
||||||
|
let observerStart;
|
||||||
|
let processingStartMin;
|
||||||
|
|
||||||
|
function verifyBufferAndObserverEntries(observedEntries) {
|
||||||
|
// Verify buffer entries
|
||||||
|
const bufferedEntries = performance.getEntriesByName('click', 'event');
|
||||||
|
const bufferedEntriesBeforeObserver = bufferedEntries.filter(e => e.startTime <
|
||||||
|
observerStart);
|
||||||
|
assert_equals(bufferedEntries.length, 0,
|
||||||
|
"Long latency events after onload should not be buffered."
|
||||||
|
);
|
||||||
|
|
||||||
|
// Verify observer entries
|
||||||
|
assert_equals(observedEntries.length, 1, "Long latency task after observer start should be observed.");
|
||||||
|
const entry = observedEntries[0];
|
||||||
|
verifyClickEvent(entry);
|
||||||
|
assert_greater_than(entry.processingStart, processingStartMin,
|
||||||
|
"The entry's processing start should be later than processingStartMin.");
|
||||||
|
assert_greater_than(callbackTime, entry.processingStart,
|
||||||
|
"The callback time should be later than the entry's processing start.");
|
||||||
|
assert_greater_than(entry.startTime, observerStart,
|
||||||
|
"The entry's start time should be later than observer start.");
|
||||||
|
assert_greater_than(callbackTime, entry.startTime,
|
||||||
|
"The callback time should be later than entry's start time.");
|
||||||
|
}
|
||||||
|
|
||||||
|
function startObserver(t) {
|
||||||
|
new PerformanceObserver(t.step_func_done((entryList, obs) => {
|
||||||
|
callbackTime = performance.now();
|
||||||
|
const observedEntries = entryList.getEntries();
|
||||||
|
verifyBufferAndObserverEntries(observedEntries);
|
||||||
|
})).observe({ entryTypes: ['event'] });
|
||||||
|
observerStart = performance.now();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Timeline:
|
||||||
|
Onload Event fires
|
||||||
|
Begin Busy Loop
|
||||||
|
Click 1 arrives
|
||||||
|
End Busy Loop
|
||||||
|
(Dispatch and Process Click 1 (not buffered, not observed))
|
||||||
|
Observer start
|
||||||
|
Begin Busy Loop
|
||||||
|
Click 2 arrives
|
||||||
|
End Busy Loop
|
||||||
|
(Dispatch and Process Click 2 (not buffered, observed))
|
||||||
|
*/
|
||||||
|
async_test(function(t) {
|
||||||
|
on_event(window, 'load', () => {
|
||||||
|
clickAndBlockMain('button').then(() => {
|
||||||
|
startObserver(t);
|
||||||
|
clickAndBlockMain('button').then(wait);
|
||||||
|
processingStartMin = performance.now();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
"Event Timing: onload, click, observer, click."
|
||||||
|
);
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</html>
|
|
@ -0,0 +1,49 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<meta charset=utf-8 />
|
||||||
|
<title>Event Timing: only observe the first input</title>
|
||||||
|
<button id='button' onclick='1'>Generate a 'click' event</button>
|
||||||
|
<script src=/resources/testharness.js></script>
|
||||||
|
<script src=/resources/testharnessreport.js></script>
|
||||||
|
<script src=/resources/testdriver.js></script>
|
||||||
|
<script src=/resources/testdriver-vendor.js></script>
|
||||||
|
|
||||||
|
<script src=resources/event-timing-support.js></script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
/* Test:
|
||||||
|
PerformanceObserver for firstInput is registered
|
||||||
|
Click 1
|
||||||
|
Click 2
|
||||||
|
Wait
|
||||||
|
Expected result:
|
||||||
|
PerformanceObserver should observe one and only one entry.
|
||||||
|
*/
|
||||||
|
async_test(function(t) {
|
||||||
|
let hasObservedFirstInput = false;
|
||||||
|
new PerformanceObserver(t.step_func((entryList) => {
|
||||||
|
assert_false(hasObservedFirstInput);
|
||||||
|
hasObservedFirstInput = true;
|
||||||
|
const observedEntries = entryList.getEntries();
|
||||||
|
assert_equals(observedEntries.length, 1);
|
||||||
|
assert_equals(observedEntries[0].entryType, 'firstInput');
|
||||||
|
assert_equals(observedEntries[0].name, 'click');
|
||||||
|
})).observe({ entryTypes: ['firstInput'] });
|
||||||
|
on_event(window, 'load', () => {
|
||||||
|
clickAndBlockMain('button').then(() => {
|
||||||
|
clickAndBlockMain('button').then(wait).then( () => {
|
||||||
|
// After some wait, the PerformanceObserver should have processed both clicks.
|
||||||
|
// One and only one firstInput entry should have been dispatched, so
|
||||||
|
// |hasObservedFirstInput| should be true.
|
||||||
|
t.step_timeout( () => {
|
||||||
|
assert_true(hasObservedFirstInput);
|
||||||
|
t.done();
|
||||||
|
}, 10);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
"Event Timing: check firstInput for a PerformanceObserver observing only firstInput."
|
||||||
|
);
|
||||||
|
</script>
|
||||||
|
</html>
|
|
@ -0,0 +1,42 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<meta charset=utf-8>
|
||||||
|
<title>Event Timing: make sure event-timing entries are retrievable by existing perf APIs.</title>
|
||||||
|
<button id='button' onclick='1'>Generate a 'click' event</button>
|
||||||
|
<script src=/resources/testharness.js></script>
|
||||||
|
<script src=/resources/testharnessreport.js></script>
|
||||||
|
<script src=/resources/testdriver.js></script>
|
||||||
|
<script src=/resources/testdriver-vendor.js></script>
|
||||||
|
|
||||||
|
<script src=resources/event-timing-support.js></script>
|
||||||
|
<img src=resources/slow-image.py>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
function validateEntries() {
|
||||||
|
const entriesByName = performance.getEntriesByName('click', 'event');
|
||||||
|
const entriesByType = performance.getEntriesByType('event');
|
||||||
|
const allEntries = performance.getEntries();
|
||||||
|
assert_equals(entriesByName.length, 1, 'event-timing entry should be retrievable by getEntriesByName');
|
||||||
|
const e = entriesByName[0];
|
||||||
|
assert_true(entriesByType.includes(e), 'event-timing entry should be retrievable by getEntries');
|
||||||
|
assert_true(allEntries.includes(e), 'event-timing entry should be retrievable by getEntriesByType');
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Timeline:
|
||||||
|
Begin Busy Loop
|
||||||
|
Click 1 arrives
|
||||||
|
End Busy Loop
|
||||||
|
(Dispatch and Process Click 1 - buffered)
|
||||||
|
Onload Event Fires
|
||||||
|
Validate entries
|
||||||
|
*/
|
||||||
|
async_test(function(t) {
|
||||||
|
clickAndBlockMain('button');
|
||||||
|
on_event(window, 'load', e => {
|
||||||
|
validateEntries();
|
||||||
|
t.done();
|
||||||
|
});
|
||||||
|
}, "Event Timing: make sure event-timing entries are retrievable by existing perf APIs.");
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</html>
|
|
@ -0,0 +1,58 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<meta charset=utf-8 />
|
||||||
|
<title>Event Timing only times certain types of trusted event.
|
||||||
|
</title>
|
||||||
|
<button id='button' onclick='mainThreadBusy(60)'
|
||||||
|
onfocus='mainThreadBusy(60)'>Generate a 'click' event</button>
|
||||||
|
<script src=/resources/testharness.js></script>
|
||||||
|
<script src=/resources/testharnessreport.js></script>
|
||||||
|
<script src=/resources/testdriver.js></script>
|
||||||
|
<script src=/resources/testdriver-vendor.js></script>
|
||||||
|
|
||||||
|
<script src=resources/event-timing-support.js></script>
|
||||||
|
<script>
|
||||||
|
let trustedClickStart;
|
||||||
|
function trustedClickAndBlockMain(id) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
trustedClickStart = performance.now();
|
||||||
|
clickOnElement(id, resolve);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function untrustedClickAndBlockMain(id) {
|
||||||
|
const target = document.getElementById(id);
|
||||||
|
// Block mainthread in the callback, as dispatchEvent() is a sync call.
|
||||||
|
target.dispatchEvent(new MouseEvent('click'));
|
||||||
|
}
|
||||||
|
|
||||||
|
function trustedFocusAndBlockMain(id) {
|
||||||
|
const target = document.getElementById(id);
|
||||||
|
trustedFocusStart = performance.now();
|
||||||
|
// Block mainthread in the callback, as focus() is a sync call.
|
||||||
|
target.focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
async_test(function(t) {
|
||||||
|
new PerformanceObserver(t.step_func_done(entryList => {
|
||||||
|
const observerCallbackTime = performance.now();
|
||||||
|
const entries = entryList.getEntries();
|
||||||
|
assert_equals(entries.length, 1,
|
||||||
|
"Should only observe one entry: " +
|
||||||
|
JSON.stringify(entries) + ".");
|
||||||
|
assert_equals(entries[0].name, 'click',
|
||||||
|
"The observed entry should be a click");
|
||||||
|
assert_less_than(entries[0].startTime, observerCallbackTime,
|
||||||
|
"The startTime should be before observerCallbackTime");
|
||||||
|
assert_greater_than(entries[0].startTime, trustedClickStart,
|
||||||
|
"The startTime should be after trustedClickStart");
|
||||||
|
})).observe({ entryTypes: ['event'] });
|
||||||
|
// Untrusted event of a type event timing cares about.
|
||||||
|
untrustedClickAndBlockMain('button');
|
||||||
|
// Trusted event of a type event timing doesn't cares about.
|
||||||
|
trustedFocusAndBlockMain('button');
|
||||||
|
// Trusted event of a type event timing cares about.
|
||||||
|
trustedClickAndBlockMain('button').then(wait);
|
||||||
|
}, "Event Timing only times certain types of trusted event.");
|
||||||
|
</script>
|
||||||
|
</html>
|
|
@ -0,0 +1,29 @@
|
||||||
|
<!DOCType html>
|
||||||
|
<html>
|
||||||
|
<script src=event-timing-support.js></script>
|
||||||
|
<button id='button_child_frame' onclick='2'>Generate a 'click' event</button>
|
||||||
|
<img src=slow-image.py>
|
||||||
|
<script>
|
||||||
|
const clickTimeMin = performance.now();
|
||||||
|
clickAndBlockMain('button_child_frame');
|
||||||
|
const processingStartMin = performance.now();
|
||||||
|
const observerPromise = new Promise((resolve, reject) => {
|
||||||
|
new PerformanceObserver((entryList) => {
|
||||||
|
resolve(entryList.getEntries());
|
||||||
|
}).observe({ entryTypes: ['event'] });
|
||||||
|
});
|
||||||
|
window.addEventListener('load', e => {
|
||||||
|
observerPromise.then((observedEntries) => {
|
||||||
|
const onloadStart = performance.now();
|
||||||
|
const bufferedEntries = performance.getEntriesByType('event');
|
||||||
|
top.postMessage({
|
||||||
|
"bufferedEntries" : bufferedEntries,
|
||||||
|
"observedEntries": observedEntries,
|
||||||
|
"clickTimeMin": clickTimeMin,
|
||||||
|
"processingStartMin" : processingStartMin,
|
||||||
|
"onloadStart" : onloadStart,
|
||||||
|
}, '*');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</html>
|
|
@ -0,0 +1,43 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset=utf-8 />
|
||||||
|
</head>
|
||||||
|
<script src=./event-timing-support.js></script>
|
||||||
|
<script>
|
||||||
|
function log(message) {
|
||||||
|
const timestamp = performance.now();
|
||||||
|
const elem = document.createElement('div');
|
||||||
|
elem.innerHTML = `${timestamp.toFixed(1)}: ${message}`;
|
||||||
|
const timeline = document.getElementById('timeline');
|
||||||
|
timeline.appendChild(elem);
|
||||||
|
}
|
||||||
|
|
||||||
|
function run() {
|
||||||
|
new PerformanceObserver((entryList) => {
|
||||||
|
entryList.getEntries().forEach(e => {
|
||||||
|
log(`entry observed: ${JSON.stringify(e)}`);
|
||||||
|
});
|
||||||
|
}).observe({ entryTypes: ['event'] });
|
||||||
|
log("observer registered");
|
||||||
|
top.postMessage('CHILD_FRAME_IS_READY', "*");
|
||||||
|
}
|
||||||
|
|
||||||
|
function onMakeBusy() {
|
||||||
|
log("busy start");
|
||||||
|
step_timeout(()=>{
|
||||||
|
mainThreadBusy(2000);
|
||||||
|
log("busy end");
|
||||||
|
}, 0);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<body onload='run()'>
|
||||||
|
<h3>Actions:</h3>
|
||||||
|
<p>
|
||||||
|
<button id='busy_button' onclick='onMakeBusy()'>Make busy</button>
|
||||||
|
<button id='click_input_button' onclick='1'> click while busy </button>
|
||||||
|
</p>
|
||||||
|
<h3>Timeline:</h3>
|
||||||
|
<p id='timeline'></p>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,66 @@
|
||||||
|
// Clicks on the element with the given ID. It adds an event handler to the element
|
||||||
|
// which ensures that the events have a long duration and reported by EventTiming
|
||||||
|
// where appropriate. Calls |callback| during event handler.
|
||||||
|
function clickOnElement(id, callback) {
|
||||||
|
const element = document.getElementById(id);
|
||||||
|
const rect = element.getBoundingClientRect();
|
||||||
|
const xCenter = rect.x + rect.width / 2;
|
||||||
|
const yCenter = rect.y + rect.height / 2;
|
||||||
|
const leftButton = 0;
|
||||||
|
const clickHandler = () => {
|
||||||
|
mainThreadBusy(60);
|
||||||
|
if (callback)
|
||||||
|
callback();
|
||||||
|
element.removeEventListener("click", clickHandler);
|
||||||
|
};
|
||||||
|
element.addEventListener("click", clickHandler);
|
||||||
|
test_driver.click(element);
|
||||||
|
}
|
||||||
|
|
||||||
|
function mainThreadBusy(duration) {
|
||||||
|
const now = performance.now();
|
||||||
|
while (performance.now() < now + duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This method should receive an entry of type 'event'. |is_first| is true only
|
||||||
|
// when the event also happens to correspond to the first event. In this case,
|
||||||
|
// the timings of the 'firstInput' entry should be equal to those of this entry.
|
||||||
|
function verifyClickEvent(entry, is_first=false) {
|
||||||
|
assert_true(entry.cancelable);
|
||||||
|
assert_equals(entry.name, 'click');
|
||||||
|
assert_equals(entry.entryType, 'event');
|
||||||
|
assert_greater_than(entry.duration, 50,
|
||||||
|
"The entry's duration should be greater than 50ms.");
|
||||||
|
assert_greater_than(entry.processingStart, entry.startTime,
|
||||||
|
"The entry's processingStart should be greater than startTime.");
|
||||||
|
assert_greater_than_equal(entry.processingEnd, entry.processingStart,
|
||||||
|
"The entry's processingEnd must be at least as large as processingStart.");
|
||||||
|
assert_greater_than_equal(entry.duration, entry.processingEnd - entry.startTime,
|
||||||
|
"The entry's duration must be at least as large as processingEnd - startTime.");
|
||||||
|
if (is_first) {
|
||||||
|
let firstInputs = performance.getEntriesByType('firstInput');
|
||||||
|
assert_equals(firstInputs.length, 1, 'There should be a single firstInput entry');
|
||||||
|
let firstInput = firstInputs[0];
|
||||||
|
assert_equals(firstInput.name, entry.name);
|
||||||
|
assert_equals(firstInput.entryType, 'firstInput');
|
||||||
|
assert_equals(firstInput.startTime, entry.startTime);
|
||||||
|
assert_equals(firstInput.duration, entry.duration);
|
||||||
|
assert_equals(firstInput.processingStart, entry.processingStart);
|
||||||
|
assert_equals(firstInput.processingEnd, entry.processingEnd);
|
||||||
|
assert_equals(firstInput.cancelable, entry.cancelable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function wait() {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
step_timeout(() => {
|
||||||
|
resolve();
|
||||||
|
}, 0);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function clickAndBlockMain(id) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
clickOnElement(id, resolve);
|
||||||
|
});
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
import time
|
||||||
|
|
||||||
|
def main(request, response):
|
||||||
|
# Sleep for 500ms to delay onload.
|
||||||
|
time.sleep(0.5)
|
||||||
|
response.headers.set("Cache-Control", "no-cache, must-revalidate");
|
||||||
|
response.headers.set("Location", "data:image/gif;base64,R0lGODlhAQABAJAAAMjIyAAAACwAAAAAAQABAAACAgQBADs%3D");
|
|
@ -16,6 +16,13 @@ var btn = document.getElementById("btn"),
|
||||||
menu_btn = document.getElementById("menu_btn"),
|
menu_btn = document.getElementById("menu_btn"),
|
||||||
t1 = async_test("The submit event must be fired when click a button in submit status"),
|
t1 = async_test("The submit event must be fired when click a button in submit status"),
|
||||||
t2 = async_test("The reset event must be fired when click a button in reset status");
|
t2 = async_test("The reset event must be fired when click a button in reset status");
|
||||||
|
t3 = async_test("type=button shouldn't trigger submit or reset events");
|
||||||
|
t4 = async_test("Switching from type=button to type=submit should submit the form");
|
||||||
|
t5 = async_test("Switching from type=button to type=reset should reset the form");
|
||||||
|
t6 = async_test("Innermost button should submit its form");
|
||||||
|
t7 = async_test("Innermost button should reset its form");
|
||||||
|
t8 = async_test("Anchor inside a button should be prevent button activation");
|
||||||
|
t9 = async_test("input type=submit inside a button should be prevent button activation");
|
||||||
|
|
||||||
document.forms.fm1.onsubmit = t1.step_func(function (evt) {
|
document.forms.fm1.onsubmit = t1.step_func(function (evt) {
|
||||||
evt.preventDefault();
|
evt.preventDefault();
|
||||||
|
@ -46,4 +53,114 @@ t2.step(function () {
|
||||||
btn.click();
|
btn.click();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
t3.step(function () {
|
||||||
|
btn.type = "button";
|
||||||
|
assert_equals(btn.type, "button", "The button type should be 'button'.");
|
||||||
|
document.forms.fm1.onsubmit = t3.step_func(function (evt) {
|
||||||
|
assert_unreached("type=button shouldn't trigger submission.");
|
||||||
|
});
|
||||||
|
document.forms.fm1.onreset = t3.step_func(function (evt) {
|
||||||
|
assert_unreached("type=button shouldn't reset the form.");
|
||||||
|
});
|
||||||
|
btn.click();
|
||||||
|
t3.done();
|
||||||
|
});
|
||||||
|
|
||||||
|
t4.step(function () {
|
||||||
|
btn.type = "button";
|
||||||
|
btn.onclick = function() { btn.type = "submit"; }
|
||||||
|
document.forms.fm1.onsubmit = t4.step_func(function (evt) {
|
||||||
|
evt.preventDefault();
|
||||||
|
assert_equals(btn.type, "submit", "The button type should be 'submit'.");
|
||||||
|
t4.done();
|
||||||
|
});
|
||||||
|
btn.click();
|
||||||
|
});
|
||||||
|
|
||||||
|
t5.step(function () {
|
||||||
|
btn.type = "button";
|
||||||
|
btn.onclick = function() { btn.type = "reset"; }
|
||||||
|
document.forms.fm1.onreset = t5.step_func(function (evt) {
|
||||||
|
evt.preventDefault();
|
||||||
|
assert_equals(btn.type, "reset", "The button type should be 'reset'.");
|
||||||
|
t5.done();
|
||||||
|
});
|
||||||
|
btn.click();
|
||||||
|
});
|
||||||
|
|
||||||
|
t6.step(function () {
|
||||||
|
btn.type = "submit";
|
||||||
|
btn.innerHTML = "";
|
||||||
|
var fm2 = document.createElement("form");
|
||||||
|
var btn2 = document.createElement("button");
|
||||||
|
btn2.type = "submit";
|
||||||
|
fm2.appendChild(btn2);
|
||||||
|
btn.appendChild(fm2);
|
||||||
|
assert_true(document.forms.fm1.contains(fm2), "Should have nested forms");
|
||||||
|
|
||||||
|
function submitListener(evt) {
|
||||||
|
evt.preventDefault();
|
||||||
|
assert_equals(evt.target, fm2, "Innermost form should have got the submit event");
|
||||||
|
};
|
||||||
|
window.addEventListener("submit", submitListener, true);
|
||||||
|
btn2.click();
|
||||||
|
window.removeEventListener("submit", submitListener, true);
|
||||||
|
t6.done();
|
||||||
|
});
|
||||||
|
|
||||||
|
t7.step(function () {
|
||||||
|
btn.type = "reset";
|
||||||
|
btn.innerHTML = "";
|
||||||
|
var fm2 = document.createElement("form");
|
||||||
|
var btn2 = document.createElement("button");
|
||||||
|
btn2.type = "reset";
|
||||||
|
fm2.appendChild(btn2);
|
||||||
|
btn.appendChild(fm2);
|
||||||
|
assert_true(document.forms.fm1.contains(fm2), "Should have nested forms");
|
||||||
|
|
||||||
|
function resetListener(evt) {
|
||||||
|
evt.currentTarget.removeEventListener(evt.type, resetListener, true);
|
||||||
|
evt.preventDefault();
|
||||||
|
assert_equals(evt.target, fm2, "Innermost form should have got the reset event");
|
||||||
|
t7.done();
|
||||||
|
};
|
||||||
|
window.addEventListener("reset", resetListener, true);
|
||||||
|
btn2.click();
|
||||||
|
});
|
||||||
|
|
||||||
|
t8.step(function () {
|
||||||
|
btn.type = "submit";
|
||||||
|
btn.innerHTML = "";
|
||||||
|
var a = document.createElement("a");
|
||||||
|
a.href = "#";
|
||||||
|
btn.appendChild(a);
|
||||||
|
document.forms.fm1.onsubmit = t8.step_func(function (evt) {
|
||||||
|
assert_unreached("type=button shouldn't trigger submission.");
|
||||||
|
});
|
||||||
|
|
||||||
|
a.click();
|
||||||
|
t8.done();
|
||||||
|
});
|
||||||
|
|
||||||
|
t9.step(function () {
|
||||||
|
btn.type = "submit";
|
||||||
|
btn.innerHTML = "";
|
||||||
|
var fm2 = document.createElement("form");
|
||||||
|
var btn2 = document.createElement("input");
|
||||||
|
btn2.type = "submit";
|
||||||
|
fm2.appendChild(btn2);
|
||||||
|
btn.appendChild(fm2);
|
||||||
|
assert_true(document.forms.fm1.contains(fm2), "Should have nested forms");
|
||||||
|
|
||||||
|
function submitListener(evt) {
|
||||||
|
evt.preventDefault();
|
||||||
|
assert_equals(evt.target, fm2, "Innermost form should have got the submit event");
|
||||||
|
};
|
||||||
|
|
||||||
|
window.addEventListener("submit", submitListener, true);
|
||||||
|
btn2.click();
|
||||||
|
window.removeEventListener("submit", submitListener, true);
|
||||||
|
t9.done();
|
||||||
|
});
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -68,6 +68,7 @@ enum PaymentShippingType {
|
||||||
|
|
||||||
dictionary PaymentOptions {
|
dictionary PaymentOptions {
|
||||||
boolean requestPayerName = false;
|
boolean requestPayerName = false;
|
||||||
|
boolean requestBillingAddress = false;
|
||||||
boolean requestPayerEmail = false;
|
boolean requestPayerEmail = false;
|
||||||
boolean requestPayerPhone = false;
|
boolean requestPayerPhone = false;
|
||||||
boolean requestShipping = false;
|
boolean requestShipping = false;
|
||||||
|
|
|
@ -5,7 +5,8 @@
|
||||||
|
|
||||||
[SecureContext, Exposed=Window] interface XR : EventTarget {
|
[SecureContext, Exposed=Window] interface XR : EventTarget {
|
||||||
// Methods
|
// Methods
|
||||||
Promise<XRDevice?> requestDevice();
|
Promise<void> supportsSessionMode(XRSessionMode mode);
|
||||||
|
Promise<XRSession> requestSession(optional XRSessionCreationOptions parameters);
|
||||||
|
|
||||||
// Events
|
// Events
|
||||||
attribute EventHandler ondevicechange;
|
attribute EventHandler ondevicechange;
|
||||||
|
@ -16,14 +17,14 @@ partial interface Navigator {
|
||||||
[SameObject] readonly attribute XR xr;
|
[SameObject] readonly attribute XR xr;
|
||||||
};
|
};
|
||||||
|
|
||||||
[SecureContext, Exposed=Window] interface XRDevice {
|
enum XRSessionMode {
|
||||||
// Methods
|
"inline",
|
||||||
Promise<void> supportsSession(optional XRSessionCreationOptions options);
|
"immersive-vr",
|
||||||
Promise<XRSession> requestSession(optional XRSessionCreationOptions options);
|
"immersive-ar"
|
||||||
};
|
};
|
||||||
|
|
||||||
dictionary XRSessionCreationOptions {
|
dictionary XRSessionCreationOptions {
|
||||||
boolean immersive = false;
|
XRSessionMode mode = "inline";
|
||||||
XRPresentationContext outputContext;
|
XRPresentationContext outputContext;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -35,8 +36,7 @@ enum XREnvironmentBlendMode {
|
||||||
|
|
||||||
[SecureContext, Exposed=Window] interface XRSession : EventTarget {
|
[SecureContext, Exposed=Window] interface XRSession : EventTarget {
|
||||||
// Attributes
|
// Attributes
|
||||||
readonly attribute XRDevice device;
|
readonly attribute XRSessionMode mode;
|
||||||
readonly attribute boolean immersive;
|
|
||||||
readonly attribute XRPresentationContext outputContext;
|
readonly attribute XRPresentationContext outputContext;
|
||||||
readonly attribute XREnvironmentBlendMode environmentBlendMode;
|
readonly attribute XREnvironmentBlendMode environmentBlendMode;
|
||||||
|
|
||||||
|
@ -60,6 +60,7 @@ enum XREnvironmentBlendMode {
|
||||||
attribute EventHandler onresetpose;
|
attribute EventHandler onresetpose;
|
||||||
attribute EventHandler onend;
|
attribute EventHandler onend;
|
||||||
attribute EventHandler onselect;
|
attribute EventHandler onselect;
|
||||||
|
attribute EventHandler oninputsourceschange;
|
||||||
attribute EventHandler onselectstart;
|
attribute EventHandler onselectstart;
|
||||||
attribute EventHandler onselectend;
|
attribute EventHandler onselectend;
|
||||||
};
|
};
|
||||||
|
@ -68,10 +69,9 @@ callback XRFrameRequestCallback = void (DOMHighResTimeStamp time, XRFrame frame)
|
||||||
|
|
||||||
[SecureContext, Exposed=Window] interface XRFrame {
|
[SecureContext, Exposed=Window] interface XRFrame {
|
||||||
readonly attribute XRSession session;
|
readonly attribute XRSession session;
|
||||||
readonly attribute FrozenArray<XRView> views;
|
|
||||||
|
|
||||||
XRDevicePose? getDevicePose(XRCoordinateSystem coordinateSystem);
|
XRViewerPose? getViewerPose(XRFrameOfReference frameOfRef);
|
||||||
XRInputPose? getInputPose(XRInputSource inputSource, XRCoordinateSystem coordinateSystem);
|
XRInputPose? getInputPose(XRInputSource inputSource, XRFrameOfReference frameOfRef);
|
||||||
};
|
};
|
||||||
|
|
||||||
[SecureContext, Exposed=Window] interface XRCoordinateSystem : EventTarget {
|
[SecureContext, Exposed=Window] interface XRCoordinateSystem : EventTarget {
|
||||||
|
@ -108,6 +108,7 @@ enum XREye {
|
||||||
[SecureContext, Exposed=Window] interface XRView {
|
[SecureContext, Exposed=Window] interface XRView {
|
||||||
readonly attribute XREye eye;
|
readonly attribute XREye eye;
|
||||||
readonly attribute Float32Array projectionMatrix;
|
readonly attribute Float32Array projectionMatrix;
|
||||||
|
readonly attribute Float32Array viewMatrix;
|
||||||
};
|
};
|
||||||
|
|
||||||
[SecureContext, Exposed=Window] interface XRViewport {
|
[SecureContext, Exposed=Window] interface XRViewport {
|
||||||
|
@ -117,10 +118,9 @@ enum XREye {
|
||||||
readonly attribute long height;
|
readonly attribute long height;
|
||||||
};
|
};
|
||||||
|
|
||||||
[SecureContext, Exposed=Window] interface XRDevicePose {
|
[SecureContext, Exposed=Window] interface XRViewerPose {
|
||||||
readonly attribute Float32Array poseModelMatrix;
|
readonly attribute Float32Array poseMatrix;
|
||||||
|
readonly attribute FrozenArray<XRView> views;
|
||||||
Float32Array getViewMatrix(XRView view);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum XRHandedness {
|
enum XRHandedness {
|
||||||
|
@ -165,7 +165,6 @@ dictionary XRWebGLLayerInit {
|
||||||
boolean depth = true;
|
boolean depth = true;
|
||||||
boolean stencil = false;
|
boolean stencil = false;
|
||||||
boolean alpha = true;
|
boolean alpha = true;
|
||||||
boolean multiview = false;
|
|
||||||
double framebufferScaleFactor = 1.0;
|
double framebufferScaleFactor = 1.0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -180,7 +179,6 @@ interface XRWebGLLayer : XRLayer {
|
||||||
readonly attribute boolean depth;
|
readonly attribute boolean depth;
|
||||||
readonly attribute boolean stencil;
|
readonly attribute boolean stencil;
|
||||||
readonly attribute boolean alpha;
|
readonly attribute boolean alpha;
|
||||||
readonly attribute boolean multiview;
|
|
||||||
|
|
||||||
readonly attribute WebGLFramebuffer framebuffer;
|
readonly attribute WebGLFramebuffer framebuffer;
|
||||||
readonly attribute unsigned long framebufferWidth;
|
readonly attribute unsigned long framebufferWidth;
|
||||||
|
@ -195,11 +193,11 @@ interface XRWebGLLayer : XRLayer {
|
||||||
};
|
};
|
||||||
|
|
||||||
partial dictionary WebGLContextAttributes {
|
partial dictionary WebGLContextAttributes {
|
||||||
XRDevice compatibleXRDevice = null;
|
boolean xrCompatible = null;
|
||||||
};
|
};
|
||||||
|
|
||||||
partial interface mixin WebGLRenderingContextBase {
|
partial interface mixin WebGLRenderingContextBase {
|
||||||
Promise<void> setCompatibleXRDevice(XRDevice device);
|
Promise<void> makeXRCompatible();
|
||||||
};
|
};
|
||||||
|
|
||||||
[SecureContext, Exposed=Window] interface XRPresentationContext {
|
[SecureContext, Exposed=Window] interface XRPresentationContext {
|
||||||
|
|
|
@ -168,4 +168,38 @@ promise_test(t => {
|
||||||
});
|
});
|
||||||
}, "Test that decodingInfo returns a valid MediaCapabilitiesDecodingInfo objects with encrypted media");
|
}, "Test that decodingInfo returns a valid MediaCapabilitiesDecodingInfo objects with encrypted media");
|
||||||
|
|
||||||
|
promise_test(t => {
|
||||||
|
return navigator.mediaCapabilities.decodingInfo({
|
||||||
|
type: 'file',
|
||||||
|
video: minimalVideoConfiguration,
|
||||||
|
keySystemConfiguration: {
|
||||||
|
keySystem: 'foobar',
|
||||||
|
videoRobustness: '',
|
||||||
|
}
|
||||||
|
}).then(ability => {
|
||||||
|
assert_false(ability.supported);
|
||||||
|
assert_false(ability.smooth);
|
||||||
|
assert_false(ability.powerEfficient);
|
||||||
|
assert_equals(ability.keySystemAccess, null);
|
||||||
|
});
|
||||||
|
}, "Test that random key systems are reported as non supported.");
|
||||||
|
|
||||||
|
// TODO(mlamouri): this test could be split in two tests for which codec support
|
||||||
|
// across browsers is widely compatible: one when all browsers wouldn't support
|
||||||
|
// and one where all browsers do support. The current approach is to check that
|
||||||
|
// the answer is consistent to the spec.
|
||||||
|
promise_test(t => {
|
||||||
|
return navigator.mediaCapabilities.decodingInfo({
|
||||||
|
type: 'file',
|
||||||
|
video: minimalVideoConfiguration,
|
||||||
|
audio: minimalAudioConfiguration,
|
||||||
|
keySystemConfiguration: minimalKeySystemConfiguration,
|
||||||
|
}).then(ability => {
|
||||||
|
if (ability.supported)
|
||||||
|
assert_not_equals(ability.keySystemAccess, null);
|
||||||
|
else
|
||||||
|
assert_equals(ability.keySystemAccess, null);
|
||||||
|
});
|
||||||
|
}, "Test that keySystemAccess is only null when not supported if keySystemConfiguration was used.");
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
import time
|
||||||
|
|
||||||
|
def main(request, response):
|
||||||
|
delay = float(request.GET.first("ms", 500)) / 1E3
|
||||||
|
count = int(request.GET.first("count", 50))
|
||||||
|
# Read request body
|
||||||
|
request.body
|
||||||
|
time.sleep(delay)
|
||||||
|
response.headers.set("Content-type", "text/plain")
|
||||||
|
response.write_status_headers()
|
||||||
|
time.sleep(delay);
|
||||||
|
for i in xrange(count):
|
||||||
|
response.writer.write_content("TEST_TRICKLE\n")
|
||||||
|
time.sleep(delay)
|
|
@ -0,0 +1,19 @@
|
||||||
|
import time
|
||||||
|
|
||||||
|
def main(request, response):
|
||||||
|
# no-cache itself to ensure the user agent finds a new version for each update.
|
||||||
|
headers = [('Cache-Control', 'no-cache, must-revalidate'),
|
||||||
|
('Pragma', 'no-cache')]
|
||||||
|
|
||||||
|
content_type = ''
|
||||||
|
extra_body = ''
|
||||||
|
|
||||||
|
content_type = 'application/javascript'
|
||||||
|
headers.append(('Content-Type', content_type))
|
||||||
|
|
||||||
|
extra_body = "self.onfetch = (event) => { event.respondWith(fetch(event.request)); };"
|
||||||
|
|
||||||
|
# Return a different script for each access. Use .time() and .clock() for
|
||||||
|
# best time resolution across different platforms.
|
||||||
|
return headers, '/* %s %s */ %s' % (time.time(), time.clock(), extra_body)
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<title>Update on navigation</title>
|
||||||
|
<script src='/resources/testharness.js'></script>
|
||||||
|
<script src='/resources/testharnessreport.js'></script>
|
||||||
|
<script src='resources/test-helpers.sub.js'></script>
|
||||||
|
<script>
|
||||||
|
promise_test(async (t) => {
|
||||||
|
var script = 'resources/update-fetch-worker.py';
|
||||||
|
var scope = 'resources/trickle.py?ms=1000&count=1';
|
||||||
|
|
||||||
|
const registration = await service_worker_unregister_and_register(t, script, scope);
|
||||||
|
t.add_cleanup(() => registration.unregister());
|
||||||
|
|
||||||
|
if (registration.installing)
|
||||||
|
await wait_for_state(t, registration.installing, 'activated');
|
||||||
|
|
||||||
|
const frame = await with_iframe(scope);
|
||||||
|
t.add_cleanup(() => frame.remove());
|
||||||
|
}, 'The active service worker in charge of a navigation load should not be terminated as part of updating the registration');
|
||||||
|
</script>
|
|
@ -0,0 +1,24 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:h="http://www.w3.org/1999/xhtml"
|
||||||
|
width="800px" height="800px">
|
||||||
|
<title>SVG Text: parsing inline-size with invalid values</title>
|
||||||
|
<metadata>
|
||||||
|
<h:link rel="help" href="https://svgwg.org/svg2-draft/text.html#InlineSizeProperty"/>
|
||||||
|
<h:link rel="help" href="https://drafts.csswg.org/css-logical/#dimension-properties"/>
|
||||||
|
<h:meta name="assert" content="inline-size supports only the grammar 'auto | length-percentage'"/>
|
||||||
|
</metadata>
|
||||||
|
<g id="target"></g>
|
||||||
|
<h:script src="/resources/testharness.js"/>
|
||||||
|
<h:script src="/resources/testharnessreport.js"/>
|
||||||
|
<h:script src="/css/support/parsing-testcommon.js"/>
|
||||||
|
<script><![CDATA[
|
||||||
|
|
||||||
|
test_invalid_value("inline-size", "none");
|
||||||
|
test_invalid_value("inline-size", "-10px");
|
||||||
|
test_invalid_value("inline-size", "20");
|
||||||
|
test_invalid_value("inline-size", "30deg");
|
||||||
|
test_invalid_value("inline-size", "40px 50%");
|
||||||
|
|
||||||
|
]]></script>
|
||||||
|
</svg>
|
После Ширина: | Высота: | Размер: 974 B |
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче