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

This commit is contained in:
Margareta Eliza Balazs 2018-07-18 12:40:51 +03:00
commit 9de29c1f5a
226 changed files with 5148 additions and 4065 deletions

View File

@ -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,

View File

@ -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;
}

View File

@ -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">

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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"

View File

@ -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>

View File

@ -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!");
}

View File

@ -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">

View File

@ -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]

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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);

View File

@ -22,6 +22,7 @@ EXTRA_COMPONENTS += [
EXTRA_JS_MODULES.sessionstore = [
'ContentRestore.jsm',
'ContentSessionStore.jsm',
'DocShellCapabilities.jsm',
'GlobalState.jsm',
'RecentlyClosedTabsAndWindowsMenuUtils.jsm',

View File

@ -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",

View File

@ -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"

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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 += [

View File

@ -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"

View File

@ -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();
/**

View File

@ -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.
*

View File

@ -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",

View File

@ -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,
})

View File

@ -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)
);
}
}

View File

@ -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,
}));

View File

@ -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,

View File

@ -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,

View File

@ -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.

View File

@ -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");

View File

@ -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");

View File

@ -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");

View File

@ -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.");

View File

@ -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,

View File

@ -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;

View File

@ -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;

View File

@ -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
};
});

View File

@ -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});" +
"};" +

View File

@ -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;
}

View File

@ -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");

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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;

View File

@ -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"

View File

@ -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 {

View File

@ -8,7 +8,7 @@
#include "ConsoleCommon.h"
#include "mozilla/ClearOnShutdown.h"
#include "NullPrincipal.h"
#include "mozilla/NullPrincipal.h"
namespace mozilla {
namespace dom {

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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

View File

@ -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"

View File

@ -31,7 +31,7 @@
#include "GeckoProfiler.h"
#include "nsPluginInstanceOwner.h"
#include "nsDataHashtable.h"
#include "NullPrincipal.h"
#include "mozilla/NullPrincipal.h"
// nsPluginStreamListenerPeer

View File

@ -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;

View File

@ -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;

View File

@ -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;
//*****************************************************************************

View File

@ -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)

View File

@ -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:

View File

@ -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)
{

View File

@ -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
{

View File

@ -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)

View File

@ -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);

View File

@ -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,

View File

@ -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)

View File

@ -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)

View File

@ -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:

View File

@ -128,7 +128,8 @@ enum class FilterType : int8_t {
DISTANT_SPECULAR,
CROP,
PREMULTIPLY,
UNPREMULTIPLY
UNPREMULTIPLY,
OPACITY
};
enum class DrawTargetType : int8_t {

View File

@ -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()

View File

@ -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()

View File

@ -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:

View File

@ -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,

View File

@ -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

View File

@ -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"

View File

@ -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,

View File

@ -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(),

View File

@ -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"

View File

@ -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

View File

@ -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')

View File

@ -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"

View File

@ -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
View 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

View File

@ -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):

View File

@ -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)

View File

@ -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)

View File

@ -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