зеркало из https://github.com/mozilla/gecko-dev.git
Merge inbound to m-c a=merge
MozReview-Commit-ID: LpxvieHR7VH
This commit is contained in:
Коммит
288405ee34
|
@ -110,5 +110,6 @@ static const AtkStateMap gAtkStateMap[] = { // Cross Platfor
|
|||
{ ATK_STATE_SENSITIVE, kMapDirectly }, // states::SENSITIVE = 1 << 45
|
||||
{ ATK_STATE_EXPANDABLE, kMapDirectly }, // states::EXPANDABLE = 1 << 46
|
||||
{ kNone, kMapDirectly }, // states::PINNED = 1 << 47
|
||||
{ kNone, kNoSuchState }, // = 1 << 48
|
||||
{ ATK_STATE_ACTIVE, kMapDirectly }, // states::CURRENT = 1 << 48
|
||||
{ kNone, kNoSuchState }, // = 1 << 49
|
||||
};
|
||||
|
|
|
@ -597,6 +597,16 @@ static const nsRoleMapEntry sWAIRoleMaps[] =
|
|||
kGenericAccType,
|
||||
kNoReqStates
|
||||
},
|
||||
{ // figure
|
||||
&nsGkAtoms::figure,
|
||||
roles::FIGURE,
|
||||
kUseMapRole,
|
||||
eNoValue,
|
||||
eNoAction,
|
||||
eNoLiveAttr,
|
||||
kGenericAccType,
|
||||
kNoReqStates
|
||||
},
|
||||
{ // form
|
||||
&nsGkAtoms::form,
|
||||
roles::FORM,
|
||||
|
@ -902,12 +912,12 @@ static const nsRoleMapEntry sWAIRoleMaps[] =
|
|||
},
|
||||
{ // region
|
||||
&nsGkAtoms::region,
|
||||
roles::PANE,
|
||||
roles::REGION,
|
||||
kUseMapRole,
|
||||
eNoValue,
|
||||
eNoAction,
|
||||
eNoLiveAttr,
|
||||
kGenericAccType,
|
||||
eLandmark,
|
||||
kNoReqStates
|
||||
},
|
||||
{ // row
|
||||
|
@ -1202,6 +1212,7 @@ nsRoleMapEntry aria::gEmptyRoleMap = {
|
|||
*/
|
||||
static const EStateRule sWAIUnivStateMap[] = {
|
||||
eARIABusy,
|
||||
eARIACurrent,
|
||||
eARIADisabled,
|
||||
eARIAExpanded, // Currently under spec review but precedent exists
|
||||
eARIAHasPopup, // Note this is technically a "property"
|
||||
|
|
|
@ -145,6 +145,16 @@ aria::MapToState(EStateRule aRule, dom::Element* aElement, uint64_t* aState)
|
|||
return true;
|
||||
}
|
||||
|
||||
case eARIACurrent:
|
||||
{
|
||||
static const TokenTypeData data(
|
||||
nsGkAtoms::aria_current, eBoolType,
|
||||
0, states::CURRENT);
|
||||
|
||||
MapTokenType(aElement, aState, data);
|
||||
return true;
|
||||
}
|
||||
|
||||
case eARIADisabled:
|
||||
{
|
||||
static const TokenTypeData data(
|
||||
|
@ -354,10 +364,12 @@ MapTokenType(dom::Element* aElement, uint64_t* aState,
|
|||
const TokenTypeData& aData)
|
||||
{
|
||||
if (nsAccUtils::HasDefinedARIAToken(aElement, aData.mAttrName)) {
|
||||
if ((aData.mType & eMixedType) &&
|
||||
aElement->AttrValueIs(kNameSpaceID_None, aData.mAttrName,
|
||||
if (aElement->AttrValueIs(kNameSpaceID_None, aData.mAttrName,
|
||||
nsGkAtoms::mixed, eCaseMatters)) {
|
||||
if (aData.mType & eMixedType)
|
||||
*aState |= aData.mPermanentState | states::MIXED;
|
||||
else // unsupported use of 'mixed' is an authoring error
|
||||
*aState |= aData.mPermanentState | aData.mFalseState;
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@ enum EStateRule
|
|||
eARIACheckableBool,
|
||||
eARIACheckableMixed,
|
||||
eARIACheckedMixed,
|
||||
eARIACurrent,
|
||||
eARIADisabled,
|
||||
eARIAExpanded,
|
||||
eARIAHasPopup,
|
||||
|
|
|
@ -1007,7 +1007,15 @@ enum Role {
|
|||
*/
|
||||
ARTICLE = 172,
|
||||
|
||||
LAST_ROLE = ARTICLE
|
||||
/**
|
||||
* A perceivable section containing content that is relevant to a specific,
|
||||
* author-specified purpose and sufficiently important that users will likely
|
||||
* want to be able to navigate to the section easily and to have it listed in
|
||||
* a summary of the page.
|
||||
*/
|
||||
REGION = 173,
|
||||
|
||||
LAST_ROLE = REGION
|
||||
};
|
||||
|
||||
} // namespace role
|
||||
|
|
|
@ -1399,3 +1399,11 @@ ROLE(ARTICLE,
|
|||
ROLE_SYSTEM_DOCUMENT,
|
||||
ROLE_SYSTEM_DOCUMENT,
|
||||
eNoNameRule)
|
||||
|
||||
ROLE(REGION,
|
||||
"region",
|
||||
ATK_ROLE_LANDMARK,
|
||||
NSAccessibilityGroupRole,
|
||||
USE_ROLE_STRING,
|
||||
IA2_ROLE_LANDMARK,
|
||||
eNoNameRule)
|
||||
|
|
|
@ -277,6 +277,12 @@ namespace states {
|
|||
* The object is pinned, usually indicating it is fixed in place and has permanence.
|
||||
*/
|
||||
const uint64_t PINNED = ((uint64_t) 0x1) << 47;
|
||||
|
||||
/**
|
||||
* The object is the current item within a container or set of related elements.
|
||||
*/
|
||||
const uint64_t CURRENT = ((uint64_t) 0x1) << 48;
|
||||
|
||||
} // namespace states
|
||||
} // namespace a11y
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -1054,6 +1054,13 @@ DocAccessible::ARIAAttributeChanged(Accessible* aAccessible, nsIAtom* aAttribute
|
|||
return;
|
||||
}
|
||||
|
||||
if (aAttribute == nsGkAtoms::aria_current) {
|
||||
RefPtr<AccEvent> event =
|
||||
new AccStateChangeEvent(aAccessible, states::CURRENT);
|
||||
FireDelayedEvent(event);
|
||||
return;
|
||||
}
|
||||
|
||||
if (aAttribute == nsGkAtoms::aria_owns) {
|
||||
mNotificationController->ScheduleRelocation(aAccessible);
|
||||
}
|
||||
|
|
|
@ -1001,4 +1001,12 @@ interface nsIAccessibleRole : nsISupports
|
|||
* e.g. in syndication.
|
||||
*/
|
||||
const unsigned long ROLE_ARTICLE = 172;
|
||||
|
||||
/**
|
||||
* A perceivable section containing content that is relevant to a specific,
|
||||
* author-specified purpose and sufficiently important that users will likely
|
||||
* want to be able to navigate to the section easily and to have it listed in
|
||||
* a summary of the page.
|
||||
*/
|
||||
const unsigned long ROLE_REGION = 173;
|
||||
};
|
||||
|
|
|
@ -72,5 +72,6 @@ interface nsIAccessibleStates : nsISupports
|
|||
const unsigned long EXT_STATE_SENSITIVE = 0x00004000; // Same as ENABLED for now
|
||||
const unsigned long EXT_STATE_EXPANDABLE = 0x00008000; // If COLLAPSED or EXPANDED
|
||||
const unsigned long EXT_STATE_PINNED = 0x00010000; // Indicates object is pinned.
|
||||
const unsigned long EXT_STATE_CURRENT = 0x00020000; // Indicates object is the current item in its container
|
||||
};
|
||||
|
||||
|
|
|
@ -798,7 +798,7 @@ ConvertToNSArray(nsTArray<ProxyAccessible*>& aArray)
|
|||
if (roleAtom == nsGkAtoms::note_)
|
||||
return @"AXDocumentNote";
|
||||
if (roleAtom == nsGkAtoms::region)
|
||||
return @"AXDocumentRegion";
|
||||
return @"AXLandmarkRegion";
|
||||
if (roleAtom == nsGkAtoms::status)
|
||||
return @"AXApplicationStatus";
|
||||
if (roleAtom == nsGkAtoms::tabpanel)
|
||||
|
@ -952,7 +952,6 @@ static const RoleDescrMap sRoleDescrMap[] = {
|
|||
{ @"AXDocumentArticle", NS_LITERAL_STRING("article") },
|
||||
{ @"AXDocumentMath", NS_LITERAL_STRING("math") },
|
||||
{ @"AXDocumentNote", NS_LITERAL_STRING("note") },
|
||||
{ @"AXDocumentRegion", NS_LITERAL_STRING("region") },
|
||||
{ @"AXLandmarkApplication", NS_LITERAL_STRING("application") },
|
||||
{ @"AXLandmarkBanner", NS_LITERAL_STRING("banner") },
|
||||
{ @"AXLandmarkComplementary", NS_LITERAL_STRING("complementary") },
|
||||
|
@ -981,6 +980,9 @@ struct RoleDescrComparator
|
|||
if (mRole == roles::DOCUMENT)
|
||||
return utils::LocalizedString(NS_LITERAL_STRING("htmlContent"));
|
||||
|
||||
if (mRole == roles::FIGURE)
|
||||
return utils::LocalizedString(NS_LITERAL_STRING("figure"));
|
||||
|
||||
if (mRole == roles::HEADING)
|
||||
return utils::LocalizedString(NS_LITERAL_STRING("heading"));
|
||||
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
testAttrs("feed", {"xml-roles": "feed"}, true);
|
||||
testAttrs("article", {"xml-roles": "article"}, true);
|
||||
testAttrs("main_element", {"xml-roles": "main"}, true);
|
||||
testAttrs("figure", {"xml-roles": "figure"}, true);
|
||||
|
||||
testAttrs("search", {"xml-roles": "searchbox"}, true);
|
||||
|
||||
|
@ -140,6 +141,12 @@
|
|||
title="ARIA 1.1: Support role 'searchbox'">
|
||||
Bug 1121518
|
||||
</a>
|
||||
<a target="_blank"
|
||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=1356049"
|
||||
title="Map ARIA figure role">
|
||||
Bug 1356049
|
||||
</a>
|
||||
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none"></div>
|
||||
<pre id="test">
|
||||
|
@ -163,6 +170,7 @@
|
|||
<div id="feed" role="feed">a feed</div>
|
||||
<article id="article">article</article>
|
||||
<main id="main_element">another main area</main>
|
||||
<div id="figure" role="figure">a figure</div>
|
||||
|
||||
<input id="search" type="search"/>
|
||||
|
||||
|
|
|
@ -68,6 +68,25 @@
|
|||
};
|
||||
}
|
||||
|
||||
function makeCurrent(aID, aIsCurrent, aValue)
|
||||
{
|
||||
this.DOMNode = getNode(aID);
|
||||
|
||||
this.eventSeq = [
|
||||
new stateChangeChecker(EXT_STATE_CURRENT, true, aIsCurrent, this.DOMNode)
|
||||
];
|
||||
|
||||
this.invoke = function makeCurrent_invoke()
|
||||
{
|
||||
this.DOMNode.setAttribute("aria-current", aValue);
|
||||
};
|
||||
|
||||
this.getID = function makeCurrent_getID()
|
||||
{
|
||||
return prettyName(aID) + " aria-current changed to " + aValue;
|
||||
};
|
||||
}
|
||||
|
||||
function setAttrOfMixedType(aID, aAttr, aState, aValue)
|
||||
{
|
||||
this.DOMNode = getNode(aID);
|
||||
|
@ -148,6 +167,12 @@
|
|||
buildQueueForAttrOfMixedType(gQueue, "checkable", setChecked);
|
||||
buildQueueForAttrOfBoolType(gQueue, "checkableBool", setChecked);
|
||||
|
||||
gQueue.push(new makeCurrent("current_page_1", false, "false"));
|
||||
gQueue.push(new makeCurrent("current_page_2", true, "page"));
|
||||
gQueue.push(new makeCurrent("current_page_2", false, "false"));
|
||||
gQueue.push(new makeCurrent("current_page_3", true, "true"));
|
||||
gQueue.push(new makeCurrent("current_page_3", false, ""));
|
||||
|
||||
gQueue.invoke(); // Will call SimpleTest.finish();
|
||||
}
|
||||
|
||||
|
@ -183,6 +208,11 @@
|
|||
title="Support ARIA 1.1 switch role">
|
||||
Mozilla Bug 1136563
|
||||
</a>
|
||||
<a target="_blank"
|
||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=1355921"
|
||||
title="Elements with a defined, non-false value for aria-current should expose ATK_STATE_ACTIVE">
|
||||
Mozilla Bug 1355921
|
||||
</a>
|
||||
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none"></div>
|
||||
|
@ -204,5 +234,10 @@
|
|||
<!-- aria-checked -->
|
||||
<div id="checkable" role="checkbox"></div>
|
||||
<div id="checkableBool" role="switch"></div>
|
||||
|
||||
<!-- aria-current -->
|
||||
<div id="current_page_1" role="link" aria-current="page">1</div>
|
||||
<div id="current_page_2" role="link" aria-current="false">2</div>
|
||||
<div id="current_page_3" role="link">3</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -100,6 +100,7 @@ const ROLE_PUSHBUTTON = nsIAccessibleRole.ROLE_PUSHBUTTON;
|
|||
const ROLE_RADIOBUTTON = nsIAccessibleRole.ROLE_RADIOBUTTON;
|
||||
const ROLE_RADIO_GROUP = nsIAccessibleRole.ROLE_RADIO_GROUP;
|
||||
const ROLE_RADIO_MENU_ITEM = nsIAccessibleRole.ROLE_RADIO_MENU_ITEM;
|
||||
const ROLE_REGION = nsIAccessibleRole.ROLE_REGION;
|
||||
const ROLE_RICH_OPTION = nsIAccessibleRole.ROLE_RICH_OPTION;
|
||||
const ROLE_ROW = nsIAccessibleRole.ROLE_ROW;
|
||||
const ROLE_ROWHEADER = nsIAccessibleRole.ROLE_ROWHEADER;
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
testRole("aria_document", ROLE_DOCUMENT);
|
||||
testRole("aria_form", ROLE_FORM);
|
||||
testRole("aria_feed", ROLE_GROUPING);
|
||||
testRole("aria_figure", ROLE_FIGURE);
|
||||
testRole("aria_grid", ROLE_TABLE);
|
||||
testRole("aria_gridcell", ROLE_GRID_CELL);
|
||||
testRole("aria_group", ROLE_GROUPING);
|
||||
|
@ -53,7 +54,7 @@
|
|||
testRole("aria_progressbar", ROLE_PROGRESSBAR);
|
||||
testRole("aria_radio", ROLE_RADIOBUTTON);
|
||||
testRole("aria_radiogroup", ROLE_RADIO_GROUP);
|
||||
testRole("aria_region", ROLE_PANE);
|
||||
testRole("aria_region", ROLE_REGION);
|
||||
testRole("aria_row", ROLE_ROW);
|
||||
testRole("aria_rowheader", ROLE_ROWHEADER);
|
||||
testRole("aria_scrollbar", ROLE_SCROLLBAR);
|
||||
|
@ -191,6 +192,11 @@
|
|||
title="Support ARIA 1.1 searchbox role">
|
||||
Bug 1121518
|
||||
</a>
|
||||
<a target="_blank"
|
||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=1356049"
|
||||
title="Map ARIA figure role">
|
||||
Bug 1356049
|
||||
</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none"></div>
|
||||
<pre id="test">
|
||||
|
@ -209,6 +215,7 @@
|
|||
<span id="aria_document" role="document"/>
|
||||
<span id="aria_form" role="form"/>
|
||||
<span id="aria_feed" role="feed"/>
|
||||
<span id="aria_figure" role="figure"/>
|
||||
<span id="aria_grid" role="grid"/>
|
||||
<span id="aria_gridcell" role="gridcell"/>
|
||||
<span id="aria_group" role="group"/>
|
||||
|
|
|
@ -37,6 +37,7 @@ const STATE_TRAVERSED = nsIAccessibleStates.STATE_TRAVERSED;
|
|||
const STATE_UNAVAILABLE = nsIAccessibleStates.STATE_UNAVAILABLE;
|
||||
|
||||
const EXT_STATE_ACTIVE = nsIAccessibleStates.EXT_STATE_ACTIVE;
|
||||
const EXT_STATE_CURRENT = nsIAccessibleStates.EXT_STATE_CURRENT;
|
||||
const EXT_STATE_DEFUNCT = nsIAccessibleStates.EXT_STATE_DEFUNCT;
|
||||
const EXT_STATE_EDITABLE = nsIAccessibleStates.EXT_STATE_EDITABLE;
|
||||
const EXT_STATE_ENABLED = nsIAccessibleStates.EXT_STATE_ENABLED;
|
||||
|
|
|
@ -94,6 +94,7 @@
|
|||
testStates("aria_mixed_checkbox", STATE_MIXED);
|
||||
testStates("aria_checked_switch", STATE_CHECKED);
|
||||
testStates("aria_mixed_switch", 0, 0, STATE_MIXED); // unsupported
|
||||
testStates("aria_mixed_switch", 0, 0, STATE_CHECKED); // not checked due to being unsupported
|
||||
|
||||
// test disabled group and all its descendants to see if they are
|
||||
// disabled, too. See bug 429285.
|
||||
|
@ -266,6 +267,13 @@
|
|||
testStates("aria_progressbar_valuenow", 0, 0, STATE_MIXED);
|
||||
testStates("aria_progressbar_valuetext", 0, 0, STATE_MIXED);
|
||||
|
||||
// aria-current
|
||||
testStates("current_page_1", 0, EXT_STATE_CURRENT);
|
||||
testStates("page_2", 0, 0, EXT_STATE_CURRENT);
|
||||
testStates("page_3", 0, 0, EXT_STATE_CURRENT);
|
||||
testStates("page_4", 0, 0, EXT_STATE_CURRENT);
|
||||
testStates("current_foo", 0, EXT_STATE_CURRENT);
|
||||
|
||||
testStates("aria_listbox", STATE_FOCUSABLE);
|
||||
testStates("aria_grid", STATE_FOCUSABLE);
|
||||
testStates("aria_tree", STATE_FOCUSABLE);
|
||||
|
@ -360,6 +368,11 @@
|
|||
title="Support ARIA 1.1 switch role">
|
||||
Mozilla Bug 1136563
|
||||
</a>
|
||||
<a target="_blank"
|
||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=1355921"
|
||||
title="Elements with a defined, non-false value for aria-current should expose ATK_STATE_ACTIVE">
|
||||
Mozilla Bug 1355921
|
||||
</a>
|
||||
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none"></div>
|
||||
|
@ -631,5 +644,11 @@
|
|||
<!-- Test that directory is readonly -->
|
||||
<div id="aria_directory" role="directory"></div>
|
||||
|
||||
<!-- aria-current -->
|
||||
<div id="current_page_1" role="link" aria-current="page">1</div>
|
||||
<div id="page_2" role="link" aria-current="false">2</div>
|
||||
<div id="page_3" role="link">3</div>
|
||||
<div id="page_4" role="link" aria-current="">4</div>
|
||||
<div id="current_foo" aria-current="foo">foo</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -36,6 +36,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=452388
|
|||
|
||||
// test (checkbox) checkable and checked states
|
||||
testStates("checkbox_checked_true", (STATE_CHECKABLE | STATE_CHECKED));
|
||||
testStates("checkbox_checked_mixed", (STATE_CHECKABLE | STATE_MIXED), 0, STATE_CHECKED);
|
||||
testStates("checkbox_checked_false", STATE_CHECKABLE, 0, STATE_CHECKED);
|
||||
testStates("checkbox_checked_empty", STATE_CHECKABLE , 0, STATE_CHECKED);
|
||||
testStates("checkbox_checked_undefined", STATE_CHECKABLE, 0, STATE_CHECKED);
|
||||
|
@ -98,6 +99,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=452388
|
|||
|
||||
// test (menuitem) checkable and checked states, which are unsupported on this role
|
||||
testStates("menuitem_checked_true", 0, 0, (STATE_CHECKABLE | STATE_CHECKED));
|
||||
testStates("menuitem_checked_mixed", 0, 0, (STATE_CHECKABLE | STATE_CHECKED | STATE_MIXED));
|
||||
testStates("menuitem_checked_false", 0, 0, (STATE_CHECKABLE | STATE_CHECKED));
|
||||
testStates("menuitem_checked_empty", 0, 0, (STATE_CHECKABLE | STATE_CHECKED));
|
||||
testStates("menuitem_checked_undefined", 0, 0, (STATE_CHECKABLE | STATE_CHECKED));
|
||||
|
@ -105,6 +107,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=452388
|
|||
|
||||
// test (menuitemcheckbox) checkable and checked states
|
||||
testStates("menuitemcheckbox_checked_true", (STATE_CHECKABLE | STATE_CHECKED));
|
||||
testStates("menuitemcheckbox_checked_mixed", (STATE_CHECKABLE | STATE_MIXED), 0, STATE_CHECKED);
|
||||
testStates("menuitemcheckbox_checked_false", STATE_CHECKABLE, 0, STATE_CHECKED);
|
||||
testStates("menuitemcheckbox_checked_empty", STATE_CHECKABLE, 0, STATE_CHECKED);
|
||||
testStates("menuitemcheckbox_checked_undefined", STATE_CHECKABLE, 0, STATE_CHECKED);
|
||||
|
@ -119,6 +122,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=452388
|
|||
|
||||
// test (menuitemradio) checkable and checked states
|
||||
testStates("menuitemradio_checked_true", (STATE_CHECKABLE | STATE_CHECKED));
|
||||
testStates("menuitemradio_checked_mixed", STATE_CHECKABLE, 0, (STATE_MIXED | STATE_CHECKED));
|
||||
testStates("menuitemradio_checked_false", STATE_CHECKABLE, 0, STATE_CHECKED);
|
||||
testStates("menuitemradio_checked_empty", STATE_CHECKABLE, 0, STATE_CHECKED);
|
||||
testStates("menuitemradio_checked_undefined", STATE_CHECKABLE, 0, STATE_CHECKED);
|
||||
|
@ -133,6 +137,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=452388
|
|||
|
||||
// test (radio) checkable and checked states
|
||||
testStates("radio_checked_true", (STATE_CHECKABLE | STATE_CHECKED));
|
||||
testStates("radio_checked_mixed", STATE_CHECKABLE, 0, (STATE_MIXED | STATE_CHECKED));
|
||||
testStates("radio_checked_false", STATE_CHECKABLE, 0, STATE_CHECKED);
|
||||
testStates("radio_checked_empty", STATE_CHECKABLE, 0, STATE_CHECKED);
|
||||
testStates("radio_checked_undefined", STATE_CHECKABLE, 0, STATE_CHECKED);
|
||||
|
@ -235,6 +240,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=452388
|
|||
<div id="button_pressed_absent" role="button">This button has <emph>no</emph> aria-pressed attribute and should <emph>not</emph> get ROLE_TOGGLE_BUTTON.</div>
|
||||
|
||||
<div id="checkbox_checked_true" role="checkbox" aria-checked="true">This checkbox has aria-checked="true" and should get STATE_CHECKABLE. It should also get STATE_checked.</div>
|
||||
<div id="checkbox_checked_mixed" role="checkbox" aria-checked="mixed">This checkbox has aria-checked="mixed" and should get STATE_CHECKABLE. It should also get STATE_MIXED.</div>
|
||||
<div id="checkbox_checked_false" role="checkbox" aria-checked="false">This checkbox has aria-checked="false" and should get STATE_CHECKABLE.</div>
|
||||
<div id="checkbox_checked_empty" role="checkbox" aria-checked="">This checkbox has aria-checked="" and should <emph>not</emph> get STATE_CHECKABLE.</div>
|
||||
<div id="checkbox_checked_undefined" role="checkbox" aria-checked="undefined">This checkbox has aria-checked="undefined" and should <emph>not</emph> get STATE_CHECKABLE.</div>
|
||||
|
@ -296,12 +302,14 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=452388
|
|||
|
||||
<div role="menu">
|
||||
<div id="menuitem_checked_true" role="menuitem" aria-checked="true">Generic menuitems don't support aria-checked.</div>
|
||||
<div id="menuitem_checked_mixed" role="menuitem" aria-checked="mixed">Generic menuitems don't support aria-checked.</div>
|
||||
<div id="menuitem_checked_false" role="menuitem" aria-checked="false">Generic menuitems don't support aria-checked.</div>
|
||||
<div id="menuitem_checked_empty" role="menuitem" aria-checked="">Generic menuitems don't support aria-checked.</div>
|
||||
<div id="menuitem_checked_undefined" role="menuitem" aria-checked="undefined">Generic menuitems don't support aria-checked.</div>
|
||||
<div id="menuitem_checked_absent" role="menuitem">Generic menuitems don't support aria-checked.</div>
|
||||
|
||||
<div id="menuitemcheckbox_checked_true" role="menuitemcheckbox" aria-checked="true">This menuitemcheckbox has aria-checked="true" and should get STATE_CHECKABLE. It should also get STATE_checked.</div>
|
||||
<div id="menuitemcheckbox_checked_mixed" role="menuitemcheckbox" aria-checked="mixed">This menuitemcheckbox has aria-checked="mixed" and should get STATE_CHECKABLE. It should also get STATE_MIXED.</div>
|
||||
<div id="menuitemcheckbox_checked_false" role="menuitemcheckbox" aria-checked="false">This menuitemcheckbox has aria-checked="false" and should get STATE_CHECKABLE.</div>
|
||||
<div id="menuitemcheckbox_checked_empty" role="menuitemcheckbox" aria-checked="">This menuitemcheckbox has aria-checked="" and should <emph>not</emph> get STATE_CHECKABLE.</div>
|
||||
<div id="menuitemcheckbox_checked_undefined" role="menuitemcheckbox" aria-checked="undefined">This menuitemcheckbox has aria-checked="undefined" and should <emph>not</emph> get STATE_CHECKABLE.</div>
|
||||
|
@ -314,6 +322,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=452388
|
|||
<div id="menuitemcheckbox_readonly_absent" role="menuitemcheckbox">This menuitemcheckbox has <emph>no</emph> aria-readonly attribute and should <emph>not</emph> get STATE_READONLY.</div>
|
||||
|
||||
<div id="menuitemradio_checked_true" role="menuitemradio" aria-checked="true">This menuitem has aria-checked="true" and should get STATE_CHECKABLE. It should also get STATE_checked.</div>
|
||||
<div id="menuitemradio_checked_mixed" role="menuitemradio" aria-checked="mixed">This menuitem has aria-checked="mixed" and should get STATE_CHECKABLE. It should not get STATE_MIXED.</div>
|
||||
<div id="menuitemradio_checked_false" role="menuitemradio" aria-checked="false">This menuitem has aria-checked="false" and should get STATE_CHECKABLE.</div>
|
||||
<div id="menuitemradio_checked_empty" role="menuitemradio" aria-checked="">This menuitem has aria-checked="" and should <emph>not</emph> get STATE_CHECKABLE.</div>
|
||||
<div id="menuitemradio_checked_undefined" role="menuitemradio" aria-checked="undefined">This menuitem has aria-checked="undefined" and should <emph>not</emph> get STATE_CHECKABLE.</div>
|
||||
|
@ -327,6 +336,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=452388
|
|||
<div id="menuitemradio_readonly_absent" role="menuitemradio">This menuitemradio has <emph>no</emph> aria-readonly attribute and should <emph>not</emph> get STATE_READONLY.</div>
|
||||
|
||||
<div id="radio_checked_true" role="radio" aria-checked="true">This menuitem has aria-checked="true" and should get STATE_CHECKABLE. It should also get STATE_CHECKED.</div>
|
||||
<div id="radio_checked_mixed" role="radio" aria-checked="mixed">This radio button has aria-checked="mixed" and should get STATE_CHECKABLE. It should not get STATE_MIXED.</div>
|
||||
<div id="radio_checked_false" role="radio" aria-checked="false">This menuitem has aria-checked="false" and should get STATE_CHECKABLE.</div>
|
||||
<div id="radio_checked_empty" role="radio" aria-checked="">This menuitem has aria-checked="" and should <emph>not</emph> get STATE_CHECKABLE.</div>
|
||||
<div id="radio_checked_undefined" role="radio" aria-checked="undefined">This menuitem has aria-checked="undefined" and should <emph>not</emph> get STATE_CHECKABLE.</div>
|
||||
|
|
|
@ -868,7 +868,23 @@ this.PanelMultiView = class {
|
|||
// sense for all platforms. If the arrow visuals change significantly,
|
||||
// this value will be easy to adjust.
|
||||
const EXTRA_MARGIN_PX = 20;
|
||||
this._viewStack.style.maxHeight = (maxHeight - EXTRA_MARGIN_PX) + "px";
|
||||
maxHeight -= EXTRA_MARGIN_PX;
|
||||
this._viewStack.style.maxHeight = maxHeight + "px";
|
||||
|
||||
// When using block-in-box layout inside a scrollable frame, like in the
|
||||
// main menu contents scroller, if we allow the contents to scroll then
|
||||
// it will not cause its container to expand. Thus, we layout first
|
||||
// without any scrolling (using "display: flex;"), and only if the view
|
||||
// exceeds the available space we set the height explicitly and enable
|
||||
// scrolling.
|
||||
if (this._mainView.hasAttribute("blockinboxworkaround")) {
|
||||
let mainViewHeight =
|
||||
this._dwu.getBoundsWithoutFlushing(this._mainView).height;
|
||||
if (mainViewHeight > maxHeight) {
|
||||
this._mainView.style.height = maxHeight + "px";
|
||||
this._mainView.setAttribute("exceeding", "true");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "popupshown":
|
||||
// Now that the main view is visible, we can check the height of the
|
||||
|
@ -890,6 +906,12 @@ this.PanelMultiView = class {
|
|||
this._resetKeyNavigation();
|
||||
this._mainViewHeight = 0;
|
||||
}
|
||||
// Always try to layout the panel normally when reopening it. This is
|
||||
// also the layout that will be used in customize mode.
|
||||
if (this._mainView.hasAttribute("blockinboxworkaround")) {
|
||||
this._mainView.style.removeProperty("height");
|
||||
this._mainView.removeAttribute("exceeding");
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
<panelmultiview id="PanelUI-multiView" mainViewId="PanelUI-mainView"
|
||||
viewCacheId="appMenu-viewCache">
|
||||
<panelview id="PanelUI-mainView" context="customizationPanelContextMenu"
|
||||
descriptionheightworkaround="true">
|
||||
descriptionheightworkaround="true" blockinboxworkaround="true">
|
||||
<vbox id="PanelUI-contents-scroller">
|
||||
<vbox id="PanelUI-contents" class="panelUI-grid"/>
|
||||
</vbox>
|
||||
|
|
|
@ -250,11 +250,6 @@ photonpanelmultiview .panel-subview-header {
|
|||
-moz-box-pack: center;
|
||||
}
|
||||
|
||||
#PanelUI-mainView {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#appMenu-popup > arrowscrollbox > autorepeatbutton,
|
||||
#PanelUI-popup > arrowscrollbox > autorepeatbutton {
|
||||
display: none;
|
||||
|
@ -381,12 +376,18 @@ photonpanelmultiview .panel-subview-body {
|
|||
}
|
||||
|
||||
#PanelUI-contents-scroller {
|
||||
-moz-box-flex: 1;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
width: @menuPanelWidth@;
|
||||
padding-left: 5px;
|
||||
padding-right: 5px;
|
||||
flex: auto;
|
||||
-moz-box-align: center;
|
||||
}
|
||||
|
||||
/* Allow box layout to take over when the view exceeds the available space. */
|
||||
#PanelUI-mainView:not([exceeding]) > #PanelUI-contents-scroller {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.toolbaritem-combined-buttons@inAnyPanel@ > toolbarbutton > .toolbarbutton-icon {
|
||||
|
|
|
@ -23,8 +23,6 @@ case "$target" in
|
|||
dnl undefined symbol (present on the hardware, just not in the
|
||||
dnl NDK.)
|
||||
LDFLAGS="-L$android_platform/usr/lib -Wl,-rpath-link=$android_platform/usr/lib --sysroot=$android_platform -Wl,--allow-shlib-undefined $LDFLAGS"
|
||||
dnl Add -llog by default, since we use it all over the place.
|
||||
LIBS="-llog $LIBS"
|
||||
ANDROID_PLATFORM="${android_platform}"
|
||||
|
||||
AC_DEFINE(ANDROID)
|
||||
|
|
|
@ -991,13 +991,18 @@ set_config('COLOR_CFLAGS', color_cflags)
|
|||
# we are properly managing visibility ourselves) and avoid this whole mess.
|
||||
# Note that we don't need to do this with gcc, as libc++ detects gcc and
|
||||
# effectively does the same thing we are doing here.
|
||||
#
|
||||
# _LIBCPP_ALWAYS_INLINE needs similar workarounds, since it too declares
|
||||
# hidden visibility.
|
||||
@depends(c_compiler, target)
|
||||
def libcxx_inline_visibility(c_compiler, target):
|
||||
def libcxx_override_visibility(c_compiler, target):
|
||||
if c_compiler.type == 'clang' and target.os == 'Android':
|
||||
return ''
|
||||
|
||||
set_define('_LIBCPP_INLINE_VISIBILITY', libcxx_inline_visibility)
|
||||
set_define('_LIBCPP_INLINE_VISIBILITY_EXCEPT_GCC49', libcxx_inline_visibility)
|
||||
set_define('_LIBCPP_INLINE_VISIBILITY', libcxx_override_visibility)
|
||||
set_define('_LIBCPP_INLINE_VISIBILITY_EXCEPT_GCC49', libcxx_override_visibility)
|
||||
set_define('_LIBCPP_ALWAYS_INLINE', libcxx_override_visibility)
|
||||
set_define('_LIBCPP_ALWAYS_INLINE_EXCEPT_GCC49', libcxx_override_visibility)
|
||||
|
||||
@depends(target, check_build_environment)
|
||||
def visibility_flags(target, env):
|
||||
|
|
|
@ -21,6 +21,10 @@ def Binary():
|
|||
if CONFIG['STLPORT_LIBS']:
|
||||
OS_LIBS += [CONFIG['STLPORT_LIBS']]
|
||||
|
||||
# Add -llog by default, since we use it all over the place.
|
||||
if CONFIG['OS_TARGET'] == 'Android':
|
||||
OS_LIBS += ['log']
|
||||
|
||||
|
||||
@template
|
||||
def Program(name):
|
||||
|
|
|
@ -130,7 +130,6 @@ HOST_LIBRARY := $(LIB_PREFIX)$(HOST_LIBRARY_NAME).$(LIB_SUFFIX)
|
|||
endif
|
||||
endif
|
||||
|
||||
ifdef LIBRARY
|
||||
ifdef FORCE_SHARED_LIB
|
||||
ifdef MKSHLIB
|
||||
|
||||
|
@ -142,7 +141,6 @@ EMBED_MANIFEST_AT=2
|
|||
|
||||
endif # MKSHLIB
|
||||
endif # FORCE_SHARED_LIB
|
||||
endif # LIBRARY
|
||||
|
||||
ifeq ($(OS_ARCH),WINNT)
|
||||
ifndef GNU_CC
|
||||
|
@ -908,15 +906,7 @@ ifdef MOZ_USING_SCCACHE
|
|||
sccache_wrap := RUSTC_WRAPPER='$(CCACHE)'
|
||||
endif
|
||||
|
||||
|
||||
# This function is intended to be called by:
|
||||
#
|
||||
# $(call CARGO_BUILD,EXTRA_ENV_VAR1=X EXTRA_ENV_VAR2=Y ...)
|
||||
#
|
||||
# but, given the idiosyncracies of make, can also be called without arguments:
|
||||
#
|
||||
# $(call CARGO_BUILD)
|
||||
define CARGO_BUILD
|
||||
define RUN_CARGO
|
||||
env $(environment_cleaner) $(rust_unlock_unstable) $(rustflags_override) $(sccache_wrap) \
|
||||
CARGO_TARGET_DIR=$(CARGO_TARGET_DIR) \
|
||||
RUSTC=$(RUSTC) \
|
||||
|
@ -927,8 +917,23 @@ env $(environment_cleaner) $(rust_unlock_unstable) $(rustflags_override) $(sccac
|
|||
PKG_CONFIG_ALLOW_CROSS=1 \
|
||||
RUST_BACKTRACE=1 \
|
||||
MOZ_TOPOBJDIR=$(topobjdir) \
|
||||
$(1) \
|
||||
$(CARGO) build $(cargo_build_flags)
|
||||
$(2) \
|
||||
$(CARGO) $(1) $(cargo_build_flags)
|
||||
endef
|
||||
|
||||
# This function is intended to be called by:
|
||||
#
|
||||
# $(call CARGO_BUILD,EXTRA_ENV_VAR1=X EXTRA_ENV_VAR2=Y ...)
|
||||
#
|
||||
# but, given the idiosyncracies of make, can also be called without arguments:
|
||||
#
|
||||
# $(call CARGO_BUILD)
|
||||
define CARGO_BUILD
|
||||
$(call RUN_CARGO,build,$(1))
|
||||
endef
|
||||
|
||||
define CARGO_CHECK
|
||||
$(call RUN_CARGO,check,$(1))
|
||||
endef
|
||||
|
||||
cargo_linker_env_var := CARGO_TARGET_$(RUST_TARGET_ENV_NAME)_LINKER
|
||||
|
@ -972,6 +977,12 @@ force-cargo-library-build:
|
|||
$(call CARGO_BUILD,$(target_cargo_env_vars)) --lib $(cargo_target_flag) $(rust_features_flag)
|
||||
|
||||
$(RUST_LIBRARY_FILE): force-cargo-library-build
|
||||
|
||||
force-cargo-library-check:
|
||||
$(call CARGO_CHECK,$(target_cargo_env_vars)) --lib $(cargo_target_flag) $(rust_features_flag)
|
||||
else
|
||||
force-cargo-library-check:
|
||||
@true
|
||||
endif # RUST_LIBRARY_FILE
|
||||
|
||||
ifdef HOST_RUST_LIBRARY_FILE
|
||||
|
@ -985,6 +996,12 @@ force-cargo-host-library-build:
|
|||
$(call CARGO_BUILD) --lib $(cargo_host_flag) $(host_rust_features_flag)
|
||||
|
||||
$(HOST_RUST_LIBRARY_FILE): force-cargo-host-library-build
|
||||
|
||||
force-cargo-host-library-check:
|
||||
$(call CARGO_CHECK) --lib $(cargo_host_flag) $(host_rust_features_flag)
|
||||
else
|
||||
force-cargo-host-library-check:
|
||||
@true
|
||||
endif # HOST_RUST_LIBRARY_FILE
|
||||
|
||||
ifdef RUST_PROGRAMS
|
||||
|
@ -993,6 +1010,12 @@ force-cargo-program-build:
|
|||
$(call CARGO_BUILD,$(target_cargo_env_vars)) $(addprefix --bin ,$(RUST_CARGO_PROGRAMS)) $(cargo_target_flag)
|
||||
|
||||
$(RUST_PROGRAMS): force-cargo-program-build
|
||||
|
||||
force-cargo-program-check:
|
||||
$(call CARGO_CHECK,$(target_cargo_env_vars)) $(addprefix --bin ,$(RUST_CARGO_PROGRAMS)) $(cargo_target_flag)
|
||||
else
|
||||
force-cargo-program-check:
|
||||
@true
|
||||
endif # RUST_PROGRAMS
|
||||
ifdef HOST_RUST_PROGRAMS
|
||||
force-cargo-host-program-build:
|
||||
|
@ -1000,6 +1023,13 @@ force-cargo-host-program-build:
|
|||
$(call CARGO_BUILD) $(addprefix --bin ,$(HOST_RUST_CARGO_PROGRAMS)) $(cargo_host_flag)
|
||||
|
||||
$(HOST_RUST_PROGRAMS): force-cargo-host-program-build
|
||||
|
||||
force-cargo-host-program-check:
|
||||
$(REPORT_BUILD)
|
||||
$(call CARGO_CHECK) $(addprefix --bin ,$(HOST_RUST_CARGO_PROGRAMS)) $(cargo_host_flag)
|
||||
else
|
||||
force-cargo-host-program-check:
|
||||
@true
|
||||
endif # HOST_RUST_PROGRAMS
|
||||
|
||||
$(SOBJS):
|
||||
|
|
|
@ -1628,16 +1628,16 @@ html .toggle-button-end.vertical svg {
|
|||
color: var(--theme-highlight-blue);
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.popover .preview .header .link:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.selected-token {
|
||||
.selection, .debug-expression.selection {
|
||||
background-color: var(--theme-highlight-yellow);
|
||||
color: var(--theme-selection-color);
|
||||
}
|
||||
|
||||
.selected-token:hover {
|
||||
.selection:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
|
@ -1711,14 +1711,14 @@ html .toggle-button-end.vertical svg {
|
|||
cursor: pointer;
|
||||
}
|
||||
.editor-wrapper {
|
||||
--debug-line-background: rgba(226, 236, 247, 0.5);
|
||||
--debug-line-border: rgb(145, 188, 219);
|
||||
--debug-expression-background: rgba(202, 227, 255, 0.5);
|
||||
--editor-searchbar-height: 27px;
|
||||
--editor-second-searchbar-height: 27px;
|
||||
}
|
||||
|
||||
.theme-dark .editor-wrapper {
|
||||
--debug-line-background: rgb(73, 82, 103);
|
||||
--debug-expression-background: rgb(73, 82, 103);
|
||||
--debug-line-border: rgb(119, 134, 162);
|
||||
}
|
||||
|
||||
|
@ -1872,13 +1872,13 @@ html[dir="rtl"] .editor-mount {
|
|||
color: var(--theme-content-color3);
|
||||
}
|
||||
|
||||
.new-debug-line .CodeMirror-line {
|
||||
background-color: var(--debug-line-background) !important;
|
||||
outline: var(--debug-line-border) solid 1px;
|
||||
.debug-expression {
|
||||
background-color: var(--debug-expression-background);
|
||||
}
|
||||
|
||||
.new-debug-line .CodeMirror-linenumber {
|
||||
.new-debug-line .CodeMirror-line {
|
||||
background-color: transparent !important;
|
||||
outline: var(--debug-line-border) solid 1px;
|
||||
}
|
||||
|
||||
/* Don't display the highlight color since the debug line
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -29952,6 +29952,7 @@ return /******/ (function(modules) { // webpackBootstrap
|
|||
}
|
||||
|
||||
this.worker.removeEventListener("message", listener);
|
||||
|
||||
if (result.error) {
|
||||
reject(result.error);
|
||||
} else {
|
||||
|
@ -30540,7 +30541,8 @@ return /******/ (function(modules) { // webpackBootstrap
|
|||
symbols.functions.push({
|
||||
name: (0, _getFunctionName2.default)(path),
|
||||
location: path.node.loc,
|
||||
parameterNames: getFunctionParameterNames(path)
|
||||
parameterNames: getFunctionParameterNames(path),
|
||||
identifier: path.node.id
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -30803,7 +30805,11 @@ return /******/ (function(modules) { // webpackBootstrap
|
|||
enter(path) {
|
||||
var node = path.node;
|
||||
|
||||
if (t.isMemberExpression(node) && node.property.name === token && (0, _helpers.nodeContainsPosition)(node, location)) {
|
||||
if (!(0, _helpers.nodeContainsPosition)(node, location)) {
|
||||
return path.skip();
|
||||
}
|
||||
|
||||
if (t.isMemberExpression(node) && node.property.name === token) {
|
||||
var memberExpression = (0, _helpers.getMemberExpression)(node);
|
||||
expression = {
|
||||
expression: memberExpression,
|
||||
|
@ -30837,7 +30843,11 @@ return /******/ (function(modules) { // webpackBootstrap
|
|||
|
||||
(0, _ast.traverseAst)(source, {
|
||||
enter(path) {
|
||||
if ((0, _helpers.isLexicalScope)(path) && (0, _helpers.nodeContainsPosition)(path.node, location)) {
|
||||
if (!(0, _helpers.nodeContainsPosition)(path.node, location)) {
|
||||
return path.skip();
|
||||
}
|
||||
|
||||
if ((0, _helpers.isLexicalScope)(path)) {
|
||||
closestPath = path;
|
||||
}
|
||||
}
|
||||
|
@ -30855,9 +30865,10 @@ return /******/ (function(modules) { // webpackBootstrap
|
|||
|
||||
(0, _ast.traverseAst)(source, {
|
||||
enter(path) {
|
||||
if ((0, _helpers.nodeContainsPosition)(path.node, location)) {
|
||||
closestPath = path;
|
||||
if (!(0, _helpers.nodeContainsPosition)(path.node, location)) {
|
||||
return path.skip();
|
||||
}
|
||||
closestPath = path;
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -30961,31 +30972,23 @@ return /******/ (function(modules) { // webpackBootstrap
|
|||
value: true
|
||||
});
|
||||
|
||||
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
|
||||
|
||||
var _get = __webpack_require__(1073);
|
||||
|
||||
var _get2 = _interopRequireDefault(_get);
|
||||
|
||||
var _helpers = __webpack_require__(1052);
|
||||
|
||||
var _ast = __webpack_require__(1051);
|
||||
var _getSymbols = __webpack_require__(1050);
|
||||
|
||||
var _getSymbols2 = _interopRequireDefault(_getSymbols);
|
||||
|
||||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||
|
||||
/**
|
||||
* Returns all functions (declarations, expressions, arrows) for the given
|
||||
* source
|
||||
*/
|
||||
function findFunctions(source) {
|
||||
var fns = [];
|
||||
(0, _ast.traverseAst)(source, {
|
||||
enter(path) {
|
||||
if ((0, _helpers.isFunction)(path)) {
|
||||
fns.push(path);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return fns;
|
||||
var symbols = (0, _getSymbols2.default)(source);
|
||||
return symbols.functions;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -30994,19 +30997,18 @@ return /******/ (function(modules) { // webpackBootstrap
|
|||
* but before the function parameters.
|
||||
*/
|
||||
|
||||
|
||||
var getLocation = path => {
|
||||
var location = Object.assign({}, (0, _get2.default)("node.loc", path));
|
||||
function getLocation(func) {
|
||||
var location = _extends({}, func.location);
|
||||
|
||||
// if the function has an identifier, start the block after it so the
|
||||
// identifier is included in the "scope" of its parent
|
||||
var identifierEnd = (0, _get2.default)("node.id.loc.end", path);
|
||||
var identifierEnd = (0, _get2.default)("identifier.loc.end", func);
|
||||
if (identifierEnd) {
|
||||
location.start = identifierEnd;
|
||||
}
|
||||
|
||||
return location;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Reduces an array of locations to remove items that are completely enclosed
|
||||
|
|
|
@ -5922,6 +5922,7 @@ return /******/ (function(modules) { // webpackBootstrap
|
|||
}
|
||||
|
||||
this.worker.removeEventListener("message", listener);
|
||||
|
||||
if (result.error) {
|
||||
reject(result.error);
|
||||
} else {
|
||||
|
|
|
@ -556,6 +556,7 @@ return /******/ (function(modules) { // webpackBootstrap
|
|||
}
|
||||
|
||||
this.worker.removeEventListener("message", listener);
|
||||
|
||||
if (result.error) {
|
||||
reject(result.error);
|
||||
} else {
|
||||
|
|
|
@ -45,6 +45,7 @@ support-files =
|
|||
[browser_dbg-breaking.js]
|
||||
[browser_dbg-breaking-from-console.js]
|
||||
[browser_dbg-breakpoints.js]
|
||||
[browser_dbg-breakpoints-reloading.js]
|
||||
[browser_dbg-breakpoints-cond.js]
|
||||
[browser_dbg-call-stack.js]
|
||||
[browser_dbg-expressions.js]
|
||||
|
@ -68,6 +69,9 @@ skip-if = os == "linux" # bug 1351952
|
|||
[browser_dbg-searching.js]
|
||||
skip-if = true
|
||||
[browser_dbg-sourcemaps.js]
|
||||
[browser_dbg-sourcemaps-reloading.js]
|
||||
[browser_dbg-sourcemaps2.js]
|
||||
[browser_dbg-sourcemaps-bogus.js]
|
||||
[browser_dbg-sources.js]
|
||||
[browser_dbg-tabs.js]
|
||||
[browser_dbg-toggling-tools.js]
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// Tests pending breakpoints when reloading
|
||||
|
||||
// Utilities for interacting with the editor
|
||||
function clickGutter(dbg, line) {
|
||||
clickElement(dbg, "gutter", line);
|
||||
}
|
||||
|
||||
function getLineEl(dbg, line) {
|
||||
const lines = dbg.win.document.querySelectorAll(".CodeMirror-code > div");
|
||||
return lines[line - 1];
|
||||
}
|
||||
|
||||
function addBreakpoint(dbg, line) {
|
||||
clickGutter(dbg, line);
|
||||
return waitForDispatch(dbg, "ADD_BREAKPOINT");
|
||||
}
|
||||
|
||||
function assertEditorBreakpoint(dbg, line) {
|
||||
const exists = !!getLineEl(dbg, line).querySelector(".new-breakpoint");
|
||||
ok(exists, `Breakpoint exists on line ${line}`);
|
||||
}
|
||||
|
||||
add_task(function*() {
|
||||
const dbg = yield initDebugger("doc-scripts.html");
|
||||
const { selectors: { getBreakpoints, getBreakpoint }, getState } = dbg;
|
||||
const source = findSource(dbg, "simple1.js");
|
||||
|
||||
yield selectSource(dbg, source.url);
|
||||
yield addBreakpoint(dbg, 5);
|
||||
yield addBreakpoint(dbg, 2);
|
||||
|
||||
yield reload(dbg, "simple1");
|
||||
yield waitForSelectedSource(dbg);
|
||||
assertEditorBreakpoint(dbg, 4);
|
||||
assertEditorBreakpoint(dbg, 5);
|
||||
});
|
|
@ -0,0 +1,52 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
add_task(function*() {
|
||||
// NOTE: the CORS call makes the test run times inconsistent
|
||||
requestLongerTimeout(2);
|
||||
|
||||
const dbg = yield initDebugger("doc-sourcemaps.html");
|
||||
const { selectors: { getBreakpoint, getBreakpoints }, getState } = dbg;
|
||||
|
||||
yield waitForSources(dbg, "entry.js", "output.js", "times2.js", "opts.js");
|
||||
ok(true, "Original sources exist");
|
||||
const entrySrc = findSource(dbg, "entry.js");
|
||||
|
||||
yield selectSource(dbg, entrySrc);
|
||||
ok(
|
||||
dbg.win.cm.getValue().includes("window.keepMeAlive"),
|
||||
"Original source text loaded correctly"
|
||||
);
|
||||
|
||||
// Test that breakpoint sliding is not attempted. The breakpoint
|
||||
// should not move anywhere.
|
||||
yield addBreakpoint(dbg, entrySrc, 13);
|
||||
is(getBreakpoints(getState()).size, 1, "One breakpoint exists");
|
||||
ok(
|
||||
getBreakpoint(getState(), { sourceId: entrySrc.id, line: 13 }),
|
||||
"Breakpoint has correct line"
|
||||
);
|
||||
|
||||
yield addBreakpoint(dbg, entrySrc, 15);
|
||||
yield disableBreakpoint(dbg, entrySrc, 15);
|
||||
|
||||
// Test reloading the debugger
|
||||
yield reload(dbg, "opts.js");
|
||||
yield waitForDispatch(dbg, "LOAD_SOURCE_TEXT");
|
||||
|
||||
is(getBreakpoints(getState()).size, 2, "One breakpoint exists");
|
||||
|
||||
ok(
|
||||
getBreakpoint(getState(), { sourceId: entrySrc.id, line: 13 }),
|
||||
"Breakpoint has correct line"
|
||||
);
|
||||
|
||||
ok(
|
||||
getBreakpoint(getState(), {
|
||||
sourceId: entrySrc.id,
|
||||
line: 15,
|
||||
disabled: true
|
||||
}),
|
||||
"Breakpoint has correct line"
|
||||
);
|
||||
});
|
|
@ -0,0 +1,39 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// Tests adding and removing tabs
|
||||
|
||||
function countTabs(dbg) {
|
||||
return findElement(dbg, "sourceTabs").children.length;
|
||||
}
|
||||
|
||||
add_task(function*() {
|
||||
let dbg = yield initDebugger("doc-scripts.html");
|
||||
|
||||
yield selectSource(dbg, "simple1");
|
||||
yield selectSource(dbg, "simple2");
|
||||
is(countTabs(dbg), 2);
|
||||
|
||||
// Test reloading the debugger
|
||||
yield reload(dbg, "simple1", "simple2");
|
||||
is(countTabs(dbg), 2);
|
||||
yield waitForSelectedSource(dbg);
|
||||
|
||||
// Test reloading the debuggee a second time
|
||||
yield reload(dbg, "simple1", "simple2");
|
||||
is(countTabs(dbg), 2);
|
||||
yield waitForSelectedSource(dbg);
|
||||
});
|
||||
|
||||
add_task(function*() {
|
||||
let dbg = yield initDebugger("doc-scripts.html", "simple1", "simple2");
|
||||
|
||||
yield selectSource(dbg, "simple1");
|
||||
yield selectSource(dbg, "simple2");
|
||||
closeTab(dbg, "simple1");
|
||||
closeTab(dbg, "simple2");
|
||||
|
||||
// Test reloading the debugger
|
||||
yield reload(dbg, "simple1", "simple2");
|
||||
is(countTabs(dbg), 0);
|
||||
});
|
|
@ -0,0 +1,38 @@
|
|||
// Return a promise with a reference to jsterm, opening the split
|
||||
// console if necessary. This cleans up the split console pref so
|
||||
// it won't pollute other tests.
|
||||
function getSplitConsole(dbg) {
|
||||
const { toolbox, win } = dbg;
|
||||
|
||||
registerCleanupFunction(() => {
|
||||
Services.prefs.clearUserPref("devtools.toolbox.splitconsoleEnabled");
|
||||
});
|
||||
|
||||
if (!win) {
|
||||
win = toolbox.win;
|
||||
}
|
||||
|
||||
if (!toolbox.splitConsole) {
|
||||
pressKey(dbg, "Escape");
|
||||
}
|
||||
|
||||
return new Promise(resolve => {
|
||||
toolbox.getPanelWhenReady("webconsole").then(() => {
|
||||
ok(toolbox.splitConsole, "Split console is shown.");
|
||||
let jsterm = toolbox.getPanel("webconsole").hud.jsterm;
|
||||
resolve(jsterm);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
add_task(function*() {
|
||||
const dbg = yield initDebugger("doc-scripts.html");
|
||||
|
||||
yield selectSource(dbg, "long");
|
||||
dbg.win.cm.scrollTo(0, 284);
|
||||
|
||||
pressKey(dbg, "inspector");
|
||||
pressKey(dbg, "debugger");
|
||||
|
||||
is(dbg.win.cm.getScrollInfo().top, 284);
|
||||
});
|
|
@ -191,6 +191,13 @@ function waitForElement(dbg, selector) {
|
|||
return waitUntil(() => findElementWithSelector(dbg, selector));
|
||||
}
|
||||
|
||||
function waitForSelectedSource(dbg) {
|
||||
return waitForState(dbg, state => {
|
||||
const source = dbg.selectors.getSelectedSource(state);
|
||||
return source && source.has("loading") && !source.get("loading");
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the debugger is paused at the correct location.
|
||||
*
|
||||
|
@ -215,10 +222,20 @@ function assertPausedLocation(dbg, source, line) {
|
|||
is(location.line, line);
|
||||
|
||||
// Check the debug line
|
||||
const lineInfo = getCM(dbg).lineInfo(line - 1);
|
||||
ok(
|
||||
getCM(dbg).lineInfo(line - 1).wrapClass.includes("debug-line"),
|
||||
lineInfo.wrapClass.includes("debug-line"),
|
||||
"Line is highlighted as paused"
|
||||
);
|
||||
|
||||
const markedSpans = lineInfo.handle.markedSpans;
|
||||
if (markedSpans && markedSpans.length > 0) {
|
||||
const marker = markedSpans[0].marker;
|
||||
ok(
|
||||
marker.className.includes("debug-expression"),
|
||||
"expression is highlighted as paused"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -381,12 +398,13 @@ function findSource(dbg, url) {
|
|||
function selectSource(dbg, url, line) {
|
||||
info("Selecting source: " + url);
|
||||
const source = findSource(dbg, url);
|
||||
const hasText = !!source.text && !source.loading;
|
||||
dbg.actions.selectSource(source.id, { line });
|
||||
|
||||
if (!hasText) {
|
||||
return waitForDispatch(dbg, "LOAD_SOURCE_TEXT");
|
||||
return dbg.actions.selectSource(source.id, { line });
|
||||
}
|
||||
|
||||
function closeTab(dbg, url) {
|
||||
info("Closing tab: " + url);
|
||||
const source = findSource(dbg, url);
|
||||
return dbg.actions.closeTab(source.url);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -460,7 +478,7 @@ function deleteExpression(dbg, input) {
|
|||
* @static
|
||||
*/
|
||||
function reload(dbg, ...sources) {
|
||||
return dbg.client.reload().then(() => waitForSources(...sources));
|
||||
return dbg.client.reload().then(() => waitForSources(dbg, ...sources));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -496,6 +514,13 @@ function addBreakpoint(dbg, source, line, col) {
|
|||
return waitForDispatch(dbg, "ADD_BREAKPOINT");
|
||||
}
|
||||
|
||||
function disableBreakpoint(dbg, source, line, col) {
|
||||
source = findSource(dbg, source);
|
||||
const sourceId = source.id;
|
||||
dbg.actions.disableBreakpoint({ sourceId, line, col });
|
||||
return waitForDispatch(dbg, "DISABLE_BREAKPOINT");
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a breakpoint from a source at line/col.
|
||||
*
|
||||
|
@ -558,6 +583,10 @@ function invokeInTab(fnc) {
|
|||
const isLinux = Services.appinfo.OS === "Linux";
|
||||
const isMac = Services.appinfo.OS === "Darwin";
|
||||
const cmdOrCtrl = isLinux ? { ctrlKey: true } : { metaKey: true };
|
||||
const shiftOrAlt = isMac
|
||||
? { accelKey: true, shiftKey: true }
|
||||
: { accelKey: true, altKey: true };
|
||||
|
||||
// On Mac, going to beginning/end only works with meta+left/right. On
|
||||
// Windows, it only works with home/end. On Linux, apparently, either
|
||||
// ctrl+left/right or home/end work.
|
||||
|
@ -567,7 +596,10 @@ const endKey = isMac
|
|||
const startKey = isMac
|
||||
? { code: "VK_LEFT", modifiers: cmdOrCtrl }
|
||||
: { code: "VK_HOME" };
|
||||
|
||||
const keyMappings = {
|
||||
debugger: { code: "s", modifiers: shiftOrAlt },
|
||||
inspector: { code: "c", modifiers: shiftOrAlt },
|
||||
sourceSearch: { code: "p", modifiers: cmdOrCtrl },
|
||||
fileSearch: { code: "f", modifiers: cmdOrCtrl },
|
||||
Enter: { code: "VK_RETURN" },
|
||||
|
@ -640,6 +672,7 @@ const selectors = {
|
|||
highlightLine: ".CodeMirror-code > .highlight-line",
|
||||
codeMirror: ".CodeMirror",
|
||||
resume: ".resume.active",
|
||||
sourceTabs: `.source-tabs`,
|
||||
stepOver: ".stepOver.active",
|
||||
stepOut: ".stepOut.active",
|
||||
stepIn: ".stepIn.active",
|
||||
|
|
|
@ -29,6 +29,7 @@ devtools.jar:
|
|||
content/sourceeditor/codemirror/codemirror.bundle.js (sourceeditor/codemirror/codemirror.bundle.js)
|
||||
content/sourceeditor/codemirror/lib/codemirror.css (sourceeditor/codemirror/lib/codemirror.css)
|
||||
content/sourceeditor/codemirror/mozilla.css (sourceeditor/codemirror/mozilla.css)
|
||||
content/sourceeditor/codemirror/cmiframe.html (sourceeditor/codemirror/cmiframe.html)
|
||||
content/sourceeditor/codemirror/old-debugger.css (sourceeditor/codemirror/old-debugger.css)
|
||||
content/debugger/new/index.html (debugger/new/index.html)
|
||||
content/debugger/debugger.xul (debugger/debugger.xul)
|
||||
|
|
|
@ -115,7 +115,7 @@ const RequestListHeader = createClass({
|
|||
id: `requests-list-${name}-button`,
|
||||
className: `requests-list-header-button`,
|
||||
"data-sorted": sorted,
|
||||
title: sortedTitle,
|
||||
title: sortedTitle ? `${label} (${sortedTitle})` : label,
|
||||
onClick: () => sortBy(name),
|
||||
},
|
||||
name === "waterfall"
|
||||
|
|
|
@ -72,6 +72,7 @@ support-files =
|
|||
[browser_net_charts-06.js]
|
||||
[browser_net_charts-07.js]
|
||||
[browser_net_clear.js]
|
||||
[browser_net_column_headers_tooltips.js]
|
||||
[browser_net_columns_last_column.js]
|
||||
[browser_net_columns_pref.js]
|
||||
[browser_net_columns_reset.js]
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* Bug 1377094 - Test that all column headers have tooltips.
|
||||
*/
|
||||
|
||||
add_task(function* () {
|
||||
let { monitor } = yield initNetMonitor(SIMPLE_URL);
|
||||
info("Starting test... ");
|
||||
|
||||
let { document } = monitor.panelWin;
|
||||
|
||||
let headers = document.querySelectorAll(".requests-list-header-button");
|
||||
for (let header of headers) {
|
||||
const buttonText = header.querySelector(".button-text").textContent;
|
||||
const tooltip = header.getAttribute("title");
|
||||
is(buttonText, tooltip,
|
||||
"The " + header.id + " header has the button text in its 'title' attribute.");
|
||||
}
|
||||
|
||||
yield teardown(monitor);
|
||||
});
|
|
@ -117,15 +117,19 @@ add_task(function* () {
|
|||
if (header != target) {
|
||||
ok(!header.hasAttribute("data-sorted"),
|
||||
"The " + header.id + " header does not have a 'data-sorted' attribute.");
|
||||
ok(!header.getAttribute("title"),
|
||||
"The " + header.id + " header does not have a 'title' attribute.");
|
||||
ok(!header.getAttribute("title").includes(L10N.getStr("networkMenu.sortedAsc")) &&
|
||||
!header.getAttribute("title").includes(L10N.getStr("networkMenu.sortedDesc")),
|
||||
"The " + header.id +
|
||||
" header does not include any sorting in the 'title' attribute.");
|
||||
} else {
|
||||
is(header.getAttribute("data-sorted"), direction,
|
||||
"The " + header.id + " header has a correct 'data-sorted' attribute.");
|
||||
is(header.getAttribute("title"), direction == "ascending"
|
||||
const sorted = direction == "ascending"
|
||||
? L10N.getStr("networkMenu.sortedAsc")
|
||||
: L10N.getStr("networkMenu.sortedDesc"),
|
||||
"The " + header.id + " header has a correct 'title' attribute.");
|
||||
: L10N.getStr("networkMenu.sortedDesc");
|
||||
ok(header.getAttribute("title").includes(sorted),
|
||||
"The " + header.id +
|
||||
" header includes the used sorting in the 'title' attribute.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -208,15 +208,19 @@ add_task(function* () {
|
|||
if (header != target) {
|
||||
ok(!header.hasAttribute("data-sorted"),
|
||||
"The " + header.id + " header does not have a 'data-sorted' attribute.");
|
||||
ok(!header.getAttribute("title"),
|
||||
"The " + header.id + " header does not have a 'title' attribute.");
|
||||
ok(!header.getAttribute("title").includes(L10N.getStr("networkMenu.sortedAsc")) &&
|
||||
!header.getAttribute("title").includes(L10N.getStr("networkMenu.sortedDesc")),
|
||||
"The " + header.id +
|
||||
" header does not include any sorting in the 'title' attribute.");
|
||||
} else {
|
||||
is(header.getAttribute("data-sorted"), direction,
|
||||
"The " + header.id + " header has a correct 'data-sorted' attribute.");
|
||||
is(header.getAttribute("title"), direction == "ascending"
|
||||
const sorted = direction == "ascending"
|
||||
? L10N.getStr("networkMenu.sortedAsc")
|
||||
: L10N.getStr("networkMenu.sortedDesc"),
|
||||
"The " + header.id + " header has a correct 'title' attribute.");
|
||||
: L10N.getStr("networkMenu.sortedDesc");
|
||||
ok(header.getAttribute("title").includes(sorted),
|
||||
"The " + header.id +
|
||||
" header includes the used sorting in the 'title' attribute.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
<!DOCTYPE html>
|
||||
<html dir='ltr'>
|
||||
<head>
|
||||
<style id="cmBaseStyle">
|
||||
html, body { height: 100%; }
|
||||
body { margin: 0; overflow: hidden; }
|
||||
.CodeMirror { width: 100% !important; line-height: 1.25 !important; }
|
||||
</style>
|
||||
<link rel='stylesheet' href="chrome://devtools/content/sourceeditor/codemirror/lib/codemirror.css">
|
||||
<link rel='stylesheet' href="chrome://devtools/content/sourceeditor/codemirror/addon/dialog/dialog.css">
|
||||
<link rel='stylesheet' href="chrome://devtools/content/sourceeditor/codemirror/mozilla.css">
|
||||
<link rel='stylesheet' href="chrome://devtools/content/sourceeditor/codemirror/old-debugger.css">
|
||||
</head>
|
||||
<body class='theme-body devtools-monospace'></body>
|
||||
</html>
|
|
@ -48,37 +48,14 @@ const {
|
|||
|
||||
const { OS } = Services.appinfo;
|
||||
|
||||
// CM_STYLES, CM_SCRIPTS and CM_IFRAME represent the HTML,
|
||||
// JavaScript and CSS that is injected into an iframe in
|
||||
// order to initialize a CodeMirror instance.
|
||||
|
||||
const CM_STYLES = [
|
||||
"chrome://devtools/content/sourceeditor/codemirror/lib/codemirror.css",
|
||||
"chrome://devtools/content/sourceeditor/codemirror/addon/dialog/dialog.css",
|
||||
"chrome://devtools/content/sourceeditor/codemirror/mozilla.css"
|
||||
];
|
||||
|
||||
CM_STYLES.push(
|
||||
"chrome://devtools/content/sourceeditor/codemirror/old-debugger.css"
|
||||
);
|
||||
// CM_SCRIPTS and CM_IFRAME represent the HTML and JavaScript that is
|
||||
// injected into an iframe in order to initialize a CodeMirror instance.
|
||||
|
||||
const CM_SCRIPTS = [
|
||||
"chrome://devtools/content/sourceeditor/codemirror/codemirror.bundle.js",
|
||||
];
|
||||
|
||||
const CM_IFRAME =
|
||||
"data:text/html;charset=utf8,<!DOCTYPE html>" +
|
||||
"<html dir='ltr'>" +
|
||||
" <head>" +
|
||||
" <style>" +
|
||||
" html, body { height: 100%; }" +
|
||||
" body { margin: 0; overflow: hidden; }" +
|
||||
" .CodeMirror { width: 100% !important; line-height: 1.25 !important; }" +
|
||||
" </style>" +
|
||||
CM_STYLES.map(style => "<link rel='stylesheet' href='" + style + "'>").join("\n") +
|
||||
" </head>" +
|
||||
" <body class='theme-body devtools-monospace'></body>" +
|
||||
"</html>";
|
||||
const CM_IFRAME = "chrome://devtools/content/sourceeditor/codemirror/cmiframe.html";
|
||||
|
||||
const CM_MAPPING = [
|
||||
"focus",
|
||||
|
|
|
@ -8,8 +8,9 @@ function test() {
|
|||
waitForExplicitFinish();
|
||||
setup((ed, win) => {
|
||||
// appendTo
|
||||
let src = win.document.querySelector("iframe").getAttribute("src");
|
||||
ok(~src.indexOf(".CodeMirror"), "correct iframe is there");
|
||||
let cmFrame = win.document.querySelector("iframe");
|
||||
let cmStyle = cmFrame.contentDocument.getElementById("cmBaseStyle");
|
||||
ok(~cmStyle.innerHTML.indexOf(".CodeMirror"), "correct iframe is there");
|
||||
|
||||
// getOption/setOption
|
||||
ok(ed.getOption("styleActiveLine"), "getOption works");
|
||||
|
|
|
@ -197,7 +197,8 @@ Link::LinkState() const
|
|||
|
||||
// If we have not yet registered for notifications and need to,
|
||||
// due to our href changing, register now!
|
||||
if (!mRegistered && mNeedsRegistration && element->IsInComposedDoc()) {
|
||||
if (!mRegistered && mNeedsRegistration && element->IsInComposedDoc() &&
|
||||
!HasPendingLinkUpdate()) {
|
||||
// Only try and register once.
|
||||
self->mNeedsRegistration = false;
|
||||
|
||||
|
|
|
@ -126,7 +126,7 @@ public:
|
|||
void TryDNSPrefetchPreconnectOrPrefetchOrPrerender();
|
||||
void CancelPrefetch();
|
||||
|
||||
bool HasPendingLinkUpdate() { return mHasPendingLinkUpdate; }
|
||||
bool HasPendingLinkUpdate() const { return mHasPendingLinkUpdate; }
|
||||
void SetHasPendingLinkUpdate() { mHasPendingLinkUpdate = true; }
|
||||
void ClearHasPendingLinkUpdate() { mHasPendingLinkUpdate = false; }
|
||||
|
||||
|
|
|
@ -0,0 +1,196 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "XPathGenerator.h"
|
||||
|
||||
#include "nsGkAtoms.h"
|
||||
#include "Element.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
/**
|
||||
* Check whether a character is a non-word character. A non-word character is a
|
||||
* character that isn't in ('a'..'z') or in ('A'..'Z') or a number or an underscore.
|
||||
* */
|
||||
bool IsNonWordCharacter(const char16_t& aChar)
|
||||
{
|
||||
if (((char16_t('A') <= aChar) && (aChar <= char16_t('Z'))) ||
|
||||
((char16_t('a') <= aChar) && (aChar <= char16_t('z'))) ||
|
||||
((char16_t('0') <= aChar) && (aChar <= char16_t('9'))) ||
|
||||
(aChar == char16_t('_'))) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether a string contains a non-word character.
|
||||
* */
|
||||
bool ContainNonWordCharacter(const nsAString& aStr)
|
||||
{
|
||||
const char16_t* cur = aStr.BeginReading();
|
||||
const char16_t* end = aStr.EndReading();
|
||||
for (; cur < end; ++cur) {
|
||||
if (IsNonWordCharacter(*cur)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the prefix according to the given namespace and assign the result to aResult.
|
||||
* */
|
||||
void GetPrefix(const nsINode* aNode, nsAString& aResult)
|
||||
{
|
||||
if (aNode->IsXULElement()) {
|
||||
aResult.Assign(NS_LITERAL_STRING("xul"));
|
||||
} else if (aNode->IsHTMLElement()) {
|
||||
aResult.Assign(NS_LITERAL_STRING("xhtml"));
|
||||
}
|
||||
}
|
||||
|
||||
void GetNameAttribute(const nsINode* aNode, nsAString& aResult)
|
||||
{
|
||||
if (aNode->HasName()) {
|
||||
const Element* elem = aNode->AsElement();
|
||||
elem->GetAttr(kNameSpaceID_None, nsGkAtoms::name, aResult);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Put all sequences of ' in a string in between '," and ",' . And then put
|
||||
* the result string in between concat(' and ').
|
||||
*
|
||||
* For example, a string 'a'' will return result concat('',"'",'a',"''",'')
|
||||
* */
|
||||
void GenerateConcatExpression(const nsAString& aStr, nsAString& aResult)
|
||||
{
|
||||
const char16_t* cur = aStr.BeginReading();
|
||||
const char16_t* end = aStr.EndReading();
|
||||
|
||||
// Put all sequences of ' in between '," and ",'
|
||||
nsAutoString result;
|
||||
const char16_t* nonQuoteBeginPtr = nullptr;
|
||||
const char16_t* quoteBeginPtr = nullptr;
|
||||
for (; cur < end; ++cur) {
|
||||
if (char16_t('\'') == *cur) {
|
||||
if (nonQuoteBeginPtr) {
|
||||
result.Append(nonQuoteBeginPtr, cur - nonQuoteBeginPtr);
|
||||
nonQuoteBeginPtr = nullptr;
|
||||
}
|
||||
if (!quoteBeginPtr) {
|
||||
result.Append(NS_LITERAL_STRING("\',\""));
|
||||
quoteBeginPtr = cur;
|
||||
}
|
||||
} else {
|
||||
if (!nonQuoteBeginPtr) {
|
||||
nonQuoteBeginPtr = cur;
|
||||
}
|
||||
if (quoteBeginPtr) {
|
||||
result.Append(quoteBeginPtr, cur - quoteBeginPtr);
|
||||
result.Append(NS_LITERAL_STRING("\",\'"));
|
||||
quoteBeginPtr = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (quoteBeginPtr) {
|
||||
result.Append(quoteBeginPtr, cur - quoteBeginPtr);
|
||||
result.Append(NS_LITERAL_STRING("\",\'"));
|
||||
} else if (nonQuoteBeginPtr) {
|
||||
result.Append(nonQuoteBeginPtr, cur - nonQuoteBeginPtr);
|
||||
}
|
||||
|
||||
// Prepend concat(' and append ').
|
||||
aResult.Assign(NS_LITERAL_STRING("concat(\'") + result + NS_LITERAL_STRING("\')"));
|
||||
}
|
||||
|
||||
void XPathGenerator::QuoteArgument(const nsAString& aArg, nsAString& aResult)
|
||||
{
|
||||
if (!aArg.Contains('\'')) {
|
||||
aResult.Assign(NS_LITERAL_STRING("\'") + aArg + NS_LITERAL_STRING("\'"));
|
||||
} else if (!aArg.Contains('\"')) {
|
||||
aResult.Assign(NS_LITERAL_STRING("\"") + aArg + NS_LITERAL_STRING("\""));
|
||||
} else {
|
||||
GenerateConcatExpression(aArg, aResult);
|
||||
}
|
||||
}
|
||||
|
||||
void XPathGenerator::EscapeName(const nsAString& aName, nsAString& aResult)
|
||||
{
|
||||
if (ContainNonWordCharacter(aName)) {
|
||||
nsAutoString quotedArg;
|
||||
QuoteArgument(aName, quotedArg);
|
||||
aResult.Assign(NS_LITERAL_STRING("*[local-name()=") + quotedArg + NS_LITERAL_STRING("]"));
|
||||
} else {
|
||||
aResult.Assign(aName);
|
||||
}
|
||||
}
|
||||
|
||||
void XPathGenerator::Generate(const nsINode* aNode, nsAString& aResult)
|
||||
{
|
||||
if (!aNode->GetParentNode()) {
|
||||
aResult.Truncate();
|
||||
return;
|
||||
}
|
||||
|
||||
nsAutoString nodeNamespaceURI;
|
||||
aNode->GetNamespaceURI(nodeNamespaceURI);
|
||||
const nsString& nodeLocalName = aNode->LocalName();
|
||||
|
||||
nsAutoString prefix;
|
||||
nsAutoString tag;
|
||||
nsAutoString nodeEscapeName;
|
||||
GetPrefix(aNode, prefix);
|
||||
EscapeName(nodeLocalName, nodeEscapeName);
|
||||
if (prefix.IsEmpty()) {
|
||||
tag.Assign(nodeEscapeName);
|
||||
} else {
|
||||
tag.Assign(prefix + NS_LITERAL_STRING(":") + nodeEscapeName);
|
||||
}
|
||||
|
||||
if (aNode->HasID()) {
|
||||
// this must be an element
|
||||
const Element* elem = aNode->AsElement();
|
||||
nsAutoString elemId;
|
||||
nsAutoString quotedArgument;
|
||||
elem->GetId(elemId);
|
||||
QuoteArgument(elemId, quotedArgument);
|
||||
aResult.Assign(NS_LITERAL_STRING("//") + tag + NS_LITERAL_STRING("[@id=") +
|
||||
quotedArgument + NS_LITERAL_STRING("]"));
|
||||
return;
|
||||
}
|
||||
|
||||
int32_t count = 1;
|
||||
nsAutoString nodeNameAttribute;
|
||||
GetNameAttribute(aNode, nodeNameAttribute);
|
||||
for (const Element* e = aNode->GetPreviousElementSibling(); e; e = e->GetPreviousElementSibling()) {
|
||||
nsAutoString elementNamespaceURI;
|
||||
e->GetNamespaceURI(elementNamespaceURI);
|
||||
nsAutoString elementNameAttribute;
|
||||
GetNameAttribute(e, elementNameAttribute);
|
||||
if (e->LocalName().Equals(nodeLocalName) && elementNamespaceURI.Equals(nodeNamespaceURI) &&
|
||||
(nodeNameAttribute.IsEmpty() || elementNameAttribute.Equals(nodeNameAttribute))) {
|
||||
++count;
|
||||
}
|
||||
}
|
||||
|
||||
nsAutoString namePart;
|
||||
nsAutoString countPart;
|
||||
if (!nodeNameAttribute.IsEmpty()) {
|
||||
nsAutoString quotedArgument;
|
||||
QuoteArgument(nodeNameAttribute, quotedArgument);
|
||||
namePart.Assign(NS_LITERAL_STRING("[@name=") + quotedArgument + NS_LITERAL_STRING("]"));
|
||||
}
|
||||
if (count != 1) {
|
||||
countPart.Assign(NS_LITERAL_STRING("["));
|
||||
countPart.AppendInt(count);
|
||||
countPart.Append(NS_LITERAL_STRING("]"));
|
||||
}
|
||||
Generate(aNode->GetParentNode(), aResult);
|
||||
aResult.Append(NS_LITERAL_STRING("/") + tag + namePart + countPart);
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef XPATHGENERATOR_H__
|
||||
#define XPATHGENERATOR_H__
|
||||
#include "nsString.h"
|
||||
#include "nsINode.h"
|
||||
|
||||
class XPathGenerator
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Return a properly quoted string to insert into an XPath
|
||||
* */
|
||||
static void QuoteArgument(const nsAString& aArg, nsAString& aResult);
|
||||
|
||||
/**
|
||||
* Return a valid XPath for the given node (usually the local name itself)
|
||||
* */
|
||||
static void EscapeName(const nsAString& aName, nsAString& aResult);
|
||||
|
||||
/**
|
||||
* Generate an approximate XPath query to an (X)HTML node
|
||||
* */
|
||||
static void Generate(const nsINode* aNode, nsAString& aResult);
|
||||
};
|
||||
|
||||
#endif
|
|
@ -128,6 +128,7 @@ EXPORTS += [
|
|||
'nsWrapperCache.h',
|
||||
'nsWrapperCacheInlines.h',
|
||||
'nsXMLNameSpaceMap.h',
|
||||
'XPathGenerator.h',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_WEBRTC']:
|
||||
|
@ -362,6 +363,7 @@ UNIFIED_SOURCES += [
|
|||
'WebSocket.cpp',
|
||||
'WindowNamedPropertiesHandler.cpp',
|
||||
'WindowOrientationObserver.cpp',
|
||||
'XPathGenerator.cpp',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_WEBRTC']:
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "nsGkAtoms.h"
|
||||
#include "nsGlobalWindow.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsIContentParent.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsIEditor.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
|
|
|
@ -113,6 +113,7 @@ GK_ATOM(aria_autocomplete, "aria-autocomplete")
|
|||
GK_ATOM(aria_busy, "aria-busy")
|
||||
GK_ATOM(aria_checked, "aria-checked")
|
||||
GK_ATOM(aria_controls, "aria-controls")
|
||||
GK_ATOM(aria_current, "aria-current")
|
||||
GK_ATOM(aria_describedby, "aria-describedby")
|
||||
GK_ATOM(aria_disabled, "aria-disabled")
|
||||
GK_ATOM(aria_dropeffect, "aria-dropeffect")
|
||||
|
|
|
@ -108,6 +108,8 @@
|
|||
#include "mozilla/dom/NodeBinding.h"
|
||||
#include "mozilla/dom/BindingDeclarations.h"
|
||||
|
||||
#include "XPathGenerator.h"
|
||||
|
||||
#ifdef ACCESSIBILITY
|
||||
#include "mozilla/dom/AccessibleNode.h"
|
||||
#endif
|
||||
|
@ -3023,6 +3025,12 @@ nsINode::AddAnimationObserverUnlessExists(
|
|||
OwnerDoc()->SetMayHaveAnimationObservers();
|
||||
}
|
||||
|
||||
void
|
||||
nsINode::GenerateXPath(nsAString& aResult)
|
||||
{
|
||||
XPathGenerator::Generate(this, aResult);
|
||||
}
|
||||
|
||||
bool
|
||||
nsINode::IsApzAware() const
|
||||
{
|
||||
|
|
|
@ -1751,6 +1751,7 @@ public:
|
|||
void UnbindObject(nsISupports* aObject);
|
||||
|
||||
void GetBoundMutationObservers(nsTArray<RefPtr<nsDOMMutationObserver> >& aResult);
|
||||
void GenerateXPath(nsAString& aResult);
|
||||
|
||||
already_AddRefed<mozilla::dom::AccessibleNode> GetAccessibleNode();
|
||||
|
||||
|
|
|
@ -0,0 +1,140 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "XPathGenerator.h"
|
||||
#include "nsString.h"
|
||||
|
||||
TEST(TestXPathGenerator, TestQuoteArgumentWithoutQuote)
|
||||
{
|
||||
nsAutoString arg;
|
||||
arg.Assign(NS_LITERAL_STRING("testing"));
|
||||
|
||||
nsAutoString expectedResult;
|
||||
expectedResult.Assign(NS_LITERAL_STRING("\'testing\'"));
|
||||
|
||||
nsAutoString result;
|
||||
XPathGenerator::QuoteArgument(arg, result);
|
||||
|
||||
ASSERT_TRUE(expectedResult.Equals(result));
|
||||
}
|
||||
|
||||
TEST(TestXPathGenerator, TestQuoteArgumentWithSingleQuote)
|
||||
{
|
||||
nsAutoString arg;
|
||||
arg.Assign(NS_LITERAL_STRING("\'testing\'"));
|
||||
|
||||
nsAutoString expectedResult;
|
||||
expectedResult.Assign(NS_LITERAL_STRING("\"\'testing\'\""));
|
||||
|
||||
nsAutoString result;
|
||||
XPathGenerator::QuoteArgument(arg, result);
|
||||
|
||||
ASSERT_TRUE(expectedResult.Equals(result));
|
||||
}
|
||||
|
||||
TEST(TestXPathGenerator, TestQuoteArgumentWithDoubleQuote)
|
||||
{
|
||||
nsAutoString arg;
|
||||
arg.Assign(NS_LITERAL_STRING("\"testing\""));
|
||||
|
||||
nsAutoString expectedResult;
|
||||
expectedResult.Assign(NS_LITERAL_STRING("\'\"testing\"\'"));
|
||||
|
||||
nsAutoString result;
|
||||
XPathGenerator::QuoteArgument(arg, result);
|
||||
|
||||
ASSERT_TRUE(expectedResult.Equals(result));
|
||||
}
|
||||
|
||||
TEST(TestXPathGenerator, TestQuoteArgumentWithSingleAndDoubleQuote)
|
||||
{
|
||||
nsAutoString arg;
|
||||
arg.Assign(NS_LITERAL_STRING("\'testing\""));
|
||||
|
||||
nsAutoString expectedResult;
|
||||
expectedResult.Assign(NS_LITERAL_STRING("concat(\'\',\"\'\",\'testing\"\')"));
|
||||
|
||||
nsAutoString result;
|
||||
XPathGenerator::QuoteArgument(arg, result);
|
||||
printf("Result: %s\nExpected: %s\n", NS_ConvertUTF16toUTF8(result).get(), NS_ConvertUTF16toUTF8(expectedResult).get());
|
||||
|
||||
ASSERT_TRUE(expectedResult.Equals(result));
|
||||
}
|
||||
|
||||
TEST(TestXPathGenerator, TestQuoteArgumentWithDoubleQuoteAndASequenceOfSingleQuote)
|
||||
{
|
||||
nsAutoString arg;
|
||||
arg.Assign(NS_LITERAL_STRING("\'\'\'\'testing\""));
|
||||
|
||||
nsAutoString expectedResult;
|
||||
expectedResult.Assign(NS_LITERAL_STRING("concat(\'\',\"\'\'\'\'\",\'testing\"\')"));
|
||||
|
||||
nsAutoString result;
|
||||
XPathGenerator::QuoteArgument(arg, result);
|
||||
printf("Result: %s\nExpected: %s\n", NS_ConvertUTF16toUTF8(result).get(), NS_ConvertUTF16toUTF8(expectedResult).get());
|
||||
|
||||
ASSERT_TRUE(expectedResult.Equals(result));
|
||||
}
|
||||
|
||||
TEST(TestXPathGenerator, TestQuoteArgumentWithDoubleQuoteAndTwoSequencesOfSingleQuote)
|
||||
{
|
||||
nsAutoString arg;
|
||||
arg.Assign(NS_LITERAL_STRING("\'\'\'\'testing\'\'\'\'\'\'\""));
|
||||
|
||||
nsAutoString expectedResult;
|
||||
expectedResult.Assign(NS_LITERAL_STRING("concat(\'\',\"\'\'\'\'\",\'testing\',\"\'\'\'\'\'\'\",\'\"\')"));
|
||||
|
||||
nsAutoString result;
|
||||
XPathGenerator::QuoteArgument(arg, result);
|
||||
printf("Result: %s\nExpected: %s\n", NS_ConvertUTF16toUTF8(result).get(), NS_ConvertUTF16toUTF8(expectedResult).get());
|
||||
|
||||
ASSERT_TRUE(expectedResult.Equals(result));
|
||||
}
|
||||
|
||||
TEST(TestXPathGenerator, TestQuoteArgumentWithDoubleQuoteAndTwoSequencesOfSingleQuoteInMiddle)
|
||||
{
|
||||
nsAutoString arg;
|
||||
arg.Assign(NS_LITERAL_STRING("t\'\'\'\'estin\'\'\'\'\'\'\"g"));
|
||||
|
||||
nsAutoString expectedResult;
|
||||
expectedResult.Assign(NS_LITERAL_STRING("concat(\'t\',\"\'\'\'\'\",\'estin\',\"\'\'\'\'\'\'\",\'\"g\')"));
|
||||
|
||||
nsAutoString result;
|
||||
XPathGenerator::QuoteArgument(arg, result);
|
||||
printf("Result: %s\nExpected: %s\n", NS_ConvertUTF16toUTF8(result).get(), NS_ConvertUTF16toUTF8(expectedResult).get());
|
||||
|
||||
ASSERT_TRUE(expectedResult.Equals(result));
|
||||
}
|
||||
|
||||
TEST(TestXPathGenerator, TestEscapeNameWithNormalCharacters)
|
||||
{
|
||||
nsAutoString arg;
|
||||
arg.Assign(NS_LITERAL_STRING("testing"));
|
||||
|
||||
nsAutoString expectedResult;
|
||||
expectedResult.Assign(NS_LITERAL_STRING("testing"));
|
||||
|
||||
nsAutoString result;
|
||||
XPathGenerator::EscapeName(arg, result);
|
||||
|
||||
ASSERT_TRUE(expectedResult.Equals(result));
|
||||
}
|
||||
|
||||
TEST(TestXPathGenerator, TestEscapeNameWithSpecialCharacters)
|
||||
{
|
||||
nsAutoString arg;
|
||||
arg.Assign(NS_LITERAL_STRING("^testing!"));
|
||||
|
||||
nsAutoString expectedResult;
|
||||
expectedResult.Assign(NS_LITERAL_STRING("*[local-name()=\'^testing!\']"));
|
||||
|
||||
nsAutoString result;
|
||||
XPathGenerator::EscapeName(arg, result);
|
||||
printf("Result: %s\nExpected: %s\n", NS_ConvertUTF16toUTF8(result).get(), NS_ConvertUTF16toUTF8(expectedResult).get());
|
||||
|
||||
ASSERT_TRUE(expectedResult.Equals(result));
|
||||
}
|
|
@ -8,6 +8,7 @@ UNIFIED_SOURCES += [
|
|||
'TestNativeXMLHttpRequest.cpp',
|
||||
'TestParserDialogOptions.cpp',
|
||||
'TestPlainTextSerializer.cpp',
|
||||
'TestXPathGenerator.cpp',
|
||||
]
|
||||
|
||||
LOCAL_INCLUDES += [
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
function run_test()
|
||||
{
|
||||
test_generate_xpath();
|
||||
}
|
||||
|
||||
// TEST CODE
|
||||
|
||||
function test_generate_xpath()
|
||||
{
|
||||
let docString = `
|
||||
<html>
|
||||
<body>
|
||||
<label><input type="checkbox" id="input1" />Input 1</label>
|
||||
<label><input type="checkbox" id="input2'" />Input 2</label>
|
||||
<label><input type="checkbox" id='"input3"' />Input 3</label>
|
||||
<label><input type="checkbox"/>Input 4</label>
|
||||
<label><input type="checkbox" />Input 5</label>
|
||||
</body>
|
||||
</html>
|
||||
`;
|
||||
let doc = DOMParser().parseFromString(docString, "text/html");
|
||||
|
||||
// Test generate xpath for body.
|
||||
do_print("Test generate xpath for body node");
|
||||
let body = doc.getElementsByTagName("body")[0];
|
||||
let bodyXPath = body.generateXPath();
|
||||
let bodyExpXPath = "/xhtml:html/xhtml:body";
|
||||
equal(bodyExpXPath, bodyXPath, " xpath generated for body");
|
||||
|
||||
// Test generate xpath for input with id.
|
||||
do_print("Test generate xpath for input with id");
|
||||
let inputWithId = doc.getElementById("input1");
|
||||
let inputWithIdXPath = inputWithId.generateXPath();
|
||||
let inputWithIdExpXPath = "//xhtml:input[@id='input1']";
|
||||
equal(inputWithIdExpXPath, inputWithIdXPath, " xpath generated for input with id");
|
||||
|
||||
// Test generate xpath for input with id has single quote.
|
||||
do_print("Test generate xpath for input with id has single quote");
|
||||
let inputWithIdSingleQuote = doc.getElementsByTagName("input")[1];
|
||||
let inputWithIdXPathSingleQuote = inputWithIdSingleQuote.generateXPath();
|
||||
let inputWithIdExpXPathSingleQuote = '//xhtml:input[@id="input2\'"]';
|
||||
equal(inputWithIdExpXPathSingleQuote, inputWithIdXPathSingleQuote, " xpath generated for input with id");
|
||||
|
||||
// Test generate xpath for input with id has double quote.
|
||||
do_print("Test generate xpath for input with id has double quote");
|
||||
let inputWithIdDoubleQuote = doc.getElementsByTagName("input")[2];
|
||||
let inputWithIdXPathDoubleQuote = inputWithIdDoubleQuote.generateXPath();
|
||||
let inputWithIdExpXPathDoubleQuote = "//xhtml:input[@id='\"input3\"']";
|
||||
equal(inputWithIdExpXPathDoubleQuote, inputWithIdXPathDoubleQuote, " xpath generated for input with id");
|
||||
|
||||
// Test generate xpath for input with id has both single and double quote.
|
||||
do_print("Test generate xpath for input with id has single and double quote");
|
||||
let inputWithIdSingleDoubleQuote = doc.getElementsByTagName("input")[3];
|
||||
inputWithIdSingleDoubleQuote.setAttribute("id", "\"input'4");
|
||||
let inputWithIdXPathSingleDoubleQuote = inputWithIdSingleDoubleQuote.generateXPath();
|
||||
let inputWithIdExpXPathSingleDoubleQuote = "//xhtml:input[@id=concat('\"input',\"'\",'4')]";
|
||||
equal(inputWithIdExpXPathSingleDoubleQuote, inputWithIdXPathSingleDoubleQuote, " xpath generated for input with id");
|
||||
|
||||
// Test generate xpath for input without id.
|
||||
do_print("Test generate xpath for input without id");
|
||||
let inputNoId = doc.getElementsByTagName("input")[4];
|
||||
let inputNoIdXPath = inputNoId.generateXPath();
|
||||
let inputNoIdExpXPath = "/xhtml:html/xhtml:body/xhtml:label[5]/xhtml:input";
|
||||
equal(inputNoIdExpXPath, inputNoIdXPath, " xpath generated for input without id");
|
||||
}
|
|
@ -52,3 +52,6 @@ head = head_xml.js
|
|||
[test_xmlserializer.js]
|
||||
[test_cancelPrefetch.js]
|
||||
[test_chromeutils_base64.js]
|
||||
[test_generate_xpath.js]
|
||||
head = head_xml.js
|
||||
|
||||
|
|
|
@ -764,7 +764,7 @@ ContentChild::ProvideWindowCommon(TabChild* aTabOpener,
|
|||
// different process if we have noopener set, but we also might if we can't
|
||||
// load in the current process.
|
||||
bool loadInDifferentProcess = aForceNoOpener && sNoopenerNewProcess;
|
||||
if (aTabOpener && !loadInDifferentProcess) {
|
||||
if (aTabOpener && !loadInDifferentProcess && aURI) {
|
||||
nsCOMPtr<nsIWebBrowserChrome3> browserChrome3;
|
||||
rv = aTabOpener->GetWebBrowserChrome(getter_AddRefs(browserChrome3));
|
||||
if (NS_SUCCEEDED(rv) && browserChrome3) {
|
||||
|
|
|
@ -40,6 +40,9 @@ alert = alert
|
|||
alertDialog = alert dialog
|
||||
article = article
|
||||
document = document
|
||||
# The (spoken) role description for the WAI-ARIA figure role
|
||||
# https://w3c.github.io/aria/core-aam/core-aam.html#role-map-figure
|
||||
figure = figure
|
||||
# The (spoken) role description for the WAI-ARIA heading role
|
||||
# https://w3c.github.io/aria/core-aam/core-aam.html#role-map-heading
|
||||
heading = heading
|
||||
|
|
|
@ -325,13 +325,10 @@ URLMainThread::UpdateURLSearchParams()
|
|||
}
|
||||
|
||||
nsAutoCString search;
|
||||
nsCOMPtr<nsIURL> url(do_QueryInterface(mURI));
|
||||
if (url) {
|
||||
nsresult rv = url->GetQuery(search);
|
||||
nsresult rv = mURI->GetQuery(search);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
search.Truncate();
|
||||
}
|
||||
}
|
||||
|
||||
mSearchParams->ParseInput(search);
|
||||
}
|
||||
|
|
|
@ -47,8 +47,14 @@ function testURL() {
|
|||
url.searchParams.set('e', 'f');
|
||||
ok(url.href.indexOf('e=f') != 1, 'URL right');
|
||||
|
||||
|
||||
url = new URL('mailto:a@b.com?subject=Hi');
|
||||
ok(url.searchParams, "URL searchParams exists!");
|
||||
ok(url.searchParams.has('subject'), "Hi");
|
||||
|
||||
runTest();
|
||||
}
|
||||
|
||||
function testParserURLSearchParams() {
|
||||
var checks = [
|
||||
{ input: '', data: {} },
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
// This file defines dictionaries used by about:networking page.
|
||||
|
||||
dictionary SocketElement {
|
||||
DOMString host = "";
|
||||
unsigned long port = 0;
|
||||
|
@ -76,8 +78,18 @@ dictionary ConnStatusDict {
|
|||
DOMString status = "";
|
||||
};
|
||||
|
||||
dictionary RcwnPerfStats {
|
||||
unsigned long avgShort = 0;
|
||||
unsigned long avgLong = 0;
|
||||
unsigned long stddevLong = 0;
|
||||
};
|
||||
|
||||
dictionary RcwnStatus {
|
||||
unsigned long totalNetworkRequests = 0;
|
||||
unsigned long rcwnCacheWonCount = 0;
|
||||
unsigned long rcwnNetWonCount = 0;
|
||||
unsigned long cacheSlowCount = 0;
|
||||
unsigned long cacheNotSlowCount = 0;
|
||||
// Sequence is indexed by CachePerfStats::EDataType
|
||||
sequence<RcwnPerfStats> perfStats;
|
||||
};
|
||||
|
|
|
@ -108,6 +108,8 @@ interface Node : EventTarget {
|
|||
readonly attribute URI? baseURIObject;
|
||||
[ChromeOnly]
|
||||
sequence<MutationObserver> getBoundMutationObservers();
|
||||
[ChromeOnly]
|
||||
DOMString generateXPath();
|
||||
|
||||
#ifdef ACCESSIBILITY
|
||||
[Pref="accessibility.AOM.enabled"]
|
||||
|
|
|
@ -185,6 +185,10 @@ GetPrincipalFromOrigin(const nsACString& aOrigin, nsIPrincipal** aPrincipal)
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// mPrivateBrowsingId must be set to false because PermissionManager is not supposed to have
|
||||
// any knowledge of private browsing. Allowing it to be true changes the suffix being hashed.
|
||||
attrs.mPrivateBrowsingId = 0;
|
||||
|
||||
// Disable userContext and firstParty isolation for permissions.
|
||||
attrs.StripAttributes(mozilla::OriginAttributes::STRIP_USER_CONTEXT_ID |
|
||||
mozilla::OriginAttributes::STRIP_FIRST_PARTY_DOMAIN);
|
||||
|
@ -3230,6 +3234,12 @@ nsPermissionManager::GetKeyForOrigin(const nsACString& aOrigin, nsACString& aKey
|
|||
aKey.Truncate();
|
||||
return;
|
||||
}
|
||||
|
||||
// mPrivateBrowsingId must be set to false because PermissionManager is not supposed to have
|
||||
// any knowledge of private browsing. Allowing it to be true changes the suffix being hashed.
|
||||
attrs.mPrivateBrowsingId = 0;
|
||||
|
||||
// Disable userContext and firstParty isolation for permissions.
|
||||
attrs.StripAttributes(OriginAttributes::STRIP_USER_CONTEXT_ID |
|
||||
OriginAttributes::STRIP_FIRST_PARTY_DOMAIN);
|
||||
|
||||
|
|
|
@ -471,8 +471,29 @@ gfxFontconfigFontEntry::ReleaseGrFace(gr_face* aFace)
|
|||
double
|
||||
gfxFontconfigFontEntry::GetAspect()
|
||||
{
|
||||
if (mAspect == 0.0) {
|
||||
// default to aspect = 0.5
|
||||
if (mAspect != 0.0) {
|
||||
return mAspect;
|
||||
}
|
||||
|
||||
// try to compute aspect from OS/2 metrics if available
|
||||
AutoTable os2Table(this, TRUETYPE_TAG('O','S','/','2'));
|
||||
if (os2Table) {
|
||||
uint16_t upem = UnitsPerEm();
|
||||
if (upem != kInvalidUPEM) {
|
||||
uint32_t len;
|
||||
auto os2 = reinterpret_cast<const OS2Table*>
|
||||
(hb_blob_get_data(os2Table, &len));
|
||||
if (uint16_t(os2->version) >= 2) {
|
||||
if (len >= offsetof(OS2Table, sxHeight) + sizeof(int16_t) &&
|
||||
int16_t(os2->sxHeight) > 0.1 * upem) {
|
||||
mAspect = double(int16_t(os2->sxHeight)) / upem;
|
||||
return mAspect;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// default to aspect = 0.5 if the code below fails
|
||||
mAspect = 0.5;
|
||||
|
||||
// create a font to calculate x-height / em-height
|
||||
|
@ -490,7 +511,7 @@ gfxFontconfigFontEntry::GetAspect()
|
|||
mAspect = metrics.xHeight / metrics.emHeight;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return mAspect;
|
||||
}
|
||||
|
||||
|
|
|
@ -62,4 +62,7 @@ USE_LIBS += [
|
|||
'mozavutil'
|
||||
]
|
||||
|
||||
if CONFIG['OS_TARGET'] != 'WINNT':
|
||||
OS_LIBS += ['m']
|
||||
|
||||
include("../ffvpxcommon.mozbuild")
|
||||
|
|
|
@ -54,5 +54,7 @@ SYMBOLS_FILE = 'avutil.symbols'
|
|||
NO_VISIBILITY_FLAGS = True
|
||||
|
||||
OS_LIBS += CONFIG['REALTIME_LIBS']
|
||||
if CONFIG['OS_TARGET'] != 'WINNT':
|
||||
OS_LIBS += ['m']
|
||||
|
||||
include("../ffvpxcommon.mozbuild")
|
||||
|
|
|
@ -370,11 +370,14 @@ PeerConnectionMedia::InitProxy()
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIEventTarget> target = mParent->GetWindow()
|
||||
? mParent->GetWindow()->EventTargetFor(TaskCategory::Network)
|
||||
: nullptr;
|
||||
RefPtr<ProtocolProxyQueryHandler> handler = new ProtocolProxyQueryHandler(this);
|
||||
rv = pps->AsyncResolve(channel,
|
||||
nsIProtocolProxyService::RESOLVE_PREFER_HTTPS_PROXY |
|
||||
nsIProtocolProxyService::RESOLVE_ALWAYS_TUNNEL,
|
||||
handler, getter_AddRefs(mProxyRequest));
|
||||
handler, target, getter_AddRefs(mProxyRequest));
|
||||
if (NS_FAILED(rv)) {
|
||||
CSFLogError(logTag, "%s: Failed to resolve protocol proxy: %d", __FUNCTION__, (int)rv);
|
||||
return NS_ERROR_FAILURE;
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "nsURLHelper.h"
|
||||
#include "mozilla/Logging.h"
|
||||
#include "nsIOService.h"
|
||||
#include "../cache2/CacheFileUtils.h"
|
||||
|
||||
using mozilla::AutoSafeJSContext;
|
||||
using mozilla::dom::Sequence;
|
||||
|
@ -822,6 +823,28 @@ Dashboard::GetRcwnData(RcwnData *aData)
|
|||
dict.mRcwnCacheWonCount = gIOService->GetCacheWonRequestNumber();
|
||||
dict.mRcwnNetWonCount = gIOService->GetNetWonRequestNumber();
|
||||
|
||||
uint32_t cacheSlow, cacheNotSlow;
|
||||
CacheFileUtils::CachePerfStats::GetSlowStats(&cacheSlow, &cacheNotSlow);
|
||||
dict.mCacheSlowCount = cacheSlow;
|
||||
dict.mCacheNotSlowCount = cacheNotSlow;
|
||||
|
||||
dict.mPerfStats.Construct();
|
||||
Sequence<mozilla::dom::RcwnPerfStats> &perfStats = dict.mPerfStats.Value();
|
||||
uint32_t length = CacheFileUtils::CachePerfStats::LAST;
|
||||
if (!perfStats.SetCapacity(length, fallible)) {
|
||||
JS_ReportOutOfMemory(cx);
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < length; i++) {
|
||||
CacheFileUtils::CachePerfStats::EDataType perfType =
|
||||
static_cast<CacheFileUtils::CachePerfStats::EDataType>(i);
|
||||
dom::RcwnPerfStats &elem = *perfStats.AppendElement(fallible);
|
||||
elem.mAvgShort = CacheFileUtils::CachePerfStats::GetAverage(perfType, false);
|
||||
elem.mAvgLong = CacheFileUtils::CachePerfStats::GetAverage(perfType, true);
|
||||
elem.mStddevLong = CacheFileUtils::CachePerfStats::GetStdDev(perfType, true);
|
||||
}
|
||||
|
||||
JS::RootedValue val(cx);
|
||||
if (!ToJSValue(cx, dict, &val)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
|
|
|
@ -269,8 +269,9 @@ class PACResolver final : public nsIDNSListener
|
|||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
|
||||
PACResolver()
|
||||
explicit PACResolver(nsIEventTarget *aTarget)
|
||||
: mStatus(NS_ERROR_FAILURE)
|
||||
, mMainThreadEventTarget(aTarget)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -303,6 +304,7 @@ public:
|
|||
nsCOMPtr<nsICancelable> mRequest;
|
||||
nsCOMPtr<nsIDNSRecord> mResponse;
|
||||
nsCOMPtr<nsITimer> mTimer;
|
||||
nsCOMPtr<nsIEventTarget> mMainThreadEventTarget;
|
||||
|
||||
private:
|
||||
~PACResolver() {}
|
||||
|
@ -405,7 +407,7 @@ ProxyAutoConfig::ResolveAddress(const nsCString &aHostName,
|
|||
if (!dns)
|
||||
return false;
|
||||
|
||||
RefPtr<PACResolver> helper = new PACResolver();
|
||||
RefPtr<PACResolver> helper = new PACResolver(mMainThreadEventTarget);
|
||||
OriginAttributes attrs;
|
||||
|
||||
if (NS_FAILED(dns->AsyncResolveNative(aHostName,
|
||||
|
@ -420,6 +422,7 @@ ProxyAutoConfig::ResolveAddress(const nsCString &aHostName,
|
|||
if (!mTimer)
|
||||
mTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
|
||||
if (mTimer) {
|
||||
mTimer->SetTarget(mMainThreadEventTarget);
|
||||
mTimer->InitWithCallback(helper, aTimeout, nsITimer::TYPE_ONE_SHOT);
|
||||
helper->mTimer = mTimer;
|
||||
}
|
||||
|
@ -678,13 +681,15 @@ nsresult
|
|||
ProxyAutoConfig::Init(const nsCString &aPACURI,
|
||||
const nsCString &aPACScript,
|
||||
bool aIncludePath,
|
||||
uint32_t aExtraHeapSize)
|
||||
uint32_t aExtraHeapSize,
|
||||
nsIEventTarget *aEventTarget)
|
||||
{
|
||||
mPACURI = aPACURI;
|
||||
mPACScript = sPacUtils;
|
||||
mPACScript.Append(aPACScript);
|
||||
mIncludePath = aIncludePath;
|
||||
mExtraHeapSize = aExtraHeapSize;
|
||||
mMainThreadEventTarget = aEventTarget;
|
||||
|
||||
if (!GetRunning())
|
||||
return SetupJS();
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "nsString.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
class nsIEventTarget;
|
||||
class nsITimer;
|
||||
namespace JS {
|
||||
class CallArgs;
|
||||
|
@ -32,7 +33,8 @@ public:
|
|||
nsresult Init(const nsCString &aPACURI,
|
||||
const nsCString &aPACScript,
|
||||
bool aIncludePath,
|
||||
uint32_t aExtraHeapSize);
|
||||
uint32_t aExtraHeapSize,
|
||||
nsIEventTarget *aEventTarget);
|
||||
void SetThreadLocalIndex(uint32_t index);
|
||||
void Shutdown();
|
||||
void GC();
|
||||
|
@ -98,6 +100,7 @@ private:
|
|||
uint32_t mExtraHeapSize;
|
||||
nsCString mRunningHost;
|
||||
nsCOMPtr<nsITimer> mTimer;
|
||||
nsCOMPtr<nsIEventTarget> mMainThreadEventTarget;
|
||||
};
|
||||
|
||||
} // namespace net
|
||||
|
|
|
@ -63,15 +63,20 @@ nsAsyncRedirectVerifyHelper::~nsAsyncRedirectVerifyHelper()
|
|||
}
|
||||
|
||||
nsresult
|
||||
nsAsyncRedirectVerifyHelper::Init(nsIChannel* oldChan, nsIChannel* newChan,
|
||||
uint32_t flags, bool synchronize)
|
||||
nsAsyncRedirectVerifyHelper::Init(nsIChannel* oldChan,
|
||||
nsIChannel* newChan,
|
||||
uint32_t flags,
|
||||
nsIEventTarget* mainThreadEventTarget,
|
||||
bool synchronize)
|
||||
{
|
||||
LOG(("nsAsyncRedirectVerifyHelper::Init() "
|
||||
"oldChan=%p newChan=%p", oldChan, newChan));
|
||||
mOldChan = oldChan;
|
||||
mNewChan = newChan;
|
||||
mFlags = flags;
|
||||
mCallbackEventTarget = GetCurrentThreadEventTarget();
|
||||
mCallbackEventTarget = NS_IsMainThread() && mainThreadEventTarget
|
||||
? mainThreadEventTarget
|
||||
: GetCurrentThreadEventTarget();
|
||||
|
||||
if (!(flags & (nsIChannelEventSink::REDIRECT_INTERNAL |
|
||||
nsIChannelEventSink::REDIRECT_STS_UPGRADE))) {
|
||||
|
@ -85,8 +90,11 @@ nsAsyncRedirectVerifyHelper::Init(nsIChannel* oldChan, nsIChannel* newChan,
|
|||
if (synchronize)
|
||||
mWaitingForRedirectCallback = true;
|
||||
|
||||
nsCOMPtr<nsIRunnable> runnable = this;
|
||||
nsresult rv;
|
||||
rv = NS_DispatchToMainThread(this);
|
||||
rv = mainThreadEventTarget
|
||||
? mainThreadEventTarget->Dispatch(runnable.forget())
|
||||
: GetMainThreadEventTarget()->Dispatch(runnable.forget());
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (synchronize) {
|
||||
|
|
|
@ -59,6 +59,8 @@ public:
|
|||
* target of the redirect channel
|
||||
* @param flags
|
||||
* redirect flags
|
||||
* @param mainThreadEventTarget
|
||||
* a labeled event target for dispatching runnables
|
||||
* @param synchronize
|
||||
* set to TRUE if you want the Init method wait synchronously for
|
||||
* all redirect callbacks
|
||||
|
@ -66,6 +68,7 @@ public:
|
|||
nsresult Init(nsIChannel* oldChan,
|
||||
nsIChannel* newChan,
|
||||
uint32_t flags,
|
||||
nsIEventTarget* mainThreadEventTarget,
|
||||
bool synchronize = false);
|
||||
|
||||
protected:
|
||||
|
|
|
@ -52,7 +52,8 @@ private:
|
|||
// nsBaseChannel
|
||||
|
||||
nsBaseChannel::nsBaseChannel()
|
||||
: mPumpingData(false)
|
||||
: NeckoTargetHolder(nullptr)
|
||||
, mPumpingData(false)
|
||||
, mLoadFlags(LOAD_NORMAL)
|
||||
, mQueriedProgressSink(true)
|
||||
, mSynthProgressEvents(false)
|
||||
|
@ -138,12 +139,13 @@ nsBaseChannel::Redirect(nsIChannel *newChannel, uint32_t redirectFlags,
|
|||
new nsAsyncRedirectVerifyHelper();
|
||||
|
||||
bool checkRedirectSynchronously = !openNewChannel;
|
||||
nsCOMPtr<nsIEventTarget> target = GetNeckoTarget();
|
||||
|
||||
mRedirectChannel = newChannel;
|
||||
mRedirectFlags = redirectFlags;
|
||||
mOpenRedirectChannel = openNewChannel;
|
||||
nsresult rv = redirectCallbackHelper->Init(this, newChannel, redirectFlags,
|
||||
checkRedirectSynchronously);
|
||||
target, checkRedirectSynchronously);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
|
@ -261,7 +263,8 @@ nsBaseChannel::BeginPumpingData()
|
|||
NS_ASSERTION(!stream || !channel, "Got both a channel and a stream?");
|
||||
|
||||
if (channel) {
|
||||
rv = NS_DispatchToCurrentThread(new RedirectRunnable(this, channel));
|
||||
nsCOMPtr<nsIRunnable> runnable = new RedirectRunnable(this, channel);
|
||||
rv = Dispatch(runnable.forget());
|
||||
if (NS_SUCCEEDED(rv))
|
||||
mWaitingOnAsyncRedirect = true;
|
||||
return rv;
|
||||
|
@ -273,8 +276,7 @@ nsBaseChannel::BeginPumpingData()
|
|||
// and especially when we call into the loadgroup. Our caller takes care to
|
||||
// release mPump if we return an error.
|
||||
|
||||
nsCOMPtr<nsIEventTarget> target =
|
||||
nsContentUtils::GetEventTargetByLoadInfo(mLoadInfo, TaskCategory::Other);
|
||||
nsCOMPtr<nsIEventTarget> target = GetNeckoTarget();
|
||||
rv = nsInputStreamPump::Create(getter_AddRefs(mPump), stream, -1, -1, 0, 0,
|
||||
true, target);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
|
@ -503,6 +505,9 @@ NS_IMETHODIMP
|
|||
nsBaseChannel::SetLoadInfo(nsILoadInfo* aLoadInfo)
|
||||
{
|
||||
mLoadInfo = aLoadInfo;
|
||||
|
||||
// Need to update |mNeckoTarget| when load info has changed.
|
||||
SetupNeckoTarget();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -683,6 +688,8 @@ nsBaseChannel::AsyncOpen(nsIStreamListener *listener, nsISupports *ctxt)
|
|||
NS_ENSURE_TRUE(!mWasOpened, NS_ERROR_ALREADY_OPENED);
|
||||
NS_ENSURE_ARG(listener);
|
||||
|
||||
SetupNeckoTarget();
|
||||
|
||||
// Skip checking for chrome:// sub-resources.
|
||||
nsAutoCString scheme;
|
||||
mURI->GetScheme(scheme);
|
||||
|
@ -923,7 +930,7 @@ nsBaseChannel::OnDataAvailable(nsIRequest *request, nsISupports *ctxt,
|
|||
|
||||
nsCOMPtr<nsIRunnable> runnable =
|
||||
new OnTransportStatusAsyncEvent(this, prog, mContentLength);
|
||||
NS_DispatchToMainThread(runnable);
|
||||
Dispatch(runnable.forget());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -982,3 +989,10 @@ nsBaseChannel::CheckListenerChain()
|
|||
|
||||
return listener->CheckListenerChain();
|
||||
}
|
||||
|
||||
void
|
||||
nsBaseChannel::SetupNeckoTarget()
|
||||
{
|
||||
mNeckoTarget =
|
||||
nsContentUtils::GetEventTargetByLoadInfo(mLoadInfo, TaskCategory::Other);
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#ifndef nsBaseChannel_h__
|
||||
#define nsBaseChannel_h__
|
||||
|
||||
#include "mozilla/net/NeckoTargetHolder.h"
|
||||
#include "nsString.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
@ -47,6 +48,7 @@ class nsBaseChannel : public nsHashPropertyBag
|
|||
, public nsITransportEventSink
|
||||
, public nsIAsyncVerifyRedirectCallback
|
||||
, public mozilla::net::PrivateBrowsingChannel<nsBaseChannel>
|
||||
, public mozilla::net::NeckoTargetHolder
|
||||
, protected nsIStreamListener
|
||||
, protected nsIThreadRetargetableStreamListener
|
||||
{
|
||||
|
@ -227,6 +229,8 @@ protected:
|
|||
mAllowThreadRetargeting = false;
|
||||
}
|
||||
|
||||
virtual void SetupNeckoTarget();
|
||||
|
||||
private:
|
||||
NS_DECL_NSISTREAMLISTENER
|
||||
NS_DECL_NSIREQUESTOBSERVER
|
||||
|
|
|
@ -1892,9 +1892,11 @@ nsIOService::SpeculativeConnectInternal(nsIURI *aURI,
|
|||
new IOServiceProxyCallback(aCallbacks, this);
|
||||
nsCOMPtr<nsIProtocolProxyService2> pps2 = do_QueryInterface(pps);
|
||||
if (pps2) {
|
||||
return pps2->AsyncResolve2(channel, 0, callback, getter_AddRefs(cancelable));
|
||||
return pps2->AsyncResolve2(channel, 0, callback, nullptr,
|
||||
getter_AddRefs(cancelable));
|
||||
}
|
||||
return pps->AsyncResolve(channel, 0, callback, getter_AddRefs(cancelable));
|
||||
return pps->AsyncResolve(channel, 0, callback, nullptr,
|
||||
getter_AddRefs(cancelable));
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
|
|
@ -13,6 +13,7 @@ interface nsIProtocolProxyChannelFilter;
|
|||
interface nsIProxyInfo;
|
||||
interface nsIChannel;
|
||||
interface nsIURI;
|
||||
interface nsIEventTarget;
|
||||
|
||||
/**
|
||||
* nsIProtocolProxyService provides methods to access information about
|
||||
|
@ -79,6 +80,8 @@ interface nsIProtocolProxyService : nsISupports
|
|||
* not correspond to a RESOLVE_ flag are reserved for future use.
|
||||
* @param aCallback
|
||||
* The object to be notified when the result is available.
|
||||
* @param aMainThreadTarget
|
||||
* A labelled event target for dispatching runnables to main thread.
|
||||
*
|
||||
* @return An object that can be used to cancel the asychronous operation.
|
||||
* If canceled, the cancelation status (aReason) will be forwarded
|
||||
|
@ -99,7 +102,8 @@ interface nsIProtocolProxyService : nsISupports
|
|||
* @see nsIProxiedProtocolHandler::newProxiedChannel
|
||||
*/
|
||||
nsICancelable asyncResolve(in nsISupports aChannelOrURI, in unsigned long aFlags,
|
||||
in nsIProtocolProxyCallback aCallback);
|
||||
in nsIProtocolProxyCallback aCallback,
|
||||
[optional] in nsIEventTarget aMainThreadTarget);
|
||||
|
||||
/**
|
||||
* This method may be called to construct a nsIProxyInfo instance from
|
||||
|
|
|
@ -26,5 +26,6 @@ interface nsIProtocolProxyService2 : nsIProtocolProxyService
|
|||
* The nsICancelable return value will be null in that case.
|
||||
*/
|
||||
nsICancelable asyncResolve2(in nsIChannel aChannel, in unsigned long aFlags,
|
||||
in nsIProtocolProxyCallback aCallback);
|
||||
in nsIProtocolProxyCallback aCallback,
|
||||
[optional] in nsIEventTarget aMainThreadTarget);
|
||||
};
|
||||
|
|
|
@ -242,13 +242,15 @@ public:
|
|||
if (mSetupPAC) {
|
||||
mSetupPAC = false;
|
||||
|
||||
nsCOMPtr<nsIEventTarget> target = mPACMan->GetNeckoTarget();
|
||||
mPACMan->mPAC.Init(mSetupPACURI,
|
||||
mSetupPACData,
|
||||
mPACMan->mIncludePath,
|
||||
mExtraHeapSize);
|
||||
mExtraHeapSize,
|
||||
target);
|
||||
|
||||
RefPtr<PACLoadComplete> runnable = new PACLoadComplete(mPACMan);
|
||||
NS_DispatchToMainThread(runnable);
|
||||
mPACMan->Dispatch(runnable.forget());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -293,7 +295,7 @@ PendingPACQuery::Complete(nsresult status, const nsCString &pacString)
|
|||
RefPtr<ExecuteCallback> runnable = new ExecuteCallback(mCallback, status);
|
||||
runnable->SetPACString(pacString);
|
||||
if (mOnMainThreadOnly)
|
||||
NS_DispatchToMainThread(runnable);
|
||||
mPACMan->Dispatch(runnable.forget());
|
||||
else
|
||||
runnable->Run();
|
||||
}
|
||||
|
@ -307,7 +309,7 @@ PendingPACQuery::UseAlternatePACFile(const nsCString &pacURL)
|
|||
RefPtr<ExecuteCallback> runnable = new ExecuteCallback(mCallback, NS_OK);
|
||||
runnable->SetPACURL(pacURL);
|
||||
if (mOnMainThreadOnly)
|
||||
NS_DispatchToMainThread(runnable);
|
||||
mPACMan->Dispatch(runnable.forget());
|
||||
else
|
||||
runnable->Run();
|
||||
}
|
||||
|
@ -328,8 +330,9 @@ static uint32_t sThreadLocalIndex = 0xdeadbeef; // out of range
|
|||
static const char *kPACIncludePath =
|
||||
"network.proxy.autoconfig_url.include_path";
|
||||
|
||||
nsPACMan::nsPACMan()
|
||||
: mLoadPending(false)
|
||||
nsPACMan::nsPACMan(nsIEventTarget *mainThreadEventTarget)
|
||||
: NeckoTargetHolder(mainThreadEventTarget)
|
||||
, mLoadPending(false)
|
||||
, mShutdown(false)
|
||||
, mLoadFailureCount(0)
|
||||
, mInProgress(false)
|
||||
|
@ -351,7 +354,7 @@ nsPACMan::~nsPACMan()
|
|||
}
|
||||
else {
|
||||
RefPtr<ShutdownThread> runnable = new ShutdownThread(mPACThread);
|
||||
NS_DispatchToMainThread(runnable);
|
||||
Dispatch(runnable.forget());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -371,7 +374,7 @@ nsPACMan::Shutdown()
|
|||
PostCancelPendingQ(NS_ERROR_ABORT);
|
||||
|
||||
RefPtr<WaitForThreadShutdown> runnable = new WaitForThreadShutdown(this);
|
||||
NS_DispatchToMainThread(runnable);
|
||||
Dispatch(runnable.forget());
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
@ -438,9 +441,12 @@ nsPACMan::LoadPACFromURI(const nsCString &spec)
|
|||
// queries the enter between now and when we actually load the PAC file.
|
||||
|
||||
if (!mLoadPending) {
|
||||
nsresult rv;
|
||||
if (NS_FAILED(rv = NS_DispatchToCurrentThread(NewRunnableMethod("nsPACMan::StartLoading",
|
||||
this, &nsPACMan::StartLoading))))
|
||||
nsCOMPtr<nsIRunnable> runnable =
|
||||
NewRunnableMethod("nsPACMan::StartLoading", this, &nsPACMan::StartLoading);
|
||||
nsresult rv = NS_IsMainThread()
|
||||
? Dispatch(runnable.forget())
|
||||
: GetCurrentThreadEventTarget()->Dispatch(runnable.forget());
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
mLoadPending = true;
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "mozilla/TimeStamp.h"
|
||||
#include "mozilla/Logging.h"
|
||||
#include "mozilla/Atomics.h"
|
||||
#include "mozilla/net/NeckoTargetHolder.h"
|
||||
|
||||
class nsISystemProxySettings;
|
||||
class nsIThread;
|
||||
|
@ -90,11 +91,12 @@ private:
|
|||
class nsPACMan final : public nsIStreamLoaderObserver
|
||||
, public nsIInterfaceRequestor
|
||||
, public nsIChannelEventSink
|
||||
, public NeckoTargetHolder
|
||||
{
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
|
||||
nsPACMan();
|
||||
explicit nsPACMan(nsIEventTarget *mainThreadEventTarget);
|
||||
|
||||
/**
|
||||
* This method may be called to shutdown the PAC manager. Any async queries
|
||||
|
|
|
@ -1147,7 +1147,7 @@ nsProtocolProxyService::IsProxyDisabled(nsProxyInfo *pi)
|
|||
}
|
||||
|
||||
nsresult
|
||||
nsProtocolProxyService::SetupPACThread()
|
||||
nsProtocolProxyService::SetupPACThread(nsIEventTarget *mainThreadEventTarget)
|
||||
{
|
||||
if (mIsShutdown) {
|
||||
return NS_ERROR_FAILURE;
|
||||
|
@ -1156,7 +1156,7 @@ nsProtocolProxyService::SetupPACThread()
|
|||
if (mPACMan)
|
||||
return NS_OK;
|
||||
|
||||
mPACMan = new nsPACMan();
|
||||
mPACMan = new nsPACMan(mainThreadEventTarget);
|
||||
|
||||
bool mainThreadOnly;
|
||||
nsresult rv;
|
||||
|
@ -1319,7 +1319,8 @@ nsresult
|
|||
nsProtocolProxyService::AsyncResolveInternal(nsIChannel *channel, uint32_t flags,
|
||||
nsIProtocolProxyCallback *callback,
|
||||
nsICancelable **result,
|
||||
bool isSyncOK)
|
||||
bool isSyncOK,
|
||||
nsIEventTarget *mainThreadEventTarget)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(channel);
|
||||
NS_ENSURE_ARG_POINTER(callback);
|
||||
|
@ -1350,6 +1351,11 @@ nsProtocolProxyService::AsyncResolveInternal(nsIChannel *channel, uint32_t flags
|
|||
}
|
||||
}
|
||||
|
||||
rv = SetupPACThread(mainThreadEventTarget);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
// SystemProxySettings and PAC files can block the main thread
|
||||
// but if neither of them are in use, we can just do the work
|
||||
// right here and directly invoke the callback
|
||||
|
@ -1386,14 +1392,17 @@ nsProtocolProxyService::AsyncResolveInternal(nsIChannel *channel, uint32_t flags
|
|||
NS_IMETHODIMP
|
||||
nsProtocolProxyService::AsyncResolve2(nsIChannel *channel, uint32_t flags,
|
||||
nsIProtocolProxyCallback *callback,
|
||||
nsIEventTarget *mainThreadEventTarget,
|
||||
nsICancelable **result)
|
||||
{
|
||||
return AsyncResolveInternal(channel, flags, callback, result, true);
|
||||
return AsyncResolveInternal(channel, flags, callback,
|
||||
result, true, mainThreadEventTarget);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsProtocolProxyService::AsyncResolve(nsISupports *channelOrURI, uint32_t flags,
|
||||
nsIProtocolProxyCallback *callback,
|
||||
nsIEventTarget *mainThreadEventTarget,
|
||||
nsICancelable **result)
|
||||
{
|
||||
|
||||
|
@ -1424,7 +1433,8 @@ nsProtocolProxyService::AsyncResolve(nsISupports *channelOrURI, uint32_t flags,
|
|||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
return AsyncResolveInternal(channel, flags, callback, result, false);
|
||||
return AsyncResolveInternal(channel, flags, callback,
|
||||
result, false, mainThreadEventTarget);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -1914,9 +1924,6 @@ nsProtocolProxyService::Resolve_Internal(nsIChannel *channel,
|
|||
nsIProxyInfo **result)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(channel);
|
||||
nsresult rv = SetupPACThread();
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
*usePACThread = false;
|
||||
*result = nullptr;
|
||||
|
@ -1925,7 +1932,7 @@ nsProtocolProxyService::Resolve_Internal(nsIChannel *channel,
|
|||
return NS_OK; // Can't proxy this (filters may not override)
|
||||
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
rv = GetProxyURI(channel, getter_AddRefs(uri));
|
||||
nsresult rv = GetProxyURI(channel, getter_AddRefs(uri));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// See bug #586908.
|
||||
|
|
|
@ -298,7 +298,7 @@ protected:
|
|||
void MaybeDisableDNSPrefetch(nsIProxyInfo *aProxy);
|
||||
|
||||
private:
|
||||
nsresult SetupPACThread();
|
||||
nsresult SetupPACThread(nsIEventTarget *mainThreadEventTarget = nullptr);
|
||||
nsresult ResetPACThread();
|
||||
nsresult ReloadNetworkPAC();
|
||||
|
||||
|
@ -406,7 +406,8 @@ private:
|
|||
nsresult AsyncResolveInternal(nsIChannel *channel, uint32_t flags,
|
||||
nsIProtocolProxyCallback *callback,
|
||||
nsICancelable **result,
|
||||
bool isSyncOK);
|
||||
bool isSyncOK,
|
||||
nsIEventTarget *mainThreadEventTarget);
|
||||
bool mIsShutdown;
|
||||
nsCOMPtr<nsIThread> mProxySettingThread;
|
||||
};
|
||||
|
|
|
@ -900,6 +900,16 @@ CacheFile::OpenOutputStream(CacheOutputCloseListener *aCloseListener, nsIOutputS
|
|||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
if (NS_FAILED(mStatus)) {
|
||||
LOG(("CacheFile::OpenOutputStream() - CacheFile is in a failure state "
|
||||
"[this=%p, status=0x%08" PRIx32 "]", this,
|
||||
static_cast<uint32_t>(mStatus)));
|
||||
|
||||
// The CacheFile is already doomed. It make no sense to allow to write any
|
||||
// data to such entry.
|
||||
return mStatus;
|
||||
}
|
||||
|
||||
// Fail if there is any input stream opened for alternative data
|
||||
for (uint32_t i = 0; i < mInputs.Length(); ++i) {
|
||||
if (mInputs[i]->IsAlternativeData()) {
|
||||
|
@ -958,6 +968,16 @@ CacheFile::OpenAlternativeOutputStream(CacheOutputCloseListener *aCloseListener,
|
|||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
if (NS_FAILED(mStatus)) {
|
||||
LOG(("CacheFile::OpenAlternativeOutputStream() - CacheFile is in a failure "
|
||||
"state [this=%p, status=0x%08" PRIx32 "]", this,
|
||||
static_cast<uint32_t>(mStatus)));
|
||||
|
||||
// The CacheFile is already doomed. It make no sense to allow to write any
|
||||
// data to such entry.
|
||||
return mStatus;
|
||||
}
|
||||
|
||||
// Fail if there is any input stream opened for alternative data
|
||||
for (uint32_t i = 0; i < mInputs.Length(); ++i) {
|
||||
if (mInputs[i]->IsAlternativeData()) {
|
||||
|
@ -1982,9 +2002,9 @@ CacheFile::Truncate(int64_t aOffset)
|
|||
MOZ_RELEASE_ASSERT(bytesInNewLastChunk == kChunkSize);
|
||||
newLastChunk++;
|
||||
bytesInNewLastChunk = 0;
|
||||
LOG(("CacheFileTruncate() - chunk %p is still in use, using newLastChunk=%u"
|
||||
" and bytesInNewLastChunk=%u", mChunks.GetWeak(newLastChunk),
|
||||
newLastChunk, bytesInNewLastChunk));
|
||||
LOG(("CacheFile::Truncate() - chunk %p is still in use, using "
|
||||
"newLastChunk=%u and bytesInNewLastChunk=%u",
|
||||
mChunks.GetWeak(newLastChunk), newLastChunk, bytesInNewLastChunk));
|
||||
}
|
||||
|
||||
// Discard all truncated chunks in mChunks
|
||||
|
|
|
@ -567,7 +567,6 @@ CacheFileChunk::Index() const
|
|||
CacheHash::Hash16_t
|
||||
CacheFileChunk::Hash() const
|
||||
{
|
||||
MOZ_ASSERT(!mListener);
|
||||
MOZ_ASSERT(IsReady());
|
||||
|
||||
return CacheHash::Hash16(mBuf->Buf(), mBuf->DataSize());
|
||||
|
|
|
@ -513,6 +513,8 @@ DetailedCacheHitTelemetry::AddRecord(ERecType aType, TimeStamp aLoadStart)
|
|||
|
||||
StaticMutex CachePerfStats::sLock;
|
||||
CachePerfStats::PerfData CachePerfStats::sData[CachePerfStats::LAST];
|
||||
uint32_t CachePerfStats::sCacheSlowCnt = 0;
|
||||
uint32_t CachePerfStats::sCacheNotSlowCnt = 0;
|
||||
|
||||
CachePerfStats::MMA::MMA(uint32_t aTotalWeight, bool aFilter)
|
||||
: mSum(0)
|
||||
|
@ -636,6 +638,14 @@ CachePerfStats::GetAverage(EDataType aType, bool aFiltered)
|
|||
return sData[aType].GetAverage(aFiltered);
|
||||
}
|
||||
|
||||
// static
|
||||
uint32_t
|
||||
CachePerfStats::GetStdDev(EDataType aType, bool aFiltered)
|
||||
{
|
||||
StaticMutexAutoLock lock(sLock);
|
||||
return sData[aType].GetStdDev(aFiltered);
|
||||
}
|
||||
|
||||
//static
|
||||
bool
|
||||
CachePerfStats::IsCacheSlow()
|
||||
|
@ -654,13 +664,26 @@ CachePerfStats::IsCacheSlow()
|
|||
uint32_t maxdiff = (avgLong / 4) + (2 * stddevLong);
|
||||
|
||||
if (avgShort > avgLong + maxdiff) {
|
||||
LOG(("CachePerfStats::IsCacheSlow() - result is slow based on perf "
|
||||
"type %u [avgShort=%u, avgLong=%u, stddevLong=%u]", i, avgShort,
|
||||
avgLong, stddevLong));
|
||||
++sCacheSlowCnt;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
++sCacheNotSlowCnt;
|
||||
return false;
|
||||
}
|
||||
|
||||
//static
|
||||
void
|
||||
CachePerfStats::GetSlowStats(uint32_t *aSlow, uint32_t *aNotSlow)
|
||||
{
|
||||
*aSlow = sCacheSlowCnt;
|
||||
*aNotSlow = sCacheNotSlowCnt;
|
||||
}
|
||||
|
||||
void
|
||||
FreeBuffer(void *aBuf) {
|
||||
#ifndef NS_FREE_PERMANENT_DATA
|
||||
|
|
|
@ -150,6 +150,8 @@ private:
|
|||
|
||||
class CachePerfStats {
|
||||
public:
|
||||
// perfStatTypes in displayRcwnStats() in toolkit/content/aboutNetworking.js
|
||||
// must match EDataType
|
||||
enum EDataType {
|
||||
IO_OPEN = 0,
|
||||
IO_READ = 1,
|
||||
|
@ -160,7 +162,9 @@ public:
|
|||
|
||||
static void AddValue(EDataType aType, uint32_t aValue, bool aShortOnly);
|
||||
static uint32_t GetAverage(EDataType aType, bool aFiltered);
|
||||
static uint32_t GetStdDev(EDataType aType, bool aFiltered);
|
||||
static bool IsCacheSlow();
|
||||
static void GetSlowStats(uint32_t *aSlow, uint32_t *aNotSlow);
|
||||
|
||||
private:
|
||||
|
||||
|
@ -211,6 +215,8 @@ private:
|
|||
static StaticMutex sLock;
|
||||
|
||||
static PerfData sData[LAST];
|
||||
static uint32_t sCacheSlowCnt;
|
||||
static uint32_t sCacheNotSlowCnt;
|
||||
};
|
||||
|
||||
void
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla/SystemGroup.h"
|
||||
#include "mozilla/net/NeckoChild.h"
|
||||
#include "mozilla/net/ChannelDiverterChild.h"
|
||||
#include "mozilla/net/FTPChannelChild.h"
|
||||
|
@ -34,8 +33,7 @@ namespace mozilla {
|
|||
namespace net {
|
||||
|
||||
FTPChannelChild::FTPChannelChild(nsIURI* uri)
|
||||
: NeckoTargetHolder(nullptr)
|
||||
, mIPCOpen(false)
|
||||
: mIPCOpen(false)
|
||||
, mUnknownDecoderInvolved(false)
|
||||
, mCanceled(false)
|
||||
, mSuspendCount(0)
|
||||
|
@ -206,7 +204,7 @@ FTPChannelChild::AsyncOpen(::nsIStreamListener* listener, nsISupports* aContext)
|
|||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// This must happen before the constructor message is sent.
|
||||
EnsureNeckoTarget();
|
||||
SetupNeckoTarget();
|
||||
|
||||
gNeckoChild->
|
||||
SendPFTPChannelConstructor(this, tabChild, IPC::SerializedLoadContext(this),
|
||||
|
@ -615,15 +613,7 @@ FTPChannelChild::DoOnStopRequest(const nsresult& aChannelStatus,
|
|||
NS_ConvertASCIItoUTF16(aErrorMsg));
|
||||
}
|
||||
|
||||
if (mNeckoTarget) {
|
||||
mNeckoTarget->Dispatch(alertEvent.forget(),
|
||||
nsIEventTarget::DISPATCH_NORMAL);
|
||||
} else {
|
||||
// In case |mNeckoTarget| is null, dispatch by SystemGroup.
|
||||
SystemGroup::Dispatch("FTPAlertEvent",
|
||||
TaskCategory::Other,
|
||||
alertEvent.forget());
|
||||
}
|
||||
Dispatch(alertEvent.forget());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -837,7 +827,7 @@ FTPChannelChild::ConnectParent(uint32_t id)
|
|||
}
|
||||
|
||||
// This must happen before the constructor message is sent.
|
||||
EnsureNeckoTarget();
|
||||
SetupNeckoTarget();
|
||||
|
||||
// The socket transport in the chrome process now holds a logical ref to us
|
||||
// until OnStopRequest, or we do a redirect, or we hit an IPDL error.
|
||||
|
@ -946,7 +936,7 @@ FTPChannelChild::GetDivertingToParent(bool* aDiverting)
|
|||
}
|
||||
|
||||
void
|
||||
FTPChannelChild::EnsureNeckoTarget()
|
||||
FTPChannelChild::SetupNeckoTarget()
|
||||
{
|
||||
if (mNeckoTarget) {
|
||||
return;
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
#include "mozilla/UniquePtr.h"
|
||||
#include "mozilla/net/PFTPChannelChild.h"
|
||||
#include "mozilla/net/ChannelEventQueue.h"
|
||||
#include "mozilla/net/NeckoTargetHolder.h"
|
||||
#include "nsBaseChannel.h"
|
||||
#include "nsIFTPChannel.h"
|
||||
#include "nsIUploadChannel.h"
|
||||
|
@ -43,7 +42,6 @@ class FTPChannelChild final : public PFTPChannelChild
|
|||
, public nsIProxiedChannel
|
||||
, public nsIChildChannel
|
||||
, public nsIDivertableChannel
|
||||
, public NeckoTargetHolder
|
||||
{
|
||||
public:
|
||||
typedef ::nsIStreamListener nsIStreamListener;
|
||||
|
@ -120,6 +118,8 @@ protected:
|
|||
void DoFailedAsyncOpen(const nsresult& statusCode);
|
||||
void DoDeleteSelf();
|
||||
|
||||
void SetupNeckoTarget() override;
|
||||
|
||||
friend class FTPStartRequestEvent;
|
||||
friend class FTPDataAvailableEvent;
|
||||
friend class MaybeDivertOnDataFTPEvent;
|
||||
|
@ -158,8 +158,6 @@ private:
|
|||
// Set if SendSuspend is called. Determines if SendResume is needed when
|
||||
// diverting callbacks to parent.
|
||||
bool mSuspendSent;
|
||||
|
||||
void EnsureNeckoTarget();
|
||||
};
|
||||
|
||||
inline bool
|
||||
|
|
|
@ -1706,7 +1706,7 @@ nsFtpState::Init(nsFtpChannel *channel)
|
|||
do_GetService(NS_PROTOCOLPROXYSERVICE_CONTRACTID);
|
||||
|
||||
if (pps && !mChannel->ProxyInfo()) {
|
||||
pps->AsyncResolve(static_cast<nsIChannel*>(mChannel), 0, this,
|
||||
pps->AsyncResolve(static_cast<nsIChannel*>(mChannel), 0, this, nullptr,
|
||||
getter_AddRefs(mProxyRequest));
|
||||
}
|
||||
|
||||
|
|
|
@ -1629,7 +1629,14 @@ HttpChannelChild::Redirect1Begin(const uint32_t& registrarId,
|
|||
}
|
||||
mRedirectChannelChild->ConnectParent(registrarId);
|
||||
}
|
||||
rv = gHttpHandler->AsyncOnChannelRedirect(this, newChannel, redirectFlags);
|
||||
|
||||
nsCOMPtr<nsIEventTarget> target = GetNeckoTarget();
|
||||
MOZ_ASSERT(target);
|
||||
|
||||
rv = gHttpHandler->AsyncOnChannelRedirect(this,
|
||||
newChannel,
|
||||
redirectFlags,
|
||||
target);
|
||||
}
|
||||
|
||||
if (NS_FAILED(rv))
|
||||
|
@ -1659,9 +1666,13 @@ HttpChannelChild::BeginNonIPCRedirect(nsIURI* responseURI,
|
|||
httpChannelChild->OverrideSecurityInfoForNonIPCRedirect(mSecurityInfo);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIEventTarget> target = GetNeckoTarget();
|
||||
MOZ_ASSERT(target);
|
||||
|
||||
rv = gHttpHandler->AsyncOnChannelRedirect(this,
|
||||
newChannel,
|
||||
nsIChannelEventSink::REDIRECT_INTERNAL);
|
||||
nsIChannelEventSink::REDIRECT_INTERNAL,
|
||||
target);
|
||||
}
|
||||
|
||||
if (NS_FAILED(rv))
|
||||
|
|
|
@ -302,6 +302,7 @@ nsHttpChannel::nsHttpChannel()
|
|||
, mIsReadingFromCache(false)
|
||||
, mOnCacheAvailableCalled(false)
|
||||
, mRaceCacheWithNetwork(false)
|
||||
, mRaceDelay(0)
|
||||
, mCacheAsyncOpenCalled(false)
|
||||
, mDidReval(false)
|
||||
{
|
||||
|
@ -3012,11 +3013,11 @@ nsHttpChannel::ResolveProxy()
|
|||
// then it is ok to use that version.
|
||||
nsCOMPtr<nsIProtocolProxyService2> pps2 = do_QueryInterface(pps);
|
||||
if (pps2) {
|
||||
rv = pps2->AsyncResolve2(this, mProxyResolveFlags,
|
||||
this, getter_AddRefs(mProxyRequest));
|
||||
rv = pps2->AsyncResolve2(this, mProxyResolveFlags, this,
|
||||
nullptr, getter_AddRefs(mProxyRequest));
|
||||
} else {
|
||||
rv = pps->AsyncResolve(static_cast<nsIChannel*>(this), mProxyResolveFlags,
|
||||
this, getter_AddRefs(mProxyRequest));
|
||||
this, nullptr, getter_AddRefs(mProxyRequest));
|
||||
}
|
||||
|
||||
return rv;
|
||||
|
@ -8982,29 +8983,37 @@ nsHttpChannel::ReportRcwnStats(nsIRequest* firstResponseRequest, bool isFromNet)
|
|||
kDidNotRaceUsedNetwork = 0,
|
||||
kDidNotRaceUsedCache = 1,
|
||||
kRaceUsedNetwork = 2,
|
||||
kRaceUsedCache = 3
|
||||
kRaceUsedCache = 3,
|
||||
kDelayedRaceUsedNetwork = 4,
|
||||
kDelayedRaceUsedCache = 5
|
||||
};
|
||||
static const Telemetry::HistogramID kRcwnTelemetry[4] = {
|
||||
static const Telemetry::HistogramID kRcwnTelemetry[6] = {
|
||||
Telemetry::NETWORK_RACE_CACHE_BANDWIDTH_NOT_RACE,
|
||||
Telemetry::NETWORK_RACE_CACHE_BANDWIDTH_NOT_RACE,
|
||||
Telemetry::NETWORK_RACE_CACHE_BANDWIDTH_RACE_NETWORK_WIN,
|
||||
Telemetry::NETWORK_RACE_CACHE_BANDWIDTH_RACE_CACHE_WIN,
|
||||
Telemetry::NETWORK_RACE_CACHE_BANDWIDTH_RACE_NETWORK_WIN,
|
||||
Telemetry::NETWORK_RACE_CACHE_BANDWIDTH_RACE_CACHE_WIN
|
||||
};
|
||||
|
||||
RaceCacheAndNetStatus rcwnStatus = kDidNotRaceUsedNetwork;
|
||||
if (isFromNet) {
|
||||
rcwnStatus = mRaceCacheWithNetwork ? kRaceUsedNetwork : kDidNotRaceUsedNetwork;
|
||||
rcwnStatus = mRaceCacheWithNetwork ?
|
||||
(mRaceDelay ? kDelayedRaceUsedNetwork : kRaceUsedNetwork) :
|
||||
kDidNotRaceUsedNetwork;
|
||||
} else if (firstResponseRequest == mCachePump) {
|
||||
rcwnStatus = mRaceCacheWithNetwork ? kRaceUsedCache : kDidNotRaceUsedCache;
|
||||
rcwnStatus = mRaceCacheWithNetwork ?
|
||||
(mRaceDelay ? kDelayedRaceUsedCache : kRaceUsedCache) :
|
||||
kDidNotRaceUsedCache;
|
||||
}
|
||||
Telemetry::Accumulate(Telemetry::NETWORK_RACE_CACHE_WITH_NETWORK_USAGE,
|
||||
rcwnStatus);
|
||||
Telemetry::Accumulate(kRcwnTelemetry[rcwnStatus], mTransferSize);
|
||||
|
||||
gIOService->IncrementRequestNumber();
|
||||
if (rcwnStatus == kRaceUsedCache) {
|
||||
if (rcwnStatus == kRaceUsedCache || rcwnStatus == kDelayedRaceUsedCache) {
|
||||
gIOService->IncrementCacheWonRequestNumber();
|
||||
} else if (rcwnStatus == kRaceUsedNetwork) {
|
||||
} else if (rcwnStatus == kRaceUsedNetwork || rcwnStatus == kDelayedRaceUsedNetwork) {
|
||||
gIOService->IncrementNetWonRequestNumber();
|
||||
}
|
||||
}
|
||||
|
@ -9232,24 +9241,23 @@ nsHttpChannel::MaybeRaceCacheWithNetwork()
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
uint32_t delay;
|
||||
if (CacheFileUtils::CachePerfStats::IsCacheSlow()) {
|
||||
// If the cache is slow, trigger the network request immediately.
|
||||
delay = 0;
|
||||
mRaceDelay = 0;
|
||||
} else {
|
||||
// Give cache a headstart of 3 times the average cache entry open time.
|
||||
delay = CacheFileUtils::CachePerfStats::GetAverage(
|
||||
mRaceDelay = CacheFileUtils::CachePerfStats::GetAverage(
|
||||
CacheFileUtils::CachePerfStats::ENTRY_OPEN, true) * 3;
|
||||
// We use microseconds in CachePerfStats but we need milliseconds
|
||||
// for TriggerNetwork.
|
||||
delay /= 1000;
|
||||
mRaceDelay /= 1000;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(sRCWNEnabled, "The pref must be truned on.");
|
||||
LOG(("nsHttpChannel::MaybeRaceCacheWithNetwork [this=%p, delay=%u]\n",
|
||||
this, delay));
|
||||
this, mRaceDelay));
|
||||
|
||||
return TriggerNetwork(delay);
|
||||
return TriggerNetwork(mRaceDelay);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
|
|
@ -708,6 +708,7 @@ private:
|
|||
// Will be true if the onCacheEntryAvailable callback is not called by the
|
||||
// time we send the network request
|
||||
Atomic<bool> mRaceCacheWithNetwork;
|
||||
uint32_t mRaceDelay;
|
||||
bool mCacheAsyncOpenCalled;
|
||||
|
||||
protected:
|
||||
|
|
|
@ -770,14 +770,19 @@ nsHttpHandler::NotifyObservers(nsIHttpChannel *chan, const char *event)
|
|||
}
|
||||
|
||||
nsresult
|
||||
nsHttpHandler::AsyncOnChannelRedirect(nsIChannel* oldChan, nsIChannel* newChan,
|
||||
uint32_t flags)
|
||||
nsHttpHandler::AsyncOnChannelRedirect(nsIChannel* oldChan,
|
||||
nsIChannel* newChan,
|
||||
uint32_t flags,
|
||||
nsIEventTarget* mainThreadEventTarget)
|
||||
{
|
||||
// TODO E10S This helper has to be initialized on the other process
|
||||
RefPtr<nsAsyncRedirectVerifyHelper> redirectCallbackHelper =
|
||||
new nsAsyncRedirectVerifyHelper();
|
||||
|
||||
return redirectCallbackHelper->Init(oldChan, newChan, flags);
|
||||
return redirectCallbackHelper->Init(oldChan,
|
||||
newChan,
|
||||
flags,
|
||||
mainThreadEventTarget);
|
||||
}
|
||||
|
||||
/* static */ nsresult
|
||||
|
|
|
@ -331,9 +331,11 @@ public:
|
|||
|
||||
// Called by channels before a redirect happens. This notifies both the
|
||||
// channel's and the global redirect observers.
|
||||
MOZ_MUST_USE nsresult AsyncOnChannelRedirect(nsIChannel* oldChan,
|
||||
MOZ_MUST_USE nsresult AsyncOnChannelRedirect(
|
||||
nsIChannel* oldChan,
|
||||
nsIChannel* newChan,
|
||||
uint32_t flags);
|
||||
uint32_t flags,
|
||||
nsIEventTarget* mainThreadEventTarget = nullptr);
|
||||
|
||||
// Called by the channel when the response is read from the cache without
|
||||
// communicating with the server.
|
||||
|
|
|
@ -2932,7 +2932,7 @@ WebSocketChannel::ApplyForAdmission()
|
|||
rv = pps->AsyncResolve(mHttpChannel,
|
||||
nsIProtocolProxyService::RESOLVE_PREFER_HTTPS_PROXY |
|
||||
nsIProtocolProxyService::RESOLVE_ALWAYS_TUNNEL,
|
||||
this, getter_AddRefs(mCancelable));
|
||||
this, nullptr, getter_AddRefs(mCancelable));
|
||||
NS_ASSERTION(NS_FAILED(rv) || mCancelable,
|
||||
"nsIProtocolProxyService::AsyncResolve succeeded but didn't "
|
||||
"return a cancelable object!");
|
||||
|
|
|
@ -133,17 +133,6 @@ but you may be able to get a recent enough version from a software install
|
|||
tool or package manager on your system, or directly from https://rust-lang.org/
|
||||
'''
|
||||
|
||||
STYLO_MOZCONFIG = '''
|
||||
To enable Stylo in your builds, paste the lines between the chevrons
|
||||
(>>> and <<<) into your mozconfig file:
|
||||
|
||||
<<<
|
||||
ac_add_options --enable-stylo
|
||||
|
||||
export LLVM_CONFIG=%s/clang/bin/llvm-config
|
||||
>>>
|
||||
'''
|
||||
|
||||
BROWSER_ARTIFACT_MODE_MOZCONFIG = '''
|
||||
Paste the lines between the chevrons (>>> and <<<) into your mozconfig file:
|
||||
|
||||
|
@ -170,7 +159,6 @@ class BaseBootstrapper(object):
|
|||
def __init__(self, no_interactive=False):
|
||||
self.package_manager_updated = False
|
||||
self.no_interactive = no_interactive
|
||||
self.stylo = False
|
||||
self.state_dir = None
|
||||
|
||||
def install_system_packages(self):
|
||||
|
@ -199,8 +187,7 @@ class BaseBootstrapper(object):
|
|||
Firefox for Desktop can in simple cases determine its build environment
|
||||
entirely from configure.
|
||||
'''
|
||||
if self.stylo:
|
||||
print(STYLO_MOZCONFIG % self.state_dir)
|
||||
pass
|
||||
|
||||
def install_browser_artifact_mode_packages(self):
|
||||
'''
|
||||
|
|
|
@ -92,18 +92,6 @@ Would you like to create this directory?
|
|||
|
||||
Your choice: '''
|
||||
|
||||
STYLO_DEVELOPMENT_INFO = '''
|
||||
Stylo is an experimental rewrite of the Gecko style system in Rust to
|
||||
be faster and make better use of modern computer hardware.
|
||||
|
||||
Would you like to download packages for working on Stylo? If you're
|
||||
not sure, select "No".
|
||||
|
||||
1. Yes
|
||||
2. No
|
||||
|
||||
Your choice: '''
|
||||
|
||||
STYLO_DIRECTORY_MESSAGE = '''
|
||||
Stylo packages require a directory to store shared, persistent state.
|
||||
On this machine, that directory is:
|
||||
|
@ -315,28 +303,20 @@ class Bootstrapper(object):
|
|||
|
||||
# Install the clang packages needed for developing stylo.
|
||||
if not self.instance.no_interactive:
|
||||
choice = self.instance.prompt_int(
|
||||
prompt=STYLO_DEVELOPMENT_INFO,
|
||||
low=1,
|
||||
high=2)
|
||||
|
||||
# The best place to install our packages is in the state directory
|
||||
# we have. If the user doesn't have one, we need them to re-run
|
||||
# bootstrap and create the directory.
|
||||
#
|
||||
# XXX Android bootstrap just assumes the existence of the state
|
||||
# directory and writes the NDK into it. Should we do the same?
|
||||
wants_stylo = choice == 1
|
||||
if wants_stylo and not state_dir_available:
|
||||
if not state_dir_available:
|
||||
print(STYLO_DIRECTORY_MESSAGE.format(statedir=state_dir))
|
||||
sys.exit(1)
|
||||
|
||||
if wants_stylo and not have_clone:
|
||||
if not have_clone:
|
||||
print(STYLO_REQUIRES_CLONE)
|
||||
sys.exit(1)
|
||||
|
||||
self.instance.stylo = wants_stylo
|
||||
if wants_stylo:
|
||||
self.instance.state_dir = state_dir
|
||||
self.instance.ensure_stylo_packages(state_dir, checkout_root)
|
||||
|
||||
|
|
|
@ -4,15 +4,6 @@
|
|||
|
||||
from mozboot.base import BaseBootstrapper
|
||||
|
||||
STYLO_MOZCONFIG = '''
|
||||
To enable Stylo in your builds, paste the lines between the chevrons
|
||||
(>>> and <<<) into your mozconfig file:
|
||||
|
||||
<<<
|
||||
ac_add_options --enable-stylo
|
||||
>>>
|
||||
'''
|
||||
|
||||
class FreeBSDBootstrapper(BaseBootstrapper):
|
||||
def __init__(self, version, flavor, **kwargs):
|
||||
BaseBootstrapper.__init__(self, **kwargs)
|
||||
|
@ -72,9 +63,5 @@ class FreeBSDBootstrapper(BaseBootstrapper):
|
|||
def ensure_stylo_packages(self, state_dir, checkout_root):
|
||||
self.pkg_install('llvm40')
|
||||
|
||||
def suggest_browser_mozconfig(self):
|
||||
if self.stylo:
|
||||
print(STYLO_MOZCONFIG)
|
||||
|
||||
def upgrade_mercurial(self, current):
|
||||
self.pkg_install('mercurial')
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче