Merge mozilla-central to inbound. a=merge CLOSED TREE

This commit is contained in:
Gurzau Raul 2018-12-21 18:40:39 +02:00
commit fcb3be1b9f
49 changed files with 547 additions and 417 deletions

View File

@ -185,7 +185,6 @@ dom/flex/**
dom/grid/**
dom/html/**
dom/jsurl/**
dom/localstorage/**
dom/media/test/**
dom/media/tests/**
dom/media/webaudio/**

View File

@ -103,7 +103,7 @@ void DocAccessibleWrap::CacheViewportCallback(nsITimer* aTimer,
nsLayoutUtils::GetFramesForArea(
presShell->GetRootFrame(), scrollPort, frames,
nsLayoutUtils::FrameForPointFlags::ONLY_VISIBLE);
nsLayoutUtils::FrameForPointOption::OnlyVisible);
AccessibleHashtable inViewAccs;
for (size_t i = 0; i < frames.Length(); i++) {
nsIContent* content = frames.ElementAt(i)->GetContent();

View File

@ -439,3 +439,69 @@ bool nsAccUtils::PersistentPropertiesToArray(nsIPersistentProperties* aProps,
return true;
}
bool nsAccUtils::IsARIALive(const Accessible* aAccessible) {
// Get computed aria-live property based on the closest container with the
// attribute. Inner nodes override outer nodes within the same
// document, but nodes in outer documents override nodes in inner documents.
// This should be the same as the container-live attribute, but we don't need
// the other container-* attributes, so we can't use the same function.
nsAutoString live;
nsIContent* startContent = aAccessible->GetContent();
while (startContent) {
nsIDocument* doc = startContent->GetComposedDoc();
if (!doc) {
break;
}
dom::Element* aTopEl = doc->GetRootElement();
nsIContent* ancestor = startContent;
while (ancestor) {
nsAutoString docLive;
const nsRoleMapEntry* role = nullptr;
if (ancestor->IsElement()) {
role = aria::GetRoleMap(ancestor->AsElement());
}
if (HasDefinedARIAToken(ancestor, nsGkAtoms::aria_live)) {
ancestor->AsElement()->GetAttr(kNameSpaceID_None, nsGkAtoms::aria_live,
docLive);
} else if (role) {
GetLiveAttrValue(role->liveAttRule, docLive);
}
if (!docLive.IsEmpty()) {
live = docLive;
break;
}
if (ancestor == aTopEl) {
break;
}
ancestor = ancestor->GetParent();
if (!ancestor) {
ancestor = aTopEl; // Use <body>/<frameset>
}
}
// Allow ARIA live region markup from outer documents to override.
nsCOMPtr<nsIDocShellTreeItem> docShellTreeItem = doc->GetDocShell();
if (!docShellTreeItem) {
break;
}
nsCOMPtr<nsIDocShellTreeItem> sameTypeParent;
docShellTreeItem->GetSameTypeParent(getter_AddRefs(sameTypeParent));
if (!sameTypeParent || sameTypeParent == docShellTreeItem) {
break;
}
nsIDocument* parentDoc = doc->GetParentDocument();
if (!parentDoc) {
break;
}
startContent = parentDoc->FindContentForSubDocument(doc);
}
return !live.IsEmpty() && !live.EqualsLiteral("off");
}

View File

@ -255,6 +255,12 @@ class nsAccUtils {
static bool PersistentPropertiesToArray(nsIPersistentProperties* aProps,
nsTArray<Attribute>* aAttributes);
/**
* Return true if the given accessible is within an ARIA live region; i.e.
* the container-live attribute would be something other than "off" or empty.
*/
static bool IsARIALive(const Accessible* aAccessible);
};
} // namespace a11y

View File

@ -846,10 +846,23 @@ nsresult Accessible::HandleAccEvent(AccEvent* aEvent) {
case nsIAccessibleEvent::EVENT_TEXT_INSERTED:
case nsIAccessibleEvent::EVENT_TEXT_REMOVED: {
AccTextChangeEvent* event = downcast_accEvent(aEvent);
ipcDoc->SendTextChangeEvent(
id, event->ModifiedText(), event->GetStartOffset(),
event->GetLength(), event->IsTextInserted(),
event->IsFromUserInput());
const nsString& text = event->ModifiedText();
#if defined(XP_WIN)
// On Windows, events for live region updates containing embedded
// objects require us to dispatch synchronous events.
bool sync = text.Contains(L'\xfffc') &&
nsAccUtils::IsARIALive(aEvent->GetAccessible());
#endif
ipcDoc->SendTextChangeEvent(id, text, event->GetStartOffset(),
event->GetLength(),
event->IsTextInserted(),
event->IsFromUserInput()
#if defined(XP_WIN)
// This parameter only exists on Windows.
,
sync
#endif
);
break;
}
case nsIAccessibleEvent::EVENT_SELECTION:

View File

@ -197,9 +197,9 @@ bool DocAccessibleChild::SendCaretMoveEvent(
bool DocAccessibleChild::SendTextChangeEvent(
const uint64_t& aID, const nsString& aStr, const int32_t& aStart,
const uint32_t& aLen, const bool& aIsInsert, const bool& aFromUser,
const bool aDoSyncCheck) {
const bool aDoSync) {
if (IsConstructedInParentProcess()) {
if (aDoSyncCheck && aStr.Contains(L'\xfffc')) {
if (aDoSync) {
// The AT is going to need to reenter content while the event is being
// dispatched synchronously.
return PDocAccessibleChild::SendSyncTextChangeEvent(

View File

@ -54,7 +54,7 @@ class DocAccessibleChild : public DocAccessibleChildBase {
bool SendTextChangeEvent(const uint64_t& aID, const nsString& aStr,
const int32_t& aStart, const uint32_t& aLen,
const bool& aIsInsert, const bool& aFromUser,
const bool aDoSyncCheck = true);
const bool aDoSync = false);
bool SendSelectionEvent(const uint64_t& aID, const uint64_t& aWidgetID,
const uint32_t& aType);
bool SendRoleChangedEvent(const a11y::role& aRole);

View File

@ -194,47 +194,53 @@ Element* DocumentOrShadowRoot::GetFullscreenElement() {
return nullptr;
}
Element* DocumentOrShadowRoot::ElementFromPoint(float aX, float aY) {
return ElementFromPointHelper(aX, aY, false, true);
namespace {
using FrameForPointOption = nsLayoutUtils::FrameForPointOption;
// Whether only one node or multiple nodes is requested.
enum class Multiple {
No,
Yes,
};
// Whether we should flush layout or not.
enum class FlushLayout {
No,
Yes,
};
template <typename NodeOrElement>
NodeOrElement* CastTo(nsIContent* aContent);
template <>
Element* CastTo<Element>(nsIContent* aContent) {
return aContent->AsElement();
}
void DocumentOrShadowRoot::ElementsFromPoint(
float aX, float aY, nsTArray<RefPtr<Element>>& aElements) {
ElementsFromPointHelper(aX, aY, nsIDocument::FLUSH_LAYOUT, aElements);
template <>
nsINode* CastTo<nsINode>(nsIContent* aContent) {
return aContent;
}
Element* DocumentOrShadowRoot::ElementFromPointHelper(
float aX, float aY, bool aIgnoreRootScrollFrame, bool aFlushLayout) {
AutoTArray<RefPtr<Element>, 1> elementArray;
ElementsFromPointHelper(
aX, aY,
((aIgnoreRootScrollFrame ? nsIDocument::IGNORE_ROOT_SCROLL_FRAME : 0) |
(aFlushLayout ? nsIDocument::FLUSH_LAYOUT : 0) |
nsIDocument::IS_ELEMENT_FROM_POINT),
elementArray);
if (elementArray.IsEmpty()) {
return nullptr;
}
return elementArray[0];
}
template <typename NodeOrElement>
static void QueryNodesFromRect(DocumentOrShadowRoot& aRoot, const nsRect& aRect,
EnumSet<FrameForPointOption> aOptions,
FlushLayout aShouldFlushLayout,
Multiple aMultiple,
nsTArray<RefPtr<NodeOrElement>>& aNodes) {
static_assert(std::is_same<nsINode, NodeOrElement>::value ||
std::is_same<Element, NodeOrElement>::value,
"Should returning nodes or elements");
void DocumentOrShadowRoot::ElementsFromPointHelper(
float aX, float aY, uint32_t aFlags,
nsTArray<RefPtr<mozilla::dom::Element>>& aElements) {
// As per the the spec, we return null if either coord is negative
if (!(aFlags & nsIDocument::IGNORE_ROOT_SCROLL_FRAME) && (aX < 0 || aY < 0)) {
return;
}
constexpr bool returningElements =
std::is_same<Element, NodeOrElement>::value;
nscoord x = nsPresContext::CSSPixelsToAppUnits(aX);
nscoord y = nsPresContext::CSSPixelsToAppUnits(aY);
nsPoint pt(x, y);
nsCOMPtr<nsIDocument> doc = AsNode().OwnerDoc();
nsCOMPtr<nsIDocument> doc = aRoot.AsNode().OwnerDoc();
// Make sure the layout information we get is up-to-date, and
// ensure we get a root frame (for everything but XUL)
if (aFlags & nsIDocument::FLUSH_LAYOUT) {
if (aShouldFlushLayout == FlushLayout::Yes) {
doc->FlushPendingNotifications(FlushType::Layout);
}
@ -242,70 +248,130 @@ void DocumentOrShadowRoot::ElementsFromPointHelper(
if (!ps) {
return;
}
nsIFrame* rootFrame = ps->GetRootFrame();
nsIFrame* rootFrame = ps->GetRootFrame();
// XUL docs, unlike HTML, have no frame tree until everything's done loading
if (!rootFrame) {
return; // return null to premature XUL callers as a reminder to wait
}
nsTArray<nsIFrame*> outFrames;
// Emulate what GetFrameAtPoint does, since we want all the frames under our
// point.
nsLayoutUtils::GetFramesForArea(
rootFrame, nsRect(pt, nsSize(1, 1)), outFrames,
nsLayoutUtils::IGNORE_PAINT_SUPPRESSION |
nsLayoutUtils::IGNORE_CROSS_DOC |
((aFlags & nsIDocument::IGNORE_ROOT_SCROLL_FRAME)
? nsLayoutUtils::IGNORE_ROOT_SCROLL_FRAME
: 0));
aOptions += FrameForPointOption::IgnorePaintSuppression;
aOptions += FrameForPointOption::IgnoreCrossDoc;
// Dunno when this would ever happen, as we should at least have a root frame
// under us?
if (outFrames.IsEmpty()) {
return;
}
AutoTArray<nsIFrame*, 8> frames;
nsLayoutUtils::GetFramesForArea(rootFrame, aRect, frames, aOptions);
// Used to filter out repeated elements in sequence.
nsIContent* lastAdded = nullptr;
for (nsIFrame* frame : frames) {
nsIContent* content = doc->GetContentInThisDocument(frame);
if (!content) {
continue;
}
for (uint32_t i = 0; i < outFrames.Length(); i++) {
nsIContent* node = doc->GetContentInThisDocument(outFrames[i]);
if (!node || !node->IsElement()) {
if (returningElements && !content->IsElement()) {
// If this helper is called via ElementsFromPoint, we need to make sure
// our frame is an element. Otherwise return whatever the top frame is
// even if it isn't the top-painted element.
// SVG 'text' element's SVGTextFrame doesn't respond to hit-testing, so
// if 'node' is a child of such an element then we need to manually defer
// to the parent here.
if (!(aFlags & nsIDocument::IS_ELEMENT_FROM_POINT) &&
!nsSVGUtils::IsInSVGTextSubtree(outFrames[i])) {
// if 'content' is a child of such an element then we need to manually
// defer to the parent here.
if (aMultiple == Multiple::Yes &&
!nsSVGUtils::IsInSVGTextSubtree(frame)) {
continue;
}
node = node->GetParent();
if (ShadowRoot* shadow = ShadowRoot::FromNodeOrNull(node)) {
node = shadow->Host();
content = content->GetParent();
if (ShadowRoot* shadow = ShadowRoot::FromNodeOrNull(content)) {
content = shadow->Host();
}
}
// XXXsmaug There is plenty of unspec'ed behavior here
// https://github.com/w3c/webcomponents/issues/735
// https://github.com/w3c/webcomponents/issues/736
node = Retarget(node);
content = aRoot.Retarget(content);
if (node && node != lastAdded) {
aElements.AppendElement(node->AsElement());
lastAdded = node;
// If this helper is called via ElementFromPoint, just return the first
// element we find.
if (aFlags & nsIDocument::IS_ELEMENT_FROM_POINT) {
if (content && content != aNodes.SafeLastElement(nullptr)) {
aNodes.AppendElement(CastTo<NodeOrElement>(content));
if (aMultiple == Multiple::No) {
return;
}
}
}
}
template <typename NodeOrElement>
static void QueryNodesFromPoint(DocumentOrShadowRoot& aRoot, float aX, float aY,
EnumSet<FrameForPointOption> aOptions,
FlushLayout aShouldFlushLayout,
Multiple aMultiple,
nsTArray<RefPtr<NodeOrElement>>& aNodes) {
// As per the spec, we return null if either coord is negative.
if (!aOptions.contains(FrameForPointOption::IgnoreRootScrollFrame) &&
(aX < 0 || aY < 0)) {
return;
}
nscoord x = nsPresContext::CSSPixelsToAppUnits(aX);
nscoord y = nsPresContext::CSSPixelsToAppUnits(aY);
nsPoint pt(x, y);
QueryNodesFromRect(aRoot, nsRect(pt, nsSize(1, 1)), aOptions,
aShouldFlushLayout, aMultiple, aNodes);
}
} // namespace
Element* DocumentOrShadowRoot::ElementFromPoint(float aX, float aY) {
return ElementFromPointHelper(aX, aY, false, true);
}
void DocumentOrShadowRoot::ElementsFromPoint(
float aX, float aY, nsTArray<RefPtr<Element>>& aElements) {
QueryNodesFromPoint(*this, aX, aY, {}, FlushLayout::Yes, Multiple::Yes,
aElements);
}
Element* DocumentOrShadowRoot::ElementFromPointHelper(
float aX, float aY, bool aIgnoreRootScrollFrame, bool aFlushLayout) {
EnumSet<FrameForPointOption> options;
if (aIgnoreRootScrollFrame) {
options += FrameForPointOption::IgnoreRootScrollFrame;
}
auto flush = aFlushLayout ? FlushLayout::Yes : FlushLayout::No;
AutoTArray<RefPtr<Element>, 1> elements;
QueryNodesFromPoint(*this, aX, aY, options, flush, Multiple::No, elements);
return elements.SafeElementAt(0);
}
void DocumentOrShadowRoot::NodesFromRect(float aX, float aY, float aTopSize,
float aRightSize, float aBottomSize,
float aLeftSize,
bool aIgnoreRootScrollFrame,
bool aFlushLayout,
nsTArray<RefPtr<nsINode>>& aReturn) {
// Following the same behavior of elementFromPoint,
// we don't return anything if either coord is negative
if (!aIgnoreRootScrollFrame && (aX < 0 || aY < 0)) {
return;
}
nscoord x = nsPresContext::CSSPixelsToAppUnits(aX - aLeftSize);
nscoord y = nsPresContext::CSSPixelsToAppUnits(aY - aTopSize);
nscoord w = nsPresContext::CSSPixelsToAppUnits(aLeftSize + aRightSize) + 1;
nscoord h = nsPresContext::CSSPixelsToAppUnits(aTopSize + aBottomSize) + 1;
nsRect rect(x, y, w, h);
EnumSet<FrameForPointOption> options;
if (aIgnoreRootScrollFrame) {
options += FrameForPointOption::IgnoreRootScrollFrame;
}
auto flush = aFlushLayout ? FlushLayout::Yes : FlushLayout::No;
QueryNodesFromRect(*this, rect, options, flush, Multiple::Yes, aReturn);
}
Element* DocumentOrShadowRoot::AddIDTargetObserver(nsAtom* aID,
IDTargetObserver aObserver,
void* aData,

View File

@ -17,6 +17,7 @@ class nsContentList;
class nsCycleCollectionTraversalCallback;
class nsIDocument;
class nsINode;
class nsINodeList;
class nsIRadioVisitor;
class nsWindowSizes;
@ -114,15 +115,11 @@ class DocumentOrShadowRoot {
Element* ElementFromPointHelper(float aX, float aY,
bool aIgnoreRootScrollFrame,
bool aFlushLayout);
enum ElementsFromPointFlags {
IGNORE_ROOT_SCROLL_FRAME = 1,
FLUSH_LAYOUT = 2,
IS_ELEMENT_FROM_POINT = 4
};
void ElementsFromPointHelper(
float aX, float aY, uint32_t aFlags,
nsTArray<RefPtr<mozilla::dom::Element>>& aElements);
void NodesFromRect(float aX, float aY, float aTopSize, float aRightSize,
float aBottomSize, float aLeftSize,
bool aIgnoreRootScrollFrame, bool aFlushLayout,
nsTArray<RefPtr<nsINode>>&);
/**
* This gets fired when the element that an id refers to changes.
@ -199,6 +196,8 @@ class DocumentOrShadowRoot {
nsRadioGroupStruct* GetRadioGroup(const nsAString& aName) const;
nsRadioGroupStruct* GetOrCreateRadioGroup(const nsAString& aName);
nsIContent* Retarget(nsIContent* aContent) const;
protected:
// Returns the reference to the sheet, if found in mStyleSheets.
already_AddRefed<StyleSheet> RemoveSheet(StyleSheet& aSheet);
@ -208,8 +207,6 @@ class DocumentOrShadowRoot {
void AddSizeOfOwnedSheetArrayExcludingThis(
nsWindowSizes&, const nsTArray<RefPtr<StyleSheet>>&) const;
nsIContent* Retarget(nsIContent* aContent) const;
/**
* If focused element's subtree root is this document or shadow root, return
* focused element, otherwise, get the shadow host recursively until the

View File

@ -1153,9 +1153,18 @@ nsDOMWindowUtils::NodesFromRect(float aX, float aY, float aTopSize,
nsCOMPtr<nsIDocument> doc = GetDocument();
NS_ENSURE_STATE(doc);
return doc->NodesFromRectHelper(aX, aY, aTopSize, aRightSize, aBottomSize,
aLeftSize, aIgnoreRootScrollFrame,
aFlushLayout, aReturn);
nsSimpleContentList* list = new nsSimpleContentList(doc);
NS_ADDREF(list);
*aReturn = list;
AutoTArray<RefPtr<nsINode>, 8> nodes;
doc->NodesFromRect(aX, aY, aTopSize, aRightSize, aBottomSize, aLeftSize,
aIgnoreRootScrollFrame, aFlushLayout, nodes);
list->SetCapacity(nodes.Length());
for (auto& node : nodes) {
list->AppendElement(node->AsContent());
}
return NS_OK;
}
NS_IMETHODIMP

View File

@ -3394,72 +3394,6 @@ Element* nsIDocument::GetCurrentScript() {
return el;
}
nsresult nsIDocument::NodesFromRectHelper(float aX, float aY, float aTopSize,
float aRightSize, float aBottomSize,
float aLeftSize,
bool aIgnoreRootScrollFrame,
bool aFlushLayout,
nsINodeList** aReturn) {
NS_ENSURE_ARG_POINTER(aReturn);
nsSimpleContentList* elements = new nsSimpleContentList(this);
NS_ADDREF(elements);
*aReturn = elements;
// Following the same behavior of elementFromPoint,
// we don't return anything if either coord is negative
if (!aIgnoreRootScrollFrame && (aX < 0 || aY < 0)) return NS_OK;
nscoord x = nsPresContext::CSSPixelsToAppUnits(aX - aLeftSize);
nscoord y = nsPresContext::CSSPixelsToAppUnits(aY - aTopSize);
nscoord w = nsPresContext::CSSPixelsToAppUnits(aLeftSize + aRightSize) + 1;
nscoord h = nsPresContext::CSSPixelsToAppUnits(aTopSize + aBottomSize) + 1;
nsRect rect(x, y, w, h);
// Make sure the layout information we get is up-to-date, and
// ensure we get a root frame (for everything but XUL)
if (aFlushLayout) {
FlushPendingNotifications(FlushType::Layout);
}
nsIPresShell* ps = GetShell();
NS_ENSURE_STATE(ps);
nsIFrame* rootFrame = ps->GetRootFrame();
// XUL docs, unlike HTML, have no frame tree until everything's done loading
if (!rootFrame)
return NS_OK; // return nothing to premature XUL callers as a reminder to
// wait
AutoTArray<nsIFrame*, 8> outFrames;
nsLayoutUtils::GetFramesForArea(
rootFrame, rect, outFrames,
nsLayoutUtils::IGNORE_PAINT_SUPPRESSION |
nsLayoutUtils::IGNORE_CROSS_DOC |
(aIgnoreRootScrollFrame ? nsLayoutUtils::IGNORE_ROOT_SCROLL_FRAME
: 0));
// Used to filter out repeated elements in sequence.
nsIContent* lastAdded = nullptr;
for (uint32_t i = 0; i < outFrames.Length(); i++) {
nsIContent* node = GetContentInThisDocument(outFrames[i]);
if (node && !node->IsElement() && !node->IsText()) {
// We have a node that isn't an element or a text node,
// use its parent content instead.
node = node->GetParent();
}
if (node && node != lastAdded) {
elements->AppendElement(node);
lastAdded = node;
}
}
return NS_OK;
}
void nsIDocument::ReleaseCapture() const {
// only release the capture if the caller can access it. This prevents a
// page from stopping a scrollbar grab for example.
@ -9253,6 +9187,8 @@ already_AddRefed<TouchList> nsIDocument::CreateTouchList(
already_AddRefed<nsDOMCaretPosition> nsIDocument::CaretPositionFromPoint(
float aX, float aY) {
using FrameForPointOption = nsLayoutUtils::FrameForPointOption;
nscoord x = nsPresContext::CSSPixelsToAppUnits(aX);
nscoord y = nsPresContext::CSSPixelsToAppUnits(aY);
nsPoint pt(x, y);
@ -9271,10 +9207,10 @@ already_AddRefed<nsDOMCaretPosition> nsIDocument::CaretPositionFromPoint(
return nullptr;
}
nsIFrame* ptFrame =
nsLayoutUtils::GetFrameForPoint(rootFrame, pt,
nsLayoutUtils::IGNORE_PAINT_SUPPRESSION |
nsLayoutUtils::IGNORE_CROSS_DOC);
nsIFrame* ptFrame = nsLayoutUtils::GetFrameForPoint(
rootFrame, pt,
{FrameForPointOption::IgnorePaintSuppression,
FrameForPointOption::IgnoreCrossDoc});
if (!ptFrame) {
return nullptr;
}

View File

@ -2184,11 +2184,6 @@ class nsIDocument : public nsINode,
nsAtom* aAttrName,
const nsAString& aAttrValue) const;
nsresult NodesFromRectHelper(float aX, float aY, float aTopSize,
float aRightSize, float aBottomSize,
float aLeftSize, bool aIgnoreRootScrollFrame,
bool aFlushLayout, nsINodeList** aReturn);
/**
* See FlushSkinBindings on nsBindingManager
*/

View File

@ -0,0 +1,7 @@
"use strict";
module.exports = {
"extends": [
"plugin:mozilla/xpcshell-test",
]
};

View File

@ -1,3 +1,5 @@
/* import-globals-from head.js */
const principalInfos = [
{ url: "http://example.com", attrs: {} },
@ -11,22 +13,19 @@ const principalInfos = [
{ url: "https://pattern.test", attrs: { userContextId: 15 } },
];
function enableNextGenLocalStorage()
{
function enableNextGenLocalStorage() {
info("Setting pref");
Services.prefs.setBoolPref("dom.storage.next_gen", true);
}
function disableNextGenLocalStorage()
{
function disableNextGenLocalStorage() {
info("Setting pref");
Services.prefs.setBoolPref("dom.storage.next_gen", false);
}
function storeData()
{
function storeData() {
for (let i = 0; i < principalInfos.length; i++) {
let principalInfo = principalInfos[i];
let principal = getPrincipal(principalInfo.url, principalInfo.attrs);
@ -49,8 +48,7 @@ function storeData()
}
}
function exportShadowDatabase(name)
{
function exportShadowDatabase(name) {
info("Verifying shadow database");
let profileDir = Services.dirsvc.get("ProfD", Ci.nsIFile);
@ -66,8 +64,7 @@ function exportShadowDatabase(name)
shadowDatabase.copyTo(currentDir, name);
}
function importShadowDatabase(name)
{
function importShadowDatabase(name) {
info("Verifying shadow database");
let currentDir = Services.dirsvc.get("CurWorkD", Ci.nsIFile);
@ -87,8 +84,7 @@ function importShadowDatabase(name)
return true;
}
function verifyData(clearedOrigins)
{
function verifyData(clearedOrigins) {
for (let i = 0; i < principalInfos.length; i++) {
let principalInfo = principalInfos[i];
let principal = getPrincipal(principalInfo.url, principalInfo.attrs);

View File

@ -3,28 +3,27 @@
* http://creativecommons.org/publicdomain/zero/1.0/
*/
// Tests are expected to define testSteps.
/* globals testSteps */
const NS_ERROR_DOM_QUOTA_EXCEEDED_ERR = 22;
ChromeUtils.import("resource://gre/modules/Services.jsm");
function is(a, b, msg)
{
function is(a, b, msg) {
Assert.equal(a, b, msg);
}
function ok(cond, msg)
{
function ok(cond, msg) {
Assert.ok(!!cond, msg);
}
function run_test()
{
function run_test() {
runTest();
};
}
if (!this.runTest) {
this.runTest = function()
{
this.runTest = function() {
do_get_profile();
enableTesting();
@ -41,120 +40,100 @@ if (!this.runTest) {
// Since we defined run_test, we must invoke run_next_test() to start the
// async test.
run_next_test();
}
};
}
function returnToEventLoop()
{
function returnToEventLoop() {
return new Promise(function(resolve) {
executeSoon(resolve);
});
}
function enableTesting()
{
function enableTesting() {
Services.prefs.setBoolPref("dom.storage.testing", true);
Services.prefs.setBoolPref("dom.quotaManager.testing", true);
}
function resetTesting()
{
function resetTesting() {
Services.prefs.clearUserPref("dom.quotaManager.testing");
Services.prefs.clearUserPref("dom.storage.testing");
}
function setGlobalLimit(globalLimit)
{
function setGlobalLimit(globalLimit) {
Services.prefs.setIntPref("dom.quotaManager.temporaryStorage.fixedLimit",
globalLimit);
}
function resetGlobalLimit()
{
function resetGlobalLimit() {
Services.prefs.clearUserPref("dom.quotaManager.temporaryStorage.fixedLimit");
}
function setOriginLimit(originLimit)
{
function setOriginLimit(originLimit) {
Services.prefs.setIntPref("dom.storage.default_quota", originLimit);
}
function resetOriginLimit()
{
function resetOriginLimit() {
Services.prefs.clearUserPref("dom.storage.default_quota");
}
function init()
{
function init() {
let request = Services.qms.init();
return request;
}
function initOrigin(principal, persistence)
{
function initOrigin(principal, persistence) {
let request = Services.qms.initStoragesForPrincipal(principal, persistence);
return request;
}
function getOriginUsage(principal)
{
function getOriginUsage(principal) {
let request = Services.qms.getUsageForPrincipal(principal, function() { });
return request;
}
function clear()
{
function clear() {
let request = Services.qms.clear();
return request;
}
function clearOriginsByPattern(pattern)
{
function clearOriginsByPattern(pattern) {
let request = Services.qms.clearStoragesForOriginAttributesPattern(pattern);
return request;
}
function clearOriginsByPrefix(principal, persistence)
{
function clearOriginsByPrefix(principal, persistence) {
let request =
Services.qms.clearStoragesForPrincipal(principal, persistence, null, true);
return request;
}
function clearOrigin(principal, persistence)
{
function clearOrigin(principal, persistence) {
let request = Services.qms.clearStoragesForPrincipal(principal, persistence);
return request;
}
function reset()
{
function reset() {
let request = Services.qms.reset();
return request;
}
function resetOrigin(principal)
{
function resetOrigin(principal) {
let request =
Services.qms.resetStoragesForPrincipal(principal, "default", "ls");
return request;
}
function installPackage(packageName)
{
let directoryService = Cc["@mozilla.org/file/directory_service;1"]
.getService(Ci.nsIProperties);
let currentDir = directoryService.get("CurWorkD", Ci.nsIFile);
function installPackage(packageName) {
let currentDir = Services.dirsvc.get("CurWorkD", Ci.nsIFile);
let packageFile = currentDir.clone();
packageFile.append(packageName + ".zip");
@ -185,7 +164,7 @@ function installPackage(packageName)
.createInstance(Ci.nsIFileOutputStream);
ostream.init(file, -1, parseInt("0644", 8), 0);
let bostream = Cc['@mozilla.org/network/buffered-output-stream;1']
let bostream = Cc["@mozilla.org/network/buffered-output-stream;1"]
.createInstance(Ci.nsIBufferedOutputStream);
bostream.init(ostream, 32768);
@ -199,12 +178,8 @@ function installPackage(packageName)
zipReader.close();
}
function getProfileDir()
{
let directoryService =
Cc["@mozilla.org/file/directory_service;1"].getService(Ci.nsIProperties);
return directoryService.get("ProfD", Ci.nsIFile);
function getProfileDir() {
return Services.dirsvc.get("ProfD", Ci.nsIFile);
}
// Given a "/"-delimited path relative to the profile directory,
@ -212,12 +187,11 @@ function getProfileDir()
// for the existence of the file or parent directories.
// It is safe even on Windows where the directory separator is not "/",
// but make sure you're not passing in a "\"-delimited path.
function getRelativeFile(relativePath)
{
function getRelativeFile(relativePath) {
let profileDir = getProfileDir();
let file = profileDir.clone();
relativePath.split('/').forEach(function(component) {
relativePath.split("/").forEach(function(component) {
file.append(component);
});
@ -241,8 +215,7 @@ function repeatChar(count, ch) {
return result + result.substring(0, count - result.length);
}
function getPrincipal(url, attrs)
{
function getPrincipal(url, attrs) {
let uri = Services.io.newURI(url);
if (!attrs) {
attrs = {};
@ -250,13 +223,11 @@ function getPrincipal(url, attrs)
return Services.scriptSecurityManager.createCodebasePrincipal(uri, attrs);
}
function getCurrentPrincipal()
{
function getCurrentPrincipal() {
return Cc["@mozilla.org/systemprincipal;1"].createInstance(Ci.nsIPrincipal);
}
function getLocalStorage(principal)
{
function getLocalStorage(principal) {
if (!principal) {
principal = getCurrentPrincipal();
}
@ -266,18 +237,17 @@ function getLocalStorage(principal)
function requestFinished(request) {
return new Promise(function(resolve, reject) {
request.callback = function(request) {
if (request.resultCode == Cr.NS_OK) {
resolve(request.result);
request.callback = function(requestInner) {
if (requestInner.resultCode == Cr.NS_OK) {
resolve(requestInner.result);
} else {
reject(request.resultCode);
reject(requestInner.resultCode);
}
}
};
});
}
function loadSubscript(path)
{
function loadSubscript(path) {
let file = do_get_file(path, false);
let uri = Services.io.newFileURI(file);
Services.scriptloader.loadSubScript(uri.spec);

View File

@ -3,23 +3,21 @@
* http://creativecommons.org/publicdomain/zero/1.0/
*/
async function testSteps()
{
async function testSteps() {
const lsArchiveFile = "storage/ls-archive.sqlite";
const principalInfo = {
url: "http://example.com",
attrs: {}
attrs: {},
};
function checkStorage()
{
function checkStorage() {
let principal = getPrincipal(principalInfo.url, principalInfo.attrs);
let storage = getLocalStorage(principal);
try {
storage.open();
ok(true, "Did not throw");
} catch(ex) {
} catch (ex) {
ok(false, "Should not have thrown");
}
}

View File

@ -3,8 +3,7 @@
* http://creativecommons.org/publicdomain/zero/1.0/
*/
async function testSteps()
{
async function testSteps() {
const principal = getPrincipal("http://example.org");
info("Setting pref");

View File

@ -3,10 +3,10 @@
* http://creativecommons.org/publicdomain/zero/1.0/
*/
/* import-globals-from databaseShadowing-shared.js */
loadSubscript("databaseShadowing-shared.js");
async function testSteps()
{
async function testSteps() {
enableNextGenLocalStorage();
storeData();

View File

@ -3,10 +3,10 @@
* http://creativecommons.org/publicdomain/zero/1.0/
*/
/* import-globals-from databaseShadowing-shared.js */
loadSubscript("databaseShadowing-shared.js");
async function testSteps()
{
async function testSteps() {
// The shadow database was prepared in test_databaseShadowing1.js
disableNextGenLocalStorage();

View File

@ -3,10 +3,10 @@
* http://creativecommons.org/publicdomain/zero/1.0/
*/
/* import-globals-from databaseShadowing-shared.js */
loadSubscript("databaseShadowing-shared.js");
async function testSteps()
{
async function testSteps() {
enableNextGenLocalStorage();
storeData();

View File

@ -3,10 +3,10 @@
* http://creativecommons.org/publicdomain/zero/1.0/
*/
/* import-globals-from databaseShadowing-shared.js */
loadSubscript("databaseShadowing-shared.js");
async function testSteps()
{
async function testSteps() {
// The shadow database was prepared in test_databaseShadowing_clearOrigin1.js
disableNextGenLocalStorage();

View File

@ -3,10 +3,10 @@
* http://creativecommons.org/publicdomain/zero/1.0/
*/
/* import-globals-from databaseShadowing-shared.js */
loadSubscript("databaseShadowing-shared.js");
async function testSteps()
{
async function testSteps() {
enableNextGenLocalStorage();
storeData();
@ -16,7 +16,7 @@ async function testSteps()
let request = clearOriginsByPattern(JSON.stringify({ userContextId: 15 }));
await requestFinished(request);
verifyData([4,5,6]);
verifyData([4, 5, 6]);
// Wait for all database connections to close.
request = reset();

View File

@ -3,10 +3,10 @@
* http://creativecommons.org/publicdomain/zero/1.0/
*/
/* import-globals-from databaseShadowing-shared.js */
loadSubscript("databaseShadowing-shared.js");
async function testSteps()
{
async function testSteps() {
// The shadow database was prepared in
// test_databaseShadowing_clearOriginsByPattern1.js
@ -16,5 +16,5 @@ async function testSteps()
return;
}
verifyData([4,5,6]);
verifyData([4, 5, 6]);
}

View File

@ -3,10 +3,10 @@
* http://creativecommons.org/publicdomain/zero/1.0/
*/
/* import-globals-from databaseShadowing-shared.js */
loadSubscript("databaseShadowing-shared.js");
async function testSteps()
{
async function testSteps() {
enableNextGenLocalStorage();
storeData();

View File

@ -3,10 +3,10 @@
* http://creativecommons.org/publicdomain/zero/1.0/
*/
/* import-globals-from databaseShadowing-shared.js */
loadSubscript("databaseShadowing-shared.js");
async function testSteps()
{
async function testSteps() {
// The shadow database was prepared in
// test_databaseShadowing_clearOriginsByPrefix1.js
@ -16,5 +16,5 @@ async function testSteps()
return;
}
verifyData([2,3]);
verifyData([2, 3]);
}

View File

@ -3,8 +3,7 @@
* http://creativecommons.org/publicdomain/zero/1.0/
*/
async function testSteps()
{
async function testSteps() {
const globalLimitKB = 5 * 1024;
const data = {};
@ -49,7 +48,7 @@ async function testSteps()
try {
storages[i].setItem("B", "");
ok(false, "Should have thrown");
} catch(ex) {
} catch (ex) {
ok(true, "Did throw");
ok(ex instanceof DOMException, "Threw DOMException");
is(ex.name, "QuotaExceededError", "Threw right DOMException");

View File

@ -3,8 +3,7 @@
* http://creativecommons.org/publicdomain/zero/1.0/
*/
async function testSteps()
{
async function testSteps() {
const groupLimitKB = 10 * 1024;
const globalLimitKB = groupLimitKB * 5;
@ -15,7 +14,7 @@ async function testSteps()
"http://example.com",
"http://test1.example.com",
"https://test2.example.com",
"http://test3.example.com:8080"
"http://test3.example.com:8080",
];
const data = {};
@ -57,7 +56,7 @@ async function testSteps()
try {
storages[i].setItem("B", "");
ok(false, "Should have thrown");
} catch(ex) {
} catch (ex) {
ok(true, "Did throw");
ok(ex instanceof DOMException, "Threw DOMException");
is(ex.name, "QuotaExceededError", "Threw right DOMException");

View File

@ -3,8 +3,7 @@
* http://creativecommons.org/publicdomain/zero/1.0/
*/
async function testSteps()
{
async function testSteps() {
const principalInfos = [
{ url: "http://localhost", attrs: {} },
{ url: "http://www.mozilla.org", attrs: {} },
@ -23,7 +22,7 @@ async function testSteps()
const data = {
key: "foo",
value: "bar"
value: "bar",
};
function verifyData(clearedOrigins) {
@ -116,7 +115,7 @@ async function testSteps()
}
default: {
throw("Unknown type: " + type);
throw ("Unknown type: " + type);
}
}

View File

@ -3,9 +3,8 @@
* http://creativecommons.org/publicdomain/zero/1.0/
*/
async function testSteps()
{
const principal = getPrincipal("http://example.com")
async function testSteps() {
const principal = getPrincipal("http://example.com");
const dataFile =
getRelativeFile("storage/default/http+++example.com/ls/data.sqlite");
@ -93,7 +92,7 @@ async function testSteps()
}
let usage = await readUsageFromUsageFile();
ok (usage == data.usage, "Correct usage");
ok(usage == data.usage, "Correct usage");
}
async function clearTestOrigin() {

View File

@ -3,8 +3,7 @@
* http://creativecommons.org/publicdomain/zero/1.0/
*/
async function testSteps()
{
async function testSteps() {
const url = "http://example.com";
const items = [
@ -17,11 +16,10 @@ async function testSteps()
{ key: "key7", value: "value7" },
{ key: "key8", value: "value8" },
{ key: "key9", value: "value9" },
{ key: "key10", value: "value10" }
{ key: "key10", value: "value10" },
];
function getPartialPrefill()
{
function getPartialPrefill() {
let size = 0;
for (let i = 0; i < items.length / 2; i++) {
let item = items[i];

View File

@ -637,6 +637,10 @@ static nsIFrame* UpdateRootFrameForTouchTargetDocument(nsIFrame* aRootFrame) {
return aRootFrame;
}
namespace {
using FrameForPointOption = nsLayoutUtils::FrameForPointOption;
// Determine the scrollable target frame for the given point and add it to
// the target list. If the frame doesn't have a displayport, set one.
// Return whether or not a displayport was set.
@ -648,15 +652,16 @@ static bool PrepareForSetTargetAPZCNotification(
ScrollableLayerGuid::NULL_SCROLL_ID);
nsPoint point = nsLayoutUtils::GetEventCoordinatesRelativeTo(
aWidget, aRefPoint, aRootFrame);
uint32_t flags = 0;
EnumSet<FrameForPointOption> options;
if (gfxPrefs::APZAllowZooming()) {
// If zooming is enabled, we need IGNORE_ROOT_SCROLL_FRAME for correct
// If zooming is enabled, we need IgnoreRootScrollFrame for correct
// hit testing. Otherwise, don't use it because it interferes with
// hit testing for some purposes such as scrollbar dragging (this will
// need to be fixed before enabling zooming by default on desktop).
flags = nsLayoutUtils::IGNORE_ROOT_SCROLL_FRAME;
options += FrameForPointOption::IgnoreRootScrollFrame;
}
nsIFrame* target = nsLayoutUtils::GetFrameForPoint(aRootFrame, point, flags);
nsIFrame* target =
nsLayoutUtils::GetFrameForPoint(aRootFrame, point, options);
nsIScrollableFrame* scrollAncestor =
target ? nsLayoutUtils::GetAsyncScrollableAncestorFrame(target)
: aRootFrame->PresShell()->GetRootScrollFrameAsScrollable();
@ -737,6 +742,8 @@ static void SendLayersDependentApzcTargetConfirmation(
shadow->SendSetConfirmedTargetAPZC(aInputBlockId, aTargets);
}
} // namespace
DisplayportSetListener::DisplayportSetListener(
nsIWidget* aWidget, nsIPresShell* aPresShell, const uint64_t& aInputBlockId,
const nsTArray<ScrollableLayerGuid>& aTargets)

View File

@ -23,6 +23,10 @@
namespace mozilla {
namespace layers {
namespace {
using FrameForPointOption = nsLayoutUtils::FrameForPointOption;
// Returns the DOM element found at |aPoint|, interpreted as being relative to
// the root frame of |aShell|. If the point is inside a subdocument, returns
// an element inside the subdocument, rather than the subdocument element
@ -33,24 +37,30 @@ namespace layers {
// presence of subdocuments.
static already_AddRefed<dom::Element> ElementFromPoint(
const nsCOMPtr<nsIPresShell>& aShell, const CSSPoint& aPoint) {
if (nsIFrame* rootFrame = aShell->GetRootFrame()) {
if (nsIFrame* frame = nsLayoutUtils::GetFrameForPoint(
rootFrame, CSSPoint::ToAppUnits(aPoint),
nsLayoutUtils::IGNORE_PAINT_SUPPRESSION |
nsLayoutUtils::IGNORE_ROOT_SCROLL_FRAME)) {
while (frame && (!frame->GetContent() ||
frame->GetContent()->IsInAnonymousSubtree())) {
frame = nsLayoutUtils::GetParentOrPlaceholderFor(frame);
}
nsIContent* content = frame->GetContent();
if (content && !content->IsElement()) {
content = content->GetParent();
}
if (content) {
nsCOMPtr<dom::Element> result = content->AsElement();
return result.forget();
}
}
nsIFrame* rootFrame = aShell->GetRootFrame();
if (!rootFrame) {
return nullptr;
}
nsIFrame* frame = nsLayoutUtils::GetFrameForPoint(
rootFrame, CSSPoint::ToAppUnits(aPoint),
{FrameForPointOption::IgnorePaintSuppression,
FrameForPointOption::IgnoreRootScrollFrame});
while (frame && (!frame->GetContent() ||
frame->GetContent()->IsInAnonymousSubtree())) {
frame = nsLayoutUtils::GetParentOrPlaceholderFor(frame);
}
if (!frame) {
return nullptr;
}
// FIXME(emilio): This should probably use the flattened tree, GetParent() is
// not guaranteed to be an element in presence of shadow DOM.
nsIContent* content = frame->GetContent();
if (content && !content->IsElement()) {
content = content->GetParent();
}
if (content && content->IsElement()) {
nsCOMPtr<dom::Element> result = content->AsElement();
return result.forget();
}
return nullptr;
}
@ -84,6 +94,8 @@ static bool IsRectZoomedIn(const CSSRect& aRect,
return showing > 0.9 && (ratioW > 0.9 || ratioH > 0.9);
}
} // namespace
CSSRect CalculateRectToZoomTo(const nsCOMPtr<nsIDocument>& aRootContentDocument,
const CSSPoint& aPoint) {
// Ensure the layout information we get is up-to-date.

View File

@ -57,7 +57,8 @@ TouchBehaviorFlags TouchActionHelper::GetAllowedTouchBehavior(
nsLayoutUtils::GetEventCoordinatesRelativeTo(aWidget, aPoint, aRootFrame);
nsIFrame* target = nsLayoutUtils::GetFrameForPoint(
aRootFrame, relativePoint, nsLayoutUtils::IGNORE_ROOT_SCROLL_FRAME);
aRootFrame, relativePoint,
nsLayoutUtils::FrameForPointOption::IgnoreRootScrollFrame);
if (!target) {
return behavior;
}

View File

@ -71,7 +71,11 @@ interface nsIXPConnectWrappedJS : nsIXPConnectJSObjectHolder
readonly attribute InterfaceInfoPtr InterfaceInfo;
readonly attribute nsIIDPtr InterfaceIID;
// Match the GetJSObject() signature.
// Returns the global object for our JS object. If this object is a
// cross-compartment wrapper, returns the compartment's first global.
// The global we return is guaranteed to be same-compartment with the
// object.
// Note: this matches the GetJSObject() signature.
[notxpcom, nostdcall] JSObjectPtr GetJSObjectGlobal();
void debugDump(in short depth);

View File

@ -515,6 +515,13 @@ class SandboxProxyHandler : public js::Wrapper {
JS::AutoIdVector& props) const override;
virtual JSObject* enumerate(JSContext* cx,
JS::Handle<JSObject*> proxy) const override;
private:
// Implements the custom getPropertyDescriptor behavior. If the getOwn
// argument is true we only look for "own" properties.
bool getPropertyDescriptorImpl(
JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
bool getOwn, JS::MutableHandle<JS::PropertyDescriptor> desc) const;
};
static const SandboxProxyHandler sandboxProxyHandler;
@ -668,14 +675,21 @@ static bool IsMaybeWrappedDOMConstructor(JSObject* obj) {
return dom::IsDOMConstructor(obj);
}
bool SandboxProxyHandler::getPropertyDescriptor(
bool SandboxProxyHandler::getPropertyDescriptorImpl(
JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
JS::MutableHandle<PropertyDescriptor> desc) const {
bool getOwn, JS::MutableHandle<PropertyDescriptor> desc) const {
JS::RootedObject obj(cx, wrappedObject(proxy));
MOZ_ASSERT(js::GetObjectCompartment(obj) == js::GetObjectCompartment(proxy));
if (!JS_GetPropertyDescriptorById(cx, obj, id, desc)) {
return false;
if (getOwn) {
if (!JS_GetOwnPropertyDescriptorById(cx, obj, id, desc)) {
return false;
}
} else {
if (!JS_GetPropertyDescriptorById(cx, obj, id, desc)) {
return false;
}
}
if (!desc.object()) {
@ -707,18 +721,16 @@ bool SandboxProxyHandler::getPropertyDescriptor(
return true;
}
bool SandboxProxyHandler::getPropertyDescriptor(
JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
JS::MutableHandle<PropertyDescriptor> desc) const {
return getPropertyDescriptorImpl(cx, proxy, id, /* getOwn = */ false, desc);
}
bool SandboxProxyHandler::getOwnPropertyDescriptor(
JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
JS::MutableHandle<PropertyDescriptor> desc) const {
if (!getPropertyDescriptor(cx, proxy, id, desc)) {
return false;
}
if (desc.object() != wrappedObject(proxy)) {
desc.object().set(nullptr);
}
return true;
return getPropertyDescriptorImpl(cx, proxy, id, /* getOwn = */ true, desc);
}
/*

View File

@ -68,10 +68,6 @@ bool nsXPCWrappedJS::CanSkip() {
if (obj && JS::ObjectIsMarkedGray(obj)) {
return false;
}
JSObject* global = GetJSObjectGlobalPreserveColor();
if (global && JS::ObjectIsMarkedGray(global)) {
return false;
}
// For non-root wrappers, check if the root wrapper will be
// added to the CC graph.
@ -133,8 +129,6 @@ NS_CYCLE_COLLECTION_CLASSNAME(nsXPCWrappedJS)::TraverseNative(
MOZ_ASSERT(refcnt > 1);
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mJSObj");
cb.NoteJSChild(JS::GCCellPtr(tmp->GetJSObjectPreserveColor()));
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mJSObjGlobal");
cb.NoteJSChild(JS::GCCellPtr(tmp->GetJSObjectGlobalPreserveColor()));
}
if (tmp->IsRootWrapper()) {
@ -307,7 +301,6 @@ nsXPCWrappedJS::DeleteCycleCollectable(void) { delete this; }
void nsXPCWrappedJS::TraceJS(JSTracer* trc) {
MOZ_ASSERT(mRefCnt >= 2 && IsValid(), "must be strongly referenced");
JS::TraceEdge(trc, &mJSObj, "nsXPCWrappedJS::mJSObj");
JS::TraceEdge(trc, &mJSObjGlobal, "nsXPCWrappedJS::mJSObjGlobal");
}
NS_IMETHODIMP
@ -321,7 +314,14 @@ nsXPCWrappedJS::GetWeakReference(nsIWeakReference** aInstancePtr) {
JSObject* nsXPCWrappedJS::GetJSObject() { return mJSObj; }
JSObject* nsXPCWrappedJS::GetJSObjectGlobal() { return mJSObjGlobal; }
JSObject* nsXPCWrappedJS::GetJSObjectGlobal() {
JSObject* obj = mJSObj;
if (js::IsCrossCompartmentWrapper(obj)) {
JS::Compartment* comp = js::GetObjectCompartment(obj);
return js::GetFirstGlobalInCompartment(comp);
}
return JS::GetNonCCWObjectGlobal(obj);
}
// static
nsresult nsXPCWrappedJS::GetNewOrUsed(JSContext* cx, JS::HandleObject jsObj,
@ -376,18 +376,14 @@ nsresult nsXPCWrappedJS::GetNewOrUsed(JSContext* cx, JS::HandleObject jsObj,
return NS_ERROR_FAILURE;
}
// Note: rootJSObj is never a CCW because GetRootJSObject unwraps. We
// also rely on this in nsXPCWrappedJS::UpdateObjectPointerAfterGC.
RootedObject global(cx, JS::GetNonCCWObjectGlobal(rootJSObj));
root = new nsXPCWrappedJS(cx, rootJSObj, global, rootClasp, nullptr, &rv);
root = new nsXPCWrappedJS(cx, rootJSObj, rootClasp, nullptr, &rv);
if (NS_FAILED(rv)) {
return rv;
}
}
RootedObject global(cx, JS::CurrentGlobalOrNull(cx));
RefPtr<nsXPCWrappedJS> wrapper =
new nsXPCWrappedJS(cx, jsObj, global, clasp, root, &rv);
new nsXPCWrappedJS(cx, jsObj, clasp, root, &rv);
if (NS_FAILED(rv)) {
return rv;
}
@ -396,18 +392,12 @@ nsresult nsXPCWrappedJS::GetNewOrUsed(JSContext* cx, JS::HandleObject jsObj,
}
nsXPCWrappedJS::nsXPCWrappedJS(JSContext* cx, JSObject* aJSObj,
JSObject* aJSObjGlobal,
nsXPCWrappedJSClass* aClass,
nsXPCWrappedJS* root, nsresult* rv)
: mJSObj(aJSObj),
mJSObjGlobal(aJSObjGlobal),
mClass(aClass),
mRoot(root ? root : this),
mNext(nullptr) {
MOZ_ASSERT(JS_IsGlobalObject(aJSObjGlobal));
MOZ_RELEASE_ASSERT(js::GetObjectCompartment(aJSObj) ==
js::GetObjectCompartment(aJSObjGlobal));
*rv = InitStub(GetClass()->GetIID());
// Continue even in the failure case, so that our refcounting/Destroy
// behavior works correctly.
@ -518,7 +508,6 @@ void nsXPCWrappedJS::Unlink() {
}
mJSObj = nullptr;
mJSObjGlobal = nullptr;
}
if (IsRootWrapper()) {
@ -647,7 +636,6 @@ void nsXPCWrappedJS::SystemIsBeingShutDown() {
// if we are not currently running an incremental GC.
MOZ_ASSERT(!IsIncrementalGCInProgress(xpc_GetSafeJSContext()));
*mJSObj.unsafeGet() = nullptr;
*mJSObjGlobal.unsafeGet() = nullptr;
// Notify other wrappers in the chain.
if (mNext) {

View File

@ -1751,10 +1751,6 @@ class nsXPCWrappedJS final : protected nsAutoXPTCStub,
*/
JSObject* GetJSObjectPreserveColor() const { return mJSObj.unbarrieredGet(); }
JSObject* GetJSObjectGlobalPreserveColor() const {
return mJSObjGlobal.unbarrieredGet();
}
// Returns true if the wrapper chain contains references to multiple
// compartments. If the wrapper chain contains references to multiple
// compartments, then it must be registered on the XPCJSContext. Otherwise,
@ -1790,11 +1786,6 @@ class nsXPCWrappedJS final : protected nsAutoXPTCStub,
void UpdateObjectPointerAfterGC() {
MOZ_ASSERT(IsRootWrapper());
JS_UpdateWeakPointerAfterGC(&mJSObj);
JS_UpdateWeakPointerAfterGC(&mJSObjGlobal);
// Note: this is a root wrapper, so mJSObj is never a CCW. Therefore,
// if mJSObj is still alive, mJSObjGlobal must also still be alive,
// because marking a JSObject will also mark its global.
MOZ_ASSERT_IF(mJSObj, mJSObjGlobal);
}
bool IsAggregatedToNative() const { return mRoot->mOuter != nullptr; }
@ -1817,9 +1808,8 @@ class nsXPCWrappedJS final : protected nsAutoXPTCStub,
protected:
nsXPCWrappedJS() = delete;
nsXPCWrappedJS(JSContext* cx, JSObject* aJSObj, JSObject* aJSObjGlobal,
nsXPCWrappedJSClass* aClass, nsXPCWrappedJS* root,
nsresult* rv);
nsXPCWrappedJS(JSContext* cx, JSObject* aJSObj, nsXPCWrappedJSClass* aClass,
nsXPCWrappedJS* root, nsresult* rv);
bool CanSkip();
void Destroy();
@ -1831,13 +1821,6 @@ class nsXPCWrappedJS final : protected nsAutoXPTCStub,
}
JS::Heap<JSObject*> mJSObj;
// A global object that must be same-compartment with mJSObj. This is the
// global/realm we enter when making calls into JS. Note that we cannot
// simply use mJSObj's global here because mJSObj might be a
// cross-compartment wrapper and CCWs are not associated with a single
// global. After removing in-content XBL, we no longer need this field
// because we can then assert against CCWs. See bug 1480121.
JS::Heap<JSObject*> mJSObjGlobal;
RefPtr<nsXPCWrappedJSClass> mClass;
nsXPCWrappedJS* mRoot; // If mRoot != this, it is an owning pointer.
nsXPCWrappedJS* mNext;

View File

@ -496,16 +496,20 @@ nsresult AccessibleCaretManager::SelectWordOrShortcut(const nsPoint& aPoint) {
}
// Find the frame under point.
uint32_t flags =
nsLayoutUtils::IGNORE_PAINT_SUPPRESSION | nsLayoutUtils::IGNORE_CROSS_DOC;
EnumSet<nsLayoutUtils::FrameForPointOption> options = {
nsLayoutUtils::FrameForPointOption::IgnorePaintSuppression,
nsLayoutUtils::FrameForPointOption::IgnoreCrossDoc};
#ifdef MOZ_WIDGET_ANDROID
// On Android, we need IGNORE_ROOT_SCROLL_FRAME for correct hit testing
// when zoomed in or out.
flags = nsLayoutUtils::IGNORE_ROOT_SCROLL_FRAME;
// On Android, we need IgnoreRootScrollFrame for correct hit testing when
// zoomed in or out.
//
// FIXME(emilio): But do we really want to override the other two flags?
options = nsLayoutUtils::FrameForPointOption::IgnoreRootScrollFrame;
#endif
AutoWeakFrame ptFrame =
nsLayoutUtils::GetFrameForPoint(rootFrame, aPoint, flags);
if (!ptFrame.IsAlive()) {
nsLayoutUtils::GetFrameForPoint(rootFrame, aPoint, options);
if (!ptFrame.GetFrame()) {
return NS_ERROR_FAILURE;
}
@ -1086,10 +1090,10 @@ nsresult AccessibleCaretManager::DragCaretInternal(const nsPoint& aPoint) {
nsPoint(aPoint.x, aPoint.y + mOffsetYToCaretLogicalPosition));
// Find out which content we point to
nsIFrame* ptFrame =
nsLayoutUtils::GetFrameForPoint(rootFrame, point,
nsLayoutUtils::IGNORE_PAINT_SUPPRESSION |
nsLayoutUtils::IGNORE_CROSS_DOC);
nsIFrame* ptFrame = nsLayoutUtils::GetFrameForPoint(
rootFrame, point,
{nsLayoutUtils::FrameForPointOption::IgnorePaintSuppression,
nsLayoutUtils::FrameForPointOption::IgnoreCrossDoc});
if (!ptFrame) {
return NS_ERROR_FAILURE;
}

View File

@ -539,11 +539,13 @@ static bool IsElementClickableAndReadable(nsIFrame* aFrame,
nsIFrame* FindFrameTargetedByInputEvent(
WidgetGUIEvent* aEvent, nsIFrame* aRootFrame,
const nsPoint& aPointRelativeToRootFrame, uint32_t aFlags) {
uint32_t flags = (aFlags & INPUT_IGNORE_ROOT_SCROLL_FRAME)
? nsLayoutUtils::IGNORE_ROOT_SCROLL_FRAME
: 0;
using FrameForPointOption = nsLayoutUtils::FrameForPointOption;
EnumSet<FrameForPointOption> options;
if (aFlags & INPUT_IGNORE_ROOT_SCROLL_FRAME) {
options += FrameForPointOption::IgnoreRootScrollFrame;
}
nsIFrame* target = nsLayoutUtils::GetFrameForPoint(
aRootFrame, aPointRelativeToRootFrame, flags);
aRootFrame, aPointRelativeToRootFrame, options);
PET_LOG(
"Found initial target %p for event class %s point %s relative to root "
"frame %p\n",
@ -598,7 +600,7 @@ nsIFrame* FindFrameTargetedByInputEvent(
mozilla::layers::Stringify(targetRect).c_str());
AutoTArray<nsIFrame*, 8> candidates;
nsresult rv = nsLayoutUtils::GetFramesForArea(aRootFrame, targetRect,
candidates, flags);
candidates, options);
if (NS_FAILED(rv)) {
return target;
}

View File

@ -2961,20 +2961,20 @@ struct AutoNestedPaintCount {
#endif
nsIFrame* nsLayoutUtils::GetFrameForPoint(nsIFrame* aFrame, nsPoint aPt,
uint32_t aFlags) {
nsIFrame* nsLayoutUtils::GetFrameForPoint(
nsIFrame* aFrame, nsPoint aPt, EnumSet<FrameForPointOption> aOptions) {
AUTO_PROFILER_LABEL("nsLayoutUtils::GetFrameForPoint", LAYOUT);
nsresult rv;
AutoTArray<nsIFrame*, 8> outFrames;
rv = GetFramesForArea(aFrame, nsRect(aPt, nsSize(1, 1)), outFrames, aFlags);
rv = GetFramesForArea(aFrame, nsRect(aPt, nsSize(1, 1)), outFrames, aOptions);
NS_ENSURE_SUCCESS(rv, nullptr);
return outFrames.Length() ? outFrames.ElementAt(0) : nullptr;
}
nsresult nsLayoutUtils::GetFramesForArea(nsIFrame* aFrame, const nsRect& aRect,
nsTArray<nsIFrame*>& aOutFrames,
uint32_t aFlags) {
nsresult nsLayoutUtils::GetFramesForArea(
nsIFrame* aFrame, const nsRect& aRect, nsTArray<nsIFrame*>& aOutFrames,
EnumSet<FrameForPointOption> aOptions) {
AUTO_PROFILER_LABEL("nsLayoutUtils::GetFramesForArea", LAYOUT);
nsDisplayListBuilder builder(aFrame, nsDisplayListBuilderMode::EVENT_DELIVERY,
@ -2982,21 +2982,21 @@ nsresult nsLayoutUtils::GetFramesForArea(nsIFrame* aFrame, const nsRect& aRect,
builder.BeginFrame();
nsDisplayList list;
if (aFlags & IGNORE_PAINT_SUPPRESSION) {
if (aOptions.contains(FrameForPointOption::IgnorePaintSuppression)) {
builder.IgnorePaintSuppression();
}
if (aFlags & IGNORE_ROOT_SCROLL_FRAME) {
if (aOptions.contains(FrameForPointOption::IgnoreRootScrollFrame)) {
nsIFrame* rootScrollFrame = aFrame->PresShell()->GetRootScrollFrame();
if (rootScrollFrame) {
builder.SetIgnoreScrollFrame(rootScrollFrame);
}
}
if (aFlags & IGNORE_CROSS_DOC) {
if (aOptions.contains(FrameForPointOption::IgnoreCrossDoc)) {
builder.SetDescendIntoSubdocuments(false);
}
builder.SetHitTestIsForVisibility(aFlags & ONLY_VISIBLE);
builder.SetHitTestIsForVisibility(
aOptions.contains(FrameForPointOption::OnlyVisible));
builder.EnterPresShell(aFrame);

View File

@ -801,25 +801,25 @@ class nsLayoutUtils {
static mozilla::LayoutDeviceIntPoint WidgetToWidgetOffset(
nsIWidget* aFromWidget, nsIWidget* aToWidget);
enum FrameForPointFlags {
enum class FrameForPointOption {
/**
* When set, paint suppression is ignored, so we'll return non-root page
* elements even if paint suppression is stopping them from painting.
*/
IGNORE_PAINT_SUPPRESSION = 0x01,
IgnorePaintSuppression = 1,
/**
* When set, clipping due to the root scroll frame (and any other viewport-
* related clipping) is ignored.
*/
IGNORE_ROOT_SCROLL_FRAME = 0x02,
IgnoreRootScrollFrame,
/**
* When set, return only content in the same document as aFrame.
*/
IGNORE_CROSS_DOC = 0x04,
IgnoreCrossDoc,
/**
* When set, return only content that is actually visible.
*/
ONLY_VISIBLE = 0x08
OnlyVisible,
};
/**
@ -827,10 +827,10 @@ class nsLayoutUtils {
* frame under the point aPt that receives a mouse event at that location,
* or nullptr if there is no such frame.
* @param aPt the point, relative to the frame origin
* @param aFlags some combination of FrameForPointFlags
* @param aFlags some combination of FrameForPointOption.
*/
static nsIFrame* GetFrameForPoint(nsIFrame* aFrame, nsPoint aPt,
uint32_t aFlags = 0);
mozilla::EnumSet<FrameForPointOption> = {});
/**
* Given aFrame, the root frame of a stacking context, find all descendant
@ -838,11 +838,11 @@ class nsLayoutUtils {
* or nullptr if there is no such frame.
* @param aRect the rect, relative to the frame origin
* @param aOutFrames an array to add all the frames found
* @param aFlags some combination of FrameForPointFlags
* @param aFlags some combination of FrameForPointOption.
*/
static nsresult GetFramesForArea(nsIFrame* aFrame, const nsRect& aRect,
nsTArray<nsIFrame*>& aOutFrames,
uint32_t aFlags = 0);
mozilla::EnumSet<FrameForPointOption> = {});
/**
* Transform aRect relative to aFrame up to the coordinate system of

View File

@ -214,8 +214,6 @@ public class BrowserApp extends GeckoApp
private static final String BROWSER_SEARCH_TAG = "browser_search";
private static final int MAX_BUNDLE_SIZE = 300000; // 300 kilobytes
// Request ID for startActivityForResult.
public static final int ACTIVITY_REQUEST_PREFERENCES = 1001;
private static final int ACTIVITY_REQUEST_TAB_QUEUE = 2001;
@ -2299,7 +2297,7 @@ public class BrowserApp extends GeckoApp
// This in some cases can lead to TransactionTooLargeException as per
// [https://developer.android.com/reference/android/os/TransactionTooLargeException] it's
// specified that the limit is fixed to 1MB per process.
if (getBundleSizeInBytes(outState) > MAX_BUNDLE_SIZE) {
if (getBundleSizeInBytes(outState) > MAX_BUNDLE_SIZE_BYTES) {
outState.remove("android:viewHierarchyState");
}
}

View File

@ -109,6 +109,7 @@ import static org.mozilla.gecko.Tabs.INTENT_EXTRA_TAB_ID;
import static org.mozilla.gecko.Tabs.INVALID_TAB_ID;
import static org.mozilla.gecko.mma.MmaDelegate.DOWNLOAD_MEDIA_SAVED_IMAGE;
import static org.mozilla.gecko.mma.MmaDelegate.READER_AVAILABLE;
import static org.mozilla.gecko.util.JavaUtil.getBundleSizeInBytes;
public abstract class GeckoApp extends GeckoActivity
implements AnchoredPopup.OnVisibilityChangeListener,
@ -156,6 +157,11 @@ public abstract class GeckoApp extends GeckoActivity
public static final String SAVED_STATE_IN_BACKGROUND = "inBackground";
public static final String SAVED_STATE_PRIVATE_SESSION = "privateSession";
/**
* Speculative value for the maximum size the Activity Bundle can have in the hope to avoid
* TransactionTooLarge exceptions.
*/
protected static final int MAX_BUNDLE_SIZE_BYTES = 300_000;
// Delay before running one-time "cleanup" tasks that may be needed
// after a version upgrade.
@ -635,6 +641,11 @@ public abstract class GeckoApp extends GeckoActivity
} catch (final InterruptedException e) { }
}
outState.putString(SAVED_STATE_PRIVATE_SESSION, mPrivateBrowsingSession);
// Make sure we are not bloating the Bundle which can result in TransactionTooLargeException
if (getBundleSizeInBytes(outState) > MAX_BUNDLE_SIZE_BYTES) {
outState.remove(SAVED_STATE_PRIVATE_SESSION);
}
}
outState.putBoolean(SAVED_STATE_IN_BACKGROUND, isApplicationInBackground());

View File

@ -3359,6 +3359,7 @@ public abstract class TreeBuilder<T> implements TokenHandler,
}
}
eltPos = currentPtr;
int origPos = currentPtr;
for (;;) {
if (eltPos == 0) {
assert fragment: "We can get this close to the root of the stack in foreign content only in the fragment case.";
@ -3366,7 +3367,7 @@ public abstract class TreeBuilder<T> implements TokenHandler,
}
if (stack[eltPos].name == name) {
while (currentPtr >= eltPos) {
pop();
popForeign(origPos);
}
break endtagloop;
}
@ -5225,6 +5226,17 @@ public abstract class TreeBuilder<T> implements TokenHandler,
node.release(this);
}
private void popForeign(int origPos) throws SAXException {
StackNode<T> node = stack[currentPtr];
if (origPos != currentPtr) {
markMalformedIfScript(node.node);
}
assert debugOnlyClearLastStackSlot();
currentPtr--;
elementPopped(node.ns, node.popName, node.node);
node.release(this);
}
private void silentPop() throws SAXException {
StackNode<T> node = stack[currentPtr];
assert debugOnlyClearLastStackSlot();

View File

@ -2349,6 +2349,7 @@ void nsHtml5TreeBuilder::endTag(nsHtml5ElementName* elementName) {
}
}
eltPos = currentPtr;
int32_t origPos = currentPtr;
for (;;) {
if (!eltPos) {
MOZ_ASSERT(fragment,
@ -2358,7 +2359,7 @@ void nsHtml5TreeBuilder::endTag(nsHtml5ElementName* elementName) {
}
if (stack[eltPos]->name == name) {
while (currentPtr >= eltPos) {
pop();
popForeign(origPos);
}
NS_HTML5_BREAK(endtagloop);
}
@ -4086,6 +4087,17 @@ void nsHtml5TreeBuilder::pop() {
node->release(this);
}
void nsHtml5TreeBuilder::popForeign(int32_t origPos) {
nsHtml5StackNode* node = stack[currentPtr];
if (origPos != currentPtr) {
markMalformedIfScript(node->node);
}
MOZ_ASSERT(debugOnlyClearLastStackSlot());
currentPtr--;
elementPopped(node->ns, node->popName, node->node);
node->release(this);
}
void nsHtml5TreeBuilder::silentPop() {
nsHtml5StackNode* node = stack[currentPtr];
MOZ_ASSERT(debugOnlyClearLastStackSlot());

View File

@ -456,6 +456,7 @@ class nsHtml5TreeBuilder : public nsAHtml5TreeBuilderState {
bool isInStack(nsHtml5StackNode* node);
void popTemplateMode();
void pop();
void popForeign(int32_t origPos);
void silentPop();
void popOnEof();
void appendHtmlElementToDocumentAndPush(nsHtml5HtmlAttributes* attributes);

View File

@ -434,6 +434,7 @@ sandbox.create = function(win, principal = null, opts = {}) {
sandboxPrototype: win,
wantComponents: true,
wantXrays: true,
wantGlobalProperties: ["ChromeUtils"],
}, opts);
return new Cu.Sandbox(p, opts);
};

View File

@ -0,0 +1,30 @@
<!doctype html>
<meta charset=utf-8>
<title></title>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<script>
var scriptWithEndTagRan = false;
var scriptWithoutEndTagRan = false;
var scriptWithBogusEndTagInsideRan = false;
</script>
<svg>
<script>scriptWithEndTagRan = true;</script>
</svg>
<svg>
<script>scriptWithoutEndTagRan = true;
</svg>
<svg>
<script>scriptWithBogusEndTagInsideRan = true;</g></script>
</svg>
<script>
test(function() {
assert_true(scriptWithEndTagRan);
}, "SVG scripts with end tag should run");
test(function() {
assert_false(scriptWithoutEndTagRan);
}, "SVG scripts without end tag should not run");
test(function() {
assert_true(scriptWithBogusEndTagInsideRan);
}, "SVG scripts with bogus end tag inside should run");
</script>

View File

@ -1335,6 +1335,7 @@ nsTypeAheadFind::IsRangeRendered(nsRange* aRange, bool* aResult) {
bool nsTypeAheadFind::IsRangeRendered(nsIPresShell* aPresShell,
nsPresContext* aPresContext,
nsRange* aRange) {
using FrameForPointOption = nsLayoutUtils::FrameForPointOption;
NS_ASSERTION(aPresShell && aPresContext && aRange, "params are invalid");
nsCOMPtr<nsIContent> content = do_QueryInterface(aRange->GetCommonAncestor());
@ -1366,9 +1367,9 @@ bool nsTypeAheadFind::IsRangeRendered(nsIPresShell* aPresShell,
// Append visible frames to frames array.
nsLayoutUtils::GetFramesForArea(
rootFrame, r, frames,
nsLayoutUtils::IGNORE_PAINT_SUPPRESSION |
nsLayoutUtils::IGNORE_ROOT_SCROLL_FRAME |
nsLayoutUtils::ONLY_VISIBLE);
{FrameForPointOption::IgnorePaintSuppression,
FrameForPointOption::IgnoreRootScrollFrame,
FrameForPointOption::OnlyVisible});
// See if any of the frames contain the content. If they do, then the range
// is visible. We search for the content rather than the original frame,