mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-09 03:15:11 +00:00
Merge mozilla-central to autoland. a=merge CLOSED TREE
This commit is contained in:
commit
9de29c1f5a
7
.flake8
7
.flake8
@ -7,6 +7,13 @@ exclude =
|
||||
browser/moz.configure,
|
||||
build/moz.configure/*.configure,
|
||||
build/pymake/,
|
||||
dom/canvas/test/webgl-conf/checkout/closure-library/,
|
||||
editor/libeditor/tests/browserscope/,
|
||||
intl/icu/,
|
||||
ipc/chromium/,
|
||||
gfx/angle/,
|
||||
gfx/harfbuzz,
|
||||
glx/skia/,
|
||||
js/*.configure,
|
||||
memory/moz.configure,
|
||||
mobile/android/*.configure,
|
||||
|
@ -209,7 +209,8 @@ SelectionManager::ProcessSelectionChanged(SelData* aSelData)
|
||||
|
||||
HyperTextAccessible* text = nsAccUtils::GetTextContainer(cntrNode);
|
||||
if (!text) {
|
||||
NS_NOTREACHED("We must reach document accessible implementing text interface!");
|
||||
// FIXME bug 1126649
|
||||
NS_ERROR("We must reach document accessible implementing text interface!");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -146,12 +146,12 @@
|
||||
|
||||
<vbox flex="1">
|
||||
|
||||
<listbox>
|
||||
<listitem label="listitem1" id="listitem1"/>
|
||||
<listitem label="listitem2" id="listitem2" type="checkbox"/>
|
||||
<listitem label="listitem3" id="listitem3" type="checkbox"/>
|
||||
<listitem label="listitem4" id="listitem4"/>
|
||||
</listbox>
|
||||
<richlistbox>
|
||||
<richlistitem id="listitem1"/>
|
||||
<richlistitem id="listitem2"><label value="listitem2"/></richlistitem>
|
||||
<richlistitem id="listitem3"/>
|
||||
<richlistitem id="listitem4"><label value="listitem4"/></richlistitem>
|
||||
</richlistbox>
|
||||
|
||||
<menubar>
|
||||
<menu label="item1" id="menu_item1">
|
||||
|
@ -63,10 +63,10 @@
|
||||
|
||||
<vbox flex="1">
|
||||
<label control="listbox1" value="listbox: "/>
|
||||
<listbox id="listbox1">
|
||||
<listitem label="item1" id="item1"/>
|
||||
<listitem label="item2" id="item2"/>
|
||||
</listbox>
|
||||
<richlistbox id="listbox1">
|
||||
<richlistitem id="item1"><label value="item1"/></richlistitem>
|
||||
<richlistitem id="item1"><label value="item2"/></richlistitem>
|
||||
</richlistbox>
|
||||
</vbox>
|
||||
</hbox>
|
||||
|
||||
|
@ -30,16 +30,6 @@
|
||||
// Test focus events.
|
||||
gQueue = new eventQueue();
|
||||
|
||||
gQueue.push(new synthFocus("listbox", new focusChecker("lb_item1")));
|
||||
gQueue.push(new synthDownKey("lb_item1", new focusChecker("lb_item2")));
|
||||
gQueue.push(new synthTab("lb_item2", new focusChecker("mslb_item1")));
|
||||
gQueue.push(new synthDownKey("mslb_item1", new focusChecker("mslb_item2"), { shiftKey: true }));
|
||||
gQueue.push(new synthTab("mslb_item2", new focusChecker("emptylistbox")));
|
||||
gQueue.push(new synthFocus("mcolumnlistbox", new focusChecker("mclb_item1")));
|
||||
gQueue.push(new synthDownKey("mclb_item1", new focusChecker("mclb_item2")));
|
||||
gQueue.push(new synthFocus("headerlistbox", new focusChecker("hlb_item1")));
|
||||
gQueue.push(new synthDownKey("hlb_item1", new focusChecker("hlb_item2")));
|
||||
|
||||
gQueue.push(new synthFocus("richlistbox", new focusChecker("rlb_item1")));
|
||||
gQueue.push(new synthDownKey("rlb_item1", new focusChecker("rlb_item2")));
|
||||
gQueue.push(new synthFocus("multiselrichlistbox", new focusChecker("msrlb_item1")));
|
||||
@ -70,9 +60,8 @@ if (!MAC) {
|
||||
|
||||
// no focus events for unfocused list controls when current item is
|
||||
// changed.
|
||||
gQueue.push(new synthFocus("emptylistbox"));
|
||||
gQueue.push(new synthFocus("emptyrichlistbox"));
|
||||
|
||||
gQueue.push(new changeCurrentItem("listbox", "lb_item1"));
|
||||
gQueue.push(new changeCurrentItem("richlistbox", "rlb_item1"));
|
||||
if (!MAC) {
|
||||
gQueue.push(new changeCurrentItem("menulist", WIN ? "ml_marmalade" : "ml_tangerine"));
|
||||
@ -110,48 +99,6 @@ if (!MAC) {
|
||||
</body>
|
||||
|
||||
<vbox flex="1">
|
||||
<listbox id="listbox" rows="3">
|
||||
<listitem id="lb_item1" label="item1"/>
|
||||
<listitem id="lb_item2" label="item1"/>
|
||||
</listbox>
|
||||
<listbox id="multisellistbox" rows="3" seltype="multiple">
|
||||
<listitem id="mslb_item1" label="item1"/>
|
||||
<listitem id="mslb_item2" label="item1"/>
|
||||
</listbox>
|
||||
<listbox id="emptylistbox" rows="3"/>
|
||||
<listbox id="mcolumnlistbox" rows="3">
|
||||
<listcols>
|
||||
<listcol/>
|
||||
<listcol/>
|
||||
</listcols>
|
||||
<listitem id="mclb_item1">
|
||||
<listcell label="George"/>
|
||||
<listcell label="House Painter"/>
|
||||
</listitem>
|
||||
<listitem id="mclb_item2">
|
||||
<listcell label="Mary Ellen"/>
|
||||
<listcell label="Candle Maker"/>
|
||||
</listitem>
|
||||
</listbox>
|
||||
<listbox id="headerlistbox" rows="3">
|
||||
<listhead>
|
||||
<listheader label="Name"/>
|
||||
<listheader label="Occupation"/>
|
||||
</listhead>
|
||||
<listcols>
|
||||
<listcol/>
|
||||
<listcol flex="1"/>
|
||||
</listcols>
|
||||
<listitem id="hlb_item1">
|
||||
<listcell label="George"/>
|
||||
<listcell label="House Painter"/>
|
||||
</listitem>
|
||||
<listitem id="hlb_item2">
|
||||
<listcell label="Mary Ellen"/>
|
||||
<listcell label="Candle Maker"/>
|
||||
</listitem>
|
||||
</listbox>
|
||||
|
||||
<richlistbox id="richlistbox">
|
||||
<richlistitem id="rlb_item1">
|
||||
<description>A XUL Description!</description>
|
||||
|
@ -166,9 +166,12 @@
|
||||
gQueue.push(new advanceTab("tabs", 1, "tab3"));
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// listbox
|
||||
gQueue.push(new synthClick("lb1_item1",
|
||||
new invokerChecker(EVENT_SELECTION, "lb1_item1")));
|
||||
// single selection listbox, the first item is selected by default
|
||||
|
||||
gQueue.push(new synthClick("lb1_item2",
|
||||
new invokerChecker(EVENT_SELECTION, "lb1_item2")));
|
||||
gQueue.push(new synthUpKey("lb1_item2",
|
||||
new invokerChecker(EVENT_SELECTION, "lb1_item1")));
|
||||
gQueue.push(new synthDownKey("lb1_item1",
|
||||
new invokerChecker(EVENT_SELECTION, "lb1_item2")));
|
||||
|
||||
@ -234,20 +237,20 @@
|
||||
</tabpanels>
|
||||
</tabbox>
|
||||
|
||||
<listbox id="listbox">
|
||||
<listitem id="lb1_item1" label="item1"/>
|
||||
<listitem id="lb1_item2" label="item2"/>
|
||||
</listbox>
|
||||
<richlistbox id="listbox">
|
||||
<richlistitem id="lb1_item1"><label value="item1"/></richlistitem>
|
||||
<richlistitem id="lb1_item2"><label value="item2"/></richlistitem>
|
||||
</richlistbox>
|
||||
|
||||
<listbox id="listbox2" seltype="multiple">
|
||||
<listitem id="lb2_item1" label="item1"/>
|
||||
<listitem id="lb2_item2" label="item2"/>
|
||||
<listitem id="lb2_item3" label="item3"/>
|
||||
<listitem id="lb2_item4" label="item4"/>
|
||||
<listitem id="lb2_item5" label="item5"/>
|
||||
<listitem id="lb2_item6" label="item6"/>
|
||||
<listitem id="lb2_item7" label="item7"/>
|
||||
</listbox>
|
||||
<richlistbox id="listbox2" seltype="multiple">
|
||||
<richlistitem id="lb2_item1"><label value="item1"/></richlistitem>
|
||||
<richlistitem id="lb2_item2"><label value="item2"/></richlistitem>
|
||||
<richlistitem id="lb2_item3"><label value="item3"/></richlistitem>
|
||||
<richlistitem id="lb2_item4"><label value="item4"/></richlistitem>
|
||||
<richlistitem id="lb2_item5"><label value="item5"/></richlistitem>
|
||||
<richlistitem id="lb2_item6"><label value="item6"/></richlistitem>
|
||||
<richlistitem id="lb2_item7"><label value="item7"/></richlistitem>
|
||||
</richlistbox>
|
||||
|
||||
</hbox>
|
||||
</window>
|
||||
|
@ -95,10 +95,10 @@
|
||||
<treechildren id="treechildren"/>
|
||||
</tree>
|
||||
|
||||
<listbox id="listbox">
|
||||
<listitem id="listitem1">item1</listitem>
|
||||
<listitem id="listitem2">item2</listitem>
|
||||
</listbox>
|
||||
<richlistbox id="listbox">
|
||||
<richlistitem id="listitem1"><label value="item1"/></richlistitem>
|
||||
<richlistitem id="listitem2"><label value="item2"/></richlistitem>
|
||||
</richlistbox>
|
||||
|
||||
<vbox id="eventdump"/>
|
||||
</vbox>
|
||||
|
@ -276,10 +276,11 @@
|
||||
label="labeled element"/>
|
||||
|
||||
<!-- nsIDOMXULSelectControlItemElement -->
|
||||
<listbox>
|
||||
<listitem id="li_nsIDOMXULSelectControlItemElement"
|
||||
label="select control item"/>
|
||||
</listbox>
|
||||
<richlistbox>
|
||||
<richlistitem id="li_nsIDOMXULSelectControlItemElement">
|
||||
<label value="select control item"/>
|
||||
</richlistitem>
|
||||
</richlistbox>
|
||||
|
||||
<!-- not nsIDOMXULSelectControlElement -->
|
||||
<box id="box_not_nsIDOMXULSelectControlElement" role="group" label="box"/>
|
||||
@ -359,11 +360,12 @@
|
||||
|
||||
<!-- bug 441991; create name from other menuitem label listitem's own label -->
|
||||
<hbox>
|
||||
<listbox>
|
||||
<listitem id="li_labelledby"
|
||||
label="The moment the event starts"
|
||||
aria-labelledby="menuitem-DISPLAY li_labelledby"/>
|
||||
</listbox>
|
||||
<richlistbox>
|
||||
<richlistitem id="li_labelledby"
|
||||
aria-labelledby="menuitem-DISPLAY li_labelledby">
|
||||
<label value="The moment the event starts"/>
|
||||
</richlistitem>
|
||||
</richlistbox>
|
||||
<menulist>
|
||||
<menupopup>
|
||||
<menuitem id="menuitem-DISPLAY"
|
||||
|
@ -32,13 +32,14 @@
|
||||
function doTest()
|
||||
{
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// single selectable listbox
|
||||
// single selectable listbox, the first item is selected by default
|
||||
|
||||
var id = "listbox";
|
||||
ok(isAccessible(id, [nsIAccessibleSelectable]),
|
||||
"No selectable accessible for list of " + id);
|
||||
|
||||
var select = getAccessible(id, [nsIAccessibleSelectable]);
|
||||
select.removeItemFromSelection(0);
|
||||
testSelectableSelection(select, [ ]);
|
||||
|
||||
select.addItemToSelection(1);
|
||||
@ -114,35 +115,27 @@
|
||||
</body>
|
||||
|
||||
<vbox flex="1">
|
||||
<listbox id="listbox">
|
||||
<listcols>
|
||||
<listcol flex="1"/>
|
||||
<listcol flex="1"/>
|
||||
</listcols>
|
||||
<listitem id="lb1_item1">
|
||||
<listcell label="cell0"/>
|
||||
<listcell label="cell1"/>
|
||||
</listitem>
|
||||
<listitem id="lb1_item2">
|
||||
<listcell label="cell3"/>
|
||||
<listcell label="cell4"/>
|
||||
</listitem>
|
||||
</listbox>
|
||||
<richlistbox id="listbox">
|
||||
<richlistitem id="lb1_item1">
|
||||
<label value="cell0"/>
|
||||
<label value="cell1"/>
|
||||
</richlistitem>
|
||||
<richlistitem id="lb1_item2">
|
||||
<label value="cell3"/>
|
||||
<label value="cell4"/>
|
||||
</richlistitem>
|
||||
</richlistbox>
|
||||
|
||||
<listbox id="listbox2" seltype="multiple">
|
||||
<listcols>
|
||||
<listcol flex="1"/>
|
||||
<listcol flex="1"/>
|
||||
</listcols>
|
||||
<listitem id="lb2_item1">
|
||||
<listcell label="cell0"/>
|
||||
<listcell label="cell1"/>
|
||||
</listitem>
|
||||
<listitem id="lb2_item2">
|
||||
<listcell label="cell3"/>
|
||||
<listcell label="cell4"/>
|
||||
</listitem>
|
||||
</listbox>
|
||||
<richlistbox id="listbox2" seltype="multiple">
|
||||
<richlistitem id="lb2_item1">
|
||||
<label value="cell0"/>
|
||||
<label value="cell1"/>
|
||||
</richlistitem>
|
||||
<richlistitem id="lb2_item2">
|
||||
<label value="cell3"/>
|
||||
<label value="cell4"/>
|
||||
</richlistitem>
|
||||
</richlistbox>
|
||||
|
||||
<vbox id="debug"/>
|
||||
</vbox>
|
||||
|
@ -155,7 +155,7 @@ function testStates(aAccOrElmOrID, aState, aExtraState, aAbsentState,
|
||||
"Mixed element cannot be state checked!");
|
||||
|
||||
// selected/selectable
|
||||
if (state & STATE_SELECTED) {
|
||||
if ((state & STATE_SELECTED) && !(aAbsentState & STATE_SELECTABLE)) {
|
||||
isState(state & STATE_SELECTABLE, STATE_SELECTABLE, false,
|
||||
"Selected element must be selectable!");
|
||||
}
|
||||
|
@ -64,9 +64,9 @@
|
||||
testStates("combobox", STATE_FOCUSABLE | STATE_HASPOPUP, 0, STATE_UNAVAILABLE);
|
||||
testStates("combobox-disabled", STATE_UNAVAILABLE | STATE_HASPOPUP, 0, STATE_FOCUSABLE);
|
||||
testStates("listbox", STATE_FOCUSABLE, 0, STATE_UNAVAILABLE);
|
||||
testStates("listitem", STATE_FOCUSABLE | STATE_SELECTABLE, 0, STATE_UNAVAILABLE);
|
||||
testStates("listitem", STATE_FOCUSABLE | STATE_SELECTABLE | STATE_SELECTED, 0, STATE_UNAVAILABLE);
|
||||
testStates("listbox-disabled", STATE_UNAVAILABLE, 0, STATE_FOCUSABLE | STATE_SELECTABLE);
|
||||
testStates("listitem-disabledlistbox", STATE_UNAVAILABLE, 0, STATE_FOCUSABLE | STATE_SELECTABLE);
|
||||
testStates("listitem-disabledlistbox", STATE_UNAVAILABLE | STATE_SELECTED, 0, STATE_FOCUSABLE | STATE_SELECTABLE);
|
||||
testStates("menubar", 0, 0, STATE_FOCUSABLE);
|
||||
testStates("menu", STATE_FOCUSABLE, 0, STATE_UNAVAILABLE);
|
||||
testStates("menu-disabled", STATE_UNAVAILABLE, 0, STATE_FOCUSABLE | STATE_SELECTABLE);
|
||||
@ -135,13 +135,17 @@
|
||||
</menupopup>
|
||||
</menulist>
|
||||
|
||||
<listbox id="listbox">
|
||||
<listitem id="listitem" label="list item"/>
|
||||
</listbox>
|
||||
<richlistbox id="listbox">
|
||||
<richlistitem id="listitem">
|
||||
<label value="list item"/>
|
||||
</richlistitem>
|
||||
</richlistbox>
|
||||
|
||||
<listbox id="listbox-disabled" disabled="true">
|
||||
<listitem id="listitem-disabledlistbox" label="list item"/>
|
||||
</listbox>
|
||||
<richlistbox id="listbox-disabled" disabled="true">
|
||||
<richlistitem id="listitem-disabledlistbox">
|
||||
<label value="list item"/>
|
||||
</richlistitem>
|
||||
</richlistbox>
|
||||
|
||||
<toolbox>
|
||||
<menubar id="menubar">
|
||||
|
@ -5,22 +5,18 @@ support-files =
|
||||
[test_css_tables.html]
|
||||
[test_headers_ariagrid.html]
|
||||
[test_headers_ariatable.html]
|
||||
[test_headers_listbox.xul]
|
||||
[test_headers_table.html]
|
||||
[test_headers_tree.xul]
|
||||
[test_indexes_ariagrid.html]
|
||||
[test_indexes_listbox.xul]
|
||||
[test_indexes_table.html]
|
||||
[test_indexes_tree.xul]
|
||||
[test_layoutguess.html]
|
||||
[test_mtable.html]
|
||||
[test_sels_ariagrid.html]
|
||||
[test_sels_listbox.xul]
|
||||
[test_sels_table.html]
|
||||
[test_sels_tree.xul]
|
||||
[test_struct_ariagrid.html]
|
||||
[test_struct_ariatreegrid.html]
|
||||
[test_struct_listbox.xul]
|
||||
[test_struct_table.html]
|
||||
[test_struct_tree.xul]
|
||||
[test_table_1.html]
|
||||
|
@ -1,194 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
|
||||
type="text/css"?>
|
||||
|
||||
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
title="Table header information cells for XUL listbox">
|
||||
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
|
||||
|
||||
<script type="application/javascript"
|
||||
src="../common.js"></script>
|
||||
<script type="application/javascript"
|
||||
src="../table.js"></script>
|
||||
|
||||
<script type="application/javascript">
|
||||
<![CDATA[
|
||||
function doTest()
|
||||
{
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// XUL listbox
|
||||
|
||||
var headerInfoMap = [
|
||||
{
|
||||
cell: "lb1_cell0",
|
||||
rowHeaderCells: [],
|
||||
columnHeaderCells: [ "lb1_header1" ]
|
||||
},
|
||||
{
|
||||
cell: "lb1_cell1",
|
||||
rowHeaderCells: [],
|
||||
columnHeaderCells: [ "lb1_header2" ]
|
||||
},
|
||||
{
|
||||
cell: "lb1_cell2",
|
||||
rowHeaderCells: [],
|
||||
columnHeaderCells: [ "lb1_header3" ]
|
||||
},
|
||||
{
|
||||
cell: "lb1_cell3",
|
||||
rowHeaderCells: [],
|
||||
columnHeaderCells: [ "lb1_header1" ]
|
||||
},
|
||||
{
|
||||
cell: "lb1_cell4",
|
||||
rowHeaderCells: [],
|
||||
columnHeaderCells: [ "lb1_header2" ]
|
||||
},
|
||||
{
|
||||
cell: "lb1_cell5",
|
||||
rowHeaderCells: [],
|
||||
columnHeaderCells: [ "lb1_header3" ]
|
||||
},
|
||||
];
|
||||
|
||||
testHeaderCells(headerInfoMap);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// XUL listbox with ARIA
|
||||
|
||||
headerInfoMap = [
|
||||
{
|
||||
cell: "lb2_cell0",
|
||||
rowHeaderCells: [],
|
||||
columnHeaderCells: []
|
||||
},
|
||||
{
|
||||
cell: "lb2_cell1",
|
||||
rowHeaderCells: [],
|
||||
columnHeaderCells: []
|
||||
},
|
||||
{
|
||||
cell: "lb2_cell2",
|
||||
rowHeaderCells: [],
|
||||
columnHeaderCells: []
|
||||
},
|
||||
{
|
||||
cell: "lb2_cell3",
|
||||
rowHeaderCells: [],
|
||||
columnHeaderCells: [ "lb2_cell0" ]
|
||||
},
|
||||
{
|
||||
cell: "lb2_cell4",
|
||||
rowHeaderCells: [ "lb2_cell3" ],
|
||||
columnHeaderCells: [ "lb2_cell1" ]
|
||||
},
|
||||
{
|
||||
cell: "lb2_cell5",
|
||||
rowHeaderCells: [ "lb2_cell3" ],
|
||||
columnHeaderCells: [ "lb2_cell2" ]
|
||||
},
|
||||
{
|
||||
cell: "lb2_cell6",
|
||||
rowHeaderCells: [],
|
||||
columnHeaderCells: [ "lb2_cell0" ]
|
||||
},
|
||||
{
|
||||
cell: "lb2_cell7",
|
||||
rowHeaderCells: [ "lb2_cell6" ],
|
||||
columnHeaderCells: [ "lb2_cell1" ]
|
||||
},
|
||||
{
|
||||
cell: "lb2_cell8",
|
||||
rowHeaderCells: [ "lb2_cell6" ],
|
||||
columnHeaderCells: [ "lb2_cell2" ]
|
||||
}
|
||||
];
|
||||
|
||||
testHeaderCells(headerInfoMap);
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
addA11yLoadEvent(doTest);
|
||||
]]>
|
||||
</script>
|
||||
|
||||
<hbox style="overflow: auto;">
|
||||
<body xmlns="http://www.w3.org/1999/xhtml">
|
||||
<a target="_blank"
|
||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=512424"
|
||||
title="implement IAccessibleTable2">
|
||||
Mozilla Bug 512424
|
||||
</a>
|
||||
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
</div>
|
||||
<pre id="test">
|
||||
</pre>
|
||||
</body>
|
||||
|
||||
<vbox flex="1">
|
||||
|
||||
<label control="listbox" value="multicolumn listbox with header"/>
|
||||
<listbox id="listbox">
|
||||
<listhead>
|
||||
<listheader id="lb1_header1" label="header1"/>
|
||||
<listheader id="lb1_header2" label="header2"/>
|
||||
<listheader id="lb1_header3" label="header3"/>
|
||||
</listhead>
|
||||
<listcols>
|
||||
<listcol flex="1"/>
|
||||
<listcol flex="1"/>
|
||||
<listcol flex="1"/>
|
||||
</listcols>
|
||||
<listitem>
|
||||
<listcell id="lb1_cell0" label="cell0"/>
|
||||
<listcell id="lb1_cell1" label="cell1"/>
|
||||
<listcell id="lb1_cell2" label="cell2"/>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<listcell id="lb1_cell3" label="cell3"/>
|
||||
<listcell id="lb1_cell4" label="cell4"/>
|
||||
<listcell id="lb1_cell5" label="cell5"/>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<listcell id="lb1_cell6" label="cell6"/>
|
||||
<listcell id="lb1_cell7" label="cell7"/>
|
||||
<listcell id="lb1_cell8" label="cell8"/>
|
||||
</listitem>
|
||||
</listbox>
|
||||
|
||||
<label control="listbox2" value="multicolumn listbox with ARIA headers"/>
|
||||
<listbox id="listbox2">
|
||||
<listcols>
|
||||
<listcol flex="1"/>
|
||||
<listcol flex="1"/>
|
||||
<listcol flex="1"/>
|
||||
</listcols>
|
||||
<listitem>
|
||||
<listcell role="columnheader" id="lb2_cell0" label="cell0"/>
|
||||
<listcell role="columnheader" id="lb2_cell1" label="cell1"/>
|
||||
<listcell role="columnheader" id="lb2_cell2" label="cell2"/>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<listcell role="rowheader" id="lb2_cell3" label="cell3"/>
|
||||
<listcell id="lb2_cell4" label="cell4"/>
|
||||
<listcell id="lb2_cell5" label="cell5"/>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<listcell role="rowheader" id="lb2_cell6" label="cell6"/>
|
||||
<listcell id="lb2_cell7" label="cell7"/>
|
||||
<listcell id="lb2_cell8" label="cell8"/>
|
||||
</listitem>
|
||||
</listbox>
|
||||
|
||||
</vbox>
|
||||
</hbox>
|
||||
|
||||
</window>
|
||||
|
@ -1,85 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
|
||||
type="text/css"?>
|
||||
|
||||
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
title="Table indices of accessible table for XUL listbox">
|
||||
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
|
||||
|
||||
<script type="application/javascript"
|
||||
src="../common.js"></script>
|
||||
<script type="application/javascript"
|
||||
src="../table.js"></script>
|
||||
|
||||
<script type="application/javascript">
|
||||
<![CDATA[
|
||||
function doTest()
|
||||
{
|
||||
var idxes = [
|
||||
[0, 1, 2],
|
||||
[3, 4, 5],
|
||||
[6, 7, 8]
|
||||
];
|
||||
testTableIndexes("listbox", idxes);
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
addA11yLoadEvent(doTest);
|
||||
]]>
|
||||
</script>
|
||||
|
||||
<hbox style="overflow: auto;">
|
||||
<body xmlns="http://www.w3.org/1999/xhtml">
|
||||
<a target="_blank"
|
||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=512424"
|
||||
title="implement IAccessibleTable2">
|
||||
Mozilla Bug 512424
|
||||
</a>
|
||||
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
</div>
|
||||
<pre id="test">
|
||||
</pre>
|
||||
</body>
|
||||
|
||||
<vbox flex="1">
|
||||
|
||||
<label control="listbox" value="multicolumn listbox with header"/>
|
||||
<listbox id="listbox">
|
||||
<listhead>
|
||||
<listheader label="header1"/>
|
||||
<listheader label="header2"/>
|
||||
<listheader label="header3"/>
|
||||
</listhead>
|
||||
<listcols>
|
||||
<listcol flex="1"/>
|
||||
<listcol flex="1"/>
|
||||
<listcol flex="1"/>
|
||||
</listcols>
|
||||
<listitem>
|
||||
<listcell label="cell0"/>
|
||||
<listcell label="cell1"/>
|
||||
<listcell label="cell2"/>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<listcell label="cell3"/>
|
||||
<listcell label="cell4"/>
|
||||
<listcell label="cell5"/>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<listcell label="cell6"/>
|
||||
<listcell label="cell7"/>
|
||||
<listcell label="cell8"/>
|
||||
</listitem>
|
||||
</listbox>
|
||||
</vbox>
|
||||
</hbox>
|
||||
|
||||
</window>
|
||||
|
@ -1,247 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
|
||||
type="text/css"?>
|
||||
|
||||
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
title="nsIAccessibleTable selection methods on xul:listbox test.">
|
||||
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
|
||||
|
||||
<script type="application/javascript"
|
||||
src="../common.js"></script>
|
||||
<script type="application/javascript"
|
||||
src="../table.js"></script>
|
||||
|
||||
<script type="application/javascript">
|
||||
<![CDATA[
|
||||
function doTest()
|
||||
{
|
||||
var id = "listbox3";
|
||||
var acc = getAccessible(id, [nsIAccessibleTable]);
|
||||
|
||||
var rowCount = acc.rows;
|
||||
var colsCount = acc.columns;
|
||||
|
||||
// columns selection
|
||||
testColumnSelection(id, acc, colsCount, 0, null);
|
||||
acc.selectColumn(0);
|
||||
testColumnSelection(id, acc, colsCount, 0, null);
|
||||
|
||||
// rows selection
|
||||
testRowSelection(id, acc, rowCount, 0, null);
|
||||
acc.selectRow(0);
|
||||
testRowSelection(id, acc, rowCount, 1, [0]);
|
||||
acc.selectRow(1);
|
||||
testRowSelection(id, acc, rowCount, 1, [1]);
|
||||
acc.unselectRow(1);
|
||||
testRowSelection(id, acc, rowCount, 0, null);
|
||||
|
||||
// cells selection
|
||||
testCellSelection(id, acc, rowCount, colsCount, 0, null);
|
||||
acc.selectRow(2);
|
||||
testCellSelection(id, acc, rowCount, colsCount, 3, [6, 7, 8]);
|
||||
acc.unselectRow(2);
|
||||
testCellSelection(id, acc, rowCount, colsCount, 0, null);
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to test isColumnSelected(), selectedColumnCount and
|
||||
* getSelectedColumn() methods.
|
||||
*/
|
||||
function testColumnSelection(aId, aAcc, aCount, aSelCount, aSelIndexesArray)
|
||||
{
|
||||
// isColumnSelected
|
||||
for (var col = 0; col < aCount; col++) {
|
||||
if (aSelIndexesArray && aSelIndexesArray.includes(col)) {
|
||||
is(aAcc.isColumnSelected(col), true,
|
||||
aId + ": column " + col + " should be selected");
|
||||
} else {
|
||||
is(aAcc.isColumnSelected(col), false,
|
||||
aId + ": column " + col + " shouldn't be selected");
|
||||
}
|
||||
}
|
||||
|
||||
// selectedColumnCount
|
||||
is(aAcc.selectedColumnCount, aSelCount,
|
||||
aId + ": wrong number of selected columns");
|
||||
|
||||
// getSelectedColumns
|
||||
var selColsCount = {}, selCols = {};
|
||||
aAcc.getSelectedColumnIndices(selColsCount, selCols);
|
||||
|
||||
is(selColsCount.value, aSelCount,
|
||||
aId + ": wrong number of selected columns");
|
||||
|
||||
if (!aSelIndexesArray) {
|
||||
is(selCols.value, undefined,
|
||||
aId + ": no columns should be selected");
|
||||
} else {
|
||||
for (var i = 0; i < selCols.length; i++) {
|
||||
is(selCols[i], aSelIndexesArray[i],
|
||||
aId + ": wrong selected column index " + i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to test isRowSelected(), selectedRowCount() and
|
||||
* getSelectedRow() methods.
|
||||
*/
|
||||
function testRowSelection(aId, aAcc, aCount, aSelCount, aSelIndexesArray)
|
||||
{
|
||||
// isRowSelected
|
||||
for (var row = 0; row < aCount; row++) {
|
||||
if (aSelIndexesArray && aSelIndexesArray.includes(row)) {
|
||||
is(aAcc.isRowSelected(row), true,
|
||||
aId + ": row " + row + " should be selected");
|
||||
} else {
|
||||
is(aAcc.isRowSelected(row), false,
|
||||
aId + ": row " + row + " shouldn't be selected");
|
||||
}
|
||||
}
|
||||
|
||||
// selectedRowCount
|
||||
is(aAcc.selectedRowCount, aSelCount,
|
||||
aId + ": wrong number of selected rows");
|
||||
|
||||
// getSelectedRows
|
||||
var selColsCount = {}, selCols = {};
|
||||
aAcc.getSelectedRowIndices(selColsCount, selCols);
|
||||
|
||||
is(selColsCount.value, aSelCount,
|
||||
aId + ": wrong number of selected rows");
|
||||
|
||||
if (!aSelIndexesArray) {
|
||||
is(selCols.value, undefined,
|
||||
aId + ": no row should be selected");
|
||||
} else {
|
||||
for (var i = 0; i < selCols.length; i++) {
|
||||
is(selCols[i], aSelIndexesArray[i],
|
||||
aId + ": wrong selected row index " + i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to test isCellSelected(), selectedCellCount() and
|
||||
* getSelectedCells() methods.
|
||||
*/
|
||||
function testCellSelection(aId, aAcc, aRowCount, aColCount,
|
||||
aSelCount, aSelIndexesArray)
|
||||
{
|
||||
// isCellSelected
|
||||
for (var row = 0; row < aRowCount; row++) {
|
||||
for (var col = 0; col < aColCount; col++) {
|
||||
var index = aAcc.getIndexAt(row, col);
|
||||
if (aSelIndexesArray && aSelIndexesArray.includes(index)) {
|
||||
is(aAcc.isCellSelected(row, col), true,
|
||||
aId + ": cell (" + row + ", " + col + ") should be selected");
|
||||
} else {
|
||||
is(aAcc.isCellSelected(row, col), false,
|
||||
aId + ": cell (" + row + ", " + col + ") shouldn't be selected");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// selectedCellCount
|
||||
is(aAcc.selectedCellCount, aSelCount,
|
||||
aId + ": wrong number of selected cells");
|
||||
|
||||
// getSelectedCells
|
||||
var selColsCount = {}, selCols = {};
|
||||
aAcc.getSelectedCellIndices(selColsCount, selCols);
|
||||
|
||||
is(selColsCount.value, aSelCount,
|
||||
aId + ": wrong number of selected cells");
|
||||
|
||||
if (!aSelIndexesArray) {
|
||||
is(selCols.value, undefined,
|
||||
aId + ": no cells should be selected");
|
||||
} else {
|
||||
for (var i = 0; i < selCols.length; i++) {
|
||||
is(selCols[i], aSelIndexesArray[i],
|
||||
aId + ": wrong selected cell index " + i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
addA11yLoadEvent(doTest);
|
||||
]]>
|
||||
</script>
|
||||
|
||||
<hbox style="overflow: auto;">
|
||||
<body xmlns="http://www.w3.org/1999/xhtml">
|
||||
<a target="_blank"
|
||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=418371"
|
||||
title="implement the rest of methods of nsIAccessibleTable on xul:listbox">
|
||||
Mozilla Bug 418371
|
||||
</a>
|
||||
<a target="_blank"
|
||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=512424"
|
||||
title="implement IAccessibleTable2">
|
||||
Mozilla Bug 512424
|
||||
</a>
|
||||
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
</div>
|
||||
<pre id="test">
|
||||
</pre>
|
||||
</body>
|
||||
|
||||
<vbox flex="1">
|
||||
|
||||
<label control="listbox2" value="multicolumn listbox: "/>
|
||||
<listbox id="listbox2">
|
||||
<listcols>
|
||||
<listcol flex="1"/>
|
||||
<listcol flex="1"/>
|
||||
</listcols>
|
||||
<listitem>
|
||||
<listcell label="cell1"/>
|
||||
<listcell label="cell2"/>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<listcell label="cell1"/>
|
||||
<listcell label="cell2"/>
|
||||
</listitem>
|
||||
</listbox>
|
||||
|
||||
<label control="listbox3" value="multicolumn listbox with header"/>
|
||||
<listbox id="listbox3">
|
||||
<listhead>
|
||||
<listheader label="header1"/>
|
||||
<listheader label="header2"/>
|
||||
<listheader label="header3"/>
|
||||
</listhead>
|
||||
<listcols>
|
||||
<listcol flex="1"/>
|
||||
<listcol flex="1"/>
|
||||
<listcol flex="1"/>
|
||||
</listcols>
|
||||
<listitem>
|
||||
<listcell label="cell0"/>
|
||||
<listcell label="cell1"/>
|
||||
<listcell label="cell2"/>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<listcell label="cell3"/>
|
||||
<listcell label="cell4"/>
|
||||
<listcell label="cell5"/>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<listcell label="cell6"/>
|
||||
<listcell label="cell7"/>
|
||||
<listcell label="cell8"/>
|
||||
</listitem>
|
||||
</listbox>
|
||||
</vbox>
|
||||
</hbox>
|
||||
|
||||
</window>
|
||||
|
@ -1,117 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
|
||||
type="text/css"?>
|
||||
|
||||
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
title="Table accessible tree and table interface tests for XUL listboxes">
|
||||
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
|
||||
|
||||
<script type="application/javascript"
|
||||
src="../common.js"></script>
|
||||
<script type="application/javascript"
|
||||
src="../role.js"></script>
|
||||
<script type="application/javascript"
|
||||
src="../table.js"></script>
|
||||
|
||||
<script type="application/javascript">
|
||||
<![CDATA[
|
||||
function doTest()
|
||||
{
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Multicolumn listbox.
|
||||
|
||||
var cellsArray = [
|
||||
[kDataCell, kDataCell],
|
||||
[kDataCell, kDataCell]
|
||||
];
|
||||
|
||||
testTableStruct("listbox1", cellsArray);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Multicolumn listbox with header.
|
||||
|
||||
var cellsArray = [
|
||||
[kDataCell, kDataCell, kDataCell],
|
||||
[kDataCell, kDataCell, kDataCell],
|
||||
[kDataCell, kDataCell, kDataCell]
|
||||
];
|
||||
|
||||
testTableStruct("listbox2", cellsArray, kListboxColumnHeader);
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
addA11yLoadEvent(doTest);
|
||||
]]>
|
||||
</script>
|
||||
|
||||
<hbox style="overflow: auto;">
|
||||
<body xmlns="http://www.w3.org/1999/xhtml">
|
||||
<a target="_blank"
|
||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=512424"
|
||||
title="implement IAccessibleTable2">
|
||||
Mozilla Bug 512424
|
||||
</a>
|
||||
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
</div>
|
||||
<pre id="test">
|
||||
</pre>
|
||||
</body>
|
||||
|
||||
<vbox flex="1">
|
||||
|
||||
<label control="listbox1" value="multicolumn listbox: "/>
|
||||
<listbox id="listbox1">
|
||||
<listcols>
|
||||
<listcol flex="1"/>
|
||||
<listcol flex="1"/>
|
||||
</listcols>
|
||||
<listitem>
|
||||
<listcell label="cell1"/>
|
||||
<listcell label="cell2"/>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<listcell label="cell1"/>
|
||||
<listcell label="cell2"/>
|
||||
</listitem>
|
||||
</listbox>
|
||||
|
||||
<label control="listbox2" value="multicolumn listbox with header"/>
|
||||
<listbox id="listbox2">
|
||||
<listhead>
|
||||
<listheader label="header1"/>
|
||||
<listheader label="header2"/>
|
||||
<listheader label="header3"/>
|
||||
</listhead>
|
||||
<listcols>
|
||||
<listcol flex="1"/>
|
||||
<listcol flex="1"/>
|
||||
<listcol flex="1"/>
|
||||
</listcols>
|
||||
<listitem>
|
||||
<listcell label="cell0"/>
|
||||
<listcell label="cell1"/>
|
||||
<listcell label="cell2"/>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<listcell label="cell3"/>
|
||||
<listcell label="cell4"/>
|
||||
<listcell label="cell5"/>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<listcell label="cell6"/>
|
||||
<listcell label="cell7"/>
|
||||
<listcell label="cell8"/>
|
||||
</listitem>
|
||||
</listbox>
|
||||
</vbox>
|
||||
</hbox>
|
||||
|
||||
</window>
|
||||
|
@ -25,8 +25,10 @@
|
||||
{
|
||||
this.listboxNode = getNode(aListboxID);
|
||||
|
||||
this.listitemNode = document.createElement("listitem");
|
||||
this.listitemNode.setAttribute("label", "item1");
|
||||
this.listitemNode = document.createElement("richlistitem");
|
||||
var label = document.createElement("label");
|
||||
label.setAttribute("value", "item1");
|
||||
this.listitemNode.appendChild(label);
|
||||
|
||||
this.eventSeq = [
|
||||
new invokerChecker(EVENT_SHOW, this.listitemNode),
|
||||
@ -168,11 +170,11 @@
|
||||
</body>
|
||||
|
||||
<vbox flex="1">
|
||||
<listbox id="listbox" rows="2">
|
||||
<listitem label="item2"/>
|
||||
<listitem label="item3"/>
|
||||
<listitem label="item4"/>
|
||||
</listbox>
|
||||
<richlistbox id="listbox">
|
||||
<richlistitem><label value="item2"/></richlistitem>
|
||||
<richlistitem><label value="item3"/></richlistitem>
|
||||
<richlistitem><label value="item4"/></richlistitem>
|
||||
</richlistbox>
|
||||
</vbox>
|
||||
</hbox>
|
||||
|
||||
|
@ -45,6 +45,7 @@ const whitelist = {
|
||||
"resource://gre/modules/Log.jsm",
|
||||
|
||||
// Session store
|
||||
"resource:///modules/sessionstore/ContentSessionStore.jsm",
|
||||
"resource://gre/modules/sessionstore/SessionHistory.jsm",
|
||||
|
||||
// Forms and passwords
|
||||
|
1043
browser/components/sessionstore/ContentSessionStore.jsm
Normal file
1043
browser/components/sessionstore/ContentSessionStore.jsm
Normal file
File diff suppressed because it is too large
Load Diff
@ -6,976 +6,6 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm", this);
|
||||
ChromeUtils.import("resource://gre/modules/Timer.jsm", this);
|
||||
ChromeUtils.import("resource://gre/modules/Services.jsm", this);
|
||||
ChromeUtils.import("resource:///modules/sessionstore/ContentSessionStore.jsm");
|
||||
|
||||
ChromeUtils.defineModuleGetter(this, "TelemetryStopwatch",
|
||||
"resource://gre/modules/TelemetryStopwatch.jsm");
|
||||
|
||||
function debug(msg) {
|
||||
Services.console.logStringMessage("SessionStoreContent: " + msg);
|
||||
}
|
||||
|
||||
ChromeUtils.defineModuleGetter(this, "FormData",
|
||||
"resource://gre/modules/FormData.jsm");
|
||||
|
||||
ChromeUtils.defineModuleGetter(this, "ContentRestore",
|
||||
"resource:///modules/sessionstore/ContentRestore.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "DocShellCapabilities",
|
||||
"resource:///modules/sessionstore/DocShellCapabilities.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "ScrollPosition",
|
||||
"resource://gre/modules/ScrollPosition.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "SessionHistory",
|
||||
"resource://gre/modules/sessionstore/SessionHistory.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "SessionStorage",
|
||||
"resource:///modules/sessionstore/SessionStorage.jsm");
|
||||
|
||||
var contentRestoreInitialized = false;
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "gContentRestore",
|
||||
() => {
|
||||
contentRestoreInitialized = true;
|
||||
return new ContentRestore(this);
|
||||
});
|
||||
|
||||
ChromeUtils.defineModuleGetter(this, "Utils",
|
||||
"resource://gre/modules/sessionstore/Utils.jsm");
|
||||
const ssu = Cc["@mozilla.org/browser/sessionstore/utils;1"]
|
||||
.getService(Ci.nsISessionStoreUtils);
|
||||
|
||||
// The current epoch.
|
||||
var gCurrentEpoch = 0;
|
||||
|
||||
// A bound to the size of data to store for DOM Storage.
|
||||
const DOM_STORAGE_LIMIT_PREF = "browser.sessionstore.dom_storage_limit";
|
||||
|
||||
// This pref controls whether or not we send updates to the parent on a timeout
|
||||
// or not, and should only be used for tests or debugging.
|
||||
const TIMEOUT_DISABLED_PREF = "browser.sessionstore.debug.no_auto_updates";
|
||||
|
||||
const PREF_INTERVAL = "browser.sessionstore.interval";
|
||||
|
||||
const kNoIndex = Number.MAX_SAFE_INTEGER;
|
||||
const kLastIndex = Number.MAX_SAFE_INTEGER - 1;
|
||||
|
||||
// Grab our global so we can access it in functions below.
|
||||
const global = this;
|
||||
|
||||
/**
|
||||
* A function that will recursively call |cb| to collect data for all
|
||||
* non-dynamic frames in the current frame/docShell tree.
|
||||
*/
|
||||
function mapFrameTree(callback) {
|
||||
let [data] = Utils.mapFrameTree(content, callback);
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Listens for state change notifcations from webProgress and notifies each
|
||||
* registered observer for either the start of a page load, or its completion.
|
||||
*/
|
||||
var StateChangeNotifier = {
|
||||
|
||||
init() {
|
||||
this._observers = new Set();
|
||||
let ifreq = docShell.QueryInterface(Ci.nsIInterfaceRequestor);
|
||||
let webProgress = ifreq.getInterface(Ci.nsIWebProgress);
|
||||
webProgress.addProgressListener(this, Ci.nsIWebProgress.NOTIFY_STATE_DOCUMENT);
|
||||
},
|
||||
|
||||
/**
|
||||
* Adds a given observer |obs| to the set of observers that will be notified
|
||||
* when when a new document starts or finishes loading.
|
||||
*
|
||||
* @param obs (object)
|
||||
*/
|
||||
addObserver(obs) {
|
||||
this._observers.add(obs);
|
||||
},
|
||||
|
||||
/**
|
||||
* Notifies all observers that implement the given |method|.
|
||||
*
|
||||
* @param method (string)
|
||||
*/
|
||||
notifyObservers(method) {
|
||||
for (let obs of this._observers) {
|
||||
if (obs.hasOwnProperty(method)) {
|
||||
obs[method]();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @see nsIWebProgressListener.onStateChange
|
||||
*/
|
||||
onStateChange(webProgress, request, stateFlags, status) {
|
||||
// Ignore state changes for subframes because we're only interested in the
|
||||
// top-document starting or stopping its load.
|
||||
if (!webProgress.isTopLevel || webProgress.DOMWindow != content) {
|
||||
return;
|
||||
}
|
||||
|
||||
// onStateChange will be fired when loading the initial about:blank URI for
|
||||
// a browser, which we don't actually care about. This is particularly for
|
||||
// the case of unrestored background tabs, where the content has not yet
|
||||
// been restored: we don't want to accidentally send any updates to the
|
||||
// parent when the about:blank placeholder page has loaded.
|
||||
if (!docShell.hasLoadedNonBlankURI) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (stateFlags & Ci.nsIWebProgressListener.STATE_START) {
|
||||
this.notifyObservers("onPageLoadStarted");
|
||||
} else if (stateFlags & Ci.nsIWebProgressListener.STATE_STOP) {
|
||||
this.notifyObservers("onPageLoadCompleted");
|
||||
}
|
||||
},
|
||||
|
||||
QueryInterface: ChromeUtils.generateQI([Ci.nsIWebProgressListener,
|
||||
Ci.nsISupportsWeakReference])
|
||||
};
|
||||
|
||||
/**
|
||||
* Listens for and handles content events that we need for the
|
||||
* session store service to be notified of state changes in content.
|
||||
*/
|
||||
var EventListener = {
|
||||
|
||||
init() {
|
||||
ssu.addDynamicFrameFilteredListener(global, "load", this, true);
|
||||
},
|
||||
|
||||
handleEvent(event) {
|
||||
// Ignore load events from subframes.
|
||||
if (event.target != content.document) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (content.document.documentURI.startsWith("about:reader")) {
|
||||
if (event.type == "load" &&
|
||||
!content.document.body.classList.contains("loaded")) {
|
||||
// Don't restore the scroll position of an about:reader page at this
|
||||
// point; listen for the custom event dispatched from AboutReader.jsm.
|
||||
content.addEventListener("AboutReaderContentReady", this);
|
||||
return;
|
||||
}
|
||||
|
||||
content.removeEventListener("AboutReaderContentReady", this);
|
||||
}
|
||||
|
||||
if (contentRestoreInitialized) {
|
||||
// Restore the form data and scroll position. If we're not currently
|
||||
// restoring a tab state then this call will simply be a noop.
|
||||
gContentRestore.restoreDocument();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Listens for and handles messages sent by the session store service.
|
||||
*/
|
||||
var MessageListener = {
|
||||
|
||||
MESSAGES: [
|
||||
"SessionStore:restoreHistory",
|
||||
"SessionStore:restoreTabContent",
|
||||
"SessionStore:resetRestore",
|
||||
"SessionStore:flush",
|
||||
"SessionStore:becomeActiveProcess",
|
||||
],
|
||||
|
||||
init() {
|
||||
this.MESSAGES.forEach(m => addMessageListener(m, this));
|
||||
},
|
||||
|
||||
receiveMessage({name, data}) {
|
||||
// The docShell might be gone. Don't process messages,
|
||||
// that will just lead to errors anyway.
|
||||
if (!docShell) {
|
||||
return;
|
||||
}
|
||||
|
||||
// A fresh tab always starts with epoch=0. The parent has the ability to
|
||||
// override that to signal a new era in this tab's life. This enables it
|
||||
// to ignore async messages that were already sent but not yet received
|
||||
// and would otherwise confuse the internal tab state.
|
||||
if (data.epoch && data.epoch != gCurrentEpoch) {
|
||||
gCurrentEpoch = data.epoch;
|
||||
}
|
||||
|
||||
switch (name) {
|
||||
case "SessionStore:restoreHistory":
|
||||
this.restoreHistory(data);
|
||||
break;
|
||||
case "SessionStore:restoreTabContent":
|
||||
if (data.isRemotenessUpdate) {
|
||||
let histogram = Services.telemetry.getKeyedHistogramById("FX_TAB_REMOTE_NAVIGATION_DELAY_MS");
|
||||
histogram.add("SessionStore:restoreTabContent",
|
||||
Services.telemetry.msSystemNow() - data.requestTime);
|
||||
}
|
||||
this.restoreTabContent(data);
|
||||
break;
|
||||
case "SessionStore:resetRestore":
|
||||
gContentRestore.resetRestore();
|
||||
break;
|
||||
case "SessionStore:flush":
|
||||
this.flush(data);
|
||||
break;
|
||||
case "SessionStore:becomeActiveProcess":
|
||||
SessionHistoryListener.collect();
|
||||
break;
|
||||
default:
|
||||
debug("received unknown message '" + name + "'");
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
restoreHistory({epoch, tabData, loadArguments, isRemotenessUpdate}) {
|
||||
gContentRestore.restoreHistory(tabData, loadArguments, {
|
||||
// Note: The callbacks passed here will only be used when a load starts
|
||||
// that was not initiated by sessionstore itself. This can happen when
|
||||
// some code calls browser.loadURI() or browser.reload() on a pending
|
||||
// browser/tab.
|
||||
|
||||
onLoadStarted() {
|
||||
// Notify the parent that the tab is no longer pending.
|
||||
sendAsyncMessage("SessionStore:restoreTabContentStarted", {epoch});
|
||||
},
|
||||
|
||||
onLoadFinished() {
|
||||
// Tell SessionStore.jsm that it may want to restore some more tabs,
|
||||
// since it restores a max of MAX_CONCURRENT_TAB_RESTORES at a time.
|
||||
sendAsyncMessage("SessionStore:restoreTabContentComplete", {epoch});
|
||||
}
|
||||
});
|
||||
|
||||
if (Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_DEFAULT) {
|
||||
// For non-remote tabs, when restoreHistory finishes, we send a synchronous
|
||||
// message to SessionStore.jsm so that it can run SSTabRestoring. Users of
|
||||
// SSTabRestoring seem to get confused if chrome and content are out of
|
||||
// sync about the state of the restore (particularly regarding
|
||||
// docShell.currentURI). Using a synchronous message is the easiest way
|
||||
// to temporarily synchronize them.
|
||||
//
|
||||
// For remote tabs, because all nsIWebProgress notifications are sent
|
||||
// asynchronously using messages, we get the same-order guarantees of the
|
||||
// message manager, and can use an async message.
|
||||
sendSyncMessage("SessionStore:restoreHistoryComplete", {epoch, isRemotenessUpdate});
|
||||
} else {
|
||||
sendAsyncMessage("SessionStore:restoreHistoryComplete", {epoch, isRemotenessUpdate});
|
||||
}
|
||||
},
|
||||
|
||||
restoreTabContent({loadArguments, isRemotenessUpdate, reason}) {
|
||||
let epoch = gCurrentEpoch;
|
||||
|
||||
// We need to pass the value of didStartLoad back to SessionStore.jsm.
|
||||
let didStartLoad = gContentRestore.restoreTabContent(loadArguments, isRemotenessUpdate, () => {
|
||||
// Tell SessionStore.jsm that it may want to restore some more tabs,
|
||||
// since it restores a max of MAX_CONCURRENT_TAB_RESTORES at a time.
|
||||
sendAsyncMessage("SessionStore:restoreTabContentComplete", {epoch, isRemotenessUpdate});
|
||||
});
|
||||
|
||||
sendAsyncMessage("SessionStore:restoreTabContentStarted", {
|
||||
epoch, isRemotenessUpdate, reason,
|
||||
});
|
||||
|
||||
if (!didStartLoad) {
|
||||
// Pretend that the load succeeded so that event handlers fire correctly.
|
||||
sendAsyncMessage("SessionStore:restoreTabContentComplete", {epoch, isRemotenessUpdate});
|
||||
}
|
||||
},
|
||||
|
||||
flush({id}) {
|
||||
// Flush the message queue, send the latest updates.
|
||||
MessageQueue.send({flushID: id});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Listens for changes to the session history. Whenever the user navigates
|
||||
* we will collect URLs and everything belonging to session history.
|
||||
*
|
||||
* Causes a SessionStore:update message to be sent that contains the current
|
||||
* session history.
|
||||
*
|
||||
* Example:
|
||||
* {entries: [{url: "about:mozilla", ...}, ...], index: 1}
|
||||
*/
|
||||
var SessionHistoryListener = {
|
||||
init() {
|
||||
// The state change observer is needed to handle initial subframe loads.
|
||||
// It will redundantly invalidate with the SHistoryListener in some cases
|
||||
// but these invalidations are very cheap.
|
||||
StateChangeNotifier.addObserver(this);
|
||||
|
||||
// By adding the SHistoryListener immediately, we will unfortunately be
|
||||
// notified of every history entry as the tab is restored. We don't bother
|
||||
// waiting to add the listener later because these notifications are cheap.
|
||||
// We will likely only collect once since we are batching collection on
|
||||
// a delay.
|
||||
docShell.QueryInterface(Ci.nsIWebNavigation).
|
||||
sessionHistory.legacySHistory.addSHistoryListener(this);
|
||||
|
||||
// Collect data if we start with a non-empty shistory.
|
||||
if (!SessionHistory.isEmpty(docShell)) {
|
||||
this.collect();
|
||||
// When a tab is detached from the window, for the new window there is a
|
||||
// new SessionHistoryListener created. Normally it is empty at this point
|
||||
// but in a test env. the initial about:blank might have a children in which
|
||||
// case we fire off a history message here with about:blank in it. If we
|
||||
// don't do it ASAP then there is going to be a browser swap and the parent
|
||||
// will be all confused by that message.
|
||||
MessageQueue.send();
|
||||
}
|
||||
|
||||
// Listen for page title changes.
|
||||
addEventListener("DOMTitleChanged", this);
|
||||
},
|
||||
|
||||
uninit() {
|
||||
let sessionHistory = docShell.QueryInterface(Ci.nsIWebNavigation).sessionHistory;
|
||||
if (sessionHistory) {
|
||||
sessionHistory.legacySHistory.removeSHistoryListener(this);
|
||||
}
|
||||
},
|
||||
|
||||
collect() {
|
||||
// We want to send down a historychange even for full collects in case our
|
||||
// session history is a partial session history, in which case we don't have
|
||||
// enough information for a full update. collectFrom(-1) tells the collect
|
||||
// function to collect all data avaliable in this process.
|
||||
if (docShell) {
|
||||
this.collectFrom(-1);
|
||||
}
|
||||
},
|
||||
|
||||
_fromIdx: kNoIndex,
|
||||
|
||||
// History can grow relatively big with the nested elements, so if we don't have to, we
|
||||
// don't want to send the entire history all the time. For a simple optimization
|
||||
// we keep track of the smallest index from after any change has occured and we just send
|
||||
// the elements from that index. If something more complicated happens we just clear it
|
||||
// and send the entire history. We always send the additional info like the current selected
|
||||
// index (so for going back and forth between history entries we set the index to kLastIndex
|
||||
// if nothing else changed send an empty array and the additonal info like the selected index)
|
||||
collectFrom(idx) {
|
||||
if (this._fromIdx <= idx) {
|
||||
// If we already know that we need to update history fromn index N we can ignore any changes
|
||||
// tha happened with an element with index larger than N.
|
||||
// Note: initially we use kNoIndex which is MAX_SAFE_INTEGER which means we don't ignore anything
|
||||
// here, and in case of navigation in the history back and forth we use kLastIndex which ignores
|
||||
// only the subsequent navigations, but not any new elements added.
|
||||
return;
|
||||
}
|
||||
|
||||
this._fromIdx = idx;
|
||||
MessageQueue.push("historychange", () => {
|
||||
if (this._fromIdx === kNoIndex) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let history = SessionHistory.collect(docShell, this._fromIdx);
|
||||
this._fromIdx = kNoIndex;
|
||||
return history;
|
||||
});
|
||||
},
|
||||
|
||||
handleEvent(event) {
|
||||
this.collect();
|
||||
},
|
||||
|
||||
onPageLoadCompleted() {
|
||||
this.collect();
|
||||
},
|
||||
|
||||
onPageLoadStarted() {
|
||||
this.collect();
|
||||
},
|
||||
|
||||
OnHistoryNewEntry(newURI, oldIndex) {
|
||||
// We ought to collect the previously current entry as well, see bug 1350567.
|
||||
this.collectFrom(oldIndex);
|
||||
},
|
||||
|
||||
OnHistoryGoBack(backURI) {
|
||||
// We ought to collect the previously current entry as well, see bug 1350567.
|
||||
this.collectFrom(kLastIndex);
|
||||
return true;
|
||||
},
|
||||
|
||||
OnHistoryGoForward(forwardURI) {
|
||||
// We ought to collect the previously current entry as well, see bug 1350567.
|
||||
this.collectFrom(kLastIndex);
|
||||
return true;
|
||||
},
|
||||
|
||||
OnHistoryGotoIndex(index, gotoURI) {
|
||||
// We ought to collect the previously current entry as well, see bug 1350567.
|
||||
this.collectFrom(kLastIndex);
|
||||
return true;
|
||||
},
|
||||
|
||||
OnHistoryPurge(numEntries) {
|
||||
this.collect();
|
||||
return true;
|
||||
},
|
||||
|
||||
OnHistoryReload(reloadURI, reloadFlags) {
|
||||
this.collect();
|
||||
return true;
|
||||
},
|
||||
|
||||
OnHistoryReplaceEntry(index) {
|
||||
this.collect();
|
||||
},
|
||||
|
||||
OnLengthChanged(aCount) {
|
||||
// Ignore, the method is implemented so that XPConnect doesn't throw!
|
||||
},
|
||||
|
||||
OnIndexChanged(aIndex) {
|
||||
// Ignore, the method is implemented so that XPConnect doesn't throw!
|
||||
},
|
||||
|
||||
QueryInterface: ChromeUtils.generateQI([
|
||||
Ci.nsISHistoryListener,
|
||||
Ci.nsISupportsWeakReference
|
||||
])
|
||||
};
|
||||
|
||||
/**
|
||||
* Listens for scroll position changes. Whenever the user scrolls the top-most
|
||||
* frame we update the scroll position and will restore it when requested.
|
||||
*
|
||||
* Causes a SessionStore:update message to be sent that contains the current
|
||||
* scroll positions as a tree of strings. If no frame of the whole frame tree
|
||||
* is scrolled this will return null so that we don't tack a property onto
|
||||
* the tabData object in the parent process.
|
||||
*
|
||||
* Example:
|
||||
* {scroll: "100,100", children: [null, null, {scroll: "200,200"}]}
|
||||
*/
|
||||
var ScrollPositionListener = {
|
||||
init() {
|
||||
ssu.addDynamicFrameFilteredListener(global, "scroll", this, false);
|
||||
StateChangeNotifier.addObserver(this);
|
||||
},
|
||||
|
||||
handleEvent() {
|
||||
MessageQueue.push("scroll", () => this.collect());
|
||||
},
|
||||
|
||||
onPageLoadCompleted() {
|
||||
MessageQueue.push("scroll", () => this.collect());
|
||||
},
|
||||
|
||||
onPageLoadStarted() {
|
||||
MessageQueue.push("scroll", () => null);
|
||||
},
|
||||
|
||||
collect() {
|
||||
return mapFrameTree(ScrollPosition.collect);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Listens for changes to input elements. Whenever the value of an input
|
||||
* element changes we will re-collect data for the current frame tree and send
|
||||
* a message to the parent process.
|
||||
*
|
||||
* Causes a SessionStore:update message to be sent that contains the form data
|
||||
* for all reachable frames.
|
||||
*
|
||||
* Example:
|
||||
* {
|
||||
* formdata: {url: "http://mozilla.org/", id: {input_id: "input value"}},
|
||||
* children: [
|
||||
* null,
|
||||
* {url: "http://sub.mozilla.org/", id: {input_id: "input value 2"}}
|
||||
* ]
|
||||
* }
|
||||
*/
|
||||
var FormDataListener = {
|
||||
init() {
|
||||
ssu.addDynamicFrameFilteredListener(global, "input", this, true);
|
||||
StateChangeNotifier.addObserver(this);
|
||||
},
|
||||
|
||||
handleEvent() {
|
||||
MessageQueue.push("formdata", () => this.collect());
|
||||
},
|
||||
|
||||
onPageLoadStarted() {
|
||||
MessageQueue.push("formdata", () => null);
|
||||
},
|
||||
|
||||
collect() {
|
||||
return mapFrameTree(FormData.collect);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Listens for changes to docShell capabilities. Whenever a new load is started
|
||||
* we need to re-check the list of capabilities and send message when it has
|
||||
* changed.
|
||||
*
|
||||
* Causes a SessionStore:update message to be sent that contains the currently
|
||||
* disabled docShell capabilities (all nsIDocShell.allow* properties set to
|
||||
* false) as a string - i.e. capability names separate by commas.
|
||||
*/
|
||||
var DocShellCapabilitiesListener = {
|
||||
/**
|
||||
* This field is used to compare the last docShell capabilities to the ones
|
||||
* that have just been collected. If nothing changed we won't send a message.
|
||||
*/
|
||||
_latestCapabilities: "",
|
||||
|
||||
init() {
|
||||
StateChangeNotifier.addObserver(this);
|
||||
},
|
||||
|
||||
onPageLoadStarted() {
|
||||
// The order of docShell capabilities cannot change while we're running
|
||||
// so calling join() without sorting before is totally sufficient.
|
||||
let caps = DocShellCapabilities.collect(docShell).join(",");
|
||||
|
||||
// Send new data only when the capability list changes.
|
||||
if (caps != this._latestCapabilities) {
|
||||
this._latestCapabilities = caps;
|
||||
MessageQueue.push("disallow", () => caps || null);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Listens for changes to the DOMSessionStorage. Whenever new keys are added,
|
||||
* existing ones removed or changed, or the storage is cleared we will send a
|
||||
* message to the parent process containing up-to-date sessionStorage data.
|
||||
*
|
||||
* Causes a SessionStore:update message to be sent that contains the current
|
||||
* DOMSessionStorage contents. The data is a nested object using host names
|
||||
* as keys and per-host DOMSessionStorage data as values.
|
||||
*/
|
||||
var SessionStorageListener = {
|
||||
init() {
|
||||
Services.obs.addObserver(this, "browser:purge-domain-data");
|
||||
StateChangeNotifier.addObserver(this);
|
||||
this.resetEventListener();
|
||||
},
|
||||
|
||||
uninit() {
|
||||
Services.obs.removeObserver(this, "browser:purge-domain-data");
|
||||
},
|
||||
|
||||
observe() {
|
||||
// Collect data on the next tick so that any other observer
|
||||
// that needs to purge data can do its work first.
|
||||
setTimeoutWithTarget(() => this.collect(), 0, tabEventTarget);
|
||||
},
|
||||
|
||||
// We don't want to send all the session storage data for all the frames
|
||||
// for every change. So if only a few value changed we send them over as
|
||||
// a "storagechange" event. If however for some reason before we send these
|
||||
// changes we have to send over the entire sessions storage data, we just
|
||||
// reset these changes.
|
||||
_changes: undefined,
|
||||
|
||||
resetChanges() {
|
||||
this._changes = undefined;
|
||||
},
|
||||
|
||||
// The event listener waiting for MozSessionStorageChanged events.
|
||||
_listener: null,
|
||||
|
||||
resetEventListener() {
|
||||
if (!this._listener) {
|
||||
this._listener =
|
||||
ssu.addDynamicFrameFilteredListener(global, "MozSessionStorageChanged",
|
||||
this, true);
|
||||
}
|
||||
},
|
||||
|
||||
removeEventListener() {
|
||||
ssu.removeDynamicFrameFilteredListener(global, "MozSessionStorageChanged",
|
||||
this._listener, true);
|
||||
this._listener = null;
|
||||
},
|
||||
|
||||
handleEvent(event) {
|
||||
if (!docShell) {
|
||||
return;
|
||||
}
|
||||
|
||||
// How much data does DOMSessionStorage contain?
|
||||
let usage = content.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDOMWindowUtils)
|
||||
.getStorageUsage(event.storageArea);
|
||||
|
||||
// Don't store any data if we exceed the limit. Wipe any data we previously
|
||||
// collected so that we don't confuse websites with partial state.
|
||||
if (usage > Services.prefs.getIntPref(DOM_STORAGE_LIMIT_PREF)) {
|
||||
MessageQueue.push("storage", () => null);
|
||||
this.removeEventListener();
|
||||
this.resetChanges();
|
||||
return;
|
||||
}
|
||||
|
||||
let {url, key, newValue} = event;
|
||||
let uri = Services.io.newURI(url);
|
||||
let domain = uri.prePath;
|
||||
if (!this._changes) {
|
||||
this._changes = {};
|
||||
}
|
||||
if (!this._changes[domain]) {
|
||||
this._changes[domain] = {};
|
||||
}
|
||||
this._changes[domain][key] = newValue;
|
||||
|
||||
MessageQueue.push("storagechange", () => {
|
||||
let tmp = this._changes;
|
||||
// If there were multiple changes we send them merged.
|
||||
// First one will collect all the changes the rest of
|
||||
// these messages will be ignored.
|
||||
this.resetChanges();
|
||||
return tmp;
|
||||
});
|
||||
},
|
||||
|
||||
collect() {
|
||||
if (!docShell) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We need the entire session storage, let's reset the pending individual change
|
||||
// messages.
|
||||
this.resetChanges();
|
||||
|
||||
MessageQueue.push("storage", () => SessionStorage.collect(content));
|
||||
},
|
||||
|
||||
onPageLoadCompleted() {
|
||||
this.collect();
|
||||
},
|
||||
|
||||
onPageLoadStarted() {
|
||||
this.resetEventListener();
|
||||
this.collect();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Listen for changes to the privacy status of the tab.
|
||||
* By definition, tabs start in non-private mode.
|
||||
*
|
||||
* Causes a SessionStore:update message to be sent for
|
||||
* field "isPrivate". This message contains
|
||||
* |true| if the tab is now private
|
||||
* |null| if the tab is now public - the field is therefore
|
||||
* not saved.
|
||||
*/
|
||||
var PrivacyListener = {
|
||||
init() {
|
||||
docShell.addWeakPrivacyTransitionObserver(this);
|
||||
|
||||
// Check that value at startup as it might have
|
||||
// been set before the frame script was loaded.
|
||||
if (docShell.QueryInterface(Ci.nsILoadContext).usePrivateBrowsing) {
|
||||
MessageQueue.push("isPrivate", () => true);
|
||||
}
|
||||
},
|
||||
|
||||
// Ci.nsIPrivacyTransitionObserver
|
||||
privateModeChanged(enabled) {
|
||||
MessageQueue.push("isPrivate", () => enabled || null);
|
||||
},
|
||||
|
||||
QueryInterface: ChromeUtils.generateQI([Ci.nsIPrivacyTransitionObserver,
|
||||
Ci.nsISupportsWeakReference])
|
||||
};
|
||||
|
||||
/**
|
||||
* A message queue that takes collected data and will take care of sending it
|
||||
* to the chrome process. It allows flushing using synchronous messages and
|
||||
* takes care of any race conditions that might occur because of that. Changes
|
||||
* will be batched if they're pushed in quick succession to avoid a message
|
||||
* flood.
|
||||
*/
|
||||
var MessageQueue = {
|
||||
/**
|
||||
* A map (string -> lazy fn) holding lazy closures of all queued data
|
||||
* collection routines. These functions will return data collected from the
|
||||
* docShell.
|
||||
*/
|
||||
_data: new Map(),
|
||||
|
||||
/**
|
||||
* The delay (in ms) used to delay sending changes after data has been
|
||||
* invalidated.
|
||||
*/
|
||||
BATCH_DELAY_MS: 1000,
|
||||
|
||||
/**
|
||||
* The minimum idle period (in ms) we need for sending data to chrome process.
|
||||
*/
|
||||
NEEDED_IDLE_PERIOD_MS: 5,
|
||||
|
||||
/**
|
||||
* Timeout for waiting an idle period to send data. We will set this from
|
||||
* the pref "browser.sessionstore.interval".
|
||||
*/
|
||||
_timeoutWaitIdlePeriodMs: null,
|
||||
|
||||
/**
|
||||
* The current timeout ID, null if there is no queue data. We use timeouts
|
||||
* to damp a flood of data changes and send lots of changes as one batch.
|
||||
*/
|
||||
_timeout: null,
|
||||
|
||||
/**
|
||||
* Whether or not sending batched messages on a timer is disabled. This should
|
||||
* only be used for debugging or testing. If you need to access this value,
|
||||
* you should probably use the timeoutDisabled getter.
|
||||
*/
|
||||
_timeoutDisabled: false,
|
||||
|
||||
/**
|
||||
* True if there is already a send pending idle dispatch, set to prevent
|
||||
* scheduling more than one. If false there may or may not be one scheduled.
|
||||
*/
|
||||
_idleScheduled: false,
|
||||
|
||||
/**
|
||||
* True if batched messages are not being fired on a timer. This should only
|
||||
* ever be true when debugging or during tests.
|
||||
*/
|
||||
get timeoutDisabled() {
|
||||
return this._timeoutDisabled;
|
||||
},
|
||||
|
||||
/**
|
||||
* Disables sending batched messages on a timer. Also cancels any pending
|
||||
* timers.
|
||||
*/
|
||||
set timeoutDisabled(val) {
|
||||
this._timeoutDisabled = val;
|
||||
|
||||
if (val && this._timeout) {
|
||||
clearTimeout(this._timeout);
|
||||
this._timeout = null;
|
||||
}
|
||||
|
||||
return val;
|
||||
},
|
||||
|
||||
init() {
|
||||
this.timeoutDisabled =
|
||||
Services.prefs.getBoolPref(TIMEOUT_DISABLED_PREF);
|
||||
this._timeoutWaitIdlePeriodMs =
|
||||
Services.prefs.getIntPref(PREF_INTERVAL);
|
||||
|
||||
Services.prefs.addObserver(TIMEOUT_DISABLED_PREF, this);
|
||||
Services.prefs.addObserver(PREF_INTERVAL, this);
|
||||
},
|
||||
|
||||
uninit() {
|
||||
Services.prefs.removeObserver(TIMEOUT_DISABLED_PREF, this);
|
||||
Services.prefs.removeObserver(PREF_INTERVAL, this);
|
||||
this.cleanupTimers();
|
||||
},
|
||||
|
||||
/**
|
||||
* Cleanup pending idle callback and timer.
|
||||
*/
|
||||
cleanupTimers() {
|
||||
this._idleScheduled = false;
|
||||
if (this._timeout) {
|
||||
clearTimeout(this._timeout);
|
||||
this._timeout = null;
|
||||
}
|
||||
},
|
||||
|
||||
observe(subject, topic, data) {
|
||||
if (topic == "nsPref:changed") {
|
||||
switch (data) {
|
||||
case TIMEOUT_DISABLED_PREF:
|
||||
this.timeoutDisabled =
|
||||
Services.prefs.getBoolPref(TIMEOUT_DISABLED_PREF);
|
||||
break;
|
||||
case PREF_INTERVAL:
|
||||
this._timeoutWaitIdlePeriodMs =
|
||||
Services.prefs.getIntPref(PREF_INTERVAL);
|
||||
break;
|
||||
default:
|
||||
debug("received unknown message '" + data + "'");
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Pushes a given |value| onto the queue. The given |key| represents the type
|
||||
* of data that is stored and can override data that has been queued before
|
||||
* but has not been sent to the parent process, yet.
|
||||
*
|
||||
* @param key (string)
|
||||
* A unique identifier specific to the type of data this is passed.
|
||||
* @param fn (function)
|
||||
* A function that returns the value that will be sent to the parent
|
||||
* process.
|
||||
*/
|
||||
push(key, fn) {
|
||||
this._data.set(key, fn);
|
||||
|
||||
if (!this._timeout && !this._timeoutDisabled) {
|
||||
// Wait a little before sending the message to batch multiple changes.
|
||||
this._timeout = setTimeoutWithTarget(
|
||||
() => this.sendWhenIdle(), this.BATCH_DELAY_MS, tabEventTarget);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Sends queued data when the remaining idle time is enough or waiting too
|
||||
* long; otherwise, request an idle time again. If the |deadline| is not
|
||||
* given, this function is going to schedule the first request.
|
||||
*
|
||||
* @param deadline (object)
|
||||
* An IdleDeadline object passed by idleDispatch().
|
||||
*/
|
||||
sendWhenIdle(deadline) {
|
||||
if (!content) {
|
||||
// The frameloader is being torn down. Nothing more to do.
|
||||
return;
|
||||
}
|
||||
|
||||
if (deadline) {
|
||||
if (deadline.didTimeout || deadline.timeRemaining() > MessageQueue.NEEDED_IDLE_PERIOD_MS) {
|
||||
MessageQueue.send();
|
||||
return;
|
||||
}
|
||||
} else if (MessageQueue._idleScheduled) {
|
||||
// Bail out if there's a pending run.
|
||||
return;
|
||||
}
|
||||
ChromeUtils.idleDispatch(MessageQueue.sendWhenIdle, {timeout: MessageQueue._timeoutWaitIdlePeriodMs});
|
||||
MessageQueue._idleScheduled = true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Sends queued data to the chrome process.
|
||||
*
|
||||
* @param options (object)
|
||||
* {flushID: 123} to specify that this is a flush
|
||||
* {isFinal: true} to signal this is the final message sent on unload
|
||||
*/
|
||||
send(options = {}) {
|
||||
// Looks like we have been called off a timeout after the tab has been
|
||||
// closed. The docShell is gone now and we can just return here as there
|
||||
// is nothing to do.
|
||||
if (!docShell) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.cleanupTimers();
|
||||
|
||||
let flushID = (options && options.flushID) || 0;
|
||||
let histID = "FX_SESSION_RESTORE_CONTENT_COLLECT_DATA_MS";
|
||||
|
||||
let data = {};
|
||||
for (let [key, func] of this._data) {
|
||||
if (key != "isPrivate") {
|
||||
TelemetryStopwatch.startKeyed(histID, key);
|
||||
}
|
||||
|
||||
let value = func();
|
||||
|
||||
if (key != "isPrivate") {
|
||||
TelemetryStopwatch.finishKeyed(histID, key);
|
||||
}
|
||||
|
||||
if (value || (key != "storagechange" && key != "historychange")) {
|
||||
data[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
this._data.clear();
|
||||
|
||||
try {
|
||||
// Send all data to the parent process.
|
||||
sendAsyncMessage("SessionStore:update", {
|
||||
data, flushID,
|
||||
isFinal: options.isFinal || false,
|
||||
epoch: gCurrentEpoch
|
||||
});
|
||||
} catch (ex) {
|
||||
if (ex && ex.result == Cr.NS_ERROR_OUT_OF_MEMORY) {
|
||||
Services.telemetry.getHistogramById("FX_SESSION_RESTORE_SEND_UPDATE_CAUSED_OOM").add(1);
|
||||
sendAsyncMessage("SessionStore:error");
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
StateChangeNotifier.init();
|
||||
EventListener.init();
|
||||
MessageListener.init();
|
||||
FormDataListener.init();
|
||||
SessionHistoryListener.init();
|
||||
SessionStorageListener.init();
|
||||
ScrollPositionListener.init();
|
||||
DocShellCapabilitiesListener.init();
|
||||
PrivacyListener.init();
|
||||
MessageQueue.init();
|
||||
|
||||
function handleRevivedTab() {
|
||||
if (!content) {
|
||||
removeEventListener("pagehide", handleRevivedTab);
|
||||
return;
|
||||
}
|
||||
|
||||
if (content.document.documentURI.startsWith("about:tabcrashed")) {
|
||||
if (Services.appinfo.processType != Services.appinfo.PROCESS_TYPE_DEFAULT) {
|
||||
// Sanity check - we'd better be loading this in a non-remote browser.
|
||||
throw new Error("We seem to be navigating away from about:tabcrashed in " +
|
||||
"a non-remote browser. This should really never happen.");
|
||||
}
|
||||
|
||||
removeEventListener("pagehide", handleRevivedTab);
|
||||
|
||||
// Notify the parent.
|
||||
sendAsyncMessage("SessionStore:crashedTabRevived");
|
||||
}
|
||||
}
|
||||
|
||||
// If we're browsing from the tab crashed UI to a blacklisted URI that keeps
|
||||
// this browser non-remote, we'll handle that in a pagehide event.
|
||||
addEventListener("pagehide", handleRevivedTab);
|
||||
|
||||
addEventListener("unload", () => {
|
||||
// Upon frameLoader destruction, send a final update message to
|
||||
// the parent and flush all data currently held in the child.
|
||||
MessageQueue.send({isFinal: true});
|
||||
|
||||
// If we're browsing from the tab crashed UI to a URI that causes the tab
|
||||
// to go remote again, we catch this in the unload event handler, because
|
||||
// swapping out the non-remote browser for a remote one in
|
||||
// tabbrowser.xml's updateBrowserRemoteness doesn't cause the pagehide
|
||||
// event to be fired.
|
||||
handleRevivedTab();
|
||||
|
||||
// Remove all registered nsIObservers.
|
||||
SessionStorageListener.uninit();
|
||||
SessionHistoryListener.uninit();
|
||||
MessageQueue.uninit();
|
||||
|
||||
if (contentRestoreInitialized) {
|
||||
// Remove progress listeners.
|
||||
gContentRestore.resetRestore();
|
||||
}
|
||||
|
||||
// We don't need to take care of any StateChangeNotifier observers as they
|
||||
// will die with the content script. The same goes for the privacy transition
|
||||
// observer that will die with the docShell when the tab is closed.
|
||||
});
|
||||
void new ContentSessionStore(this);
|
||||
|
@ -22,6 +22,7 @@ EXTRA_COMPONENTS += [
|
||||
|
||||
EXTRA_JS_MODULES.sessionstore = [
|
||||
'ContentRestore.jsm',
|
||||
'ContentSessionStore.jsm',
|
||||
'DocShellCapabilities.jsm',
|
||||
'GlobalState.jsm',
|
||||
'RecentlyClosedTabsAndWindowsMenuUtils.jsm',
|
||||
|
@ -12,6 +12,8 @@
|
||||
|
||||
ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
ChromeUtils.import("resource://formautofill/FormAutofillContent.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "setTimeout",
|
||||
"resource://gre/modules/Timer.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "FormAutofill",
|
||||
"resource://formautofill/FormAutofill.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "FormAutofillUtils",
|
||||
|
@ -12,14 +12,14 @@
|
||||
#include "nsIObjectOutputStream.h"
|
||||
#include "nsIStandardURL.h"
|
||||
|
||||
#include "ContentPrincipal.h"
|
||||
#include "ExpandedPrincipal.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsIURIWithPrincipal.h"
|
||||
#include "NullPrincipal.h"
|
||||
#include "nsScriptSecurityManager.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
|
||||
#include "mozilla/ContentPrincipal.h"
|
||||
#include "mozilla/NullPrincipal.h"
|
||||
#include "mozilla/dom/ChromeUtils.h"
|
||||
#include "mozilla/dom/CSPDictionariesBinding.h"
|
||||
#include "mozilla/dom/ToJSValue.h"
|
||||
|
@ -3,8 +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/. */
|
||||
|
||||
#ifndef ContentPrincipal_h
|
||||
#define ContentPrincipal_h
|
||||
#ifndef mozilla_ContentPrincipal_h
|
||||
#define mozilla_ContentPrincipal_h
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsJSPrincipals.h"
|
||||
@ -16,7 +16,9 @@
|
||||
#include "mozilla/BasePrincipal.h"
|
||||
#include "mozilla/extensions/WebExtensionPolicy.h"
|
||||
|
||||
class ContentPrincipal final : public mozilla::BasePrincipal
|
||||
namespace mozilla {
|
||||
|
||||
class ContentPrincipal final : public BasePrincipal
|
||||
{
|
||||
public:
|
||||
NS_DECL_NSISERIALIZABLE
|
||||
@ -35,7 +37,7 @@ public:
|
||||
|
||||
// Init() must be called before the principal is in a usable state.
|
||||
nsresult Init(nsIURI* aCodebase,
|
||||
const mozilla::OriginAttributes& aOriginAttributes,
|
||||
const OriginAttributes& aOriginAttributes,
|
||||
const nsACString& aOriginNoSuffix);
|
||||
|
||||
virtual nsresult GetScriptLocation(nsACString& aStr) override;
|
||||
@ -43,7 +45,7 @@ public:
|
||||
static nsresult
|
||||
GenerateOriginNoSuffixFromURI(nsIURI* aURI, nsACString& aOrigin);
|
||||
|
||||
mozilla::extensions::WebExtensionPolicy* AddonPolicy();
|
||||
extensions::WebExtensionPolicy* AddonPolicy();
|
||||
|
||||
nsCOMPtr<nsIURI> mDomain;
|
||||
nsCOMPtr<nsIURI> mCodebase;
|
||||
@ -56,12 +58,14 @@ protected:
|
||||
bool MayLoadInternal(nsIURI* aURI) override;
|
||||
|
||||
private:
|
||||
mozilla::Maybe<mozilla::WeakPtr<mozilla::extensions::WebExtensionPolicy>> mAddon;
|
||||
Maybe<WeakPtr<extensions::WebExtensionPolicy>> mAddon;
|
||||
};
|
||||
|
||||
} // mozilla namespace
|
||||
|
||||
#define NS_PRINCIPAL_CONTRACTID "@mozilla.org/principal;1"
|
||||
#define NS_PRINCIPAL_CID \
|
||||
{ 0x653e0e4d, 0x3ee4, 0x45fa, \
|
||||
{ 0xb2, 0x72, 0x97, 0xc2, 0x0b, 0xc0, 0x1e, 0xb8 } }
|
||||
|
||||
#endif // ContentPrincipal_h
|
||||
#endif // mozilla_ContentPrincipal_h
|
||||
|
@ -69,7 +69,7 @@ NullPrincipal::Create(const OriginAttributes& aOriginAttributes, nsIURI* aURI)
|
||||
/* static */ already_AddRefed<NullPrincipal>
|
||||
NullPrincipal::CreateWithoutOriginAttributes()
|
||||
{
|
||||
return NullPrincipal::Create(mozilla::OriginAttributes(), nullptr);
|
||||
return NullPrincipal::Create(OriginAttributes(), nullptr);
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
@ -9,8 +9,8 @@
|
||||
* same-origin with anything but themselves.
|
||||
*/
|
||||
|
||||
#ifndef NullPrincipal_h
|
||||
#define NullPrincipal_h
|
||||
#ifndef mozilla_NullPrincipal_h
|
||||
#define mozilla_NullPrincipal_h
|
||||
|
||||
#include "nsIPrincipal.h"
|
||||
#include "nsJSPrincipals.h"
|
||||
@ -30,7 +30,9 @@ class nsIURI;
|
||||
|
||||
#define NS_NULLPRINCIPAL_SCHEME "moz-nullprincipal"
|
||||
|
||||
class NullPrincipal final : public mozilla::BasePrincipal
|
||||
namespace mozilla {
|
||||
|
||||
class NullPrincipal final : public BasePrincipal
|
||||
{
|
||||
public:
|
||||
// This should only be used by deserialization, and the factory constructor.
|
||||
@ -64,13 +66,13 @@ public:
|
||||
CreateWithInheritedAttributes(nsIDocShell* aDocShell, bool aIsFirstParty = false);
|
||||
|
||||
static already_AddRefed<NullPrincipal>
|
||||
Create(const mozilla::OriginAttributes& aOriginAttributes,
|
||||
Create(const OriginAttributes& aOriginAttributes,
|
||||
nsIURI* aURI = nullptr);
|
||||
|
||||
static already_AddRefed<NullPrincipal>
|
||||
CreateWithoutOriginAttributes();
|
||||
|
||||
nsresult Init(const mozilla::OriginAttributes& aOriginAttributes = mozilla::OriginAttributes(),
|
||||
nsresult Init(const OriginAttributes& aOriginAttributes = OriginAttributes(),
|
||||
nsIURI* aURI = nullptr);
|
||||
|
||||
virtual nsresult GetScriptLocation(nsACString &aStr) override;
|
||||
@ -91,7 +93,9 @@ private:
|
||||
// If aIsFirstParty is true, this NullPrincipal will be initialized base on
|
||||
// the aOriginAttributes with FirstPartyDomain set to an unique value, and this
|
||||
// value is generated from mURI.path, with ".mozilla" appending at the end.
|
||||
nsresult Init(const mozilla::OriginAttributes& aOriginAttributes, bool aIsFirstParty);
|
||||
nsresult Init(const OriginAttributes& aOriginAttributes, bool aIsFirstParty);
|
||||
};
|
||||
|
||||
#endif // NullPrincipal_h__
|
||||
} // mozilla namespace
|
||||
|
||||
#endif // mozilla_NullPrincipal_h
|
||||
|
@ -15,6 +15,8 @@
|
||||
#include "nsCRT.h"
|
||||
#include "nsIUUIDGenerator.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// NullPrincipalURI
|
||||
|
||||
@ -406,13 +408,13 @@ NullPrincipalURI::Deserialize(const mozilla::ipc::URIParams& aParams)
|
||||
//// nsISizeOf
|
||||
|
||||
size_t
|
||||
NullPrincipalURI::SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
|
||||
NullPrincipalURI::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
|
||||
{
|
||||
return mPath.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
|
||||
}
|
||||
|
||||
size_t
|
||||
NullPrincipalURI::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
|
||||
NullPrincipalURI::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
|
||||
{
|
||||
return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
|
||||
}
|
||||
|
@ -8,8 +8,8 @@
|
||||
* This wraps nsSimpleURI so that all calls to it are done on the main thread.
|
||||
*/
|
||||
|
||||
#ifndef __NullPrincipalURI_h__
|
||||
#define __NullPrincipalURI_h__
|
||||
#ifndef mozilla_NullPrincipalURI_h
|
||||
#define mozilla_NullPrincipalURI_h
|
||||
|
||||
#include "nsIURI.h"
|
||||
#include "nsISizeOf.h"
|
||||
@ -27,8 +27,8 @@
|
||||
{0xb9, 0x1b, 0x6b, 0x54, 0x10, 0x22, 0x36, 0xe6} }
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class Encoding;
|
||||
}
|
||||
|
||||
class NullPrincipalURI final : public nsIURI
|
||||
, public nsISizeOf
|
||||
@ -40,8 +40,8 @@ public:
|
||||
NS_DECL_NSIIPCSERIALIZABLEURI
|
||||
|
||||
// nsISizeOf
|
||||
virtual size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const override;
|
||||
virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const override;
|
||||
virtual size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const override;
|
||||
virtual size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override;
|
||||
|
||||
// Returns null on failure.
|
||||
static already_AddRefed<NullPrincipalURI> Create();
|
||||
@ -69,7 +69,7 @@ private:
|
||||
nsresult SetRef(const nsACString &input);
|
||||
nsresult SetFilePath(const nsACString &input);
|
||||
nsresult SetQuery(const nsACString &input);
|
||||
nsresult SetQueryWithEncoding(const nsACString &input, const mozilla::Encoding* encoding);
|
||||
nsresult SetQueryWithEncoding(const nsACString &input, const Encoding* encoding);
|
||||
bool Deserialize(const mozilla::ipc::URIParams&);
|
||||
|
||||
public:
|
||||
@ -110,4 +110,6 @@ public:
|
||||
friend class BaseURIMutator<NullPrincipalURI>;
|
||||
};
|
||||
|
||||
#endif // __NullPrincipalURI_h__
|
||||
} // mozilla namespace
|
||||
|
||||
#endif // mozilla_NullPrincipalURI_h
|
||||
|
@ -18,6 +18,8 @@
|
||||
#include "nsIScriptSecurityManager.h"
|
||||
#include "pratom.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
NS_IMPL_CLASSINFO(SystemPrincipal, nullptr,
|
||||
nsIClassInfo::SINGLETON | nsIClassInfo::MAIN_THREAD_ONLY,
|
||||
NS_SYSTEMPRINCIPAL_CID)
|
||||
|
@ -6,8 +6,8 @@
|
||||
|
||||
/* The privileged system principal. */
|
||||
|
||||
#ifndef SystemPrincipal_h
|
||||
#define SystemPrincipal_h
|
||||
#ifndef mozilla_SystemPrincipal_h
|
||||
#define mozilla_SystemPrincipal_h
|
||||
|
||||
#include "nsIPrincipal.h"
|
||||
#include "nsJSPrincipals.h"
|
||||
@ -19,8 +19,9 @@
|
||||
{ 0xb7, 0x65, 0x0, 0x60, 0xb0, 0xb6, 0xce, 0xcb }}
|
||||
#define NS_SYSTEMPRINCIPAL_CONTRACTID "@mozilla.org/systemprincipal;1"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class SystemPrincipal final : public mozilla::BasePrincipal
|
||||
class SystemPrincipal final : public BasePrincipal
|
||||
{
|
||||
SystemPrincipal()
|
||||
: BasePrincipal(eSystemPrincipal)
|
||||
@ -63,4 +64,6 @@ protected:
|
||||
}
|
||||
};
|
||||
|
||||
#endif // SystemPrincipal_h
|
||||
} // mozilla namespace
|
||||
|
||||
#endif // mozilla_SystemPrincipal_h
|
||||
|
@ -24,17 +24,17 @@ XPIDL_SOURCES += [
|
||||
XPIDL_MODULE = 'caps'
|
||||
|
||||
EXPORTS += [
|
||||
'ContentPrincipal.h',
|
||||
'nsJSPrincipals.h',
|
||||
'nsScriptSecurityManager.h',
|
||||
'NullPrincipal.h',
|
||||
'NullPrincipalURI.h',
|
||||
'SystemPrincipal.h',
|
||||
]
|
||||
|
||||
EXPORTS.mozilla = [
|
||||
'BasePrincipal.h',
|
||||
'ContentPrincipal.h',
|
||||
'NullPrincipal.h',
|
||||
'NullPrincipalURI.h',
|
||||
'OriginAttributes.h',
|
||||
'SystemPrincipal.h',
|
||||
]
|
||||
|
||||
SOURCES += [
|
||||
|
@ -23,7 +23,6 @@
|
||||
#include "mozilla/BasePrincipal.h"
|
||||
#include "ExpandedPrincipal.h"
|
||||
#include "SystemPrincipal.h"
|
||||
#include "NullPrincipal.h"
|
||||
#include "DomainPolicy.h"
|
||||
#include "nsString.h"
|
||||
#include "nsCRT.h"
|
||||
@ -59,6 +58,7 @@
|
||||
#include "nsIAsyncVerifyRedirectCallback.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/dom/BindingUtils.h"
|
||||
#include "mozilla/NullPrincipal.h"
|
||||
#include <stdint.h>
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
#include "mozilla/ClearOnShutdown.h"
|
||||
|
@ -21,10 +21,10 @@
|
||||
|
||||
class nsIIOService;
|
||||
class nsIStringBundle;
|
||||
class SystemPrincipal;
|
||||
|
||||
namespace mozilla {
|
||||
class OriginAttributes;
|
||||
class SystemPrincipal;
|
||||
} // namespace mozilla
|
||||
|
||||
/////////////////////////////
|
||||
@ -50,7 +50,7 @@ public:
|
||||
// Invoked exactly once, by XPConnect.
|
||||
static void InitStatics();
|
||||
|
||||
static already_AddRefed<SystemPrincipal>
|
||||
static already_AddRefed<mozilla::SystemPrincipal>
|
||||
SystemPrincipalSingletonConstructor();
|
||||
|
||||
/**
|
||||
|
@ -7,6 +7,7 @@
|
||||
const {
|
||||
CLEAR_FLEXBOX,
|
||||
UPDATE_FLEXBOX,
|
||||
UPDATE_FLEXBOX_COLOR,
|
||||
UPDATE_FLEXBOX_HIGHLIGHTED,
|
||||
} = require("./index");
|
||||
|
||||
@ -31,6 +32,19 @@ module.exports = {
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Update the color used for the flexbox's highlighter.
|
||||
*
|
||||
* @param {String} color
|
||||
* The color to use for this nodeFront's flexbox highlighter.
|
||||
*/
|
||||
updateFlexboxColor(color) {
|
||||
return {
|
||||
type: UPDATE_FLEXBOX_COLOR,
|
||||
color,
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Updates the flexbox highlighted state.
|
||||
*
|
||||
|
@ -14,6 +14,9 @@ createEnum([
|
||||
// Updates the flexbox state with the newly selected flexbox.
|
||||
"UPDATE_FLEXBOX",
|
||||
|
||||
// Update the color used for the overlay of a flexbox.
|
||||
"UPDATE_FLEXBOX_COLOR",
|
||||
|
||||
// Updates the flexbox highlighted state.
|
||||
"UPDATE_FLEXBOX_HIGHLIGHTED",
|
||||
|
||||
|
@ -17,8 +17,10 @@ class Flexbox extends PureComponent {
|
||||
static get propTypes() {
|
||||
return {
|
||||
flexbox: PropTypes.shape(Types.flexbox).isRequired,
|
||||
getSwatchColorPickerTooltip: PropTypes.func.isRequired,
|
||||
setSelectedNode: PropTypes.func.isRequired,
|
||||
onHideBoxModelHighlighter: PropTypes.func.isRequired,
|
||||
onSetFlexboxOverlayColor: PropTypes.func.isRequired,
|
||||
onShowBoxModelHighlighterForNode: PropTypes.func.isRequired,
|
||||
onToggleFlexboxHighlighter: PropTypes.func.isRequired,
|
||||
};
|
||||
@ -27,8 +29,10 @@ class Flexbox extends PureComponent {
|
||||
render() {
|
||||
const {
|
||||
flexbox,
|
||||
getSwatchColorPickerTooltip,
|
||||
setSelectedNode,
|
||||
onHideBoxModelHighlighter,
|
||||
onSetFlexboxOverlayColor,
|
||||
onShowBoxModelHighlighterForNode,
|
||||
onToggleFlexboxHighlighter,
|
||||
} = this.props;
|
||||
@ -46,8 +50,10 @@ class Flexbox extends PureComponent {
|
||||
FlexboxItem({
|
||||
key: flexbox.id,
|
||||
flexbox,
|
||||
getSwatchColorPickerTooltip,
|
||||
setSelectedNode,
|
||||
onHideBoxModelHighlighter,
|
||||
onSetFlexboxOverlayColor,
|
||||
onShowBoxModelHighlighterForNode,
|
||||
onToggleFlexboxHighlighter,
|
||||
})
|
||||
|
@ -7,6 +7,7 @@
|
||||
const { PureComponent } = require("devtools/client/shared/vendor/react");
|
||||
const dom = require("devtools/client/shared/vendor/react-dom-factories");
|
||||
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
|
||||
const { findDOMNode } = require("devtools/client/shared/vendor/react-dom");
|
||||
const { translateNodeFrontToGrip } = require("devtools/client/inspector/shared/utils");
|
||||
|
||||
// Reps
|
||||
@ -20,8 +21,10 @@ class FlexboxItem extends PureComponent {
|
||||
static get propTypes() {
|
||||
return {
|
||||
flexbox: PropTypes.shape(Types.flexbox).isRequired,
|
||||
getSwatchColorPickerTooltip: PropTypes.func.isRequired,
|
||||
setSelectedNode: PropTypes.func.isRequired,
|
||||
onHideBoxModelHighlighter: PropTypes.func.isRequired,
|
||||
onSetFlexboxOverlayColor: PropTypes.func.isRequired,
|
||||
onShowBoxModelHighlighterForNode: PropTypes.func.isRequired,
|
||||
onToggleFlexboxHighlighter: PropTypes.func.isRequired,
|
||||
};
|
||||
@ -29,10 +32,46 @@ class FlexboxItem extends PureComponent {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.setFlexboxColor = this.setFlexboxColor.bind(this);
|
||||
this.onFlexboxCheckboxClick = this.onFlexboxCheckboxClick.bind(this);
|
||||
this.onFlexboxInspectIconClick = this.onFlexboxInspectIconClick.bind(this);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const {
|
||||
flexbox,
|
||||
getSwatchColorPickerTooltip,
|
||||
onSetFlexboxOverlayColor,
|
||||
} = this.props;
|
||||
|
||||
const swatchEl = findDOMNode(this).querySelector(".flexbox-color-swatch");
|
||||
const tooltip = getSwatchColorPickerTooltip();
|
||||
|
||||
let previousColor;
|
||||
tooltip.addSwatch(swatchEl, {
|
||||
onCommit: this.setFlexboxColor,
|
||||
onPreview: this.setFlexboxColor,
|
||||
onRevert: () => {
|
||||
onSetFlexboxOverlayColor(previousColor);
|
||||
},
|
||||
onShow: () => {
|
||||
previousColor = flexbox.color;
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
componentWillUnMount() {
|
||||
const swatchEl = findDOMNode(this).querySelector(".flexbox-color-swatch");
|
||||
const tooltip = this.props.getSwatchColorPickerTooltip();
|
||||
tooltip.removeSwatch(swatchEl);
|
||||
}
|
||||
|
||||
setFlexboxColor() {
|
||||
const color = findDOMNode(this).querySelector(".flexbox-color-value").textContent;
|
||||
this.props.onSetFlexboxOverlayColor(color);
|
||||
}
|
||||
|
||||
onFlexboxCheckboxClick(e) {
|
||||
// If the click was on the svg icon to select the node in the inspector, bail out.
|
||||
const originalTarget = e.nativeEvent && e.nativeEvent.explicitOriginalTarget;
|
||||
@ -65,6 +104,7 @@ class FlexboxItem extends PureComponent {
|
||||
} = this.props;
|
||||
const {
|
||||
actorID,
|
||||
color,
|
||||
highlighted,
|
||||
nodeFront,
|
||||
} = flexbox;
|
||||
@ -91,7 +131,21 @@ class FlexboxItem extends PureComponent {
|
||||
onInspectIconClick: () => this.onFlexboxInspectIconClick(nodeFront),
|
||||
}
|
||||
)
|
||||
)
|
||||
),
|
||||
dom.div(
|
||||
{
|
||||
className: "flexbox-color-swatch",
|
||||
style: {
|
||||
backgroundColor: color,
|
||||
},
|
||||
title: color,
|
||||
}
|
||||
),
|
||||
// The SwatchColorPicker relies on the nextSibling of the swatch element to apply
|
||||
// the selected color. This is why we use a span in display: none for now.
|
||||
// Ideally we should modify the SwatchColorPickerTooltip to bypass this requirement.
|
||||
// See https://bugzilla.mozilla.org/show_bug.cgi?id=1341578
|
||||
dom.span({ className: "flexbox-color-value" }, color)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -9,9 +9,15 @@ const { throttle } = require("devtools/client/inspector/shared/utils");
|
||||
const {
|
||||
clearFlexbox,
|
||||
updateFlexbox,
|
||||
updateFlexboxColor,
|
||||
updateFlexboxHighlighted,
|
||||
} = require("./actions/flexbox");
|
||||
|
||||
loader.lazyRequireGetter(this, "parseURL", "devtools/client/shared/source-utils", true);
|
||||
loader.lazyRequireGetter(this, "asyncStorage", "devtools/shared/async-storage");
|
||||
|
||||
const FLEXBOX_COLOR = "#9400FF";
|
||||
|
||||
class FlexboxInspector {
|
||||
constructor(inspector, window) {
|
||||
this.document = window.document;
|
||||
@ -22,6 +28,7 @@ class FlexboxInspector {
|
||||
this.onHighlighterShown = this.onHighlighterShown.bind(this);
|
||||
this.onHighlighterHidden = this.onHighlighterHidden.bind(this);
|
||||
this.onReflow = throttle(this.onReflow, 500, this);
|
||||
this.onSetFlexboxOverlayColor = this.onSetFlexboxOverlayColor.bind(this);
|
||||
this.onSidebarSelect = this.onSidebarSelect.bind(this);
|
||||
this.onToggleFlexboxHighlighter = this.onToggleFlexboxHighlighter.bind(this);
|
||||
this.onUpdatePanel = this.onUpdatePanel.bind(this);
|
||||
@ -86,10 +93,21 @@ class FlexboxInspector {
|
||||
|
||||
getComponentProps() {
|
||||
return {
|
||||
getSwatchColorPickerTooltip: this.getSwatchColorPickerTooltip,
|
||||
onSetFlexboxOverlayColor: this.onSetFlexboxOverlayColor,
|
||||
onToggleFlexboxHighlighter: this.onToggleFlexboxHighlighter,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an object containing the custom flexbox colors for different hosts.
|
||||
*
|
||||
* @return {Object} that maps a host name to a custom flexbox color for a given host.
|
||||
*/
|
||||
async getCustomFlexboxColors() {
|
||||
return await asyncStorage.getItem("flexboxInspectorHostColors") || {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the layout panel is visible, and false otherwise.
|
||||
*/
|
||||
@ -190,6 +208,31 @@ class FlexboxInspector {
|
||||
this.update(flexboxFront);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler for a change in the flexbox overlay color picker for a flex container.
|
||||
*
|
||||
* @param {String} color
|
||||
* A hex string representing the color to use.
|
||||
*/
|
||||
async onSetFlexboxOverlayColor(color) {
|
||||
this.store.dispatch(updateFlexboxColor(color));
|
||||
|
||||
const { flexbox } = this.store.getState();
|
||||
|
||||
if (flexbox.highlighted) {
|
||||
this.highlighters.showFlexboxHighlighter(flexbox.nodeFront);
|
||||
}
|
||||
|
||||
const currentUrl = this.inspector.target.url;
|
||||
// Get the hostname, if there is no hostname, fall back on protocol
|
||||
// ex: `data:` uri, and `about:` pages
|
||||
const hostname = parseURL(currentUrl).hostname || parseURL(currentUrl).protocol;
|
||||
const customFlexboxColors = await this.getCustomFlexboxColors();
|
||||
|
||||
customFlexboxColors[hostname] = color;
|
||||
await asyncStorage.setItem("flexboxInspectorHostColors", customFlexboxColors);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler for the inspector sidebar "select" event. Updates the flexbox panel if it
|
||||
* is visible.
|
||||
@ -241,7 +284,7 @@ class FlexboxInspector {
|
||||
* with new flexbox data.
|
||||
*
|
||||
* @param {FlexboxFront|Null} flexboxFront
|
||||
* THe FlexboxFront of the flex container for the current node selection.
|
||||
* The FlexboxFront of the flex container for the current node selection.
|
||||
*/
|
||||
async update(flexboxFront) {
|
||||
// Stop refreshing if the inspector or store is already destroyed or no node is
|
||||
@ -292,8 +335,16 @@ class FlexboxInspector {
|
||||
const highlighted = this._highlighters &&
|
||||
nodeFront == this.highlighters.flexboxHighlighterShown;
|
||||
|
||||
const currentUrl = this.inspector.target.url;
|
||||
// Get the hostname, if there is no hostname, fall back on protocol
|
||||
// ex: `data:` uri, and `about:` pages
|
||||
const hostname = parseURL(currentUrl).hostname || parseURL(currentUrl).protocol;
|
||||
const customColors = await this.getCustomFlexboxColors();
|
||||
const color = customColors[hostname] ? customColors[hostname] : FLEXBOX_COLOR;
|
||||
|
||||
this.store.dispatch(updateFlexbox({
|
||||
actorID: flexboxFront.actorID,
|
||||
color,
|
||||
highlighted,
|
||||
nodeFront,
|
||||
}));
|
||||
|
@ -7,12 +7,15 @@
|
||||
const {
|
||||
CLEAR_FLEXBOX,
|
||||
UPDATE_FLEXBOX,
|
||||
UPDATE_FLEXBOX_COLOR,
|
||||
UPDATE_FLEXBOX_HIGHLIGHTED,
|
||||
} = require("../actions/index");
|
||||
|
||||
const INITIAL_FLEXBOX = {
|
||||
// The actor ID of the flex container.
|
||||
actorID: null,
|
||||
// The color of the flexbox highlighter overlay.
|
||||
color: "",
|
||||
// Whether or not the flexbox highlighter is highlighting the flex container.
|
||||
highlighted: false,
|
||||
// The NodeFront of the flex container.
|
||||
@ -29,6 +32,12 @@ const reducers = {
|
||||
return flexbox;
|
||||
},
|
||||
|
||||
[UPDATE_FLEXBOX_COLOR](flexbox, { color }) {
|
||||
return Object.assign({}, flexbox, {
|
||||
color,
|
||||
});
|
||||
},
|
||||
|
||||
[UPDATE_FLEXBOX_HIGHLIGHTED](flexbox, { highlighted }) {
|
||||
return Object.assign({}, flexbox, {
|
||||
highlighted,
|
||||
|
@ -9,7 +9,10 @@ const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
|
||||
exports.flexbox = {
|
||||
|
||||
// The actor ID of the flex container.
|
||||
actorID: PropTypes.number,
|
||||
actorID: PropTypes.string,
|
||||
|
||||
// The color of the flexbox highlighter overlay.
|
||||
color: PropTypes.string,
|
||||
|
||||
// Whether or not the flexbox highlighter is highlighting the flex container.
|
||||
highlighted: PropTypes.bool,
|
||||
|
@ -19,7 +19,6 @@ const {
|
||||
} = require("./actions/highlighter-settings");
|
||||
|
||||
loader.lazyRequireGetter(this, "compareFragmentsGeometry", "devtools/client/inspector/grids/utils/utils", true);
|
||||
loader.lazyRequireGetter(this, "SwatchColorPickerTooltip", "devtools/client/shared/widgets/tooltip/SwatchColorPickerTooltip");
|
||||
loader.lazyRequireGetter(this, "parseURL", "devtools/client/shared/source-utils", true);
|
||||
loader.lazyRequireGetter(this, "asyncStorage", "devtools/shared/async-storage");
|
||||
|
||||
@ -57,7 +56,6 @@ class GridInspector {
|
||||
this.telemetry = inspector.telemetry;
|
||||
this.walker = this.inspector.walker;
|
||||
|
||||
this.getSwatchColorPickerTooltip = this.getSwatchColorPickerTooltip.bind(this);
|
||||
this.updateGridPanel = this.updateGridPanel.bind(this);
|
||||
|
||||
this.onHighlighterShown = this.onHighlighterShown.bind(this);
|
||||
@ -83,21 +81,9 @@ class GridInspector {
|
||||
return this._highlighters;
|
||||
}
|
||||
|
||||
get swatchColorPickerTooltip() {
|
||||
if (!this._swatchColorPickerTooltip) {
|
||||
this._swatchColorPickerTooltip = new SwatchColorPickerTooltip(
|
||||
this.inspector.toolbox.doc,
|
||||
this.inspector,
|
||||
{ supportsCssColor4ColorFunction: () => false }
|
||||
);
|
||||
}
|
||||
|
||||
return this._swatchColorPickerTooltip;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the grid inspector by fetching the LayoutFront from the walker, loading
|
||||
* the highlighter settings and initalizing the SwatchColorPicker instance.
|
||||
* Initializes the grid inspector by fetching the LayoutFront from the walker and
|
||||
* loading the highlighter settings.
|
||||
*/
|
||||
async init() {
|
||||
if (!this.inspector) {
|
||||
@ -138,13 +124,6 @@ class GridInspector {
|
||||
|
||||
this.inspector.reflowTracker.untrackReflows(this, this.onReflow);
|
||||
|
||||
// The color picker may not be ready as `init` function is async,
|
||||
// and we do not wait for its completion before calling destroy in tests
|
||||
if (this._swatchColorPickerTooltip) {
|
||||
this._swatchColorPickerTooltip.destroy();
|
||||
this._swatchColorPickerTooltip = null;
|
||||
}
|
||||
|
||||
this._highlighters = null;
|
||||
this.document = null;
|
||||
this.inspector = null;
|
||||
@ -155,7 +134,6 @@ class GridInspector {
|
||||
|
||||
getComponentProps() {
|
||||
return {
|
||||
getSwatchColorPickerTooltip: this.getSwatchColorPickerTooltip,
|
||||
onSetGridOverlayColor: this.onSetGridOverlayColor,
|
||||
onShowGridOutlineHighlight: this.onShowGridOutlineHighlight,
|
||||
onToggleGridHighlighter: this.onToggleGridHighlighter,
|
||||
@ -215,13 +193,6 @@ class GridInspector {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the shared SwatchColorPicker instance.
|
||||
*/
|
||||
getSwatchColorPickerTooltip() {
|
||||
return this.swatchColorPickerTooltip;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a list of new grid fronts, and if we have a currently highlighted grid, check
|
||||
* if its fragments have changed.
|
||||
|
@ -20,10 +20,10 @@ const TEST_URI = `
|
||||
|
||||
add_task(async function() {
|
||||
await addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
|
||||
const { inspector, gridInspector } = await openLayoutView();
|
||||
const { inspector, gridInspector, layoutView } = await openLayoutView();
|
||||
const { document: doc } = gridInspector;
|
||||
const { store } = inspector;
|
||||
const cPicker = gridInspector.getSwatchColorPickerTooltip();
|
||||
const cPicker = layoutView.getSwatchColorPickerTooltip();
|
||||
const spectrum = cPicker.spectrum;
|
||||
const swatch = doc.querySelector(".grid-color-swatch");
|
||||
|
||||
|
@ -20,10 +20,10 @@ const TEST_URI = `
|
||||
|
||||
add_task(async function() {
|
||||
await addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
|
||||
const { inspector, gridInspector } = await openLayoutView();
|
||||
const { inspector, gridInspector, layoutView } = await openLayoutView();
|
||||
const { document: doc } = gridInspector;
|
||||
const { store } = inspector;
|
||||
const cPicker = gridInspector.getSwatchColorPickerTooltip();
|
||||
const cPicker = layoutView.getSwatchColorPickerTooltip();
|
||||
const spectrum = cPicker.spectrum;
|
||||
const swatch = doc.querySelector(".grid-color-swatch");
|
||||
|
||||
|
@ -20,10 +20,10 @@ const TEST_URI = `
|
||||
|
||||
add_task(async function() {
|
||||
await addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
|
||||
const { inspector, gridInspector } = await openLayoutView();
|
||||
const { inspector, gridInspector, layoutView } = await openLayoutView();
|
||||
const { document: doc } = gridInspector;
|
||||
const { store } = inspector;
|
||||
const cPicker = gridInspector.getSwatchColorPickerTooltip();
|
||||
const cPicker = layoutView.getSwatchColorPickerTooltip();
|
||||
const spectrum = cPicker.spectrum;
|
||||
const swatch = doc.querySelector(".grid-color-swatch");
|
||||
|
||||
|
@ -20,10 +20,10 @@ const TEST_URI = `
|
||||
|
||||
add_task(async function() {
|
||||
await addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
|
||||
const { inspector, gridInspector, toolbox } = await openLayoutView();
|
||||
const { inspector, gridInspector, layoutView, toolbox } = await openLayoutView();
|
||||
const { document: doc } = gridInspector;
|
||||
const { store } = inspector;
|
||||
const cPicker = gridInspector.getSwatchColorPickerTooltip();
|
||||
const cPicker = layoutView.getSwatchColorPickerTooltip();
|
||||
const swatch = doc.querySelector(".grid-color-swatch");
|
||||
|
||||
info("Scrolling into view of the #grid color swatch.");
|
||||
|
@ -42,6 +42,7 @@ class LayoutApp extends PureComponent {
|
||||
setSelectedNode: PropTypes.func.isRequired,
|
||||
showBoxModelProperties: PropTypes.bool.isRequired,
|
||||
onHideBoxModelHighlighter: PropTypes.func.isRequired,
|
||||
onSetFlexboxOverlayColor: PropTypes.func.isRequired,
|
||||
onSetGridOverlayColor: PropTypes.func.isRequired,
|
||||
onShowBoxModelEditor: PropTypes.func.isRequired,
|
||||
onShowBoxModelHighlighter: PropTypes.func.isRequired,
|
||||
|
@ -15,6 +15,7 @@ const INSPECTOR_L10N =
|
||||
|
||||
loader.lazyRequireGetter(this, "FlexboxInspector", "devtools/client/inspector/flexbox/flexbox");
|
||||
loader.lazyRequireGetter(this, "GridInspector", "devtools/client/inspector/grids/grid-inspector");
|
||||
loader.lazyRequireGetter(this, "SwatchColorPickerTooltip", "devtools/client/shared/widgets/tooltip/SwatchColorPickerTooltip");
|
||||
|
||||
class LayoutView {
|
||||
constructor(inspector, window) {
|
||||
@ -22,6 +23,8 @@ class LayoutView {
|
||||
this.inspector = inspector;
|
||||
this.store = inspector.store;
|
||||
|
||||
this.getSwatchColorPickerTooltip = this.getSwatchColorPickerTooltip.bind(this);
|
||||
|
||||
this.init();
|
||||
}
|
||||
|
||||
@ -42,15 +45,14 @@ class LayoutView {
|
||||
onToggleGeometryEditor,
|
||||
} = this.inspector.getPanel("boxmodel").getComponentProps();
|
||||
|
||||
this.flexboxInspector = new FlexboxInspector(this.inspector,
|
||||
this.inspector.panelWin);
|
||||
this.flexboxInspector = new FlexboxInspector(this.inspector, this.inspector.panelWin);
|
||||
const {
|
||||
onSetFlexboxOverlayColor,
|
||||
onToggleFlexboxHighlighter,
|
||||
} = this.flexboxInspector.getComponentProps();
|
||||
|
||||
this.gridInspector = new GridInspector(this.inspector, this.inspector.panelWin);
|
||||
const {
|
||||
getSwatchColorPickerTooltip,
|
||||
onSetGridOverlayColor,
|
||||
onShowGridOutlineHighlight,
|
||||
onToggleGridHighlighter,
|
||||
@ -60,7 +62,7 @@ class LayoutView {
|
||||
} = this.gridInspector.getComponentProps();
|
||||
|
||||
const layoutApp = LayoutApp({
|
||||
getSwatchColorPickerTooltip,
|
||||
getSwatchColorPickerTooltip: this.getSwatchColorPickerTooltip,
|
||||
setSelectedNode,
|
||||
/**
|
||||
* Shows the box model properties under the box model if true, otherwise, hidden by
|
||||
@ -68,6 +70,7 @@ class LayoutView {
|
||||
*/
|
||||
showBoxModelProperties: true,
|
||||
onHideBoxModelHighlighter,
|
||||
onSetFlexboxOverlayColor,
|
||||
onSetGridOverlayColor,
|
||||
onShowBoxModelEditor,
|
||||
onShowBoxModelHighlighter,
|
||||
@ -96,6 +99,11 @@ class LayoutView {
|
||||
* Destruction function called when the inspector is destroyed. Cleans up references.
|
||||
*/
|
||||
destroy() {
|
||||
if (this._swatchColorPickerTooltip) {
|
||||
this._swatchColorPickerTooltip.destroy();
|
||||
this._swatchColorPickerTooltip = null;
|
||||
}
|
||||
|
||||
this.flexboxInspector.destroy();
|
||||
this.gridInspector.destroy();
|
||||
|
||||
@ -103,6 +111,25 @@ class LayoutView {
|
||||
this.inspector = null;
|
||||
this.store = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the shared SwatchColorPicker instance.
|
||||
*/
|
||||
getSwatchColorPickerTooltip() {
|
||||
return this.swatchColorPickerTooltip;
|
||||
}
|
||||
|
||||
get swatchColorPickerTooltip() {
|
||||
if (!this._swatchColorPickerTooltip) {
|
||||
this._swatchColorPickerTooltip = new SwatchColorPickerTooltip(
|
||||
this.inspector.toolbox.doc,
|
||||
this.inspector,
|
||||
{ supportsCssColor4ColorFunction: () => false }
|
||||
);
|
||||
}
|
||||
|
||||
return this._swatchColorPickerTooltip;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = LayoutView;
|
||||
|
@ -215,6 +215,18 @@ class HighlightersOverlay {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a flexbox highlighter settings object for the provided nodeFront.
|
||||
*
|
||||
* @param {NodeFront} nodeFront
|
||||
* The NodeFront for which we need highlighter settings.
|
||||
*/
|
||||
getFlexboxHighlighterSettings(nodeFront) {
|
||||
const { flexbox } = this.store.getState();
|
||||
const color = flexbox.color;
|
||||
return { color };
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle the flexbox highlighter for the given flexbox container element.
|
||||
*
|
||||
@ -246,6 +258,8 @@ class HighlightersOverlay {
|
||||
return;
|
||||
}
|
||||
|
||||
options = Object.assign({}, options, this.getFlexboxHighlighterSettings(node));
|
||||
|
||||
const isShown = await highlighter.show(node, options);
|
||||
if (!isShown) {
|
||||
return;
|
||||
|
@ -151,6 +151,7 @@ function openLayoutView() {
|
||||
inspector: data.inspector,
|
||||
boxmodel: data.inspector.getPanel("boxmodel"),
|
||||
gridInspector: data.inspector.layoutview.gridInspector,
|
||||
layoutView: data.inspector.layoutview,
|
||||
testActor: data.testActor
|
||||
};
|
||||
});
|
||||
|
@ -28,6 +28,7 @@ function runCodeMirrorTest(browser) {
|
||||
// setting a timeout to check again if not.
|
||||
/* eslint-disable max-len */
|
||||
mm.loadFrameScript("data:," +
|
||||
"ChromeUtils.import('resource://gre/modules/Timer.jsm');" +
|
||||
"content.wrappedJSObject.mozilla_setStatus = function(statusMsg, type, customMsg) {" +
|
||||
" sendSyncMessage('setStatus', {statusMsg: statusMsg, type: type, customMsg: customMsg});" +
|
||||
"};" +
|
||||
|
@ -130,9 +130,10 @@
|
||||
}
|
||||
|
||||
/**
|
||||
* Grid Item
|
||||
* Flexbox and Grid Item
|
||||
*/
|
||||
|
||||
.flexbox-color-swatch,
|
||||
.grid-color-swatch {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
@ -144,6 +145,7 @@
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.flexbox-color-value,
|
||||
.grid-color-value {
|
||||
display: none;
|
||||
}
|
||||
|
@ -60,12 +60,15 @@ const JUSTIFY_CONTENT = "justify-content";
|
||||
* display: [inline-]flex elements.
|
||||
*
|
||||
* Available Options:
|
||||
* - color(colorValue)
|
||||
* @param {String} colorValue
|
||||
* The color that should be used to draw the highlighter for this flexbox.
|
||||
* - showAlignment(isShown)
|
||||
* @param {Boolean} isShown
|
||||
* Shows the alignment in the flexbox highlighter.
|
||||
* @param {Boolean} isShown
|
||||
* Shows the alignment in the flexbox highlighter.
|
||||
* - showFlexBasis(isShown)
|
||||
* @param {Boolean} isShown
|
||||
* Shows the flex basis in the flexbox highlighter.
|
||||
* @param {Boolean} isShown
|
||||
* Shows the flex basis in the flexbox highlighter.
|
||||
*/
|
||||
class FlexboxHighlighter extends AutoRefreshHighlighter {
|
||||
constructor(highlighterEnv) {
|
||||
@ -169,6 +172,10 @@ class FlexboxHighlighter extends AutoRefreshHighlighter {
|
||||
return this.getElement("canvas");
|
||||
}
|
||||
|
||||
get color() {
|
||||
return this.options.color || DEFAULT_COLOR;
|
||||
}
|
||||
|
||||
get ctx() {
|
||||
return this.canvas.getCanvasContext("2d");
|
||||
}
|
||||
@ -211,7 +218,7 @@ class FlexboxHighlighter extends AutoRefreshHighlighter {
|
||||
ctx.moveTo(0, 0);
|
||||
ctx.lineTo(width, height);
|
||||
|
||||
ctx.strokeStyle = DEFAULT_COLOR;
|
||||
ctx.strokeStyle = this.color;
|
||||
ctx.stroke();
|
||||
ctx.restore();
|
||||
|
||||
@ -258,7 +265,7 @@ class FlexboxHighlighter extends AutoRefreshHighlighter {
|
||||
ctx.moveTo(0, height);
|
||||
ctx.lineTo(width, 0);
|
||||
|
||||
ctx.strokeStyle = DEFAULT_COLOR;
|
||||
ctx.strokeStyle = this.color;
|
||||
ctx.stroke();
|
||||
ctx.restore();
|
||||
|
||||
@ -393,7 +400,7 @@ class FlexboxHighlighter extends AutoRefreshHighlighter {
|
||||
this.ctx.translate(offset - canvasX, offset - canvasY);
|
||||
this.ctx.setLineDash(FLEXBOX_LINES_PROPERTIES.alignItems.lineDash);
|
||||
this.ctx.lineWidth = lineWidth * 3;
|
||||
this.ctx.strokeStyle = DEFAULT_COLOR;
|
||||
this.ctx.strokeStyle = this.color;
|
||||
|
||||
const { bounds } = this.currentQuads.content[0];
|
||||
const isColumn = this.flexDirection.startsWith("column");
|
||||
@ -493,7 +500,7 @@ class FlexboxHighlighter extends AutoRefreshHighlighter {
|
||||
this.ctx.translate(offset - canvasX, offset - canvasY);
|
||||
this.ctx.setLineDash(FLEXBOX_LINES_PROPERTIES.edge.lineDash);
|
||||
this.ctx.lineWidth = lineWidth;
|
||||
this.ctx.strokeStyle = DEFAULT_COLOR;
|
||||
this.ctx.strokeStyle = this.color;
|
||||
|
||||
const { bounds } = this.currentQuads.content[0];
|
||||
drawRect(this.ctx, 0, 0, bounds.width, bounds.height, this.currentMatrix);
|
||||
@ -517,7 +524,7 @@ class FlexboxHighlighter extends AutoRefreshHighlighter {
|
||||
this.ctx.translate(offset - canvasX, offset - canvasY);
|
||||
this.ctx.setLineDash(FLEXBOX_LINES_PROPERTIES.edge.lineDash);
|
||||
this.ctx.lineWidth = 0;
|
||||
this.ctx.strokeStyle = DEFAULT_COLOR;
|
||||
this.ctx.strokeStyle = this.color;
|
||||
this.ctx.fillStyle = this.getFlexContainerPattern(devicePixelRatio);
|
||||
|
||||
const { bounds } = this.currentQuads.content[0];
|
||||
@ -572,7 +579,7 @@ class FlexboxHighlighter extends AutoRefreshHighlighter {
|
||||
this.ctx.translate(offset - canvasX, offset - canvasY);
|
||||
this.ctx.setLineDash(FLEXBOX_LINES_PROPERTIES.item.lineDash);
|
||||
this.ctx.lineWidth = lineWidth;
|
||||
this.ctx.strokeStyle = DEFAULT_COLOR;
|
||||
this.ctx.strokeStyle = this.color;
|
||||
|
||||
const { bounds } = this.currentQuads.content[0];
|
||||
|
||||
@ -615,7 +622,7 @@ class FlexboxHighlighter extends AutoRefreshHighlighter {
|
||||
this.ctx.save();
|
||||
this.ctx.translate(offset - canvasX, offset - canvasY);
|
||||
this.ctx.lineWidth = lineWidth;
|
||||
this.ctx.strokeStyle = DEFAULT_COLOR;
|
||||
this.ctx.strokeStyle = this.color;
|
||||
|
||||
const { bounds } = this.currentQuads.content[0];
|
||||
const isColumn = this.flexDirection.startsWith("column");
|
||||
|
@ -199,8 +199,8 @@
|
||||
#include "nsXULAppAPI.h"
|
||||
|
||||
#include "GeckoProfiler.h"
|
||||
#include "mozilla/NullPrincipal.h"
|
||||
#include "Navigator.h"
|
||||
#include "NullPrincipal.h"
|
||||
#include "prenv.h"
|
||||
#include "URIUtils.h"
|
||||
|
||||
|
@ -19,8 +19,8 @@
|
||||
#include "nsDOMJSUtils.h"
|
||||
#include "nsError.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
#include "NullPrincipal.h"
|
||||
#include "mozilla/LoadInfo.h"
|
||||
#include "mozilla/NullPrincipal.h"
|
||||
#include "mozilla/dom/BindingUtils.h"
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
|
||||
|
@ -31,7 +31,7 @@
|
||||
#include "nsGlobalWindow.h"
|
||||
#include "mozilla/Likely.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "NullPrincipal.h"
|
||||
#include "mozilla/NullPrincipal.h"
|
||||
#include "mozilla/Unused.h"
|
||||
#include "mozilla/dom/LocationBinding.h"
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
|
@ -158,6 +158,7 @@
|
||||
#include "nsIMIMEService.h"
|
||||
#include "nsINode.h"
|
||||
#include "mozilla/dom/NodeInfo.h"
|
||||
#include "mozilla/NullPrincipal.h"
|
||||
#include "nsIObjectLoadingContent.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsIObserverService.h"
|
||||
@ -187,7 +188,6 @@
|
||||
#include "nsNetCID.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsNodeInfoManager.h"
|
||||
#include "NullPrincipal.h"
|
||||
#include "nsParserCIID.h"
|
||||
#include "nsParserConstants.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
|
@ -110,7 +110,7 @@
|
||||
#include "nsIPermissionManager.h"
|
||||
#include "nsIPrincipal.h"
|
||||
#include "ExpandedPrincipal.h"
|
||||
#include "NullPrincipal.h"
|
||||
#include "mozilla/NullPrincipal.h"
|
||||
|
||||
#include "nsIDOMWindow.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
|
@ -44,7 +44,6 @@
|
||||
#include "nsIXULWindow.h"
|
||||
#include "nsIMozBrowserFrame.h"
|
||||
#include "nsISHistory.h"
|
||||
#include "NullPrincipal.h"
|
||||
#include "nsIScriptError.h"
|
||||
#include "nsGlobalWindow.h"
|
||||
#include "nsHTMLDocument.h"
|
||||
@ -76,6 +75,7 @@
|
||||
#include "mozilla/BasePrincipal.h"
|
||||
#include "mozilla/GuardObjects.h"
|
||||
#include "mozilla/HTMLEditor.h"
|
||||
#include "mozilla/NullPrincipal.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/Unused.h"
|
||||
#include "mozilla/dom/ChromeMessageSender.h"
|
||||
@ -102,7 +102,7 @@
|
||||
|
||||
#include "mozilla/dom/HTMLBodyElement.h"
|
||||
|
||||
#include "ContentPrincipal.h"
|
||||
#include "mozilla/ContentPrincipal.h"
|
||||
|
||||
#ifdef XP_WIN
|
||||
#include "mozilla/plugins/PPluginWidgetParent.h"
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "mozilla/DebugOnly.h"
|
||||
#include "mozilla/dom/NodeInfo.h"
|
||||
#include "mozilla/dom/NodeInfoInlines.h"
|
||||
#include "mozilla/NullPrincipal.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsString.h"
|
||||
#include "nsAtom.h"
|
||||
@ -30,7 +31,6 @@
|
||||
#include "nsNameSpaceManager.h"
|
||||
#include "nsDocument.h"
|
||||
#include "nsWindowSizes.h"
|
||||
#include "NullPrincipal.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using mozilla::dom::NodeInfo;
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include "mozilla/dom/CSSRuleList.h"
|
||||
#include "mozilla/dom/DocumentFragment.h"
|
||||
#include "mozilla/dom/SRIMetadata.h"
|
||||
#include "mozilla/NullPrincipal.h"
|
||||
#include "nsCSSPropertyID.h"
|
||||
#include "nsUnicharInputStream.h"
|
||||
#include "nsAttrName.h"
|
||||
@ -21,7 +22,6 @@
|
||||
#include "nsIScriptSecurityManager.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "NullPrincipal.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsIParserUtils.h"
|
||||
#include "nsIDocument.h"
|
||||
|
@ -10,13 +10,13 @@
|
||||
#include "js/Class.h"
|
||||
|
||||
#include "nsJSPrincipals.h"
|
||||
#include "NullPrincipal.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsContentUtils.h"
|
||||
|
||||
#include "xpcprivate.h"
|
||||
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
#include "mozilla/NullPrincipal.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
@ -8,7 +8,7 @@
|
||||
#include "ConsoleCommon.h"
|
||||
|
||||
#include "mozilla/ClearOnShutdown.h"
|
||||
#include "NullPrincipal.h"
|
||||
#include "mozilla/NullPrincipal.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
@ -23,12 +23,12 @@
|
||||
#include "js/Date.h"
|
||||
#include "js/StructuredClone.h"
|
||||
#include "KeyPath.h"
|
||||
#include "NullPrincipal.h"
|
||||
#include "mozilla/ClearOnShutdown.h"
|
||||
#include "mozilla/EndianUtils.h"
|
||||
#include "mozilla/ErrorResult.h"
|
||||
#include "mozilla/JSObjectHolder.h"
|
||||
#include "mozilla/Move.h"
|
||||
#include "mozilla/NullPrincipal.h"
|
||||
#include "mozilla/dom/BindingUtils.h"
|
||||
#include "mozilla/dom/ContentChild.h"
|
||||
#include "mozilla/dom/ContentParent.h"
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/BackgroundHangMonitor.h"
|
||||
#include "mozilla/LookAndFeel.h"
|
||||
#include "mozilla/NullPrincipal.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/ProcessHangMonitorIPC.h"
|
||||
#include "mozilla/Unused.h"
|
||||
@ -85,7 +86,6 @@
|
||||
#include "mozilla/HangDetails.h"
|
||||
#include "imgLoader.h"
|
||||
#include "GMPServiceChild.h"
|
||||
#include "NullPrincipal.h"
|
||||
#include "nsISimpleEnumerator.h"
|
||||
#include "nsIStringBundle.h"
|
||||
#include "nsIWorkerDebuggerManager.h"
|
||||
|
@ -95,10 +95,10 @@
|
||||
#include "ImageOps.h"
|
||||
#include "UnitTransforms.h"
|
||||
#include <algorithm>
|
||||
#include "mozilla/NullPrincipal.h"
|
||||
#include "mozilla/WebBrowserPersistDocumentParent.h"
|
||||
#include "ProcessPriorityManager.h"
|
||||
#include "nsString.h"
|
||||
#include "NullPrincipal.h"
|
||||
|
||||
#ifdef XP_WIN
|
||||
#include "mozilla/plugins/PluginWidgetParent.h"
|
||||
|
@ -36,6 +36,7 @@
|
||||
#include "nsPIDOMWindow.h"
|
||||
#include "mozilla/EventStateManager.h"
|
||||
#include "mozilla/MozPromise.h"
|
||||
#include "mozilla/NullPrincipal.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
#include "mozilla/Types.h"
|
||||
#include "mozilla/PeerIdentity.h"
|
||||
@ -57,7 +58,6 @@
|
||||
#include "ThreadSafeRefcountingWithMainThreadDestruction.h"
|
||||
#include "Latency.h"
|
||||
#include "nsProxyRelease.h"
|
||||
#include "NullPrincipal.h"
|
||||
#include "nsVariant.h"
|
||||
|
||||
// For snprintf
|
||||
|
@ -50,6 +50,7 @@
|
||||
#include "nsIWritablePropertyBag2.h"
|
||||
#include "nsICategoryManager.h"
|
||||
#include "nsPluginStreamListenerPeer.h"
|
||||
#include "mozilla/NullPrincipal.h"
|
||||
#include "mozilla/dom/ContentChild.h"
|
||||
#include "mozilla/dom/ContentParent.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
@ -96,7 +97,6 @@
|
||||
#include "nsIImageLoadingContent.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "nsVersionComparator.h"
|
||||
#include "NullPrincipal.h"
|
||||
|
||||
#include "mozilla/dom/Promise.h"
|
||||
|
||||
|
@ -31,7 +31,7 @@
|
||||
#include "GeckoProfiler.h"
|
||||
#include "nsPluginInstanceOwner.h"
|
||||
#include "nsDataHashtable.h"
|
||||
#include "NullPrincipal.h"
|
||||
#include "mozilla/NullPrincipal.h"
|
||||
|
||||
// nsPluginStreamListenerPeer
|
||||
|
||||
|
@ -13,7 +13,9 @@
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsIPrincipal.h"
|
||||
#include "nsScriptSecurityManager.h"
|
||||
#include "NullPrincipal.h"
|
||||
#include "mozilla/NullPrincipal.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
static const uint32_t kURIMaxLength = 64;
|
||||
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "mozilla/dom/ContentParent.h"
|
||||
#include "mozilla/dom/ContentChild.h"
|
||||
#include "mozilla/BasePrincipal.h"
|
||||
#include "mozilla/ContentPrincipal.h"
|
||||
#include "mozilla/Services.h"
|
||||
#include "mozilla/SystemGroup.h"
|
||||
#include "mozilla/Unused.h"
|
||||
@ -44,7 +45,6 @@
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsPrintfCString.h"
|
||||
#include "mozilla/AbstractThread.h"
|
||||
#include "ContentPrincipal.h"
|
||||
#include "ExpandedPrincipal.h"
|
||||
|
||||
static nsPermissionManager *gPermissionManager = nullptr;
|
||||
|
@ -16,15 +16,16 @@
|
||||
#include "nspr.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/NullPrincipal.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsIScriptSecurityManager.h"
|
||||
#include "nsJSPrincipals.h"
|
||||
#include "nsIScriptError.h"
|
||||
#include "js/Wrapper.h"
|
||||
#include "NullPrincipal.h"
|
||||
|
||||
extern mozilla::LazyLogModule MCD;
|
||||
using mozilla::AutoSafeJSContext;
|
||||
using mozilla::NullPrincipal;
|
||||
using mozilla::dom::AutoJSAPI;
|
||||
|
||||
//*****************************************************************************
|
||||
|
@ -472,6 +472,7 @@ GetD2D1PropsForIntSize(FilterType aType, uint32_t aIndex, UINT32 *aPropWidth, UI
|
||||
static inline REFCLSID GetCLDIDForFilterType(FilterType aType)
|
||||
{
|
||||
switch (aType) {
|
||||
case FilterType::OPACITY:
|
||||
case FilterType::COLOR_MATRIX:
|
||||
return CLSID_D2D1ColorMatrix;
|
||||
case FilterType::TRANSFORM:
|
||||
@ -585,6 +586,10 @@ FilterNodeD2D1::Create(ID2D1DeviceContext *aDC, FilterType aType)
|
||||
effect->SetValue(D2D1_ARITHMETICCOMPOSITE_PROP_CLAMP_OUTPUT, TRUE);
|
||||
}
|
||||
|
||||
if (aType == FilterType::OPACITY) {
|
||||
return MakeAndAddRef<FilterNodeOpacityD2D1>(effect, aType);
|
||||
}
|
||||
|
||||
RefPtr<FilterNodeD2D1> filter = new FilterNodeD2D1(effect, aType);
|
||||
|
||||
if (HasUnboundedOutputRegion(aType)) {
|
||||
@ -870,6 +875,20 @@ FilterNodeD2D1::SetAttribute(uint32_t aIndex, const Matrix &aMatrix)
|
||||
mEffect->SetValue(input, D2DMatrix(aMatrix));
|
||||
}
|
||||
|
||||
void
|
||||
FilterNodeOpacityD2D1::SetAttribute(uint32_t aIndex, Float aValue)
|
||||
{
|
||||
D2D1_MATRIX_5X4_F matrix = D2D1::Matrix5x4F(aValue, 0, 0, 0,
|
||||
0, aValue, 0, 0,
|
||||
0, 0, aValue, 0,
|
||||
0, 0, 0, aValue,
|
||||
0, 0, 0, 0);
|
||||
|
||||
mEffect->SetValue(D2D1_COLORMATRIX_PROP_COLOR_MATRIX, matrix);
|
||||
mEffect->SetValue(D2D1_COLORMATRIX_PROP_ALPHA_MODE, D2D1_COLORMATRIX_ALPHA_MODE_STRAIGHT);
|
||||
}
|
||||
|
||||
|
||||
FilterNodeConvolveD2D1::FilterNodeConvolveD2D1(ID2D1DeviceContext *aDC)
|
||||
: FilterNodeD2D1(nullptr, FilterType::CONVOLVE_MATRIX)
|
||||
, mEdgeMode(EDGE_MODE_DUPLICATE)
|
||||
|
@ -108,6 +108,17 @@ private:
|
||||
IntRect mSourceRect;
|
||||
};
|
||||
|
||||
class FilterNodeOpacityD2D1 : public FilterNodeD2D1
|
||||
{
|
||||
public:
|
||||
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(FilterNodeOpacityD2D1, override)
|
||||
explicit FilterNodeOpacityD2D1(ID2D1Effect *aEffect, FilterType aType)
|
||||
: FilterNodeD2D1(aEffect, aType)
|
||||
{}
|
||||
|
||||
virtual void SetAttribute(uint32_t aIndex, Float aValue) override;
|
||||
};
|
||||
|
||||
class FilterNodeExtendInputAdapterD2D1 : public FilterNodeD2D1
|
||||
{
|
||||
public:
|
||||
|
@ -514,6 +514,9 @@ FilterNodeSoftware::Create(FilterType aType)
|
||||
case FilterType::UNPREMULTIPLY:
|
||||
filter = new FilterNodeUnpremultiplySoftware();
|
||||
break;
|
||||
case FilterType::OPACITY:
|
||||
filter = new FilterNodeOpacitySoftware();
|
||||
break;
|
||||
case FilterType::POINT_DIFFUSE:
|
||||
filter = new FilterNodeLightingSoftware<PointLightSoftware, DiffuseLightingSoftware>("FilterNodeLightingSoftware<PointLight, DiffuseLighting>");
|
||||
break;
|
||||
@ -1432,6 +1435,44 @@ Unpremultiply(DataSourceSurface* aSurface)
|
||||
return target.forget();
|
||||
}
|
||||
|
||||
static already_AddRefed<DataSourceSurface>
|
||||
Opacity(DataSourceSurface* aSurface, Float aValue)
|
||||
{
|
||||
if (aValue == 1.0f) {
|
||||
RefPtr<DataSourceSurface> surface(aSurface);
|
||||
return surface.forget();
|
||||
}
|
||||
|
||||
IntSize size = aSurface->GetSize();
|
||||
RefPtr<DataSourceSurface> target =
|
||||
Factory::CreateDataSourceSurface(size, aSurface->GetFormat());
|
||||
if (MOZ2D_WARN_IF(!target)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
DataSourceSurface::ScopedMap inputMap(aSurface, DataSourceSurface::READ);
|
||||
DataSourceSurface::ScopedMap targetMap(target, DataSourceSurface::WRITE);
|
||||
if (MOZ2D_WARN_IF(!inputMap.IsMapped() || !targetMap.IsMapped())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
uint8_t* inputData = inputMap.GetData();
|
||||
int32_t inputStride = inputMap.GetStride();
|
||||
uint8_t* targetData = targetMap.GetData();
|
||||
int32_t targetStride = targetMap.GetStride();
|
||||
|
||||
if (aSurface->GetFormat() == SurfaceFormat::A8) {
|
||||
FilterProcessing::DoOpacityCalculationA8(
|
||||
size, targetData, targetStride, inputData, inputStride, aValue);
|
||||
} else {
|
||||
MOZ_ASSERT(aSurface->GetFormat() == SurfaceFormat::B8G8R8A8);
|
||||
FilterProcessing::DoOpacityCalculation(
|
||||
size, targetData, targetStride, inputData, inputStride, aValue);
|
||||
}
|
||||
|
||||
return target.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<DataSourceSurface>
|
||||
FilterNodeColorMatrixSoftware::Render(const IntRect& aRect)
|
||||
{
|
||||
@ -3212,6 +3253,44 @@ FilterNodeUnpremultiplySoftware::GetOutputRectInRect(const IntRect& aRect)
|
||||
return GetInputRectInRect(IN_UNPREMULTIPLY_IN, aRect);
|
||||
}
|
||||
|
||||
void
|
||||
FilterNodeOpacitySoftware::SetAttribute(uint32_t aIndex,
|
||||
Float aValue)
|
||||
{
|
||||
MOZ_ASSERT(aIndex == ATT_OPACITY_VALUE);
|
||||
mValue = aValue;
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
int32_t
|
||||
FilterNodeOpacitySoftware::InputIndex(uint32_t aInputEnumIndex)
|
||||
{
|
||||
switch (aInputEnumIndex) {
|
||||
case IN_OPACITY_IN: return 0;
|
||||
default: return -1;
|
||||
}
|
||||
}
|
||||
|
||||
already_AddRefed<DataSourceSurface>
|
||||
FilterNodeOpacitySoftware::Render(const IntRect& aRect)
|
||||
{
|
||||
RefPtr<DataSourceSurface> input =
|
||||
GetInputDataSourceSurface(IN_OPACITY_IN, aRect);
|
||||
return input ? Opacity(input, mValue) : nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
FilterNodeOpacitySoftware::RequestFromInputsForRect(const IntRect &aRect)
|
||||
{
|
||||
RequestInputRect(IN_OPACITY_IN, aRect);
|
||||
}
|
||||
|
||||
IntRect
|
||||
FilterNodeOpacitySoftware::GetOutputRectInRect(const IntRect& aRect)
|
||||
{
|
||||
return GetInputRectInRect(IN_OPACITY_IN, aRect);
|
||||
}
|
||||
|
||||
bool
|
||||
PointLightSoftware::SetAttribute(uint32_t aIndex, const Point3D &aPoint)
|
||||
{
|
||||
|
@ -688,6 +688,22 @@ protected:
|
||||
virtual void RequestFromInputsForRect(const IntRect &aRect) override;
|
||||
};
|
||||
|
||||
class FilterNodeOpacitySoftware : public FilterNodeSoftware
|
||||
{
|
||||
public:
|
||||
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(FilterNodeOpacitySoftware, override)
|
||||
virtual const char* GetName() override { return "Opacity"; }
|
||||
using FilterNodeSoftware::SetAttribute;
|
||||
virtual void SetAttribute(uint32_t aIndex, Float aValue) override;
|
||||
protected:
|
||||
virtual already_AddRefed<DataSourceSurface> Render(const IntRect& aRect) override;
|
||||
virtual IntRect GetOutputRectInRect(const IntRect& aRect) override;
|
||||
virtual int32_t InputIndex(uint32_t aInputEnumIndex) override;
|
||||
virtual void RequestFromInputsForRect(const IntRect &aRect) override;
|
||||
|
||||
Float mValue = 1.0f;
|
||||
};
|
||||
|
||||
template<typename LightType, typename LightingType>
|
||||
class FilterNodeLightingSoftware : public FilterNodeSoftware
|
||||
{
|
||||
|
@ -236,6 +236,34 @@ FilterProcessing::DoUnpremultiplicationCalculation(const IntSize& aSize,
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FilterProcessing::DoOpacityCalculation(const IntSize& aSize,
|
||||
uint8_t* aTargetData, int32_t aTargetStride,
|
||||
uint8_t* aSourceData, int32_t aSourceStride,
|
||||
Float aValue)
|
||||
{
|
||||
if (Factory::HasSSE2()) {
|
||||
#ifdef USE_SSE2
|
||||
DoOpacityCalculation_SSE2(
|
||||
aSize, aTargetData, aTargetStride, aSourceData, aSourceStride, aValue);
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
DoOpacityCalculation_Scalar(
|
||||
aSize, aTargetData, aTargetStride, aSourceData, aSourceStride, aValue);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FilterProcessing::DoOpacityCalculationA8(const IntSize& aSize,
|
||||
uint8_t* aTargetData, int32_t aTargetStride,
|
||||
uint8_t* aSourceData, int32_t aSourceStride,
|
||||
Float aValue)
|
||||
{
|
||||
DoOpacityCalculationA8_Scalar(
|
||||
aSize, aTargetData, aTargetStride, aSourceData, aSourceStride, aValue);
|
||||
}
|
||||
|
||||
already_AddRefed<DataSourceSurface>
|
||||
FilterProcessing::RenderTurbulence(const IntSize &aSize, const Point &aOffset, const Size &aBaseFrequency,
|
||||
int32_t aSeed, int aNumOctaves, TurbulenceType aType, bool aStitch, const Rect &aTileRect)
|
||||
|
@ -59,6 +59,14 @@ public:
|
||||
static void DoUnpremultiplicationCalculation(const IntSize& aSize,
|
||||
uint8_t* aTargetData, int32_t aTargetStride,
|
||||
uint8_t* aSourceData, int32_t aSourceStride);
|
||||
static void DoOpacityCalculation(const IntSize& aSize,
|
||||
uint8_t* aTargetData, int32_t aTargetStride,
|
||||
uint8_t* aSourceData, int32_t aSourceStride,
|
||||
Float aValue);
|
||||
static void DoOpacityCalculationA8(const IntSize& aSize,
|
||||
uint8_t* aTargetData, int32_t aTargetStride,
|
||||
uint8_t* aSourceData, int32_t aSourceStride,
|
||||
Float aValue);
|
||||
static already_AddRefed<DataSourceSurface>
|
||||
RenderTurbulence(const IntSize &aSize, const Point &aOffset, const Size &aBaseFrequency,
|
||||
int32_t aSeed, int aNumOctaves, TurbulenceType aType, bool aStitch, const Rect &aTileRect);
|
||||
@ -87,6 +95,14 @@ protected:
|
||||
static void DoUnpremultiplicationCalculation_Scalar(const IntSize& aSize,
|
||||
uint8_t* aTargetData, int32_t aTargetStride,
|
||||
uint8_t* aSourceData, int32_t aSourceStride);
|
||||
static void DoOpacityCalculation_Scalar(const IntSize& aSize,
|
||||
uint8_t* aTargetData, int32_t aTargetStride,
|
||||
uint8_t* aSourceData, int32_t aSourceStride,
|
||||
Float aValue);
|
||||
static void DoOpacityCalculationA8_Scalar(const IntSize& aSize,
|
||||
uint8_t* aTargetData, int32_t aTargetStride,
|
||||
uint8_t* aSourceData, int32_t aSourceStride,
|
||||
Float aValue);
|
||||
static already_AddRefed<DataSourceSurface>
|
||||
RenderTurbulence_Scalar(const IntSize &aSize, const Point &aOffset, const Size &aBaseFrequency,
|
||||
int32_t aSeed, int aNumOctaves, TurbulenceType aType, bool aStitch, const Rect &aTileRect);
|
||||
@ -115,6 +131,10 @@ protected:
|
||||
static void DoUnpremultiplicationCalculation_SSE2(const IntSize& aSize,
|
||||
uint8_t* aTargetData, int32_t aTargetStride,
|
||||
uint8_t* aSourceData, int32_t aSourceStride);
|
||||
static void DoOpacityCalculation_SSE2(const IntSize& aSize,
|
||||
uint8_t* aTargetData, int32_t aTargetStride,
|
||||
uint8_t* aSourceData, int32_t aSourceStride,
|
||||
Float aValue);
|
||||
static already_AddRefed<DataSourceSurface>
|
||||
RenderTurbulence_SSE2(const IntSize &aSize, const Point &aOffset, const Size &aBaseFrequency,
|
||||
int32_t aSeed, int aNumOctaves, TurbulenceType aType, bool aStitch, const Rect &aTileRect);
|
||||
|
@ -982,6 +982,38 @@ DoUnpremultiplicationCalculation_SIMD(const IntSize& aSize,
|
||||
}
|
||||
}
|
||||
|
||||
template<typename u16x8_t, typename u8x16_t>
|
||||
static void
|
||||
DoOpacityCalculation_SIMD(const IntSize& aSize,
|
||||
uint8_t* aTargetData, int32_t aTargetStride,
|
||||
uint8_t* aSourceData, int32_t aSourceStride,
|
||||
Float aOpacity)
|
||||
{
|
||||
uint8_t alphaValue = uint8_t(roundf(255.f * aOpacity));
|
||||
u16x8_t alphaValues = simd::FromU16<u16x8_t>(alphaValue, alphaValue, alphaValue, alphaValue,
|
||||
alphaValue, alphaValue, alphaValue, alphaValue);
|
||||
for (int32_t y = 0; y < aSize.height; y++) {
|
||||
for (int32_t x = 0; x < aSize.width; x += 4) {
|
||||
int32_t inputIndex = y * aSourceStride + 4 * x;
|
||||
int32_t targetIndex = y * aTargetStride + 4 * x;
|
||||
|
||||
u8x16_t p1234 = simd::Load8<u8x16_t>(&aSourceData[inputIndex]);
|
||||
u16x8_t p12 = simd::UnpackLo8x8ToU16x8(p1234);
|
||||
u16x8_t p34 = simd::UnpackHi8x8ToU16x8(p1234);
|
||||
|
||||
// Multiply all components with alpha.
|
||||
p12 = simd::Mul16(p12, alphaValues);
|
||||
p34 = simd::Mul16(p34, alphaValues);
|
||||
|
||||
// Divide by 255 and pack.
|
||||
u8x16_t result = simd::PackAndSaturate16To8(simd::ShiftRight16<8>(p12),
|
||||
simd::ShiftRight16<8>(p34));
|
||||
|
||||
simd::Store8(&aTargetData[targetIndex], result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename f32x4_t, typename i32x4_t, typename u8x16_t>
|
||||
static already_AddRefed<DataSourceSurface>
|
||||
RenderTurbulence_SIMD(const IntSize &aSize, const Point &aOffset, const Size &aBaseFrequency,
|
||||
|
@ -96,6 +96,15 @@ FilterProcessing::DoUnpremultiplicationCalculation_SSE2(
|
||||
DoUnpremultiplicationCalculation_SIMD<__m128i,__m128i>(aSize, aTargetData, aTargetStride, aSourceData, aSourceStride);
|
||||
}
|
||||
|
||||
void
|
||||
FilterProcessing::DoOpacityCalculation_SSE2(const IntSize& aSize,
|
||||
uint8_t* aTargetData, int32_t aTargetStride,
|
||||
uint8_t* aSourceData, int32_t aSourceStride,
|
||||
Float aValue)
|
||||
{
|
||||
DoOpacityCalculation_SIMD<__m128i, __m128i>(aSize, aTargetData, aTargetStride, aSourceData, aSourceStride, aValue);
|
||||
}
|
||||
|
||||
already_AddRefed<DataSourceSurface>
|
||||
FilterProcessing::RenderTurbulence_SSE2(const IntSize &aSize, const Point &aOffset, const Size &aBaseFrequency,
|
||||
int32_t aSeed, int aNumOctaves, TurbulenceType aType, bool aStitch, const Rect &aTileRect)
|
||||
|
@ -227,6 +227,46 @@ FilterProcessing::DoUnpremultiplicationCalculation_Scalar(
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FilterProcessing::DoOpacityCalculation_Scalar(const IntSize& aSize,
|
||||
uint8_t* aTargetData, int32_t aTargetStride,
|
||||
uint8_t* aSourceData, int32_t aSourceStride,
|
||||
Float aValue)
|
||||
{
|
||||
uint8_t alpha = uint8_t(roundf(255.f * aValue));
|
||||
for (int32_t y = 0; y < aSize.height; y++) {
|
||||
for (int32_t x = 0; x < aSize.width; x++) {
|
||||
int32_t inputIndex = y * aSourceStride + 4 * x;
|
||||
int32_t targetIndex = y * aTargetStride + 4 * x;
|
||||
aTargetData[targetIndex + B8G8R8A8_COMPONENT_BYTEOFFSET_R] =
|
||||
(aSourceData[inputIndex + B8G8R8A8_COMPONENT_BYTEOFFSET_R] * alpha) >> 8;
|
||||
aTargetData[targetIndex + B8G8R8A8_COMPONENT_BYTEOFFSET_G] =
|
||||
(aSourceData[inputIndex + B8G8R8A8_COMPONENT_BYTEOFFSET_G] * alpha) >> 8;
|
||||
aTargetData[targetIndex + B8G8R8A8_COMPONENT_BYTEOFFSET_B] =
|
||||
(aSourceData[inputIndex + B8G8R8A8_COMPONENT_BYTEOFFSET_B] * alpha) >> 8;
|
||||
aTargetData[targetIndex + B8G8R8A8_COMPONENT_BYTEOFFSET_A] =
|
||||
(aSourceData[inputIndex + B8G8R8A8_COMPONENT_BYTEOFFSET_A] * alpha) >> 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FilterProcessing::DoOpacityCalculationA8_Scalar(const IntSize& aSize,
|
||||
uint8_t* aTargetData, int32_t aTargetStride,
|
||||
uint8_t* aSourceData, int32_t aSourceStride,
|
||||
Float aValue)
|
||||
{
|
||||
uint8_t alpha = uint8_t(255.f * aValue);
|
||||
for (int32_t y = 0; y < aSize.height; y++) {
|
||||
for (int32_t x = 0; x < aSize.width; x++) {
|
||||
int32_t inputIndex = y * aSourceStride;
|
||||
int32_t targetIndex = y * aTargetStride;
|
||||
aTargetData[targetIndex] =
|
||||
FastDivideBy255<uint8_t>(aSourceData[inputIndex] * alpha);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
already_AddRefed<DataSourceSurface>
|
||||
FilterProcessing::RenderTurbulence_Scalar(const IntSize &aSize, const Point &aOffset, const Size &aBaseFrequency,
|
||||
int32_t aSeed, int aNumOctaves, TurbulenceType aType, bool aStitch, const Rect &aTileRect)
|
||||
|
@ -476,6 +476,16 @@ enum UnpremultiplyInputs
|
||||
IN_UNPREMULTIPLY_IN = 0
|
||||
};
|
||||
|
||||
enum OpacityAtts
|
||||
{
|
||||
ATT_OPACITY_VALUE = 0
|
||||
};
|
||||
|
||||
enum OpacityInputs
|
||||
{
|
||||
IN_OPACITY_IN = 0
|
||||
};
|
||||
|
||||
class FilterNode : public external::AtomicRefCounted<FilterNode>
|
||||
{
|
||||
public:
|
||||
|
@ -128,7 +128,8 @@ enum class FilterType : int8_t {
|
||||
DISTANT_SPECULAR,
|
||||
CROP,
|
||||
PREMULTIPLY,
|
||||
UNPREMULTIPLY
|
||||
UNPREMULTIPLY,
|
||||
OPACITY
|
||||
};
|
||||
|
||||
enum class DrawTargetType : int8_t {
|
||||
|
@ -22,6 +22,7 @@
|
||||
################################################################################
|
||||
|
||||
# includes
|
||||
from __future__ import print_function
|
||||
import os
|
||||
import sys
|
||||
import xml.etree.ElementTree
|
||||
@ -34,7 +35,6 @@ class GLConstHeader:
|
||||
def __init__(self, f):
|
||||
self.f = f
|
||||
|
||||
|
||||
def write(self, arg):
|
||||
if isinstance(arg, list):
|
||||
self.f.write('\n'.join(arg) + '\n')
|
||||
@ -43,7 +43,6 @@ class GLConstHeader:
|
||||
else:
|
||||
self.f.write(str(arg) + '\n')
|
||||
|
||||
|
||||
def formatFileBegin(self):
|
||||
self.write([
|
||||
'/* This Source Code Form is subject to the terms of the Mozilla Public',
|
||||
@ -63,12 +62,10 @@ class GLConstHeader:
|
||||
''
|
||||
])
|
||||
|
||||
|
||||
def formatLibBegin(self, lib):
|
||||
# lib would be 'GL', 'EGL', 'GLX' or 'WGL'
|
||||
self.write('// ' + lib)
|
||||
|
||||
|
||||
def formatLibConstant(self, lib, name, value):
|
||||
# lib would be 'GL', 'EGL', 'GLX' or 'WGL'
|
||||
# name is the name of the const (example: MAX_TEXTURE_SIZE)
|
||||
@ -76,23 +73,21 @@ class GLConstHeader:
|
||||
|
||||
define = '#define LOCAL_' + lib + '_' + name
|
||||
whitespace = 60 - len(define)
|
||||
|
||||
|
||||
if whitespace < 0:
|
||||
whitespace = whitespace % 8
|
||||
|
||||
self.write(define + ' ' * whitespace + ' ' + value)
|
||||
|
||||
self.write(define + ' ' * whitespace + ' ' + value)
|
||||
|
||||
def formatLibEnd(self, lib):
|
||||
# lib would be 'GL', 'EGL', 'GLX' or 'WGL'
|
||||
self.write(2)
|
||||
|
||||
|
||||
def formatFileEnd(self):
|
||||
self.write([
|
||||
'',
|
||||
'#endif // GLCONSTS_H_'
|
||||
])
|
||||
'',
|
||||
'#endif // GLCONSTS_H_'
|
||||
])
|
||||
|
||||
|
||||
################################################################################
|
||||
@ -132,12 +127,11 @@ class GLDatabase:
|
||||
# there is no vendor="EXT" and vendor="ATI" in gl.xml,
|
||||
# so we manualy declare them
|
||||
|
||||
|
||||
def loadXML(self, path):
|
||||
xmlPath = getXMLDir() + path
|
||||
|
||||
if not os.path.isfile(xmlPath):
|
||||
print 'missing file "' + xmlPath + '"'
|
||||
print('missing file "' + xmlPath + '"')
|
||||
return False
|
||||
|
||||
tree = xml.etree.ElementTree.parse(xmlPath)
|
||||
@ -179,9 +173,8 @@ class GLDatabase:
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def exportConsts(self, path):
|
||||
with open(getScriptDir() + path,'w') as f:
|
||||
with open(getScriptDir() + path, 'w') as f:
|
||||
|
||||
headerFile = GLConstHeader(f)
|
||||
headerFile.formatFileBegin()
|
||||
|
@ -12,19 +12,22 @@ import tempfile
|
||||
import yaml
|
||||
import buildconfig
|
||||
|
||||
def shell_main():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('-o', '--output', type=str, required=True,
|
||||
help='Output file')
|
||||
parser.add_argument('manifest', type=str,
|
||||
help='Manifest source file')
|
||||
args = parser.parse_args()
|
||||
|
||||
with open(args.output, 'w') as out_file:
|
||||
process_manifest(out_file, args.manifest)
|
||||
def shell_main():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('-o', '--output', type=str, required=True,
|
||||
help='Output file')
|
||||
parser.add_argument('manifest', type=str,
|
||||
help='Manifest source file')
|
||||
args = parser.parse_args()
|
||||
|
||||
with open(args.output, 'w') as out_file:
|
||||
process_manifest(out_file, args.manifest)
|
||||
|
||||
|
||||
def main(output_fp, input_filename):
|
||||
return process_manifest(output_fp, input_filename)
|
||||
return process_manifest(output_fp, input_filename)
|
||||
|
||||
|
||||
HEADER = """// AUTOGENERATED - DO NOT EDIT
|
||||
namespace mozilla {
|
||||
@ -36,123 +39,133 @@ FOOTER = """
|
||||
} // namespace layers
|
||||
} // namespace mozilla"""
|
||||
|
||||
|
||||
def process_manifest(output_fp, manifest_filename):
|
||||
with codecs.open(manifest_filename, 'r', 'UTF-8') as in_fp:
|
||||
manifest = yaml.safe_load(in_fp)
|
||||
shader_folder, _ = os.path.split(manifest_filename)
|
||||
with codecs.open(manifest_filename, 'r', 'UTF-8') as in_fp:
|
||||
manifest = yaml.safe_load(in_fp)
|
||||
shader_folder, _ = os.path.split(manifest_filename)
|
||||
|
||||
output_fp.write(HEADER)
|
||||
output_fp.write(HEADER)
|
||||
|
||||
deps = set()
|
||||
for block in manifest:
|
||||
if 'type' not in block:
|
||||
raise Exception("Expected 'type' key with shader mode")
|
||||
if 'file' not in block:
|
||||
raise Exception("Expected 'file' key with shader file")
|
||||
if 'shaders' not in block:
|
||||
raise Exception("Expected 'shaders' key with shader name list")
|
||||
deps = set()
|
||||
for block in manifest:
|
||||
if 'type' not in block:
|
||||
raise Exception("Expected 'type' key with shader mode")
|
||||
if 'file' not in block:
|
||||
raise Exception("Expected 'file' key with shader file")
|
||||
if 'shaders' not in block:
|
||||
raise Exception("Expected 'shaders' key with shader name list")
|
||||
|
||||
shader_file = os.path.join(shader_folder, block['file'])
|
||||
deps.add(shader_file)
|
||||
shader_file = os.path.join(shader_folder, block['file'])
|
||||
deps.add(shader_file)
|
||||
|
||||
shader_model = block['type']
|
||||
for shader_name in block['shaders']:
|
||||
new_deps = run_fxc(
|
||||
shader_model = shader_model,
|
||||
shader_file = shader_file,
|
||||
shader_name = shader_name,
|
||||
output_fp = output_fp)
|
||||
deps |= new_deps
|
||||
shader_model = block['type']
|
||||
for shader_name in block['shaders']:
|
||||
new_deps = run_fxc(
|
||||
shader_model=shader_model,
|
||||
shader_file=shader_file,
|
||||
shader_name=shader_name,
|
||||
output_fp=output_fp)
|
||||
deps |= new_deps
|
||||
|
||||
output_fp.write(FOOTER)
|
||||
return deps
|
||||
|
||||
output_fp.write(FOOTER)
|
||||
return deps
|
||||
|
||||
def run_fxc(shader_model,
|
||||
shader_file,
|
||||
shader_name,
|
||||
output_fp):
|
||||
fxc_location = buildconfig.substs['FXC']
|
||||
fxc_location = buildconfig.substs['FXC']
|
||||
|
||||
argv = [
|
||||
fxc_location,
|
||||
'-nologo',
|
||||
'-T{0}'.format(shader_model),
|
||||
shader_file,
|
||||
'-E{0}'.format(shader_name),
|
||||
'-Vn{0}'.format(shader_name),
|
||||
'-Vi',
|
||||
]
|
||||
if 'Linux' in buildconfig.substs['HOST_OS_ARCH']:
|
||||
argv.insert(0, buildconfig.substs['WINE'])
|
||||
if shader_model.startswith('vs_'):
|
||||
argv += ['-DVERTEX_SHADER']
|
||||
elif shader_model.startswith('ps_'):
|
||||
argv += ['-DPIXEL_SHADER']
|
||||
argv = [
|
||||
fxc_location,
|
||||
'-nologo',
|
||||
'-T{0}'.format(shader_model),
|
||||
shader_file,
|
||||
'-E{0}'.format(shader_name),
|
||||
'-Vn{0}'.format(shader_name),
|
||||
'-Vi',
|
||||
]
|
||||
if 'Linux' in buildconfig.substs['HOST_OS_ARCH']:
|
||||
argv.insert(0, buildconfig.substs['WINE'])
|
||||
if shader_model.startswith('vs_'):
|
||||
argv += ['-DVERTEX_SHADER']
|
||||
elif shader_model.startswith('ps_'):
|
||||
argv += ['-DPIXEL_SHADER']
|
||||
|
||||
deps = None
|
||||
with ScopedTempFilename() as temp_filename:
|
||||
argv += ['-Fh{0}'.format(temp_filename)]
|
||||
deps = None
|
||||
with ScopedTempFilename() as temp_filename:
|
||||
argv += ['-Fh{0}'.format(temp_filename)]
|
||||
|
||||
sys.stdout.write('{0}\n'.format(' '.join(argv)))
|
||||
proc_stdout = subprocess.check_output(argv)
|
||||
proc_stdout = decode_console_text(sys.stdout, proc_stdout)
|
||||
deps = find_dependencies(proc_stdout)
|
||||
assert 'fxc2' in fxc_location or len(deps) > 0
|
||||
sys.stdout.write('{0}\n'.format(' '.join(argv)))
|
||||
proc_stdout = subprocess.check_output(argv)
|
||||
proc_stdout = decode_console_text(sys.stdout, proc_stdout)
|
||||
deps = find_dependencies(proc_stdout)
|
||||
assert 'fxc2' in fxc_location or len(deps) > 0
|
||||
|
||||
with open(temp_filename, 'r') as temp_fp:
|
||||
output_fp.write(temp_fp.read())
|
||||
with open(temp_filename, 'r') as temp_fp:
|
||||
output_fp.write(temp_fp.read())
|
||||
|
||||
output_fp.write("ShaderBytes s{0} = {{ {0}, sizeof({0}) }};\n".format(
|
||||
shader_name))
|
||||
return deps
|
||||
|
||||
output_fp.write("ShaderBytes s{0} = {{ {0}, sizeof({0}) }};\n".format(
|
||||
shader_name))
|
||||
return deps
|
||||
|
||||
def find_dependencies(fxc_output):
|
||||
# Dependencies look like this:
|
||||
# Resolved to [<path>]
|
||||
#
|
||||
# Microsoft likes to change output strings based on the user's language, so
|
||||
# instead of pattern matching on that string, we take everything in between
|
||||
# brackets. We filter out potentially bogus strings later.
|
||||
deps = set()
|
||||
for line in fxc_output.split('\n'):
|
||||
m = re.search(r"\[([^\]]+)\]", line)
|
||||
if m is None:
|
||||
continue
|
||||
dep_path = m.group(1)
|
||||
dep_path = os.path.normpath(dep_path)
|
||||
if os.path.isfile(dep_path):
|
||||
deps.add(dep_path)
|
||||
return deps
|
||||
# Dependencies look like this:
|
||||
# Resolved to [<path>]
|
||||
#
|
||||
# Microsoft likes to change output strings based on the user's language, so
|
||||
# instead of pattern matching on that string, we take everything in between
|
||||
# brackets. We filter out potentially bogus strings later.
|
||||
deps = set()
|
||||
for line in fxc_output.split('\n'):
|
||||
m = re.search(r"\[([^\]]+)\]", line)
|
||||
if m is None:
|
||||
continue
|
||||
dep_path = m.group(1)
|
||||
dep_path = os.path.normpath(dep_path)
|
||||
if os.path.isfile(dep_path):
|
||||
deps.add(dep_path)
|
||||
return deps
|
||||
|
||||
# Python reads the raw bytes from stdout, so we need to try our best to
|
||||
# capture that as a valid Python string.
|
||||
|
||||
|
||||
def decode_console_text(pipe, text):
|
||||
try:
|
||||
if pipe.encoding:
|
||||
return text.decode(pipe.encoding, 'replace')
|
||||
except:
|
||||
pass
|
||||
try:
|
||||
return text.decode(locale.getpreferredencoding(), 'replace')
|
||||
except:
|
||||
return text.decode('utf8', 'replace')
|
||||
try:
|
||||
if pipe.encoding:
|
||||
return text.decode(pipe.encoding, 'replace')
|
||||
except Exception:
|
||||
pass
|
||||
try:
|
||||
return text.decode(locale.getpreferredencoding(), 'replace')
|
||||
except Exception:
|
||||
return text.decode('utf8', 'replace')
|
||||
|
||||
# Allocate a temporary file name and delete it when done. We need an extra
|
||||
# wrapper for this since TemporaryNamedFile holds the file open.
|
||||
|
||||
|
||||
class ScopedTempFilename(object):
|
||||
def __init__(self):
|
||||
self.name = None
|
||||
def __enter__(self):
|
||||
with tempfile.NamedTemporaryFile(delete = False) as tmp:
|
||||
self.name = tmp.name
|
||||
return self.name
|
||||
def __exit__(self, type, value, traceback):
|
||||
if not self.name:
|
||||
return
|
||||
try:
|
||||
os.unlink(self.name)
|
||||
except:
|
||||
pass
|
||||
def __init__(self):
|
||||
self.name = None
|
||||
|
||||
def __enter__(self):
|
||||
with tempfile.NamedTemporaryFile(delete=False) as tmp:
|
||||
self.name = tmp.name
|
||||
return self.name
|
||||
|
||||
def __exit__(self, type, value, traceback):
|
||||
if not self.name:
|
||||
return
|
||||
try:
|
||||
os.unlink(self.name)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
shell_main()
|
||||
shell_main()
|
||||
|
@ -862,6 +862,17 @@ FilterNodeFromPrimitiveDescription(const FilterPrimitiveDescription& aDescriptio
|
||||
return lastFilter.forget();
|
||||
}
|
||||
|
||||
case PrimitiveType::Opacity:
|
||||
{
|
||||
RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::OPACITY);
|
||||
if (!filter) {
|
||||
return nullptr;
|
||||
}
|
||||
filter->SetAttribute(ATT_OPACITY_VALUE, atts.GetFloat(eOpacityOpacity));
|
||||
filter->SetInput(IN_OPACITY_IN, aSources[0]);
|
||||
return filter.forget();
|
||||
}
|
||||
|
||||
case PrimitiveType::ConvolveMatrix:
|
||||
{
|
||||
RefPtr<FilterNode> filter = aDT->CreateFilter(FilterType::CONVOLVE_MATRIX);
|
||||
@ -1394,6 +1405,7 @@ ResultChangeRegionForPrimitive(const FilterPrimitiveDescription& aDescription,
|
||||
case PrimitiveType::Blend:
|
||||
case PrimitiveType::Composite:
|
||||
case PrimitiveType::Merge:
|
||||
case PrimitiveType::Opacity:
|
||||
return UnionOfRegions(aInputChangeRegions);
|
||||
|
||||
case PrimitiveType::ColorMatrix:
|
||||
@ -1614,6 +1626,14 @@ FilterSupport::PostFilterExtentsForPrimitive(const FilterPrimitiveDescription& a
|
||||
return aInputExtents[0];
|
||||
}
|
||||
|
||||
case PrimitiveType::Opacity:
|
||||
{
|
||||
if (atts.GetFloat(eOpacityOpacity) == 0.0f) {
|
||||
return IntRect();
|
||||
}
|
||||
return ResultChangeRegionForPrimitive(aDescription, aInputExtents);
|
||||
}
|
||||
|
||||
case PrimitiveType::Turbulence:
|
||||
case PrimitiveType::Image:
|
||||
case PrimitiveType::DiffuseLighting:
|
||||
@ -1692,6 +1712,7 @@ SourceNeededRegionForPrimitive(const FilterPrimitiveDescription& aDescription,
|
||||
case PrimitiveType::ColorMatrix:
|
||||
case PrimitiveType::ComponentTransfer:
|
||||
case PrimitiveType::ToAlpha:
|
||||
case PrimitiveType::Opacity:
|
||||
return aResultNeededRegion;
|
||||
|
||||
case PrimitiveType::Morphology:
|
||||
|
@ -95,6 +95,7 @@ enum AttributeName {
|
||||
eColorMatrixValues,
|
||||
eFloodColor,
|
||||
eTileSourceRect,
|
||||
eOpacityOpacity,
|
||||
eComponentTransferFunctionR,
|
||||
eComponentTransferFunctionG,
|
||||
eComponentTransferFunctionB,
|
||||
@ -277,6 +278,7 @@ enum class PrimitiveType {
|
||||
Flood,
|
||||
Tile,
|
||||
ComponentTransfer,
|
||||
Opacity,
|
||||
ConvolveMatrix,
|
||||
Offset,
|
||||
DisplacementMap,
|
||||
|
@ -17,7 +17,7 @@ while True:
|
||||
line = f.readline()
|
||||
if not line:
|
||||
break
|
||||
if not 'CJK COMPATIBILITY IDEOGRAPH-' in line:
|
||||
if 'CJK COMPATIBILITY IDEOGRAPH-' not in line:
|
||||
continue
|
||||
|
||||
m = r.search(line)
|
||||
@ -25,7 +25,7 @@ while True:
|
||||
vs = int(m.group(2), 16)
|
||||
compat = int(m.group(3), 16)
|
||||
|
||||
if not vs in vsdict:
|
||||
if vs not in vsdict:
|
||||
vsdict[vs] = {}
|
||||
vsdict[vs][unified] = compat
|
||||
|
||||
|
@ -15,7 +15,6 @@
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsIPresShell.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "NullPrincipal.h"
|
||||
#include "nsIInputStream.h"
|
||||
#include "nsStringStream.h"
|
||||
#include "nsStreamUtils.h"
|
||||
@ -25,6 +24,7 @@
|
||||
#include "mozilla/dom/FontTableURIProtocolHandler.h"
|
||||
#include "mozilla/dom/SVGDocument.h"
|
||||
#include "mozilla/LoadInfo.h"
|
||||
#include "mozilla/NullPrincipal.h"
|
||||
#include "nsSVGUtils.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "gfxFont.h"
|
||||
|
@ -5,6 +5,7 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "mozilla/dom/ContentChild.h"
|
||||
#include "mozilla/NullPrincipal.h"
|
||||
#include "nsMimeTypes.h"
|
||||
#include "nsIURL.h"
|
||||
#include "nsXULAppAPI.h"
|
||||
@ -13,7 +14,6 @@
|
||||
#include "nsIStringStream.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "NullPrincipal.h"
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsIconChannel,
|
||||
nsIRequest,
|
||||
|
@ -10,6 +10,7 @@
|
||||
|
||||
#include "mozilla/DebugOnly.h"
|
||||
#include "mozilla/EndianUtils.h"
|
||||
#include "mozilla/NullPrincipal.h"
|
||||
#include <algorithm>
|
||||
|
||||
#include <gio/gio.h>
|
||||
@ -25,7 +26,6 @@
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsIStringStream.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "NullPrincipal.h"
|
||||
#include "nsIURL.h"
|
||||
#include "prlink.h"
|
||||
#include "gfxPlatform.h"
|
||||
@ -106,7 +106,8 @@ moz_gdk_pixbuf_to_channel(GdkPixbuf* aPixbuf, nsIURI* aURI,
|
||||
// nsIconProtocolHandler::NewChannel2 will provide the correct loadInfo for
|
||||
// this iconChannel. Use the most restrictive security settings for the
|
||||
// temporary loadInfo to make sure the channel can not be openend.
|
||||
nsCOMPtr<nsIPrincipal> nullPrincipal = NullPrincipal::CreateWithoutOriginAttributes();
|
||||
nsCOMPtr<nsIPrincipal> nullPrincipal =
|
||||
mozilla::NullPrincipal::CreateWithoutOriginAttributes();
|
||||
return NS_NewInputStreamChannel(aChannel,
|
||||
aURI,
|
||||
stream.forget(),
|
||||
|
@ -9,11 +9,11 @@
|
||||
|
||||
#include "ImageLogging.h"
|
||||
#include "imgLoader.h"
|
||||
#include "NullPrincipal.h"
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/ClearOnShutdown.h"
|
||||
#include "mozilla/Move.h"
|
||||
#include "mozilla/NullPrincipal.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/ChaosMode.h"
|
||||
#include "mozilla/LoadInfo.h"
|
||||
|
@ -84,11 +84,11 @@ def try_run(name, command, cwd=None, **kwargs):
|
||||
try:
|
||||
with tempfile.NamedTemporaryFile(prefix=name, delete=False) as f:
|
||||
subprocess.check_call(command, cwd=cwd, stdout=f,
|
||||
stderr=subprocess.STDOUT, **kwargs)
|
||||
stderr=subprocess.STDOUT, **kwargs)
|
||||
except subprocess.CalledProcessError:
|
||||
print('''Error running "{}" in directory {}
|
||||
See output in {}'''.format(' '.join(command), cwd, f.name),
|
||||
file=sys.stderr)
|
||||
file=sys.stderr)
|
||||
return False
|
||||
else:
|
||||
os.unlink(f.name)
|
||||
@ -151,7 +151,7 @@ def update_data_file(topsrcdir):
|
||||
shutil.copy(new_data_file, tree_data_path)
|
||||
try:
|
||||
shutil.rmtree(objdir)
|
||||
except:
|
||||
except Exception:
|
||||
print('Warning: failed to remove %s' % objdir, file=sys.stderr)
|
||||
return True
|
||||
|
||||
|
@ -2,26 +2,24 @@
|
||||
# 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/.
|
||||
|
||||
import sys
|
||||
|
||||
def main(header, propFile):
|
||||
mappings = {}
|
||||
mappings = {}
|
||||
|
||||
with open(propFile, 'r') as f:
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
if not line.startswith('#'):
|
||||
parts = line.split("=", 1)
|
||||
if len(parts) == 2 and len(parts[0]) > 0:
|
||||
mappings[parts[0].strip()] = parts[1].strip()
|
||||
|
||||
keys = mappings.keys()
|
||||
keys.sort()
|
||||
with open(propFile, 'r') as f:
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
if not line.startswith('#'):
|
||||
parts = line.split("=", 1)
|
||||
if len(parts) == 2 and len(parts[0]) > 0:
|
||||
mappings[parts[0].strip()] = parts[1].strip()
|
||||
|
||||
header.write("// This is a generated file. Please do not edit.\n")
|
||||
header.write("// Please edit the corresponding .properties file instead.\n")
|
||||
keys = mappings.keys()
|
||||
keys.sort()
|
||||
|
||||
entries = ['{ "%s", "%s", %d }'
|
||||
% (key, mappings[key], len(mappings[key])) for key in keys]
|
||||
header.write(',\n'.join(entries) + '\n')
|
||||
header.write("// This is a generated file. Please do not edit.\n")
|
||||
header.write("// Please edit the corresponding .properties file instead.\n")
|
||||
|
||||
entries = ['{ "%s", "%s", %d }'
|
||||
% (key, mappings[key], len(mappings[key])) for key in keys]
|
||||
header.write(',\n'.join(entries) + '\n')
|
||||
|
@ -9,6 +9,8 @@
|
||||
#include "MainThreadUtils.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/BasePrincipal.h"
|
||||
#include "mozilla/ContentPrincipal.h"
|
||||
#include "mozilla/NullPrincipal.h"
|
||||
#include "mozilla/ipc/PBackgroundSharedTypes.h"
|
||||
#include "mozilla/ipc/URIUtils.h"
|
||||
#include "mozilla/net/NeckoChannelParams.h"
|
||||
@ -17,8 +19,6 @@
|
||||
#include "nsIURI.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "mozilla/LoadInfo.h"
|
||||
#include "ContentPrincipal.h"
|
||||
#include "NullPrincipal.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsString.h"
|
||||
#include "nsTArray.h"
|
||||
|
@ -11,12 +11,12 @@
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/dom/BlobURL.h"
|
||||
#include "mozilla/NullPrincipalURI.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsDebug.h"
|
||||
#include "nsID.h"
|
||||
#include "nsJARURI.h"
|
||||
#include "nsIIconURI.h"
|
||||
#include "NullPrincipalURI.h"
|
||||
#include "nsJSProtocolHandler.h"
|
||||
#include "nsNetCID.h"
|
||||
#include "nsSimpleNestedURI.h"
|
||||
|
5
ipc/ipdl/.flake8
Normal file
5
ipc/ipdl/.flake8
Normal file
@ -0,0 +1,5 @@
|
||||
[flake8]
|
||||
# See http://pep8.readthedocs.io/en/latest/intro.html#configuration
|
||||
ignore = E121, E123, E126, E129, E133, E226, E241, E242, E704, W503, E402, E741, F405, F403
|
||||
max-line-length = 99
|
||||
|
@ -1,22 +1,24 @@
|
||||
# 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/.
|
||||
|
||||
import optparse, os, re, sys
|
||||
import optparse
|
||||
import os
|
||||
import sys
|
||||
from cStringIO import StringIO
|
||||
import mozpack.path as mozpath
|
||||
from ConfigParser import RawConfigParser
|
||||
|
||||
import ipdl
|
||||
|
||||
|
||||
def log(minv, fmt, *args):
|
||||
if _verbosity >= minv:
|
||||
print fmt % args
|
||||
print(fmt % args)
|
||||
|
||||
# process command line
|
||||
|
||||
|
||||
op = optparse.OptionParser(usage='ipdl.py [options] IPDLfiles...')
|
||||
op.add_option('-I', '--include', dest='includedirs', default=[ ],
|
||||
op.add_option('-I', '--include', dest='includedirs', default=[],
|
||||
action='append',
|
||||
help='Additional directory to search for included protocol specifications')
|
||||
op.add_option('-s', '--sync-msg-list', dest='syncMsgList', default='sync-messages.ini',
|
||||
@ -44,7 +46,7 @@ syncMsgList = options.syncMsgList
|
||||
msgMetadata = options.msgMetadata
|
||||
headersdir = options.headersdir
|
||||
cppdir = options.cppdir
|
||||
includedirs = [ os.path.abspath(incdir) for incdir in options.includedirs ]
|
||||
includedirs = [os.path.abspath(incdir) for incdir in options.includedirs]
|
||||
|
||||
if not len(files):
|
||||
op.error("No IPDL files specified")
|
||||
@ -59,11 +61,13 @@ allmessages = {}
|
||||
allmessageprognames = []
|
||||
allprotocols = []
|
||||
|
||||
|
||||
def normalizedFilename(f):
|
||||
if f == '-':
|
||||
return '<stdin>'
|
||||
return f
|
||||
|
||||
|
||||
log(2, 'Reading sync message list')
|
||||
parser = RawConfigParser()
|
||||
parser.readfp(open(options.syncMsgList))
|
||||
@ -104,7 +108,7 @@ for f in files:
|
||||
sys.exit(1)
|
||||
|
||||
if not ipdl.checkSyncMessage(ast, syncMsgList):
|
||||
print >>sys.stderr, 'Error: New sync IPC messages must be reviewed by an IPC peer and recorded in %s' % options.syncMsgList
|
||||
print >>sys.stderr, 'Error: New sync IPC messages must be reviewed by an IPC peer and recorded in %s' % options.syncMsgList # NOQA: E501
|
||||
sys.exit(1)
|
||||
|
||||
if not ipdl.checkFixedSyncMessages(parser):
|
||||
|
@ -2,10 +2,11 @@
|
||||
# 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/.
|
||||
|
||||
__all__ = [ 'gencxx', 'genipdl', 'parse', 'typecheck', 'writeifmodified',
|
||||
'checkSyncMessage', 'checkFixedSyncMessages' ]
|
||||
__all__ = ['gencxx', 'genipdl', 'parse', 'typecheck', 'writeifmodified',
|
||||
'checkSyncMessage', 'checkFixedSyncMessages']
|
||||
|
||||
import os, sys
|
||||
import os
|
||||
import sys
|
||||
from cStringIO import StringIO
|
||||
|
||||
from ipdl.cgen import IPDLCodeGen
|
||||
@ -17,7 +18,7 @@ from ipdl.checker import checkSyncMessage, checkFixedSyncMessages
|
||||
from ipdl.cxx.cgen import CxxCodeGen
|
||||
|
||||
|
||||
def parse(specstring, filename='/stdin', includedirs=[ ], errout=sys.stderr):
|
||||
def parse(specstring, filename='/stdin', includedirs=[], errout=sys.stderr):
|
||||
'''Return an IPDL AST if parsing was successful. Print errors to |errout|
|
||||
if it is not.'''
|
||||
# The file type and name are later enforced by the type checker.
|
||||
@ -35,6 +36,7 @@ def parse(specstring, filename='/stdin', includedirs=[ ], errout=sys.stderr):
|
||||
print >>errout, p
|
||||
return None
|
||||
|
||||
|
||||
def typecheck(ast, errout=sys.stderr):
|
||||
'''Return True iff |ast| is well typed. Print errors to |errout| if
|
||||
it is not.'''
|
||||
@ -51,11 +53,12 @@ def gencxx(ipdlfilename, ast, outheadersdir, outcppdir, segmentcapacitydict):
|
||||
outheadersdir,
|
||||
*([ns.name for ns in ast.namespaces] + [hdr.name]))
|
||||
]
|
||||
def resolveCpp(cpp):
|
||||
return [ cpp, os.path.join(outcppdir, cpp.name) ]
|
||||
|
||||
for ast, filename in ([ resolveHeader(hdr) for hdr in headers ]
|
||||
+ [ resolveCpp(cpp) for cpp in cpps ]):
|
||||
def resolveCpp(cpp):
|
||||
return [cpp, os.path.join(outcppdir, cpp.name)]
|
||||
|
||||
for ast, filename in ([resolveHeader(hdr) for hdr in headers]
|
||||
+ [resolveCpp(cpp) for cpp in cpps]):
|
||||
tempfile = StringIO()
|
||||
CxxCodeGen(tempfile).cgen(ast)
|
||||
writeifmodified(tempfile.getvalue(), filename)
|
||||
@ -68,6 +71,7 @@ def genipdl(ast, outdir):
|
||||
def genmsgenum(ast):
|
||||
return msgenums(ast.protocol, pretty=True)
|
||||
|
||||
|
||||
def writeifmodified(contents, file):
|
||||
dir = os.path.dirname(file)
|
||||
os.path.exists(dir) or os.makedirs(dir)
|
||||
|
@ -2,8 +2,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/.
|
||||
|
||||
import sys
|
||||
|
||||
NOT_NESTED = 1
|
||||
INSIDE_SYNC_NESTED = 2
|
||||
INSIDE_CPOW_NESTED = 3
|
||||
@ -12,10 +10,11 @@ NORMAL_PRIORITY = 1
|
||||
INPUT_PRIORITY = 2
|
||||
HIGH_PRIORITY = 3
|
||||
|
||||
|
||||
class Visitor:
|
||||
def defaultVisit(self, node):
|
||||
raise Exception, "INTERNAL ERROR: no visitor for node type `%s'"% (
|
||||
node.__class__.__name__)
|
||||
raise Exception("INTERNAL ERROR: no visitor for node type `%s'" %
|
||||
(node.__class__.__name__))
|
||||
|
||||
def visitTranslationUnit(self, tu):
|
||||
for cxxInc in tu.cxxIncludes:
|
||||
@ -31,7 +30,6 @@ class Visitor:
|
||||
if tu.protocol:
|
||||
tu.protocol.accept(self)
|
||||
|
||||
|
||||
def visitCxxInclude(self, inc):
|
||||
pass
|
||||
|
||||
@ -88,27 +86,33 @@ class Visitor:
|
||||
def visitDecl(self, d):
|
||||
pass
|
||||
|
||||
|
||||
class Loc:
|
||||
def __init__(self, filename='<??>', lineno=0):
|
||||
assert filename
|
||||
self.filename = filename
|
||||
self.lineno = lineno
|
||||
|
||||
def __repr__(self):
|
||||
return '%r:%r'% (self.filename, self.lineno)
|
||||
return '%r:%r' % (self.filename, self.lineno)
|
||||
|
||||
def __str__(self):
|
||||
return '%s:%s'% (self.filename, self.lineno)
|
||||
return '%s:%s' % (self.filename, self.lineno)
|
||||
|
||||
|
||||
Loc.NONE = Loc(filename='<??>', lineno=0)
|
||||
|
||||
|
||||
class _struct:
|
||||
pass
|
||||
|
||||
|
||||
class Node:
|
||||
def __init__(self, loc=Loc.NONE):
|
||||
self.loc = loc
|
||||
|
||||
def accept(self, visitor):
|
||||
visit = getattr(visitor, 'visit'+ self.__class__.__name__, None)
|
||||
visit = getattr(visitor, 'visit' + self.__class__.__name__, None)
|
||||
if visit is None:
|
||||
return getattr(visitor, 'defaultVisit')(self)
|
||||
return visit(self)
|
||||
@ -122,40 +126,47 @@ class NamespacedNode(Node):
|
||||
def __init__(self, loc=Loc.NONE, name=None):
|
||||
Node.__init__(self, loc)
|
||||
self.name = name
|
||||
self.namespaces = [ ]
|
||||
self.namespaces = []
|
||||
|
||||
def addOuterNamespace(self, namespace):
|
||||
self.namespaces.insert(0, namespace)
|
||||
|
||||
def qname(self):
|
||||
return QualifiedId(self.loc, self.name,
|
||||
[ ns.name for ns in self.namespaces ])
|
||||
[ns.name for ns in self.namespaces])
|
||||
|
||||
|
||||
class TranslationUnit(NamespacedNode):
|
||||
def __init__(self, type, name):
|
||||
NamespacedNode.__init__(self, name=name)
|
||||
self.filetype = type
|
||||
self.filename = None
|
||||
self.cxxIncludes = [ ]
|
||||
self.includes = [ ]
|
||||
self.builtinUsing = [ ]
|
||||
self.using = [ ]
|
||||
self.structsAndUnions = [ ]
|
||||
self.cxxIncludes = []
|
||||
self.includes = []
|
||||
self.builtinUsing = []
|
||||
self.using = []
|
||||
self.structsAndUnions = []
|
||||
self.protocol = None
|
||||
|
||||
def addCxxInclude(self, cxxInclude): self.cxxIncludes.append(cxxInclude)
|
||||
|
||||
def addInclude(self, inc): self.includes.append(inc)
|
||||
|
||||
def addStructDecl(self, struct): self.structsAndUnions.append(struct)
|
||||
|
||||
def addUnionDecl(self, union): self.structsAndUnions.append(union)
|
||||
|
||||
def addUsingStmt(self, using): self.using.append(using)
|
||||
|
||||
def setProtocol(self, protocol): self.protocol = protocol
|
||||
|
||||
|
||||
class CxxInclude(Node):
|
||||
def __init__(self, loc, cxxFile):
|
||||
Node.__init__(self, loc)
|
||||
self.file = cxxFile
|
||||
|
||||
|
||||
class Include(Node):
|
||||
def __init__(self, loc, type, name):
|
||||
Node.__init__(self, loc)
|
||||
@ -164,43 +175,61 @@ class Include(Node):
|
||||
suffix += 'h'
|
||||
self.file = "%s.%s" % (name, suffix)
|
||||
|
||||
|
||||
class UsingStmt(Node):
|
||||
def __init__(self, loc, cxxTypeSpec, cxxHeader=None, kind=None, refcounted=False):
|
||||
Node.__init__(self, loc)
|
||||
assert not isinstance(cxxTypeSpec, str)
|
||||
assert cxxHeader is None or isinstance(cxxHeader, str);
|
||||
assert cxxHeader is None or isinstance(cxxHeader, str)
|
||||
assert kind is None or kind == 'class' or kind == 'struct'
|
||||
self.type = cxxTypeSpec
|
||||
self.header = cxxHeader
|
||||
self.kind = kind
|
||||
self.refcounted = refcounted
|
||||
|
||||
def canBeForwardDeclared(self):
|
||||
return self.isClass() or self.isStruct()
|
||||
|
||||
def isClass(self):
|
||||
return self.kind == 'class'
|
||||
|
||||
def isStruct(self):
|
||||
return self.kind == 'struct'
|
||||
|
||||
def isRefcounted(self):
|
||||
return self.refcounted
|
||||
|
||||
# "singletons"
|
||||
|
||||
|
||||
class PrettyPrinted:
|
||||
@classmethod
|
||||
def __hash__(cls): return hash(cls.pretty)
|
||||
|
||||
@classmethod
|
||||
def __str__(cls): return cls.pretty
|
||||
def __str__(cls): return cls.pretty
|
||||
|
||||
|
||||
class ASYNC(PrettyPrinted):
|
||||
pretty = 'async'
|
||||
|
||||
|
||||
class INTR(PrettyPrinted):
|
||||
pretty = 'intr'
|
||||
|
||||
|
||||
class SYNC(PrettyPrinted):
|
||||
pretty = 'sync'
|
||||
|
||||
|
||||
class INOUT(PrettyPrinted):
|
||||
pretty = 'inout'
|
||||
|
||||
|
||||
class IN(PrettyPrinted):
|
||||
pretty = 'in'
|
||||
|
||||
|
||||
class OUT(PrettyPrinted):
|
||||
pretty = 'out'
|
||||
|
||||
@ -210,14 +239,16 @@ class Namespace(Node):
|
||||
Node.__init__(self, loc)
|
||||
self.name = namespace
|
||||
|
||||
|
||||
class Protocol(NamespacedNode):
|
||||
def __init__(self, loc):
|
||||
NamespacedNode.__init__(self, loc)
|
||||
self.sendSemantics = ASYNC
|
||||
self.nested = NOT_NESTED
|
||||
self.managers = [ ]
|
||||
self.managesStmts = [ ]
|
||||
self.messageDecls = [ ]
|
||||
self.managers = []
|
||||
self.managesStmts = []
|
||||
self.messageDecls = []
|
||||
|
||||
|
||||
class StructField(Node):
|
||||
def __init__(self, loc, type, name):
|
||||
@ -225,26 +256,31 @@ class StructField(Node):
|
||||
self.typespec = type
|
||||
self.name = name
|
||||
|
||||
|
||||
class StructDecl(NamespacedNode):
|
||||
def __init__(self, loc, name, fields):
|
||||
NamespacedNode.__init__(self, loc, name)
|
||||
self.fields = fields
|
||||
|
||||
|
||||
class UnionDecl(NamespacedNode):
|
||||
def __init__(self, loc, name, components):
|
||||
NamespacedNode.__init__(self, loc, name)
|
||||
self.components = components
|
||||
|
||||
|
||||
class Manager(Node):
|
||||
def __init__(self, loc, managerName):
|
||||
Node.__init__(self, loc)
|
||||
self.name = managerName
|
||||
|
||||
|
||||
class ManagesStmt(Node):
|
||||
def __init__(self, loc, managedName):
|
||||
Node.__init__(self, loc)
|
||||
self.name = managedName
|
||||
|
||||
|
||||
class MessageDecl(Node):
|
||||
def __init__(self, loc):
|
||||
Node.__init__(self, loc)
|
||||
@ -253,8 +289,8 @@ class MessageDecl(Node):
|
||||
self.nested = NOT_NESTED
|
||||
self.prio = NORMAL_PRIORITY
|
||||
self.direction = None
|
||||
self.inParams = [ ]
|
||||
self.outParams = [ ]
|
||||
self.inParams = []
|
||||
self.outParams = []
|
||||
self.compress = ''
|
||||
self.verify = ''
|
||||
|
||||
@ -271,7 +307,8 @@ class MessageDecl(Node):
|
||||
elif modifier == 'verify':
|
||||
self.verify = modifier
|
||||
elif modifier != '':
|
||||
raise Exception, "Unexpected message modifier `%s'"% modifier
|
||||
raise Exception("Unexpected message modifier `%s'" % modifier)
|
||||
|
||||
|
||||
class Param(Node):
|
||||
def __init__(self, loc, typespec, name):
|
||||
@ -279,21 +316,25 @@ class Param(Node):
|
||||
self.name = name
|
||||
self.typespec = typespec
|
||||
|
||||
|
||||
class TypeSpec(Node):
|
||||
def __init__(self, loc, spec):
|
||||
Node.__init__(self, loc)
|
||||
self.spec = spec # QualifiedId
|
||||
self.array = 0 # bool
|
||||
self.nullable = 0 # bool
|
||||
|
||||
def basename(self):
|
||||
return self.spec.baseid
|
||||
|
||||
def __str__(self): return str(self.spec)
|
||||
def __str__(self): return str(self.spec)
|
||||
|
||||
|
||||
class QualifiedId: # FIXME inherit from node?
|
||||
def __init__(self, loc, baseid, quals=[ ]):
|
||||
def __init__(self, loc, baseid, quals=[]):
|
||||
assert isinstance(baseid, str)
|
||||
for qual in quals: assert isinstance(qual, str)
|
||||
for qual in quals:
|
||||
assert isinstance(qual, str)
|
||||
|
||||
self.loc = loc
|
||||
self.baseid = baseid
|
||||
@ -306,9 +347,11 @@ class QualifiedId: # FIXME inherit from node?
|
||||
def __str__(self):
|
||||
if 0 == len(self.quals):
|
||||
return self.baseid
|
||||
return '::'.join(self.quals) +'::'+ self.baseid
|
||||
return '::'.join(self.quals) + '::' + self.baseid
|
||||
|
||||
# added by type checking passes
|
||||
|
||||
|
||||
class Decl(Node):
|
||||
def __init__(self, loc):
|
||||
Node.__init__(self, loc)
|
||||
|
@ -2,10 +2,11 @@
|
||||
# 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/.
|
||||
|
||||
import os, sys
|
||||
import sys
|
||||
|
||||
from ipdl.ast import Visitor
|
||||
|
||||
|
||||
class CodePrinter:
|
||||
def __init__(self, outf=sys.stdout, indentCols=4):
|
||||
self.outf = outf
|
||||
@ -16,19 +17,20 @@ class CodePrinter:
|
||||
self.outf.write(str)
|
||||
|
||||
def printdent(self, str=''):
|
||||
self.write((' '* self.col) + str)
|
||||
self.write((' ' * self.col) + str)
|
||||
|
||||
def println(self, str=''):
|
||||
self.write(str +'\n')
|
||||
self.write(str + '\n')
|
||||
|
||||
def printdentln(self, str):
|
||||
self.write((' '* self.col) + str +'\n')
|
||||
self.write((' ' * self.col) + str + '\n')
|
||||
|
||||
def indent(self): self.col += self.indentCols
|
||||
|
||||
def dedent(self): self.col -= self.indentCols
|
||||
|
||||
|
||||
##-----------------------------------------------------------------------------
|
||||
# -----------------------------------------------------------------------------
|
||||
class IPDLCodeGen(CodePrinter, Visitor):
|
||||
'''Spits back out equivalent IPDL to the code that generated this.
|
||||
Also known as pretty-printing.'''
|
||||
@ -40,13 +42,13 @@ Also known as pretty-printing.'''
|
||||
def visitTranslationUnit(self, tu):
|
||||
self.printed.add(tu.filename)
|
||||
self.println('//\n// Automatically generated by ipdlc\n//')
|
||||
CodeGen.visitTranslationUnit(self, tu)
|
||||
CodeGen.visitTranslationUnit(self, tu) # NOQA: F821
|
||||
|
||||
def visitCxxInclude(self, inc):
|
||||
self.println('include "'+ inc.file +'";')
|
||||
self.println('include "' + inc.file + '";')
|
||||
|
||||
def visitProtocolInclude(self, inc):
|
||||
self.println('include protocol "'+ inc.file +'";')
|
||||
self.println('include protocol "' + inc.file + '";')
|
||||
if inc.tu.filename not in self.printed:
|
||||
self.println('/* Included file:')
|
||||
IPDLCodeGen(outf=self.outf, indentCols=self.indentCols,
|
||||
@ -56,33 +58,37 @@ Also known as pretty-printing.'''
|
||||
|
||||
def visitProtocol(self, p):
|
||||
self.println()
|
||||
for namespace in p.namespaces: namespace.accept(self)
|
||||
for namespace in p.namespaces:
|
||||
namespace.accept(self)
|
||||
|
||||
self.println('%s protocol %s\n{'% (p.sendSemantics[0], p.name))
|
||||
self.println('%s protocol %s\n{' % (p.sendSemantics[0], p.name))
|
||||
self.indent()
|
||||
|
||||
for mgs in p.managesStmts:
|
||||
mgs.accept(self)
|
||||
if len(p.managesStmts): self.println()
|
||||
if len(p.managesStmts):
|
||||
self.println()
|
||||
|
||||
for msgDecl in p.messageDecls: msgDecl.accept(self)
|
||||
for msgDecl in p.messageDecls:
|
||||
msgDecl.accept(self)
|
||||
self.println()
|
||||
|
||||
self.dedent()
|
||||
self.println('}')
|
||||
self.write('}\n'* len(p.namespaces))
|
||||
self.write('}\n' * len(p.namespaces))
|
||||
|
||||
def visitManagerStmt(self, mgr):
|
||||
self.printdentln('manager '+ mgr.name +';')
|
||||
self.printdentln('manager ' + mgr.name + ';')
|
||||
|
||||
def visitManagesStmt(self, mgs):
|
||||
self.printdentln('manages '+ mgs.name +';')
|
||||
self.printdentln('manages ' + mgs.name + ';')
|
||||
|
||||
def visitMessageDecl(self, msg):
|
||||
self.printdent('%s %s %s('% (msg.sendSemantics[0], msg.direction[0], msg.name))
|
||||
self.printdent('%s %s %s(' % (msg.sendSemantics[0], msg.direction[0], msg.name))
|
||||
for i, inp in enumerate(msg.inParams):
|
||||
inp.accept(self)
|
||||
if i != (len(msg.inParams) - 1): self.write(', ')
|
||||
if i != (len(msg.inParams) - 1):
|
||||
self.write(', ')
|
||||
self.write(')')
|
||||
if 0 == len(msg.outParams):
|
||||
self.println(';')
|
||||
@ -93,6 +99,7 @@ Also known as pretty-printing.'''
|
||||
self.printdent('returns (')
|
||||
for i, outp in enumerate(msg.outParams):
|
||||
outp.accept(self)
|
||||
if i != (len(msg.outParams) - 1): self.write(', ')
|
||||
if i != (len(msg.outParams) - 1):
|
||||
self.write(', ')
|
||||
self.println(');')
|
||||
self.dedent()
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user