зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-central to inbound. a=merge CLOSED TREE
This commit is contained in:
Коммит
fcb3be1b9f
|
@ -185,7 +185,6 @@ dom/flex/**
|
|||
dom/grid/**
|
||||
dom/html/**
|
||||
dom/jsurl/**
|
||||
dom/localstorage/**
|
||||
dom/media/test/**
|
||||
dom/media/tests/**
|
||||
dom/media/webaudio/**
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
"use strict";
|
||||
|
||||
module.exports = {
|
||||
"extends": [
|
||||
"plugin:mozilla/xpcshell-test",
|
||||
]
|
||||
};
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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]);
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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]);
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -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>
|
|
@ -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,
|
||||
|
|
Загрузка…
Ссылка в новой задаче