Merge m-c to inbound.

This commit is contained in:
Ryan VanderMeulen 2013-10-16 17:02:56 -04:00
commit 2ad9e11ee0
67 changed files with 1976 additions and 1572 deletions

View File

@ -802,10 +802,7 @@ pref("dom.datastore.enabled", true);
#endif
// DOM Inter-App Communication API.
#ifdef MOZ_WIDGET_GONK
// Enable this only for gonk-specific build but not for desktop build.
pref("dom.inter-app-communication-api.enabled", true);
#endif
// Allow ADB to run for this many hours before disabling
// (only applies when marionette is disabled)

View File

@ -1,4 +1,4 @@
{
"revision": "36aa3e5d226a844b07b3e4b2219f54b549456ec1",
"revision": "86e06b1db110e34eb66826d3b1bdee3a5d57b3a7",
"repo_path": "/integration/gaia-central"
}

View File

@ -307,6 +307,9 @@ let SessionStoreInternal = {
// states for all currently opened windows
_windows: {},
// counter for creating unique window IDs
_nextWindowID: 0,
// states for all recently closed windows
_closedWindows: [],
@ -682,6 +685,15 @@ let SessionStoreInternal = {
this._clearRestoringWindows();
},
/**
* Generate a unique window identifier
* @return string
* A unique string to identify a window
*/
_generateWindowID: function ssi_generateWindowID() {
return "window" + (this._nextWindowID++);
},
/**
* If it's the first window load since app start...
* - determine if we're reloading after a crash or a forced-restart
@ -703,8 +715,9 @@ let SessionStoreInternal = {
this._loadState == STATE_QUITTING)
return;
// assign it a unique identifier (timestamp)
aWindow.__SSi = "window" + Date.now();
// Assign the window a unique identifier we can use to reference
// internal data about the window.
aWindow.__SSi = this._generateWindowID();
// and create its data object
this._windows[aWindow.__SSi] = { tabs: [], selected: 0, _closedTabs: [], busy: false };
@ -880,8 +893,10 @@ let SessionStoreInternal = {
// this window was about to be restored - conserve its original data, if any
let isFullyLoaded = this._isWindowLoaded(aWindow);
if (!isFullyLoaded) {
if (!aWindow.__SSi)
aWindow.__SSi = "window" + Date.now();
if (!aWindow.__SSi) {
aWindow.__SSi = this._generateWindowID();
}
this._windows[aWindow.__SSi] = this._statesToRestore[aWindow.__SS_restoreID];
delete this._statesToRestore[aWindow.__SS_restoreID];
delete aWindow.__SS_restoreID;

View File

@ -1037,14 +1037,10 @@ var GestureModule = {
*/
var InputSourceHelper = {
isPrecise: false,
touchIsActive: false,
init: function ish_init() {
window.addEventListener("mousemove", this, true);
window.addEventListener("mousedown", this, true);
window.addEventListener("touchstart", this, true);
window.addEventListener("touchend", this, true);
window.addEventListener("touchcancel", this, true);
Services.obs.addObserver(this, "metro_precise_input", false);
Services.obs.addObserver(this, "metro_imprecise_input", false);
},
_precise: function () {
@ -1061,37 +1057,17 @@ var InputSourceHelper = {
}
},
handleEvent: function ish_handleEvent(aEvent) {
switch(aEvent.type) {
case "touchstart":
observe: function BrowserUI_observe(aSubject, aTopic, aData) {
switch (aTopic) {
case "metro_precise_input":
this._precise();
break;
case "metro_imprecise_input":
this._imprecise();
this.touchIsActive = true;
break;
case "touchend":
case "touchcancel":
this.touchIsActive = false;
break;
default:
// Ignore mouse movement when touch is active. Prevents both mouse scrollbars
// and touch scrollbars from displaying at the same time. Also works around
// odd win8 bug involving an erant mousemove event after a touch sequence
// starts (bug 896017).
if (this.touchIsActive) {
return;
}
switch (aEvent.mozInputSource) {
case Ci.nsIDOMMouseEvent.MOZ_SOURCE_MOUSE:
case Ci.nsIDOMMouseEvent.MOZ_SOURCE_PEN:
case Ci.nsIDOMMouseEvent.MOZ_SOURCE_ERASER:
case Ci.nsIDOMMouseEvent.MOZ_SOURCE_CURSOR:
this._precise();
break;
}
break;
}
},
fireUpdate: function fireUpdate() {
if (this.isPrecise) {
this._fire("MozPrecisePointer");

View File

@ -32,44 +32,28 @@ function testState(aState) {
}
}
function sendMouseMoves() {
let utils = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsIDOMWindowUtils);
for (let deg = 0; deg < 180; deg++) {
let coord = Math.sin((deg * Math.PI)/180) * 750;
utils.sendMouseEventToWindow("mousemove", coord, coord, 2, 1, 0, true,
1, Ci.nsIDOMMouseEvent.MOZ_SOURCE_MOUSE);
}
function notifyPrecise()
{
Services.obs.notifyObservers(null, "metro_precise_input", null);
}
function sendTouchStart() {
EventUtils.synthesizeTouchAtPoint(100, 100, { type: "touchstart" }, window);
}
function sendTouchMove() {
EventUtils.synthesizeTouchAtPoint(100, 100, { type: "touchmove" }, window);
}
function sendTouchEnd() {
EventUtils.synthesizeTouchAtPoint(100, 100, { type: "touchend" }, window);
function notifyImprecise()
{
Services.obs.notifyObservers(null, "metro_imprecise_input", null);
}
gTests.push({
desc: "precise/imprecise input switcher",
setUp: setUp,
run: function () {
sendMouseMoves();
notifyPrecise();
testState("precise");
sendTouchStart();
notifyImprecise();
testState("imprecise");
sendMouseMoves();
testState("imprecise");
sendTouchMove();
testState("imprecise");
sendTouchEnd();
testState("imprecise");
sendMouseMoves();
notifyPrecise();
testState("precise");
notifyImprecise();
testState("imprecise");
}
});

View File

@ -66,8 +66,14 @@
display: none;
}
#sources .side-menu-widget-item.selected > .side-menu-widget-item-checkbox:not([checked]) ~ .side-menu-widget-item-arrow {
#sources .side-menu-widget-item.selected > .side-menu-widget-item-checkbox:not([checked]) ~ .side-menu-widget-item-arrow:-moz-locale-dir(ltr) {
background-image: none;
box-shadow: inset -1px 0 0 #222426;
}
#sources .side-menu-widget-item.selected > .side-menu-widget-item-checkbox:not([checked]) ~ .side-menu-widget-item-arrow:-moz-locale-dir(rtl) {
background-image: none;
box-shadow: inset 1px 0 0 #222426;
}
/* Black box message and source progress meter */

View File

@ -64,8 +64,14 @@
display: none;
}
#sources .side-menu-widget-item.selected > .side-menu-widget-item-checkbox:not([checked]) ~ .side-menu-widget-item-arrow {
#sources .side-menu-widget-item.selected > .side-menu-widget-item-checkbox:not([checked]) ~ .side-menu-widget-item-arrow:-moz-locale-dir(ltr) {
background-image: none;
box-shadow: inset -1px 0 0 #222426;
}
#sources .side-menu-widget-item.selected > .side-menu-widget-item-checkbox:not([checked]) ~ .side-menu-widget-item-arrow:-moz-locale-dir(rtl) {
background-image: none;
box-shadow: inset 1px 0 0 #222426;
}
/* Black box message and source progress meter */

View File

@ -64,8 +64,14 @@
display: none;
}
#sources .side-menu-widget-item.selected > .side-menu-widget-item-checkbox:not([checked]) ~ .side-menu-widget-item-arrow {
#sources .side-menu-widget-item.selected > .side-menu-widget-item-checkbox:not([checked]) ~ .side-menu-widget-item-arrow:-moz-locale-dir(ltr) {
background-image: none;
box-shadow: inset -1px 0 0 #222426;
}
#sources .side-menu-widget-item.selected > .side-menu-widget-item-checkbox:not([checked]) ~ .side-menu-widget-item-arrow:-moz-locale-dir(rtl) {
background-image: none;
box-shadow: inset 1px 0 0 #222426;
}
/* Black box message and source progress meter */

View File

@ -66,7 +66,9 @@ nsDOMCameraManager::~nsDOMCameraManager()
/* destructor code */
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
obs->RemoveObserver(this, "xpcom-shutdown");
if (obs) {
obs->RemoveObserver(this, "xpcom-shutdown");
}
}
bool

View File

@ -1062,6 +1062,23 @@ ContactDB.prototype = {
substringResult[event.target.result[i].id] = event.target.result[i];
}
}.bind(this);
} else if (normalized[0] !== "+") {
// We might have an international prefix like '00'
let parsed = PhoneNumberUtils.parse(normalized);
if (parsed && parsed.internationalNumber &&
parsed.nationalNumber &&
parsed.nationalNumber !== normalized &&
parsed.internationalNumber !== normalized) {
if (DEBUG) debug("Search with " + parsed.internationalNumber);
let prefixRequest = index.mozGetAll(parsed.internationalNumber, limit);
prefixRequest.onsuccess = function (event) {
if (DEBUG) debug("Request successful. Record count: " + event.target.result.length);
for (let i in event.target.result) {
substringResult[event.target.result[i].id] = event.target.result[i];
}
}.bind(this);
}
}
request = index.mozGetAll(normalized, limit);

View File

@ -61,6 +61,16 @@ var properties2 = {
tel: [{type: ["work"], value: shortNumber, carrier: "testCarrier"}]
};
var number3 = {
international1: "0041557932012345",
international2: "+557932012345"
};
var properties3 = {
name: "Testname2",
tel: [{value: number3.international2}]
};
var req;
var index = 0;
var createResult1;
@ -237,6 +247,41 @@ var steps = [
}
req.onerror = onFailure;
},
function () {
ok(true, "Adding a new contact with country code");
createResult1 = new mozContact();
createResult1.init(properties3);
req = navigator.mozContacts.save(createResult1);
req.onsuccess = function () {
ok(createResult1.id, "The contact now has an ID.");
sample_id1 = createResult1.id;
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Searching for international number with prefix");
var options = {filterBy: ["tel"],
filterOp: "match",
filterValue: number3.international1};
req = mozContacts.find(options);
req.onsuccess = function () {
ok(req.result.length == 1, "Found exactly 1 contact.");
findResult1 = req.result[0];
ok(findResult1.id == sample_id1, "Same ID");
next();
};
req.onerror = onFailure;
},
function () {
ok(true, "Deleting database");
req = mozContacts.clear();
req.onsuccess = function () {
ok(true, "Deleted the database");
next();
}
req.onerror = onFailure;
},
function () {
ok(true, "all done!\n");
SimpleTest.finish();

View File

@ -45,15 +45,17 @@
}, cbError);
}
var itemNumber = 60;
function testStoreAdd() {
var objects = [];
for (var i = 0; i < 300; ++i) {
for (var i = 0; i < itemNumber; ++i) {
objects.push(i);
}
function testStoreAddInternal() {
if (!objects.length) {
ok(true, "We inserted 300 items");
ok(true, "We inserted " + itemNumber + " items");
runTest();
return;
}
@ -70,7 +72,7 @@
function testStoreGet() {
var objects = [];
for (var i = 1; i <= 300; ++i) {
for (var i = 1; i <= itemNumber; ++i) {
objects.push(i);
}

View File

@ -136,6 +136,7 @@ SystemMessageManager.prototype = {
dispatchers[aType] = { handler: aHandler, messages: [], isHandling: false };
// Ask for the list of currently pending messages.
this.addMessageListeners("SystemMessageManager:GetPendingMessages:Return");
cpmm.sendAsyncMessage("SystemMessageManager:GetPendingMessages",
{ type: aType,
uri: this._uri,
@ -214,6 +215,8 @@ SystemMessageManager.prototype = {
manifest: this._manifest,
uri: this._uri,
msgID: msg.msgID });
} else if (aMessage.name == "SystemMessageManager:GetPendingMessages:Return") {
this.removeMessageListeners(aMessage.name);
}
let messages = (aMessage.name == "SystemMessageManager:Message")
@ -248,8 +251,7 @@ SystemMessageManager.prototype = {
// nsIDOMGlobalPropertyInitializer implementation.
init: function sysMessMgr_init(aWindow) {
debug("init");
this.initDOMRequestHelper(aWindow, ["SystemMessageManager:Message",
"SystemMessageManager:GetPendingMessages:Return"]);
this.initDOMRequestHelper(aWindow, ["SystemMessageManager:Message"]);
let principal = aWindow.document.nodePrincipal;
this._isInBrowserElement = principal.isInBrowserElement;

View File

@ -1152,6 +1152,7 @@ this.GECKO_ICC_SERVICES = {
ADN: 2,
FDN: 3,
PLMNSEL: 7,
MSISDN: 9,
CBMI: 14,
SPN: 17,
SDN: 18,
@ -1161,6 +1162,7 @@ this.GECKO_ICC_SERVICES = {
BDN: 31,
PNN: 51,
OPL: 52,
MDN: 53,
SPDI: 56
},
usim: {
@ -1170,10 +1172,12 @@ this.GECKO_ICC_SERVICES = {
CBMI: 15,
CBMIR: 16,
SPN: 19,
MSISDN: 21,
DATA_DOWNLOAD_SMS_PP: 28,
DATA_DOWNLOAD_SMS_CB: 29,
PNN: 45,
OPL: 46,
MDN: 47,
SPDI: 51
},
ruim: {

View File

@ -10995,10 +10995,8 @@ let ICCRecordHelper = {
fetchICCRecords: function fetchICCRecords() {
this.readICCID();
RIL.getIMSI();
this.readMSISDN();
this.readAD();
this.readSST();
this.readMBDN();
},
/**
@ -11143,6 +11141,13 @@ let ICCRecordHelper = {
debug("SST: " + str);
}
if (ICCUtilsHelper.isICCServiceAvailable("MSISDN")) {
if (DEBUG) debug("MSISDN: MSISDN is available");
this.readMSISDN();
} else {
if (DEBUG) debug("MSISDN: MSISDN service is not available");
}
// Fetch SPN and PLMN list, if some of them are available.
if (ICCUtilsHelper.isICCServiceAvailable("SPN")) {
if (DEBUG) debug("SPN: SPN is available");
@ -11151,6 +11156,13 @@ let ICCRecordHelper = {
if (DEBUG) debug("SPN: SPN service is not available");
}
if (ICCUtilsHelper.isICCServiceAvailable("MDN")) {
if (DEBUG) debug("MDN: MDN available.");
this.readMBDN();
} else {
if (DEBUG) debug("MDN: MDN service is not available");
}
if (ICCUtilsHelper.isICCServiceAvailable("SPDI")) {
if (DEBUG) debug("SPDI: SPDI available.");
this.readSPDI();

View File

@ -1895,3 +1895,86 @@ add_test(function test_reading_ad_and_parsing_mcc_mnc() {
run_next_test();
});
add_test(function test_reading_optional_efs() {
let worker = newUint8Worker();
let record = worker.ICCRecordHelper;
let gsmPdu = worker.GsmPDUHelper;
let ril = worker.RIL;
let buf = worker.Buf;
let io = worker.ICCIOHelper;
function buildSST(supportedEf) {
let sst = [];
let len = supportedEf.length;
for (let i = 0; i < len; i++) {
let index, bitmask, iccService;
if (ril.appType === CARD_APPTYPE_SIM) {
iccService = GECKO_ICC_SERVICES.sim[supportedEf[i]];
iccService -= 1;
index = Math.floor(iccService / 4);
bitmask = 2 << ((iccService % 4) << 1);
} else if (ril.appType === CARD_APPTYPE_USIM){
iccService = GECKO_ICC_SERVICES.usim[supportedEf[i]];
iccService -= 1;
index = Math.floor(iccService / 8);
bitmask = 1 << ((iccService % 8) << 0);
}
if (sst) {
sst[index] |= bitmask;
}
}
return sst;
}
ril.updateCellBroadcastConfig = function fakeUpdateCellBroadcastConfig() {
// Ignore updateCellBroadcastConfig after reading SST
};
function do_test(sst, supportedEf) {
// Clone supportedEf to local array for testing
let testEf = supportedEf.slice(0);
record.readMSISDN = function fakeReadMSISDN() {
testEf.splice(testEf.indexOf("MSISDN"), 1);
};
record.readMBDN = function fakeReadMBDN() {
testEf.splice(testEf.indexOf("MDN"), 1);
};
io.loadTransparentEF = function fakeLoadTransparentEF(options) {
// Write data size
buf.writeInt32(sst.length * 2);
// Write data
for (let i = 0; i < sst.length; i++) {
gsmPdu.writeHexOctet(sst[i] || 0);
}
// Write string delimiter
buf.writeStringDelimiter(sst.length * 2);
if (options.callback) {
options.callback(options);
}
if (testEf.length !== 0) {
do_print("Un-handled EF: " + JSON.stringify(testEf));
do_check_true(false);
}
};
record.readSST();
}
// TODO: Add all necessary optional EFs eventually
let supportedEf = ["MSISDN", "MDN"];
ril.appType = CARD_APPTYPE_SIM;
do_test(buildSST(supportedEf), supportedEf);
ril.appType = CARD_APPTYPE_USIM;
do_test(buildSST(supportedEf), supportedEf);
run_next_test();
});

View File

@ -198,7 +198,13 @@ ContainerRender(ContainerT* aContainer,
continue;
}
layerToRender->RenderLayer(childOffset, clipRect);
if (layerToRender->HasLayerBeenComposited()) {
// Composer2D will compose this layer so skip GPU composition
// this time & reset composition flag for next composition phase
layerToRender->SetLayerComposited(false);
} else {
layerToRender->RenderLayer(childOffset, clipRect);
}
// invariant: our GL context should be current here, I don't think we can
// assert it though
}

View File

@ -726,6 +726,7 @@ LayerComposite::LayerComposite(LayerManagerComposite *aManager)
, mUseShadowClipRect(false)
, mShadowTransformSetByAnimation(false)
, mDestroyed(false)
, mLayerComposited(false)
{ }
LayerComposite::~LayerComposite()

View File

@ -381,12 +381,18 @@ public:
mShadowTransformSetByAnimation = aSetByAnimation;
}
void SetLayerComposited(bool value)
{
mLayerComposited = value;
}
// These getters can be used anytime.
float GetShadowOpacity() { return mShadowOpacity; }
const nsIntRect* GetShadowClipRect() { return mUseShadowClipRect ? &mShadowClipRect : nullptr; }
const nsIntRegion& GetShadowVisibleRegion() { return mShadowVisibleRegion; }
const gfx3DMatrix& GetShadowTransform() { return mShadowTransform; }
bool GetShadowTransformSetByAnimation() { return mShadowTransformSetByAnimation; }
bool HasLayerBeenComposited() { return mLayerComposited; }
protected:
gfx3DMatrix mShadowTransform;
@ -398,6 +404,7 @@ protected:
bool mUseShadowClipRect;
bool mShadowTransformSetByAnimation;
bool mDestroyed;
bool mLayerComposited;
};

View File

@ -635,6 +635,7 @@ RES_DRAWABLE_MDPI = \
res/drawable-mdpi/ic_url_bar_search.png \
res/drawable-mdpi/ic_url_bar_star.png \
res/drawable-mdpi/ic_url_bar_tab.png \
res/drawable-mdpi/icon_bookmarks_empty.png \
res/drawable-mdpi/icon_last_tabs.png \
res/drawable-mdpi/icon_last_tabs_empty.png \
res/drawable-mdpi/icon_most_recent.png \
@ -752,6 +753,7 @@ RES_DRAWABLE_HDPI = \
res/drawable-hdpi/ic_url_bar_search.png \
res/drawable-hdpi/ic_url_bar_star.png \
res/drawable-hdpi/ic_url_bar_tab.png \
res/drawable-hdpi/icon_bookmarks_empty.png \
res/drawable-hdpi/icon_last_tabs.png \
res/drawable-hdpi/icon_last_tabs_empty.png \
res/drawable-hdpi/icon_most_recent.png \
@ -855,6 +857,7 @@ RES_DRAWABLE_XHDPI = \
res/drawable-xhdpi/ic_url_bar_search.png \
res/drawable-xhdpi/ic_url_bar_star.png \
res/drawable-xhdpi/ic_url_bar_tab.png \
res/drawable-xhdpi/icon_bookmarks_empty.png \
res/drawable-xhdpi/icon_last_tabs.png \
res/drawable-xhdpi/icon_last_tabs_empty.png \
res/drawable-xhdpi/icon_most_recent.png \

View File

@ -20,7 +20,10 @@ import android.support.v4.app.LoaderManager.LoaderCallbacks;
import android.support.v4.content.Loader;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewStub;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
/**
* A page in about:home that displays a ListView of bookmarks.
@ -40,6 +43,9 @@ public class BookmarksPage extends HomeFragment {
// Adapter for list of bookmarks.
private BookmarksListAdapter mListAdapter;
// Reference to the View to display when there are no results.
private View mEmptyView;
// Callback for cursor loaders.
private CursorLoaderCallbacks mLoaderCallbacks;
@ -102,6 +108,7 @@ public class BookmarksPage extends HomeFragment {
public void onDestroyView() {
mList = null;
mListAdapter = null;
mEmptyView = null;
super.onDestroyView();
}
@ -130,6 +137,22 @@ public class BookmarksPage extends HomeFragment {
getLoaderManager().initLoader(LOADER_ID_BOOKMARKS_LIST, null, mLoaderCallbacks);
}
private void updateUiFromCursor(Cursor c) {
if ((c == null || c.getCount() == 0) && mEmptyView == null) {
// Set empty page view. We delay this so that the empty view won't flash.
final ViewStub emptyViewStub = (ViewStub) getView().findViewById(R.id.home_empty_view_stub);
mEmptyView = emptyViewStub.inflate();
final ImageView emptyIcon = (ImageView) mEmptyView.findViewById(R.id.home_empty_image);
emptyIcon.setImageResource(R.drawable.icon_bookmarks_empty);
final TextView emptyText = (TextView) mEmptyView.findViewById(R.id.home_empty_text);
emptyText.setText(R.string.home_bookmarks_empty);
mList.setEmptyView(mEmptyView);
}
}
/**
* Loader for the list for bookmarks.
*/
@ -167,6 +190,7 @@ public class BookmarksPage extends HomeFragment {
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor c) {
mListAdapter.swapCursor(c);
updateUiFromCursor(c);
}
@Override

View File

@ -140,7 +140,13 @@ public class BrowserSearch extends HomeFragment
}
public static BrowserSearch newInstance() {
return new BrowserSearch();
BrowserSearch browserSearch = new BrowserSearch();
final Bundle args = new Bundle();
args.putBoolean(HomePager.CAN_LOAD_ARG, true);
browserSearch.setArguments(args);
return browserSearch;
}
public BrowserSearch() {
@ -282,7 +288,7 @@ public class BrowserSearch extends HomeFragment
registerForContextMenu(mList);
registerEventListener("SearchEngines:Data");
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("SearchEngines:Get", null));
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("SearchEngines:GetVisible", null));
}
@Override
@ -315,7 +321,7 @@ public class BrowserSearch extends HomeFragment
@Override
protected void load() {
getLoaderManager().initLoader(LOADER_ID_SEARCH, null, mCursorLoaderCallbacks);
SearchLoader.init(getLoaderManager(), LOADER_ID_SEARCH, mCursorLoaderCallbacks, mSearchTerm);
}
private void handleAutocomplete(String searchTerm, Cursor c) {
@ -606,7 +612,7 @@ public class BrowserSearch extends HomeFragment
mAdapter.notifyDataSetChanged();
// Restart loaders with the new search term
SearchLoader.restart(getLoaderManager(), LOADER_ID_SEARCH, mCursorLoaderCallbacks, mSearchTerm, false);
SearchLoader.restart(getLoaderManager(), LOADER_ID_SEARCH, mCursorLoaderCallbacks, mSearchTerm);
filterSuggestions();
}
}

View File

@ -246,7 +246,7 @@ public class LastTabsPage extends HomeFragment {
private static class LastTabsAdapter extends CursorAdapter {
public LastTabsAdapter(Context context) {
super(context, null);
super(context, null, 0);
}
@Override

View File

@ -25,7 +25,7 @@ abstract class MultiTypeCursorAdapter extends CursorAdapter {
abstract public void bindView(View view, Context context, int position);
public MultiTypeCursorAdapter(Context context, Cursor cursor, int[] viewTypes, int[] layouts) {
super(context, cursor);
super(context, cursor, 0);
if (viewTypes.length != layouts.length) {
throw new IllegalStateException("The view types and the layouts should be of same size");

View File

@ -178,7 +178,7 @@ class PinSiteDialog extends DialogFragment {
private LayoutInflater mInflater;
public SearchAdapter(Context context) {
super(context, null);
super(context, null, 0);
mInflater = LayoutInflater.from(context);
}

View File

@ -198,7 +198,7 @@ public class ReadingListPage extends HomeFragment {
*/
private class ReadingListAdapter extends CursorAdapter {
public ReadingListAdapter(Context context, Cursor cursor) {
super(context, cursor);
super(context, cursor, 0);
}
@Override

View File

@ -22,33 +22,35 @@ class SearchLoader {
// Key for search terms
private static final String KEY_SEARCH_TERM = "search_term";
// Key for performing empty search
private static final String KEY_PERFORM_EMPTY_SEARCH = "perform_empty_search";
private SearchLoader() {
}
public static Loader<Cursor> createInstance(Context context, Bundle args) {
if (args != null) {
final String searchTerm = args.getString(KEY_SEARCH_TERM);
final boolean performEmptySearch = args.getBoolean(KEY_PERFORM_EMPTY_SEARCH, false);
return new SearchCursorLoader(context, searchTerm, performEmptySearch);
return new SearchCursorLoader(context, searchTerm);
} else {
return new SearchCursorLoader(context, "", false);
return new SearchCursorLoader(context, "");
}
}
private static Bundle createArgs(String searchTerm) {
Bundle args = new Bundle();
args.putString(SearchLoader.KEY_SEARCH_TERM, searchTerm);
return args;
}
public static void init(LoaderManager manager, int loaderId,
LoaderCallbacks<Cursor> callbacks, String searchTerm) {
final Bundle args = createArgs(searchTerm);
manager.initLoader(loaderId, args, callbacks);
}
public static void restart(LoaderManager manager, int loaderId,
LoaderCallbacks<Cursor> callbacks, String searchTerm) {
restart(manager, loaderId, callbacks, searchTerm, true);
}
public static void restart(LoaderManager manager, int loaderId,
LoaderCallbacks<Cursor> callbacks, String searchTerm, boolean performEmptySearch) {
Bundle bundle = new Bundle();
bundle.putString(SearchLoader.KEY_SEARCH_TERM, searchTerm);
bundle.putBoolean(SearchLoader.KEY_PERFORM_EMPTY_SEARCH, performEmptySearch);
manager.restartLoader(loaderId, bundle, callbacks);
final Bundle args = createArgs(searchTerm);
manager.restartLoader(loaderId, args, callbacks);
}
public static class SearchCursorLoader extends SimpleCursorLoader {
@ -58,21 +60,13 @@ class SearchLoader {
// The target search term associated with the loader
private final String mSearchTerm;
// An empty search on the DB
private final boolean mPerformEmptySearch;
public SearchCursorLoader(Context context, String searchTerm, boolean performEmptySearch) {
public SearchCursorLoader(Context context, String searchTerm) {
super(context);
mSearchTerm = searchTerm;
mPerformEmptySearch = performEmptySearch;
}
@Override
public Cursor loadCursor() {
if (!mPerformEmptySearch && TextUtils.isEmpty(mSearchTerm)) {
return null;
}
return BrowserDB.filter(getContext().getContentResolver(), mSearchTerm, SEARCH_LIMIT);
}

View File

@ -15,6 +15,7 @@ import org.mozilla.gecko.util.StringUtils;
import android.content.Context;
import android.content.res.TypedArray;
import android.database.Cursor;
import android.graphics.Rect;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.ContextMenu.ContextMenuInfo;
@ -32,9 +33,9 @@ import java.util.EnumSet;
public class TopSitesGridView extends GridView {
private static final String LOGTAG = "GeckoTopSitesGridView";
// Listener for pinning sites.
public static interface OnPinSiteListener {
public void onPinSite(int position);
// Listener for editing pinned sites.
public static interface OnEditPinnedSiteListener {
public void onEditPinnedSite(int position);
}
// Max number of top sites that needs to be shown.
@ -58,12 +59,17 @@ public class TopSitesGridView extends GridView {
// On URL open listener.
private OnUrlOpenListener mUrlOpenListener;
// Pin site listener.
private OnPinSiteListener mPinSiteListener;
// Edit pinned site listener.
private OnEditPinnedSiteListener mEditPinnedSiteListener;
// Context menu info.
private TopSitesGridContextMenuInfo mContextMenuInfo;
// Whether we're handling focus changes or not. This is used
// to avoid infinite re-layouts when using this GridView as
// a ListView header view (see bug 918044).
private boolean mIsHandlingFocusChange;
public TopSitesGridView(Context context) {
this(context, null);
}
@ -82,6 +88,8 @@ public class TopSitesGridView extends GridView {
mHorizontalSpacing = a.getDimensionPixelOffset(R.styleable.TopSitesGridView_android_horizontalSpacing, 0x00);
mVerticalSpacing = a.getDimensionPixelOffset(R.styleable.TopSitesGridView_android_verticalSpacing, 0x00);
a.recycle();
mIsHandlingFocusChange = false;
}
/**
@ -106,8 +114,8 @@ public class TopSitesGridView extends GridView {
mUrlOpenListener.onUrlOpen(url, EnumSet.noneOf(OnUrlOpenListener.Flags.class));
}
} else {
if (mPinSiteListener != null) {
mPinSiteListener.onPinSite(position);
if (mEditPinnedSiteListener != null) {
mEditPinnedSiteListener.onEditPinnedSite(position);
}
}
}
@ -128,7 +136,21 @@ public class TopSitesGridView extends GridView {
super.onDetachedFromWindow();
mUrlOpenListener = null;
mPinSiteListener = null;
mEditPinnedSiteListener = null;
}
@Override
protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) {
mIsHandlingFocusChange = true;
super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
mIsHandlingFocusChange = false;
}
@Override
public void requestLayout() {
if (!mIsHandlingFocusChange) {
super.requestLayout();
}
}
/**
@ -207,12 +229,12 @@ public class TopSitesGridView extends GridView {
}
/**
* Set a pin site listener to be used by this view.
* Set an edit pinned site listener to be used by this view.
*
* @param listener A pin site listener for this view.
* @param listener An edit pinned site listener for this view.
*/
public void setOnPinSiteListener(OnPinSiteListener listener) {
mPinSiteListener = listener;
public void setOnEditPinnedSiteListener(final OnEditPinnedSiteListener listener) {
mEditPinnedSiteListener = listener;
}
/**

View File

@ -20,7 +20,7 @@ import org.mozilla.gecko.gfx.BitmapUtils;
import org.mozilla.gecko.home.HomeListView.HomeContextMenuInfo;
import org.mozilla.gecko.home.HomePager.OnUrlOpenListener;
import org.mozilla.gecko.home.PinSiteDialog.OnSiteSelectedListener;
import org.mozilla.gecko.home.TopSitesGridView.OnPinSiteListener;
import org.mozilla.gecko.home.TopSitesGridView.OnEditPinnedSiteListener;
import org.mozilla.gecko.home.TopSitesGridView.TopSitesGridContextMenuInfo;
import org.mozilla.gecko.util.ThreadUtils;
@ -100,8 +100,8 @@ public class TopSitesPage extends HomeFragment {
// Callback for thumbnail loader
private ThumbnailsLoaderCallbacks mThumbnailsLoaderCallbacks;
// Listener for pinning sites
private PinSiteListener mPinSiteListener;
// Listener for editing pinned sites.
private EditPinnedSiteListener mEditPinnedSiteListener;
// On URL open listener
private OnUrlOpenListener mUrlOpenListener;
@ -155,7 +155,7 @@ public class TopSitesPage extends HomeFragment {
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
mPinSiteListener = new PinSiteListener();
mEditPinnedSiteListener = new EditPinnedSiteListener();
mList.setTag(HomePager.LIST_TAG_TOP_SITES);
mList.setHeaderDividersEnabled(false);
@ -186,7 +186,7 @@ public class TopSitesPage extends HomeFragment {
});
mGrid.setOnUrlOpenListener(mUrlOpenListener);
mGrid.setOnPinSiteListener(mPinSiteListener);
mGrid.setOnEditPinnedSiteListener(mEditPinnedSiteListener);
registerForContextMenu(mList);
registerForContextMenu(mGrid);
@ -338,7 +338,7 @@ public class TopSitesPage extends HomeFragment {
}
if (itemId == R.id.top_sites_edit) {
mPinSiteListener.onPinSite(info.position);
mEditPinnedSiteListener.onEditPinnedSite(info.position);
return true;
}
@ -371,10 +371,10 @@ public class TopSitesPage extends HomeFragment {
}
/**
* Listener for pinning sites.
* Listener for editing pinned sites.
*/
private class PinSiteListener implements OnPinSiteListener,
OnSiteSelectedListener {
private class EditPinnedSiteListener implements OnEditPinnedSiteListener,
OnSiteSelectedListener {
// Tag for the PinSiteDialog fragment.
private static final String TAG_PIN_SITE = "pin_site";
@ -382,7 +382,7 @@ public class TopSitesPage extends HomeFragment {
private int mPosition;
@Override
public void onPinSite(int position) {
public void onEditPinnedSite(int position) {
mPosition = position;
final FragmentManager manager = getActivity().getSupportFragmentManager();
@ -485,7 +485,7 @@ public class TopSitesPage extends HomeFragment {
private class VisitedAdapter extends CursorAdapter {
public VisitedAdapter(Context context, Cursor cursor) {
super(context, cursor);
super(context, cursor, 0);
}
@Override
@ -518,7 +518,7 @@ public class TopSitesPage extends HomeFragment {
private Map<String, Bitmap> mThumbnails;
public TopSitesGridAdapter(Context context, Cursor cursor) {
super(context, cursor);
super(context, cursor, 0);
}
@Override

View File

@ -275,6 +275,7 @@ size. -->
<!ENTITY home_top_sites_add "Add a site">
<!ENTITY home_history_title "History">
<!ENTITY home_bookmarks_empty "Bookmarks you save show up here.">
<!ENTITY home_last_tabs_title "Tabs from last time">
<!ENTITY home_last_tabs_open "Open all tabs from last time">
<!ENTITY home_last_tabs_empty "Your recent tabs show up here.">

View File

@ -141,7 +141,8 @@ public class SearchEnginePreference extends Preference implements View.OnLongCli
}
/**
* Set if this object's UI should show that this is the default engine.
* Set if this object's UI should show that this is the default engine. To ensure proper ordering,
* this method should only be called after this Preference is added to the PreferenceCategory.
* @param isDefault Flag indicating if this represents the default engine.
*/
public void setIsDefaultEngine(boolean isDefault) {
@ -206,7 +207,9 @@ public class SearchEnginePreference extends Preference implements View.OnLongCli
if (mPromptIcon == null && mIconBitmap != null) {
mPromptIcon = new BitmapDrawable(mFaviconView.getBitmap());
}
builder.setIcon(mPromptIcon);
// Icons are hidden until Bug 926711 is fixed.
//builder.setIcon(mPromptIcon);
// We have to construct the dialog itself on the UI thread.
ThreadUtils.postToUiThread(new Runnable() {

View File

@ -41,7 +41,7 @@ public class SearchPreferenceCategory extends PreferenceCategory implements Geck
super.onAttachedToActivity();
// Ensures default engine remains at top of list.
setOrderingAsAdded(false);
setOrderingAsAdded(true);
// Request list of search engines from Gecko.
GeckoAppShell.registerEventListener("SearchEngines:Data", this);
@ -51,17 +51,14 @@ public class SearchPreferenceCategory extends PreferenceCategory implements Geck
@Override
public void handleMessage(String event, final JSONObject data) {
if (event.equals("SearchEngines:Data")) {
// Parse engines array from JSON. The first element in the array is the default engine.
// We are no longer interested in this event from Gecko, as we do not request it again with
// this instance.
GeckoAppShell.unregisterEventListener("SearchEngines:Data", this);
// Parse engines array from JSON.
JSONArray engines;
JSONObject defaultEngine;
final String defaultEngineName;
try {
engines = data.getJSONArray("searchEngines");
if (engines.length() == 0) {
return;
}
defaultEngine = engines.getJSONObject(0);
defaultEngineName = defaultEngine.getString("name");
} catch (JSONException e) {
Log.e(LOGTAG, "Unable to decode search engine data from Gecko.", e);
return;
@ -75,14 +72,6 @@ public class SearchPreferenceCategory extends PreferenceCategory implements Geck
SearchEnginePreference enginePreference = new SearchEnginePreference(getContext(), this);
enginePreference.setSearchEngineFromJSON(engineJSON);
if (engineName.equals(defaultEngineName)) {
// We set this here, not in setSearchEngineFromJSON, because it allows us to
// keep a reference to the default engine to use when the AlertDialog
// callbacks are used.
enginePreference.setIsDefaultEngine(true);
mDefaultEngineReference = enginePreference;
}
enginePreference.setOnPreferenceClickListener(new OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
@ -94,15 +83,20 @@ public class SearchPreferenceCategory extends PreferenceCategory implements Geck
});
addPreference(enginePreference);
// The first element in the array is the default engine.
if (i == 0) {
// We set this here, not in setSearchEngineFromJSON, because it allows us to
// keep a reference to the default engine to use when the AlertDialog
// callbacks are used.
enginePreference.setIsDefaultEngine(true);
mDefaultEngineReference = enginePreference;
}
} catch (JSONException e) {
Log.e(LOGTAG, "JSONException parsing engine at index " + i, e);
}
}
}
// We are no longer interested in this event from Gecko, as we do not request it again with
// this instance.
GeckoAppShell.unregisterEventListener("SearchEngines:Data", this);
}
/**

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 997 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -7,6 +7,11 @@
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<ViewStub android:id="@+id/home_empty_view_stub"
android:layout="@layout/home_empty_page"
android:layout_width="fill_parent"
android:layout_height="fill_parent"/>
<org.mozilla.gecko.home.BookmarksListView
android:id="@+id/bookmarks_list"
android:layout_width="fill_parent"

View File

@ -257,6 +257,7 @@
<string name="home_top_sites_title">&home_top_sites_title;</string>
<string name="home_top_sites_add">&home_top_sites_add;</string>
<string name="home_history_title">&home_history_title;</string>
<string name="home_bookmarks_empty">&home_bookmarks_empty;</string>
<string name="home_last_tabs_title">&home_last_tabs_title;</string>
<string name="home_last_tabs_open">&home_last_tabs_open;</string>
<string name="home_last_tabs_empty">&home_last_tabs_empty;</string>

View File

@ -98,7 +98,7 @@ PromiseWorker.prototype = {
* @param {Error} error Some JS error.
*/
worker.onerror = function onerror(error) {
self._log("Received uncaught error from worker", error.message);
self._log("Received uncaught error from worker", error.message, error.filename, error.lineno);
error.preventDefault();
let {deferred} = self._queue.pop();
deferred.reject(error);

View File

@ -29,24 +29,21 @@ Cu.import("resource://gre/modules/osfile/osfile_shared_allthreads.jsm", SharedAl
Cu.import("resource://gre/modules/Deprecated.jsm", this);
// Boilerplate, to simplify the transition to require()
let OS = SharedAll.OS;
let LOG = OS.Shared.LOG.bind(OS.Shared, "Controller");
let isTypedArray = OS.Shared.isTypedArray;
let LOG = SharedAll.LOG.bind(SharedAll, "Controller");
let isTypedArray = SharedAll.isTypedArray;
// The constructor for file errors.
let OSError;
if (OS.Constants.Win) {
Cu.import("resource://gre/modules/osfile/osfile_win_allthreads.jsm", this);
OSError = OS.Shared.Win.Error;
} else if (OS.Constants.libc) {
Cu.import("resource://gre/modules/osfile/osfile_unix_allthreads.jsm", this);
OSError = OS.Shared.Unix.Error;
let SysAll = {};
if (SharedAll.Constants.Win) {
Cu.import("resource://gre/modules/osfile/osfile_win_allthreads.jsm", SysAll);
} else if (SharedAll.Constants.libc) {
Cu.import("resource://gre/modules/osfile/osfile_unix_allthreads.jsm", SysAll);
} else {
throw new Error("I am neither under Windows nor under a Posix system");
}
let Type = OS.Shared.Type;
let OSError = SysAll.Error;
let Type = SysAll.Type;
let Path = {};
Cu.import("resource://gre/modules/osfile/ospath.jsm", Path);
@ -60,18 +57,16 @@ Cu.import("resource://gre/modules/Services.jsm", this);
Cu.import("resource://gre/modules/AsyncShutdown.jsm", this);
LOG("Checking profileDir", OS.Constants.Path);
// If profileDir is not available, osfile.jsm has been imported before the
// profile is setup. In this case, make this a lazy getter.
if (!("profileDir" in OS.Constants.Path)) {
Object.defineProperty(OS.Constants.Path, "profileDir", {
if (!("profileDir" in SharedAll.Constants.Path)) {
Object.defineProperty(SharedAll.Constants.Path, "profileDir", {
get: function() {
let path = undefined;
try {
path = Services.dirsvc.get("ProfD", Ci.nsIFile).path;
delete OS.Constants.Path.profileDir;
OS.Constants.Path.profileDir = path;
delete SharedAll.Constants.Path.profileDir;
SharedAll.Constants.Path.profileDir = path;
} catch (ex) {
// Ignore errors: profileDir is still not available
}
@ -82,14 +77,14 @@ if (!("profileDir" in OS.Constants.Path)) {
LOG("Checking localProfileDir");
if (!("localProfileDir" in OS.Constants.Path)) {
Object.defineProperty(OS.Constants.Path, "localProfileDir", {
if (!("localProfileDir" in SharedAll.Constants.Path)) {
Object.defineProperty(SharedAll.Constants.Path, "localProfileDir", {
get: function() {
let path = undefined;
try {
path = Services.dirsvc.get("ProfLD", Ci.nsIFile).path;
delete OS.Constants.Path.localProfileDir;
OS.Constants.Path.localProfileDir = path;
delete SharedAll.Constants.Path.localProfileDir;
SharedAll.Constants.Path.localProfileDir = path;
} catch (ex) {
// Ignore errors: localProfileDir is still not available
}
@ -123,7 +118,7 @@ let Scheduler = {
latestPromise: Promise.resolve("OS.File scheduler hasn't been launched yet"),
post: function post(...args) {
if (!this.launched && OS.Shared.DEBUG) {
if (!this.launched && SharedAll.Config.DEBUG) {
// If we have delayed sending SET_DEBUG, do it now.
worker.post("SET_DEBUG", [true]);
}
@ -212,23 +207,23 @@ let readDebugPref = function readDebugPref(prefName, oldPref = false) {
*/
Services.prefs.addObserver(PREF_OSFILE_LOG,
function prefObserver(aSubject, aTopic, aData) {
OS.Shared.DEBUG = readDebugPref(PREF_OSFILE_LOG, OS.Shared.DEBUG);
SharedAll.Config.DEBUG = readDebugPref(PREF_OSFILE_LOG, SharedAll.Config.DEBUG);
if (Scheduler.launched) {
// Don't start the worker just to set this preference.
Scheduler.post("SET_DEBUG", [OS.Shared.DEBUG]);
Scheduler.post("SET_DEBUG", [SharedAll.Config.DEBUG]);
}
}, false);
OS.Shared.DEBUG = readDebugPref(PREF_OSFILE_LOG, false);
SharedAll.Config.DEBUG = readDebugPref(PREF_OSFILE_LOG, false);
Services.prefs.addObserver(PREF_OSFILE_LOG_REDIRECT,
function prefObserver(aSubject, aTopic, aData) {
OS.Shared.TEST = readDebugPref(PREF_OSFILE_LOG_REDIRECT, OS.Shared.TEST);
SharedAll.Config.TEST = readDebugPref(PREF_OSFILE_LOG_REDIRECT, OS.Shared.TEST);
}, false);
OS.Shared.TEST = readDebugPref(PREF_OSFILE_LOG_REDIRECT, false);
SharedAll.Config.TEST = readDebugPref(PREF_OSFILE_LOG_REDIRECT, false);
// Update worker's DEBUG flag if it's true.
// Don't start the worker just for this, though.
if (OS.Shared.DEBUG && Scheduler.launched) {
if (SharedAll.Config.DEBUG && Scheduler.launched) {
Scheduler.post("SET_DEBUG", [true]);
}
@ -507,6 +502,35 @@ File.open = function open(path, mode, options) {
);
};
/**
* Creates and opens a file with a unique name. By default, generate a random HEX number and use it to create a unique new file name.
*
* @param {string} path The path to the file.
* @param {*=} options Additional options for file opening. This
* implementation interprets the following fields:
*
* - {number} humanReadable If |true|, create a new filename appending a decimal number. ie: filename-1.ext, filename-2.ext.
* If |false| use HEX numbers ie: filename-A65BC0.ext
* - {number} maxReadableNumber Used to limit the amount of tries after a failed
* file creation. Default is 20.
*
* @return {Object} contains A file object{file} and the path{path}.
* @throws {OS.File.Error} If the file could not be opened.
*/
File.openUnique = function openUnique(path, options) {
return Scheduler.post(
"openUnique", [Type.path.toMsg(path), options],
path
).then(
function onSuccess(msg) {
return {
path: msg.path,
file: new File(msg.file)
};
}
);
};
/**
* Get the information on the file.
*
@ -769,13 +793,7 @@ File.Info = function Info(value) {
}
Object.defineProperty(this, "_deprecatedCreationDate", {value: value["creationDate"]});
};
if (OS.Constants.Win) {
File.Info.prototype = Object.create(OS.Shared.Win.AbstractInfo.prototype);
} else if (OS.Constants.libc) {
File.Info.prototype = Object.create(OS.Shared.Unix.AbstractInfo.prototype);
} else {
throw new Error("I am neither under Windows nor under a Posix system");
}
File.Info.prototype = SysAll.AbstractInfo.prototype;
// Deprecated
Object.defineProperty(File.Info.prototype, "creationDate", {
@ -971,26 +989,35 @@ DirectoryIterator.prototype = {
DirectoryIterator.Entry = function Entry(value) {
return value;
};
if (OS.Constants.Win) {
DirectoryIterator.Entry.prototype = Object.create(OS.Shared.Win.AbstractEntry.prototype);
} else if (OS.Constants.libc) {
DirectoryIterator.Entry.prototype = Object.create(OS.Shared.Unix.AbstractEntry.prototype);
} else {
throw new Error("I am neither under Windows nor under a Posix system");
}
DirectoryIterator.Entry.prototype = Object.create(SysAll.AbstractEntry.prototype);
DirectoryIterator.Entry.fromMsg = function fromMsg(value) {
return new DirectoryIterator.Entry(value);
};
// Constants
Object.defineProperty(File, "POS_START", {value: OS.Shared.POS_START});
Object.defineProperty(File, "POS_CURRENT", {value: OS.Shared.POS_CURRENT});
Object.defineProperty(File, "POS_END", {value: OS.Shared.POS_END});
File.POS_START = SysAll.POS_START;
File.POS_CURRENT = SysAll.POS_CURRENT;
File.POS_END = SysAll.POS_END;
// Exports
File.Error = OSError;
File.DirectoryIterator = DirectoryIterator;
this.OS = {};
OS.File = File;
OS.File.Error = OSError;
OS.File.DirectoryIterator = DirectoryIterator;
OS.Constants = SharedAll.Constants;
OS.Shared = {
LOG: SharedAll.LOG,
Type: SysAll.Type,
get DEBUG() {
return SharedAll.Config.DEBUG;
},
set DEBUG(x) {
return SharedAll.Config.DEBUG = x;
}
};
Object.freeze(OS.Shared);
OS.Path = Path;

View File

@ -14,7 +14,8 @@ if (this.Components) {
importScripts("resource://gre/modules/osfile.jsm");
let LOG = exports.OS.Shared.LOG.bind(exports.OS.Shared.LOG, "Agent");
let SharedAll = require("resource://gre/modules/osfile/osfile_shared_allthreads.jsm");
let LOG = SharedAll.LOG.bind(SharedAll, "Agent");
/**
* Communications with the controller.
@ -216,12 +217,12 @@ if (this.Components) {
let Agent = {
// Update worker's OS.Shared.DEBUG flag message from controller.
SET_DEBUG: function SET_DEBUG (aDEBUG) {
exports.OS.Shared.DEBUG = aDEBUG;
SharedAll.Config.DEBUG = aDEBUG;
},
// Return worker's current OS.Shared.DEBUG value to controller.
// Note: This is used for testing purposes.
GET_DEBUG: function GET_DEBUG () {
return exports.OS.Shared.DEBUG;
return SharedAll.Config.DEBUG;
},
// Report file descriptors leaks.
System_shutdown: function System_shutdown () {
@ -270,6 +271,20 @@ if (this.Components) {
path: filePath
});
},
openUnique: function openUnique(path, options) {
let filePath = Type.path.fromMsg(path);
let openedFile = OS.Shared.AbstractFile.openUnique(filePath, options);
let resourceId = OpenedFiles.add(openedFile.file, {
// Adding path information to keep track of opened files
// to report leaks when debugging.
path: openedFile.path
});
return {
path: openedFile.path,
file: resourceId
};
},
read: function read(path, bytes, options) {
let data = File.read(Type.path.fromMsg(path), bytes, options);
return new Transfer({buffer: data.buffer, byteOffset: data.byteOffset, byteLength: data.byteLength}, [data.buffer]);

View File

@ -1026,11 +1026,6 @@ exports.OS = {
offsetBy: offsetBy
}
};
if (exports.Constants.Win) {
exports.OS.Win = {};
} else {
exports.OS.Unix = {};
}
Object.defineProperty(exports.OS.Shared, "DEBUG", {
get: function() {

View File

@ -14,10 +14,11 @@ if (typeof Components != "undefined") {
}
(function(exports) {
exports.OS = require("resource://gre/modules/osfile/osfile_shared_allthreads.jsm").OS;
let SharedAll =
require("resource://gre/modules/osfile/osfile_shared_allthreads.jsm");
let LOG = exports.OS.Shared.LOG.bind(OS.Shared, "Shared front-end");
let clone = exports.OS.Shared.clone;
let LOG = SharedAll.LOG.bind(SharedAll, "Shared front-end");
let clone = SharedAll.clone;
/**
* Code shared by implementations of File.
@ -89,7 +90,7 @@ AbstractFile.prototype = {
break;
}
pos += chunkSize;
ptr = exports.OS.Shared.offsetBy(ptr, chunkSize);
ptr = SharedAll.offsetBy(ptr, chunkSize);
}
return pos;
@ -121,12 +122,70 @@ AbstractFile.prototype = {
while (pos < bytes) {
let chunkSize = this._write(ptr, bytes - pos, options);
pos += chunkSize;
ptr = exports.OS.Shared.offsetBy(ptr, chunkSize);
ptr = SharedAll.offsetBy(ptr, chunkSize);
}
return pos;
}
};
/**
* Creates and opens a file with a unique name. By default, generate a random HEX number and use it to create a unique new file name.
*
* @param {string} path The path to the file.
* @param {*=} options Additional options for file opening. This
* implementation interprets the following fields:
*
* - {number} humanReadable If |true|, create a new filename appending a decimal number. ie: filename-1.ext, filename-2.ext.
* If |false| use HEX numbers ie: filename-A65BC0.ext
* - {number} maxReadableNumber Used to limit the amount of tries after a failed
* file creation. Default is 20.
*
* @return {Object} contains A file object{file} and the path{path}.
* @throws {OS.File.Error} If the file could not be opened.
*/
AbstractFile.openUnique = function openUnique(path, options = {}) {
let mode = {
create : true
};
let dirName = OS.Path.dirname(path);
let leafName = OS.Path.basename(path);
let lastDotCharacter = leafName.lastIndexOf('.');
let fileName = leafName.substring(0, lastDotCharacter != -1 ? lastDotCharacter : leafName.length);
let suffix = (lastDotCharacter != -1 ? leafName.substring(lastDotCharacter) : "");
let uniquePath = "";
let maxAttempts = options.maxAttempts || 99;
let humanReadable = !!options.humanReadable;
const HEX_RADIX = 16;
// We produce HEX numbers between 0 and 2^24 - 1.
const MAX_HEX_NUMBER = 16777215;
try {
return {
path: path,
file: OS.File.open(path, mode)
};
} catch (ex if ex instanceof OS.File.Error && ex.becauseExists) {
for (let i = 0; i < maxAttempts; ++i) {
try {
if (humanReadable) {
uniquePath = OS.Path.join(dirName, fileName + "-" + (i + 1) + suffix);
} else {
let hexNumber = Math.floor(Math.random() * MAX_HEX_NUMBER).toString(HEX_RADIX);
uniquePath = OS.Path.join(dirName, fileName + "-" + hexNumber + suffix);
}
return {
path: uniquePath,
file: OS.File.open(uniquePath, mode)
};
} catch (ex if ex instanceof OS.File.Error && ex.becauseExists) {
// keep trying ...
}
}
throw OS.File.Error.exists("could not find an unused file name.");
}
};
/**
* Utility function used to normalize a Typed Array or C
* pointer into a uint8_t C pointer.
@ -150,13 +209,13 @@ AbstractFile.normalizeToPointer = function normalizeToPointer(candidate, bytes)
if (candidate.isNull()) {
throw new TypeError("Expecting a non-null pointer");
}
ptr = exports.OS.Shared.Type.uint8_t.out_ptr.cast(candidate);
ptr = SharedAll.Type.uint8_t.out_ptr.cast(candidate);
if (bytes == null) {
throw new TypeError("C pointer missing bytes indication.");
}
} else if (exports.OS.Shared.isTypedArray(candidate)) {
} else if (SharedAll.isTypedArray(candidate)) {
// Typed Array
ptr = exports.OS.Shared.Type.uint8_t.out_ptr.implementation(candidate.buffer);
ptr = SharedAll.Type.uint8_t.out_ptr.implementation(candidate.buffer);
if (bytes == null) {
bytes = candidate.byteLength;
} else if (candidate.byteLength < bytes) {
@ -430,5 +489,8 @@ AbstractFile.removeDir = function(path, options = {}) {
OS.File.removeEmptyDir(path);
};
exports.OS.Shared.AbstractFile = AbstractFile;
if (!exports.OS.Shared) {
exports.OS.Shared = {};
}
exports.OS.Shared.AbstractFile = AbstractFile;
})(this);

View File

@ -14,323 +14,339 @@
*
* This module can be:
* - opened from the main thread as a jsm module;
* - opened from a chrome worker through importScripts.
* - opened from a chrome worker through require().
*/
"use strict";
let SharedAll;
if (typeof Components != "undefined") {
let Cu = Components.utils;
// Module is opened as a jsm module
this.EXPORTED_SYMBOLS = ["OS"];
Components.utils.import("resource://gre/modules/ctypes.jsm");
Cu.import("resource://gre/modules/ctypes.jsm", this);
SharedAll = {};
Components.utils.import("resource://gre/modules/osfile/osfile_shared_allthreads.jsm", SharedAll);
} else {
Cu.import("resource://gre/modules/osfile/osfile_shared_allthreads.jsm", SharedAll);
this.exports = {};
} else if (typeof "module" != "undefined" && typeof "require" != "undefined") {
// Module is loaded with require()
SharedAll = require("resource://gre/modules/osfile/osfile_shared_allthreads.jsm");
} else {
throw new Error("Please open this module with Component.utils.import or with require()");
}
(function(exports) {
"use strict";
if ("OS" in exports && "Shared" in exports.OS && "Unix" in exports.OS.Shared) {
// Avoid double inclusion
return;
let LOG = SharedAll.LOG.bind(SharedAll, "Unix", "allthreads");
let Const = SharedAll.Constants.libc;
// Open libc
let libc;
let libc_candidates = [ "libSystem.B.dylib",
"libc.so.6",
"libc.so" ];
for (let i = 0; i < libc_candidates.length; ++i) {
try {
libc = ctypes.open(libc_candidates[i]);
break;
} catch (x) {
LOG("Could not open libc ", libc_candidates[i]);
}
}
exports.OS = SharedAll.OS;
if (!libc) {
// Note: If you change the string here, please adapt tests accordingly
throw new Error("Could not open system library: no libc");
}
exports.libc = libc;
exports.OS.Shared.Unix = {};
// Define declareFFI
let declareFFI = SharedAll.declareFFI.bind(null, libc);
exports.declareFFI = declareFFI;
let LOG = OS.Shared.LOG.bind(OS.Shared, "Unix", "allthreads");
// Define Error
let strerror = libc.declare("strerror",
ctypes.default_abi,
/*return*/ ctypes.char.ptr,
/*errnum*/ ctypes.int);
// Open libc
let libc;
let libc_candidates = [ "libSystem.B.dylib",
"libc.so.6",
"libc.so" ];
for (let i = 0; i < libc_candidates.length; ++i) {
try {
libc = ctypes.open(libc_candidates[i]);
break;
} catch (x) {
LOG("Could not open libc ", libc_candidates[i]);
}
/**
* A File-related error.
*
* To obtain a human-readable error message, use method |toString|.
* To determine the cause of the error, use the various |becauseX|
* getters. To determine the operation that failed, use field
* |operation|.
*
* Additionally, this implementation offers a field
* |unixErrno|, which holds the OS-specific error
* constant. If you need this level of detail, you may match the value
* of this field against the error constants of |OS.Constants.libc|.
*
* @param {string=} operation The operation that failed. If unspecified,
* the name of the calling function is taken to be the operation that
* failed.
* @param {number=} lastError The OS-specific constant detailing the
* reason of the error. If unspecified, this is fetched from the system
* status.
*
* @constructor
* @extends {OS.Shared.Error}
*/
let OSError = function OSError(operation, errno) {
operation = operation || "unknown operation";
SharedAll.OSError.call(this, operation);
this.unixErrno = errno || ctypes.errno;
};
OSError.prototype = Object.create(SharedAll.OSError.prototype);
OSError.prototype.toString = function toString() {
return "Unix error " + this.unixErrno +
" during operation " + this.operation +
" (" + strerror(this.unixErrno).readString() + ")";
};
/**
* |true| if the error was raised because a file or directory
* already exists, |false| otherwise.
*/
Object.defineProperty(OSError.prototype, "becauseExists", {
get: function becauseExists() {
return this.unixErrno == Const.EEXIST;
}
if (!libc) {
// Note: If you change the string here, please adapt tests accordingly
throw new Error("Could not open system library: no libc");
});
/**
* |true| if the error was raised because a file or directory
* does not exist, |false| otherwise.
*/
Object.defineProperty(OSError.prototype, "becauseNoSuchFile", {
get: function becauseNoSuchFile() {
return this.unixErrno == Const.ENOENT;
}
exports.OS.Shared.Unix.libc = libc;
});
// Define declareFFI
let declareFFI = OS.Shared.declareFFI.bind(null, libc);
exports.OS.Shared.Unix.declareFFI = declareFFI;
/**
* |true| if the error was raised because a directory is not empty
* does not exist, |false| otherwise.
*/
Object.defineProperty(OSError.prototype, "becauseNotEmpty", {
get: function becauseNotEmpty() {
return this.unixErrno == Const.ENOTEMPTY;
}
});
/**
* |true| if the error was raised because a file or directory
* is closed, |false| otherwise.
*/
Object.defineProperty(OSError.prototype, "becauseClosed", {
get: function becauseClosed() {
return this.unixErrno == Const.EBADF;
}
});
/**
* |true| if the error was raised because permission is denied to
* access a file or directory, |false| otherwise.
*/
Object.defineProperty(OSError.prototype, "becauseAccessDenied", {
get: function becauseAccessDenied() {
return this.unixErrno == Const.EACCES;
}
});
// Define Error
let strerror = libc.declare("strerror",
ctypes.default_abi,
/*return*/ ctypes.char.ptr,
/*errnum*/ ctypes.int);
/**
* Serialize an instance of OSError to something that can be
* transmitted across threads (not necessarily a string).
*/
OSError.toMsg = function toMsg(error) {
return {
operation: error.operation,
unixErrno: error.unixErrno
};
};
/**
* Deserialize a message back to an instance of OSError
*/
OSError.fromMsg = function fromMsg(msg) {
return new OSError(msg.operation, msg.unixErrno);
};
exports.Error = OSError;
/**
* Code shared by implementations of File.Info on Unix
*
* @constructor
*/
let AbstractInfo = function AbstractInfo(isDir, isSymLink, size, lastAccessDate,
lastModificationDate, unixLastStatusChangeDate,
unixOwner, unixGroup, unixMode) {
this._isDir = isDir;
this._isSymlLink = isSymLink;
this._size = size;
this._lastAccessDate = lastAccessDate;
this._lastModificationDate = lastModificationDate;
this._unixLastStatusChangeDate = unixLastStatusChangeDate;
this._unixOwner = unixOwner;
this._unixGroup = unixGroup;
this._unixMode = unixMode;
};
AbstractInfo.prototype = {
/**
* A File-related error.
* |true| if this file is a directory, |false| otherwise
*/
get isDir() {
return this._isDir;
},
/**
* |true| if this file is a symbolink link, |false| otherwise
*/
get isSymLink() {
return this._isSymlLink;
},
/**
* The size of the file, in bytes.
*
* To obtain a human-readable error message, use method |toString|.
* To determine the cause of the error, use the various |becauseX|
* getters. To determine the operation that failed, use field
* |operation|.
* Note that the result may be |NaN| if the size of the file cannot be
* represented in JavaScript.
*
* Additionally, this implementation offers a field
* |unixErrno|, which holds the OS-specific error
* constant. If you need this level of detail, you may match the value
* of this field against the error constants of |OS.Constants.libc|.
* @type {number}
*/
get size() {
return this._size;
},
/**
* The date of last access to this file.
*
* @param {string=} operation The operation that failed. If unspecified,
* the name of the calling function is taken to be the operation that
* failed.
* @param {number=} lastError The OS-specific constant detailing the
* reason of the error. If unspecified, this is fetched from the system
* status.
* Note that the definition of last access may depend on the
* underlying operating system and file system.
*
* @constructor
* @extends {OS.Shared.Error}
* @type {Date}
*/
let OSError = function OSError(operation, errno) {
operation = operation || "unknown operation";
exports.OS.Shared.Error.call(this, operation);
this.unixErrno = errno || ctypes.errno;
};
OSError.prototype = new exports.OS.Shared.Error();
OSError.prototype.toString = function toString() {
return "Unix error " + this.unixErrno +
" during operation " + this.operation +
" (" + strerror(this.unixErrno).readString() + ")";
};
get lastAccessDate() {
return this._lastAccessDate;
},
/**
* |true| if the error was raised because a file or directory
* already exists, |false| otherwise.
* Return the date of last modification of this file.
*/
Object.defineProperty(OSError.prototype, "becauseExists", {
get: function becauseExists() {
return this.unixErrno == OS.Constants.libc.EEXIST;
}
});
get lastModificationDate() {
return this._lastModificationDate;
},
/**
* |true| if the error was raised because a file or directory
* does not exist, |false| otherwise.
* Return the date at which the status of this file was last modified
* (this is the date of the latest write/renaming/mode change/...
* of the file)
*/
Object.defineProperty(OSError.prototype, "becauseNoSuchFile", {
get: function becauseNoSuchFile() {
return this.unixErrno == OS.Constants.libc.ENOENT;
}
});
/**
* |true| if the error was raised because a directory is not empty
* does not exist, |false| otherwise.
get unixLastStatusChangeDate() {
return this._unixLastStatusChangeDate;
},
/*
* Return the Unix owner of this file
*/
Object.defineProperty(OSError.prototype, "becauseNotEmpty", {
get: function becauseNotEmpty() {
return this.unixErrno == OS.Constants.libc.ENOTEMPTY;
}
});
/**
* |true| if the error was raised because a file or directory
* is closed, |false| otherwise.
get unixOwner() {
return this._unixOwner;
},
/*
* Return the Unix group of this file
*/
Object.defineProperty(OSError.prototype, "becauseClosed", {
get: function becauseClosed() {
return this.unixErrno == OS.Constants.libc.EBADF;
}
});
/**
* |true| if the error was raised because permission is denied to
* access a file or directory, |false| otherwise.
get unixGroup() {
return this._unixGroup;
},
/*
* Return the Unix group of this file
*/
Object.defineProperty(OSError.prototype, "becauseAccessDenied", {
get: function becauseAccessDenied() {
return this.unixErrno == OS.Constants.libc.EACCES;
}
});
get unixMode() {
return this._unixMode;
}
};
exports.AbstractInfo = AbstractInfo;
/**
* Code shared by implementations of File.DirectoryIterator.Entry on Unix
*
* @constructor
*/
let AbstractEntry = function AbstractEntry(isDir, isSymLink, name, path) {
this._isDir = isDir;
this._isSymlLink = isSymLink;
this._name = name;
this._path = path;
};
AbstractEntry.prototype = {
/**
* Serialize an instance of OSError to something that can be
* transmitted across threads (not necessarily a string).
* |true| if the entry is a directory, |false| otherwise
*/
OSError.toMsg = function toMsg(error) {
return {
operation: error.operation,
unixErrno: error.unixErrno
};
};
get isDir() {
return this._isDir;
},
/**
* Deserialize a message back to an instance of OSError
* |true| if the entry is a directory, |false| otherwise
*/
OSError.fromMsg = function fromMsg(msg) {
return new OSError(msg.operation, msg.unixErrno);
};
exports.OS.Shared.Unix.Error = OSError;
get isSymLink() {
return this._isSymlLink;
},
/**
* Code shared by implementations of File.Info on Unix
*
* @constructor
*/
let AbstractInfo = function AbstractInfo(isDir, isSymLink, size, lastAccessDate,
lastModificationDate, unixLastStatusChangeDate,
unixOwner, unixGroup, unixMode) {
this._isDir = isDir;
this._isSymlLink = isSymLink;
this._size = size;
this._lastAccessDate = lastAccessDate;
this._lastModificationDate = lastModificationDate;
this._unixLastStatusChangeDate = unixLastStatusChangeDate;
this._unixOwner = unixOwner;
this._unixGroup = unixGroup;
this._unixMode = unixMode;
};
AbstractInfo.prototype = {
/**
* |true| if this file is a directory, |false| otherwise
*/
get isDir() {
return this._isDir;
},
/**
* |true| if this file is a symbolink link, |false| otherwise
*/
get isSymLink() {
return this._isSymlLink;
},
/**
* The size of the file, in bytes.
*
* Note that the result may be |NaN| if the size of the file cannot be
* represented in JavaScript.
*
* @type {number}
*/
get size() {
return this._size;
},
/**
* The date of last access to this file.
*
* Note that the definition of last access may depend on the
* underlying operating system and file system.
*
* @type {Date}
*/
get lastAccessDate() {
return this._lastAccessDate;
},
/**
* Return the date of last modification of this file.
*/
get lastModificationDate() {
return this._lastModificationDate;
},
/**
* Return the date at which the status of this file was last modified
* (this is the date of the latest write/renaming/mode change/...
* of the file)
*/
get unixLastStatusChangeDate() {
return this._unixLastStatusChangeDate;
},
/*
* Return the Unix owner of this file
*/
get unixOwner() {
return this._unixOwner;
},
/*
* Return the Unix group of this file
*/
get unixGroup() {
return this._unixGroup;
},
/*
* Return the Unix group of this file
*/
get unixMode() {
return this._unixMode;
}
};
exports.OS.Shared.Unix.AbstractInfo = AbstractInfo;
* The name of the entry
* @type {string}
*/
get name() {
return this._name;
},
/**
* Code shared by implementations of File.DirectoryIterator.Entry on Unix
*
* @constructor
*/
let AbstractEntry = function AbstractEntry(isDir, isSymLink, name, path) {
this._isDir = isDir;
this._isSymlLink = isSymLink;
this._name = name;
this._path = path;
};
* The full path to the entry
*/
get path() {
return this._path;
}
};
exports.AbstractEntry = AbstractEntry;
AbstractEntry.prototype = {
/**
* |true| if the entry is a directory, |false| otherwise
*/
get isDir() {
return this._isDir;
},
/**
* |true| if the entry is a directory, |false| otherwise
*/
get isSymLink() {
return this._isSymlLink;
},
/**
* The name of the entry
* @type {string}
*/
get name() {
return this._name;
},
/**
* The full path to the entry
*/
get path() {
return this._path;
}
};
exports.OS.Shared.Unix.AbstractEntry = AbstractEntry;
// Special constants that need to be defined on all platforms
// Special constants that need to be defined on all platforms
exports.POS_START = Const.SEEK_SET;
exports.POS_CURRENT = Const.SEEK_CUR;
exports.POS_END = Const.SEEK_END;
Object.defineProperty(exports.OS.Shared, "POS_START", { value: exports.OS.Constants.libc.SEEK_SET });
Object.defineProperty(exports.OS.Shared, "POS_CURRENT", { value: exports.OS.Constants.libc.SEEK_CUR });
Object.defineProperty(exports.OS.Shared, "POS_END", { value: exports.OS.Constants.libc.SEEK_END });
// Special types that need to be defined for communication
// between threads
let Type = Object.create(SharedAll.Type);
exports.Type = Type;
// Special types that need to be defined for communication
// between threads
let Types = exports.OS.Shared.Type;
/**
* Native paths
*
* Under Unix, expressed as C strings
*/
Type.path = Type.cstring.withName("[in] path");
Type.out_path = Type.out_cstring.withName("[out] path");
/**
* Native paths
*
* Under Unix, expressed as C strings
*/
Types.path = Types.cstring.withName("[in] path");
Types.out_path = Types.out_cstring.withName("[out] path");
// Special constructors that need to be defined on all threads
OSError.closed = function closed(operation) {
return new OSError(operation, Const.EBADF);
};
// Special constructors that need to be defined on all threads
OSError.closed = function closed(operation) {
return new OSError(operation, OS.Constants.libc.EBADF);
};
OSError.exists = function exists(operation) {
return new OSError(operation, Const.EEXIST);
};
OSError.exists = function exists(operation) {
return new OSError(operation, OS.Constants.libc.EEXIST);
};
OSError.noSuchFile = function noSuchFile(operation) {
return new OSError(operation, Const.ENOENT);
};
OSError.noSuchFile = function noSuchFile(operation) {
return new OSError(operation, OS.Constants.libc.ENOENT);
};
})(this);
let EXPORTED_SYMBOLS = [
"declareFFI",
"libc",
"Error",
"AbstractInfo",
"AbstractEntry",
"Type",
"POS_START",
"POS_CURRENT",
"POS_END"
];
//////////// Boilerplate
if (typeof Components != "undefined") {
this.EXPORTED_SYMBOLS = EXPORTED_SYMBOLS;
for (let symbol of EXPORTED_SYMBOLS) {
this[symbol] = exports[symbol];
}
}

View File

@ -17,12 +17,13 @@
return; // Avoid double initialization
}
exports.OS = require("resource://gre/modules/osfile/osfile_shared_allthreads.jsm").OS;
exports.OS.Unix.File = {};
let LOG = exports.OS.Shared.LOG.bind(OS.Shared, "Unix", "back");
let libc = exports.OS.Shared.Unix.libc;
let SharedAll =
require("resource://gre/modules/osfile/osfile_shared_allthreads.jsm");
let SysAll =
require("resource://gre/modules/osfile/osfile_unix_allthreads.jsm");
let LOG = SharedAll.LOG.bind(SharedAll, "Unix", "back");
let libc = SysAll.libc;
let Const = SharedAll.Constants.libc;
/**
* Initialize the Unix module.
@ -35,27 +36,20 @@
if (aDeclareFFI) {
declareFFI = aDeclareFFI.bind(null, libc);
} else {
declareFFI = exports.OS.Shared.Unix.declareFFI;
declareFFI = SysAll.declareFFI;
}
// Shorthands
let OSUnix = exports.OS.Unix;
let UnixFile = exports.OS.Unix.File;
if (!exports.OS.Types) {
exports.OS.Types = {};
}
let Type = exports.OS.Shared.Type;
let Types = Type;
// Initialize types that require additional OS-specific
// support - either finalization or matching against
// OS-specific constants.
let Type = Object.create(SysAll.Type);
let SysFile = exports.OS.Unix.File = { Type: Type };
/**
* A file descriptor.
*/
Types.fd = Type.int.withName("fd");
Types.fd.importFromC = function importFromC(fd_int) {
Type.fd = Type.int.withName("fd");
Type.fd.importFromC = function importFromC(fd_int) {
return ctypes.CDataFinalizer(fd_int, _close);
};
@ -64,8 +58,8 @@
* A C integer holding -1 in case of error or a file descriptor
* in case of success.
*/
Types.negativeone_or_fd = Types.fd.withName("negativeone_or_fd");
Types.negativeone_or_fd.importFromC =
Type.negativeone_or_fd = Type.fd.withName("negativeone_or_fd");
Type.negativeone_or_fd.importFromC =
function importFromC(fd_int) {
if (fd_int == -1) {
return -1;
@ -77,31 +71,31 @@
* A C integer holding -1 in case of error or a meaningless value
* in case of success.
*/
Types.negativeone_or_nothing =
Types.int.withName("negativeone_or_nothing");
Type.negativeone_or_nothing =
Type.int.withName("negativeone_or_nothing");
/**
* A C integer holding -1 in case of error or a positive integer
* in case of success.
*/
Types.negativeone_or_ssize_t =
Types.ssize_t.withName("negativeone_or_ssize_t");
Type.negativeone_or_ssize_t =
Type.ssize_t.withName("negativeone_or_ssize_t");
/**
* Various libc integer types
*/
Types.mode_t =
Types.intn_t(OS.Constants.libc.OSFILE_SIZEOF_MODE_T).withName("mode_t");
Types.uid_t =
Types.intn_t(OS.Constants.libc.OSFILE_SIZEOF_UID_T).withName("uid_t");
Types.gid_t =
Types.intn_t(OS.Constants.libc.OSFILE_SIZEOF_GID_T).withName("gid_t");
Type.mode_t =
Type.intn_t(Const.OSFILE_SIZEOF_MODE_T).withName("mode_t");
Type.uid_t =
Type.intn_t(Const.OSFILE_SIZEOF_UID_T).withName("uid_t");
Type.gid_t =
Type.intn_t(Const.OSFILE_SIZEOF_GID_T).withName("gid_t");
/**
* Type |time_t|
*/
Types.time_t =
Types.intn_t(OS.Constants.libc.OSFILE_SIZEOF_TIME_T).withName("time_t");
Type.time_t =
Type.intn_t(Const.OSFILE_SIZEOF_TIME_T).withName("time_t");
// Structure |dirent|
// Building this type is rather complicated, as its layout varies between
@ -115,90 +109,90 @@
// };
{
let d_name_extra_size = 0;
if (OS.Constants.libc.OSFILE_SIZEOF_DIRENT_D_NAME < 8) {
if (Const.OSFILE_SIZEOF_DIRENT_D_NAME < 8) {
// d_name is defined like "char d_name[1];" on some platforms
// (e.g. Solaris), we need to give it more size for our structure.
d_name_extra_size = 256;
}
let dirent = new OS.Shared.HollowStructure("dirent",
OS.Constants.libc.OSFILE_SIZEOF_DIRENT + d_name_extra_size);
if (OS.Constants.libc.OSFILE_OFFSETOF_DIRENT_D_TYPE != undefined) {
let dirent = new SharedAll.HollowStructure("dirent",
Const.OSFILE_SIZEOF_DIRENT + d_name_extra_size);
if (Const.OSFILE_OFFSETOF_DIRENT_D_TYPE != undefined) {
// |dirent| doesn't have d_type on some platforms (e.g. Solaris).
dirent.add_field_at(OS.Constants.libc.OSFILE_OFFSETOF_DIRENT_D_TYPE,
dirent.add_field_at(Const.OSFILE_OFFSETOF_DIRENT_D_TYPE,
"d_type", ctypes.uint8_t);
}
dirent.add_field_at(OS.Constants.libc.OSFILE_OFFSETOF_DIRENT_D_NAME,
dirent.add_field_at(Const.OSFILE_OFFSETOF_DIRENT_D_NAME,
"d_name", ctypes.ArrayType(ctypes.char,
OS.Constants.libc.OSFILE_SIZEOF_DIRENT_D_NAME + d_name_extra_size));
Const.OSFILE_SIZEOF_DIRENT_D_NAME + d_name_extra_size));
// We now have built |dirent|.
Types.dirent = dirent.getType();
Type.dirent = dirent.getType();
}
Types.null_or_dirent_ptr =
new Type("null_of_dirent",
Types.dirent.out_ptr.implementation);
Type.null_or_dirent_ptr =
new SharedAll.Type("null_of_dirent",
Type.dirent.out_ptr.implementation);
// Structure |stat|
// Same technique
{
let stat = new OS.Shared.HollowStructure("stat",
OS.Constants.libc.OSFILE_SIZEOF_STAT);
stat.add_field_at(OS.Constants.libc.OSFILE_OFFSETOF_STAT_ST_MODE,
"st_mode", Types.mode_t.implementation);
stat.add_field_at(OS.Constants.libc.OSFILE_OFFSETOF_STAT_ST_UID,
"st_uid", Types.uid_t.implementation);
stat.add_field_at(OS.Constants.libc.OSFILE_OFFSETOF_STAT_ST_GID,
"st_gid", Types.gid_t.implementation);
let stat = new SharedAll.HollowStructure("stat",
Const.OSFILE_SIZEOF_STAT);
stat.add_field_at(Const.OSFILE_OFFSETOF_STAT_ST_MODE,
"st_mode", Type.mode_t.implementation);
stat.add_field_at(Const.OSFILE_OFFSETOF_STAT_ST_UID,
"st_uid", Type.uid_t.implementation);
stat.add_field_at(Const.OSFILE_OFFSETOF_STAT_ST_GID,
"st_gid", Type.gid_t.implementation);
// Here, things get complicated with different data structures.
// Some platforms have |time_t st_atime| and some platforms have
// |timespec st_atimespec|. However, since |timespec| starts with
// a |time_t|, followed by nanoseconds, we just cheat and pretend
// that everybody has |time_t st_atime|, possibly followed by padding
stat.add_field_at(OS.Constants.libc.OSFILE_OFFSETOF_STAT_ST_ATIME,
"st_atime", Types.time_t.implementation);
stat.add_field_at(OS.Constants.libc.OSFILE_OFFSETOF_STAT_ST_MTIME,
"st_mtime", Types.time_t.implementation);
stat.add_field_at(OS.Constants.libc.OSFILE_OFFSETOF_STAT_ST_CTIME,
"st_ctime", Types.time_t.implementation);
stat.add_field_at(Const.OSFILE_OFFSETOF_STAT_ST_ATIME,
"st_atime", Type.time_t.implementation);
stat.add_field_at(Const.OSFILE_OFFSETOF_STAT_ST_MTIME,
"st_mtime", Type.time_t.implementation);
stat.add_field_at(Const.OSFILE_OFFSETOF_STAT_ST_CTIME,
"st_ctime", Type.time_t.implementation);
// To complicate further, MacOS and some BSDs have a field |birthtime|
if ("OSFILE_OFFSETOF_STAT_ST_BIRTHTIME" in OS.Constants.libc) {
stat.add_field_at(OS.Constants.libc.OSFILE_OFFSETOF_STAT_ST_BIRTHTIME,
"st_birthtime", Types.time_t.implementation);
if ("OSFILE_OFFSETOF_STAT_ST_BIRTHTIME" in Const) {
stat.add_field_at(Const.OSFILE_OFFSETOF_STAT_ST_BIRTHTIME,
"st_birthtime", Type.time_t.implementation);
}
stat.add_field_at(OS.Constants.libc.OSFILE_OFFSETOF_STAT_ST_SIZE,
"st_size", Types.size_t.implementation);
Types.stat = stat.getType();
stat.add_field_at(Const.OSFILE_OFFSETOF_STAT_ST_SIZE,
"st_size", Type.size_t.implementation);
Type.stat = stat.getType();
}
// Structure |DIR|
if ("OSFILE_SIZEOF_DIR" in OS.Constants.libc) {
if ("OSFILE_SIZEOF_DIR" in Const) {
// On platforms for which we need to access the fields of DIR
// directly (e.g. because certain functions are implemented
// as macros), we need to define DIR as a hollow structure.
let DIR = new OS.Shared.HollowStructure(
let DIR = new SharedAll.HollowStructure(
"DIR",
OS.Constants.libc.OSFILE_SIZEOF_DIR);
Const.OSFILE_SIZEOF_DIR);
DIR.add_field_at(
OS.Constants.libc.OSFILE_OFFSETOF_DIR_DD_FD,
Const.OSFILE_OFFSETOF_DIR_DD_FD,
"dd_fd",
Types.fd.implementation);
Type.fd.implementation);
Types.DIR = DIR.getType();
Type.DIR = DIR.getType();
} else {
// On other platforms, we keep DIR as a blackbox
Types.DIR =
new Type("DIR",
Type.DIR =
new SharedAll.Type("DIR",
ctypes.StructType("DIR"));
}
Types.null_or_DIR_ptr =
Types.DIR.out_ptr.withName("null_or_DIR*");
Types.null_or_DIR_ptr.importFromC = function importFromC(dir) {
Type.null_or_DIR_ptr =
Type.DIR.out_ptr.withName("null_or_DIR*");
Type.null_or_DIR_ptr.importFromC = function importFromC(dir) {
if (dir == null || dir.isNull()) {
return null;
}
@ -208,12 +202,12 @@
// Declare libc functions as functions of |OS.Unix.File|
// Finalizer-related functions
let _close = UnixFile._close =
let _close = SysFile._close =
libc.declare("close", ctypes.default_abi,
/*return */ctypes.int,
/*fd*/ ctypes.int);
UnixFile.close = function close(fd) {
SysFile.close = function close(fd) {
// Detach the finalizer and call |_close|.
return fd.dispose();
};
@ -221,9 +215,9 @@
let _close_dir =
libc.declare("closedir", ctypes.default_abi,
/*return */ctypes.int,
/*dirp*/ Types.DIR.in_ptr.implementation);
/*dirp*/ Type.DIR.in_ptr.implementation);
UnixFile.closedir = function closedir(fd) {
SysFile.closedir = function closedir(fd) {
// Detach the finalizer and call |_close_dir|.
return fd.dispose();
};
@ -238,7 +232,7 @@
// correct implementation free().
default_lib = ctypes.open("a.out");
UnixFile.free =
SysFile.free =
default_lib.declare("free", ctypes.default_abi,
/*return*/ ctypes.void_t,
/*ptr*/ ctypes.voidptr_t);
@ -247,7 +241,7 @@
// We don't have an a.out library or a.out doesn't contain free.
// Either way, use the ordinary libc free.
UnixFile.free =
SysFile.free =
libc.declare("free", ctypes.default_abi,
/*return*/ ctypes.void_t,
/*ptr*/ ctypes.voidptr_t);
@ -256,293 +250,293 @@
// Other functions
UnixFile.access =
SysFile.access =
declareFFI("access", ctypes.default_abi,
/*return*/ Types.negativeone_or_nothing,
/*path*/ Types.path,
/*mode*/ Types.int);
/*return*/ Type.negativeone_or_nothing,
/*path*/ Type.path,
/*mode*/ Type.int);
UnixFile.chdir =
SysFile.chdir =
declareFFI("chdir", ctypes.default_abi,
/*return*/ Types.negativeone_or_nothing,
/*path*/ Types.path);
/*return*/ Type.negativeone_or_nothing,
/*path*/ Type.path);
UnixFile.chmod =
SysFile.chmod =
declareFFI("chmod", ctypes.default_abi,
/*return*/ Types.negativeone_or_nothing,
/*path*/ Types.path,
/*mode*/ Types.mode_t);
/*return*/ Type.negativeone_or_nothing,
/*path*/ Type.path,
/*mode*/ Type.mode_t);
UnixFile.chown =
SysFile.chown =
declareFFI("chown", ctypes.default_abi,
/*return*/ Types.negativeone_or_nothing,
/*path*/ Types.path,
/*uid*/ Types.uid_t,
/*gid*/ Types.gid_t);
/*return*/ Type.negativeone_or_nothing,
/*path*/ Type.path,
/*uid*/ Type.uid_t,
/*gid*/ Type.gid_t);
UnixFile.copyfile =
SysFile.copyfile =
declareFFI("copyfile", ctypes.default_abi,
/*return*/ Types.negativeone_or_nothing,
/*source*/ Types.path,
/*dest*/ Types.path,
/*state*/ Types.void_t.in_ptr, // Ignored atm
/*flags*/ Types.uint32_t);
/*return*/ Type.negativeone_or_nothing,
/*source*/ Type.path,
/*dest*/ Type.path,
/*state*/ Type.void_t.in_ptr, // Ignored atm
/*flags*/ Type.uint32_t);
UnixFile.dup =
SysFile.dup =
declareFFI("dup", ctypes.default_abi,
/*return*/ Types.negativeone_or_fd,
/*fd*/ Types.fd);
/*return*/ Type.negativeone_or_fd,
/*fd*/ Type.fd);
if ("OSFILE_SIZEOF_DIR" in OS.Constants.libc) {
if ("OSFILE_SIZEOF_DIR" in Const) {
// On platforms for which |dirfd| is a macro
UnixFile.dirfd =
SysFile.dirfd =
function dirfd(DIRp) {
return Types.DIR.in_ptr.implementation(DIRp).contents.dd_fd;
return Type.DIR.in_ptr.implementation(DIRp).contents.dd_fd;
};
} else {
// On platforms for which |dirfd| is a function
UnixFile.dirfd =
SysFile.dirfd =
declareFFI("dirfd", ctypes.default_abi,
/*return*/ Types.negativeone_or_fd,
/*dir*/ Types.DIR.in_ptr);
/*return*/ Type.negativeone_or_fd,
/*dir*/ Type.DIR.in_ptr);
}
UnixFile.chdir =
SysFile.chdir =
declareFFI("chdir", ctypes.default_abi,
/*return*/ Types.negativeone_or_nothing,
/*path*/ Types.path);
/*return*/ Type.negativeone_or_nothing,
/*path*/ Type.path);
UnixFile.fchdir =
SysFile.fchdir =
declareFFI("fchdir", ctypes.default_abi,
/*return*/ Types.negativeone_or_nothing,
/*fd*/ Types.fd);
/*return*/ Type.negativeone_or_nothing,
/*fd*/ Type.fd);
UnixFile.fchown =
SysFile.fchown =
declareFFI("fchown", ctypes.default_abi,
/*return*/ Types.negativeone_or_nothing,
/*fd*/ Types.fd,
/*uid_t*/ Types.uid_t,
/*gid_t*/ Types.gid_t);
/*return*/ Type.negativeone_or_nothing,
/*fd*/ Type.fd,
/*uid_t*/ Type.uid_t,
/*gid_t*/ Type.gid_t);
UnixFile.fsync =
SysFile.fsync =
declareFFI("fsync", ctypes.default_abi,
/*return*/ Types.negativeone_or_nothing,
/*fd*/ Types.fd);
/*return*/ Type.negativeone_or_nothing,
/*fd*/ Type.fd);
UnixFile.getcwd =
SysFile.getcwd =
declareFFI("getcwd", ctypes.default_abi,
/*return*/ Types.out_path,
/*buf*/ Types.out_path,
/*size*/ Types.size_t);
/*return*/ Type.out_path,
/*buf*/ Type.out_path,
/*size*/ Type.size_t);
UnixFile.getwd =
SysFile.getwd =
declareFFI("getwd", ctypes.default_abi,
/*return*/ Types.out_path,
/*buf*/ Types.out_path);
/*return*/ Type.out_path,
/*buf*/ Type.out_path);
// Two variants of |getwd| which allocate the memory
// dynamically.
// Linux/Android version
UnixFile.get_current_dir_name =
SysFile.get_current_dir_name =
declareFFI("get_current_dir_name", ctypes.default_abi,
/*return*/ Types.out_path.releaseWith(UnixFile.free));
/*return*/ Type.out_path.releaseWith(SysFile.free));
// MacOS/BSD version (will return NULL on Linux/Android)
UnixFile.getwd_auto =
SysFile.getwd_auto =
declareFFI("getwd", ctypes.default_abi,
/*return*/ Types.out_path.releaseWith(UnixFile.free),
/*buf*/ Types.void_t.out_ptr);
/*return*/ Type.out_path.releaseWith(SysFile.free),
/*buf*/ Type.void_t.out_ptr);
UnixFile.fdatasync =
SysFile.fdatasync =
declareFFI("fdatasync", ctypes.default_abi,
/*return*/ Types.negativeone_or_nothing,
/*fd*/ Types.fd); // Note: MacOS/BSD-specific
/*return*/ Type.negativeone_or_nothing,
/*fd*/ Type.fd); // Note: MacOS/BSD-specific
UnixFile.ftruncate =
SysFile.ftruncate =
declareFFI("ftruncate", ctypes.default_abi,
/*return*/ Types.negativeone_or_nothing,
/*fd*/ Types.fd,
/*length*/ Types.off_t);
/*return*/ Type.negativeone_or_nothing,
/*fd*/ Type.fd,
/*length*/ Type.off_t);
if (OS.Constants.libc._DARWIN_FEATURE_64_BIT_INODE) {
UnixFile.fstat =
if (Const._DARWIN_FEATURE_64_BIT_INODE) {
SysFile.fstat =
declareFFI("fstat$INODE64", ctypes.default_abi,
/*return*/ Types.negativeone_or_nothing,
/*path*/ Types.fd,
/*buf*/ Types.stat.out_ptr
/*return*/ Type.negativeone_or_nothing,
/*path*/ Type.fd,
/*buf*/ Type.stat.out_ptr
);
} else {
UnixFile.fstat =
SysFile.fstat =
declareFFI("fstat", ctypes.default_abi,
/*return*/ Types.negativeone_or_nothing,
/*path*/ Types.fd,
/*buf*/ Types.stat.out_ptr
/*return*/ Type.negativeone_or_nothing,
/*path*/ Type.fd,
/*buf*/ Type.stat.out_ptr
);
}
UnixFile.lchown =
SysFile.lchown =
declareFFI("lchown", ctypes.default_abi,
/*return*/ Types.negativeone_or_nothing,
/*path*/ Types.path,
/*uid_t*/ Types.uid_t,
/*gid_t*/ Types.gid_t);
/*return*/ Type.negativeone_or_nothing,
/*path*/ Type.path,
/*uid_t*/ Type.uid_t,
/*gid_t*/ Type.gid_t);
UnixFile.link =
SysFile.link =
declareFFI("link", ctypes.default_abi,
/*return*/ Types.negativeone_or_nothing,
/*source*/ Types.path,
/*dest*/ Types.path);
/*return*/ Type.negativeone_or_nothing,
/*source*/ Type.path,
/*dest*/ Type.path);
UnixFile.lseek =
SysFile.lseek =
declareFFI("lseek", ctypes.default_abi,
/*return*/ Types.off_t,
/*fd*/ Types.fd,
/*offset*/ Types.off_t,
/*whence*/ Types.int);
/*return*/ Type.off_t,
/*fd*/ Type.fd,
/*offset*/ Type.off_t,
/*whence*/ Type.int);
UnixFile.mkdir =
SysFile.mkdir =
declareFFI("mkdir", ctypes.default_abi,
/*return*/ Types.int,
/*path*/ Types.path,
/*mode*/ Types.int);
/*return*/ Type.int,
/*path*/ Type.path,
/*mode*/ Type.int);
UnixFile.mkstemp =
SysFile.mkstemp =
declareFFI("mkstemp", ctypes.default_abi,
/*return*/ Types.fd,
/*template*/Types.out_path);
/*return*/ Type.fd,
/*template*/Type.out_path);
UnixFile.open =
SysFile.open =
declareFFI("open", ctypes.default_abi,
/*return*/Types.negativeone_or_fd,
/*path*/ Types.path,
/*oflags*/Types.int,
/*mode*/ Types.int);
/*return*/Type.negativeone_or_fd,
/*path*/ Type.path,
/*oflags*/Type.int,
/*mode*/ Type.int);
UnixFile.opendir =
SysFile.opendir =
declareFFI("opendir", ctypes.default_abi,
/*return*/ Types.null_or_DIR_ptr,
/*path*/ Types.path);
/*return*/ Type.null_or_DIR_ptr,
/*path*/ Type.path);
UnixFile.pread =
SysFile.pread =
declareFFI("pread", ctypes.default_abi,
/*return*/ Types.negativeone_or_ssize_t,
/*fd*/ Types.fd,
/*buf*/ Types.void_t.out_ptr,
/*nbytes*/ Types.size_t,
/*offset*/ Types.off_t);
/*return*/ Type.negativeone_or_ssize_t,
/*fd*/ Type.fd,
/*buf*/ Type.void_t.out_ptr,
/*nbytes*/ Type.size_t,
/*offset*/ Type.off_t);
UnixFile.pwrite =
SysFile.pwrite =
declareFFI("pwrite", ctypes.default_abi,
/*return*/ Types.negativeone_or_ssize_t,
/*fd*/ Types.fd,
/*buf*/ Types.void_t.in_ptr,
/*nbytes*/ Types.size_t,
/*offset*/ Types.off_t);
/*return*/ Type.negativeone_or_ssize_t,
/*fd*/ Type.fd,
/*buf*/ Type.void_t.in_ptr,
/*nbytes*/ Type.size_t,
/*offset*/ Type.off_t);
UnixFile.read =
SysFile.read =
declareFFI("read", ctypes.default_abi,
/*return*/Types.negativeone_or_ssize_t,
/*fd*/ Types.fd,
/*buf*/ Types.void_t.out_ptr,
/*nbytes*/Types.size_t);
/*return*/Type.negativeone_or_ssize_t,
/*fd*/ Type.fd,
/*buf*/ Type.void_t.out_ptr,
/*nbytes*/Type.size_t);
UnixFile.posix_fadvise =
SysFile.posix_fadvise =
declareFFI("posix_fadvise", ctypes.default_abi,
/*return*/ Types.int,
/*fd*/ Types.fd,
/*offset*/ Types.off_t,
/*len*/ Types.off_t,
/*advise*/ Types.int);
/*return*/ Type.int,
/*fd*/ Type.fd,
/*offset*/ Type.off_t,
/*len*/ Type.off_t,
/*advise*/ Type.int);
if (OS.Constants.libc._DARWIN_FEATURE_64_BIT_INODE) {
if (Const._DARWIN_FEATURE_64_BIT_INODE) {
// Special case for MacOS X 10.5+
// Symbol name "readdir" still exists but is used for a
// deprecated function that does not match the
// constants of |OS.Constants.libc|.
UnixFile.readdir =
// constants of |Const|.
SysFile.readdir =
declareFFI("readdir$INODE64", ctypes.default_abi,
/*return*/Types.null_or_dirent_ptr,
/*dir*/ Types.DIR.in_ptr); // For MacOS X
/*return*/Type.null_or_dirent_ptr,
/*dir*/ Type.DIR.in_ptr); // For MacOS X
} else {
UnixFile.readdir =
SysFile.readdir =
declareFFI("readdir", ctypes.default_abi,
/*return*/Types.null_or_dirent_ptr,
/*dir*/ Types.DIR.in_ptr); // Other Unices
/*return*/Type.null_or_dirent_ptr,
/*dir*/ Type.DIR.in_ptr); // Other Unices
}
UnixFile.rename =
SysFile.rename =
declareFFI("rename", ctypes.default_abi,
/*return*/ Types.negativeone_or_nothing,
/*old*/ Types.path,
/*new*/ Types.path);
/*return*/ Type.negativeone_or_nothing,
/*old*/ Type.path,
/*new*/ Type.path);
UnixFile.rmdir =
SysFile.rmdir =
declareFFI("rmdir", ctypes.default_abi,
/*return*/ Types.int,
/*path*/ Types.path);
/*return*/ Type.int,
/*path*/ Type.path);
UnixFile.splice =
SysFile.splice =
declareFFI("splice", ctypes.default_abi,
/*return*/ Types.long,
/*fd_in*/ Types.fd,
/*off_in*/ Types.off_t.in_ptr,
/*fd_out*/ Types.fd,
/*off_out*/Types.off_t.in_ptr,
/*len*/ Types.size_t,
/*flags*/ Types.unsigned_int); // Linux/Android-specific
/*return*/ Type.long,
/*fd_in*/ Type.fd,
/*off_in*/ Type.off_t.in_ptr,
/*fd_out*/ Type.fd,
/*off_out*/Type.off_t.in_ptr,
/*len*/ Type.size_t,
/*flags*/ Type.unsigned_int); // Linux/Android-specific
UnixFile.symlink =
SysFile.symlink =
declareFFI("symlink", ctypes.default_abi,
/*return*/ Types.negativeone_or_nothing,
/*source*/ Types.path,
/*dest*/ Types.path);
/*return*/ Type.negativeone_or_nothing,
/*source*/ Type.path,
/*dest*/ Type.path);
UnixFile.truncate =
SysFile.truncate =
declareFFI("truncate", ctypes.default_abi,
/*return*/Types.negativeone_or_nothing,
/*path*/ Types.path,
/*length*/ Types.off_t);
/*return*/Type.negativeone_or_nothing,
/*path*/ Type.path,
/*length*/ Type.off_t);
UnixFile.unlink =
SysFile.unlink =
declareFFI("unlink", ctypes.default_abi,
/*return*/ Types.negativeone_or_nothing,
/*path*/ Types.path);
/*return*/ Type.negativeone_or_nothing,
/*path*/ Type.path);
UnixFile.write =
SysFile.write =
declareFFI("write", ctypes.default_abi,
/*return*/ Types.negativeone_or_ssize_t,
/*fd*/ Types.fd,
/*buf*/ Types.void_t.in_ptr,
/*nbytes*/ Types.size_t);
/*return*/ Type.negativeone_or_ssize_t,
/*fd*/ Type.fd,
/*buf*/ Type.void_t.in_ptr,
/*nbytes*/ Type.size_t);
// Weird cases that require special treatment
// OSes use a variety of hacks to differentiate between
// 32-bits and 64-bits versions of |stat|, |lstat|, |fstat|.
if (OS.Constants.libc._DARWIN_FEATURE_64_BIT_INODE) {
if (Const._DARWIN_FEATURE_64_BIT_INODE) {
// MacOS X 64-bits
UnixFile.stat =
SysFile.stat =
declareFFI("stat$INODE64", ctypes.default_abi,
/*return*/ Types.negativeone_or_nothing,
/*path*/ Types.path,
/*buf*/ Types.stat.out_ptr
/*return*/ Type.negativeone_or_nothing,
/*path*/ Type.path,
/*buf*/ Type.stat.out_ptr
);
UnixFile.lstat =
SysFile.lstat =
declareFFI("lstat$INODE64", ctypes.default_abi,
/*return*/ Types.negativeone_or_nothing,
/*path*/ Types.path,
/*buf*/ Types.stat.out_ptr
/*return*/ Type.negativeone_or_nothing,
/*path*/ Type.path,
/*buf*/ Type.stat.out_ptr
);
UnixFile.fstat =
SysFile.fstat =
declareFFI("fstat$INODE64", ctypes.default_abi,
/*return*/ Types.negativeone_or_nothing,
/*path*/ Types.fd,
/*buf*/ Types.stat.out_ptr
/*return*/ Type.negativeone_or_nothing,
/*path*/ Type.fd,
/*buf*/ Type.stat.out_ptr
);
} else if (OS.Constants.libc._STAT_VER != undefined) {
const ver = OS.Constants.libc._STAT_VER;
let xstat_name, lxstat_name, fxstat_name
} else if (Const._STAT_VER != undefined) {
const ver = Const._STAT_VER;
let xstat_name, lxstat_name, fxstat_name;
if (OS.Constants.Sys.Name == "SunOS") {
// Solaris
xstat_name = "_xstat";
@ -557,51 +551,51 @@
let xstat =
declareFFI(xstat_name, ctypes.default_abi,
/*return*/ Types.negativeone_or_nothing,
/*_stat_ver*/ Types.int,
/*path*/ Types.path,
/*buf*/ Types.stat.out_ptr);
/*return*/ Type.negativeone_or_nothing,
/*_stat_ver*/ Type.int,
/*path*/ Type.path,
/*buf*/ Type.stat.out_ptr);
let lxstat =
declareFFI(lxstat_name, ctypes.default_abi,
/*return*/ Types.negativeone_or_nothing,
/*_stat_ver*/ Types.int,
/*path*/ Types.path,
/*buf*/ Types.stat.out_ptr);
/*return*/ Type.negativeone_or_nothing,
/*_stat_ver*/ Type.int,
/*path*/ Type.path,
/*buf*/ Type.stat.out_ptr);
let fxstat =
declareFFI(fxstat_name, ctypes.default_abi,
/*return*/ Types.negativeone_or_nothing,
/*_stat_ver*/ Types.int,
/*fd*/ Types.fd,
/*buf*/ Types.stat.out_ptr);
/*return*/ Type.negativeone_or_nothing,
/*_stat_ver*/ Type.int,
/*fd*/ Type.fd,
/*buf*/ Type.stat.out_ptr);
UnixFile.stat = function stat(path, buf) {
SysFile.stat = function stat(path, buf) {
return xstat(ver, path, buf);
};
UnixFile.lstat = function stat(path, buf) {
SysFile.lstat = function stat(path, buf) {
return lxstat(ver, path, buf);
};
UnixFile.fstat = function stat(fd, buf) {
SysFile.fstat = function stat(fd, buf) {
return fxstat(ver, fd, buf);
};
} else {
// Mac OS X 32-bits, other Unix
UnixFile.stat =
SysFile.stat =
declareFFI("stat", ctypes.default_abi,
/*return*/ Types.negativeone_or_nothing,
/*path*/ Types.path,
/*buf*/ Types.stat.out_ptr
/*return*/ Type.negativeone_or_nothing,
/*path*/ Type.path,
/*buf*/ Type.stat.out_ptr
);
UnixFile.lstat =
SysFile.lstat =
declareFFI("lstat", ctypes.default_abi,
/*return*/ Types.negativeone_or_nothing,
/*path*/ Types.path,
/*buf*/ Types.stat.out_ptr
/*return*/ Type.negativeone_or_nothing,
/*path*/ Type.path,
/*buf*/ Type.stat.out_ptr
);
UnixFile.fstat =
SysFile.fstat =
declareFFI("fstat", ctypes.default_abi,
/*return*/ Types.negativeone_or_nothing,
/*fd*/ Types.fd,
/*buf*/ Types.stat.out_ptr
/*return*/ Type.negativeone_or_nothing,
/*fd*/ Type.fd,
/*buf*/ Type.stat.out_ptr
);
}
@ -610,14 +604,14 @@
let _pipe =
declareFFI("pipe", ctypes.default_abi,
/*return*/ Types.negativeone_or_nothing,
/*fds*/ new Type("two file descriptors",
/*return*/ Type.negativeone_or_nothing,
/*fds*/ new SharedAll.Type("two file descriptors",
ctypes.ArrayType(ctypes.int, 2)));
// A shared per-thread buffer used to communicate with |pipe|
let _pipebuf = new (ctypes.ArrayType(ctypes.int, 2))();
UnixFile.pipe = function pipe(array) {
SysFile.pipe = function pipe(array) {
let result = _pipe(_pipebuf);
if (result == -1) {
return result;
@ -627,6 +621,11 @@
return result;
};
};
exports.OS.Unix.File._init = init;
exports.OS.Unix = {
File: {
_init: init
}
};
})(this);
}

View File

@ -19,18 +19,19 @@
(function(exports) {
"use strict";
exports.OS = require("resource://gre/modules/osfile/osfile_shared_allthreads.jsm").OS;
let Path = require("resource://gre/modules/osfile/ospath.jsm");
// exports.OS.Unix is created by osfile_unix_back.jsm
if (exports.OS && exports.OS.File) {
return; // Avoid double-initialization
}
let SharedAll = require("resource://gre/modules/osfile/osfile_shared_allthreads.jsm");
let Path = require("resource://gre/modules/osfile/ospath.jsm");
let SysAll = require("resource://gre/modules/osfile/osfile_unix_allthreads.jsm");
exports.OS.Unix.File._init();
let Const = exports.OS.Constants.libc;
let LOG = SharedAll.LOG.bind(SharedAll, "Unix front-end");
let Const = SharedAll.Constants.libc;
let UnixFile = exports.OS.Unix.File;
let LOG = OS.Shared.LOG.bind(OS.Shared, "Unix front-end");
let Type = UnixFile.Type;
/**
* Representation of a file.
@ -269,7 +270,7 @@
* @return {bool} true if the file exists, false otherwise.
*/
File.exists = function Unix_exists(path) {
if (UnixFile.access(path, OS.Constants.libc.F_OK) == -1) {
if (UnixFile.access(path, Const.F_OK) == -1) {
return false;
} else {
return true;
@ -338,7 +339,7 @@
let omode = options.unixMode !== undefined ? options.unixMode : DEFAULT_UNIX_MODE_DIR;
let result = UnixFile.mkdir(path, omode);
if (result != -1 ||
options.ignoreExisting && ctypes.errno == OS.Constants.libc.EEXIST) {
options.ignoreExisting && ctypes.errno == Const.EEXIST) {
return;
}
throw new File.Error("makeDir");
@ -518,10 +519,10 @@
// We *might* be on a file system that does not support splice.
// Try again with a fallback pump.
if (total_read) {
source.setPosition(-total_read, OS.File.POS_CURRENT);
source.setPosition(-total_read, File.POS_CURRENT);
}
if (total_written) {
dest.setPosition(-total_written, OS.File.POS_CURRENT);
dest.setPosition(-total_written, File.POS_CURRENT);
}
return pump_userland(source, dest, options);
}
@ -620,7 +621,7 @@
this._dir = UnixFile.opendir(this._path);
if (this._dir == null) {
let error = ctypes.errno;
if (error != OS.Constants.libc.ENOENT) {
if (error != Const.ENOENT) {
throw new File.Error("DirectoryIterator", error);
}
this._exists = false;
@ -663,11 +664,11 @@
// |dirent| doesn't have d_type on some platforms (e.g. Solaris).
let path = Path.join(this._path, name);
throw_on_negative("lstat", UnixFile.lstat(path, gStatDataPtr));
isDir = (gStatData.st_mode & OS.Constants.libc.S_IFMT) == OS.Constants.libc.S_IFDIR;
isSymLink = (gStatData.st_mode & OS.Constants.libc.S_IFMT) == OS.Constants.libc.S_IFLNK;
isDir = (gStatData.st_mode & Const.S_IFMT) == Const.S_IFDIR;
isSymLink = (gStatData.st_mode & Const.S_IFMT) == Const.S_IFLNK;
} else {
isDir = contents.d_type == OS.Constants.libc.DT_DIR;
isSymLink = contents.d_type == OS.Constants.libc.DT_LNK;
isDir = contents.d_type == Const.DT_DIR;
isSymLink = contents.d_type == Const.DT_LNK;
}
return new File.DirectoryIterator.Entry(isDir, isSymLink, name, this._path);
@ -713,9 +714,9 @@
this._parent = parent;
let path = Path.join(this._parent, name);
exports.OS.Shared.Unix.AbstractEntry.call(this, isDir, isSymLink, name, path);
SysAll.AbstractEntry.call(this, isDir, isSymLink, name, path);
};
File.DirectoryIterator.Entry.prototype = Object.create(exports.OS.Shared.Unix.AbstractEntry.prototype);
File.DirectoryIterator.Entry.prototype = Object.create(SysAll.AbstractEntry.prototype);
/**
* Return a version of an instance of
@ -737,28 +738,28 @@
return serialized;
};
let gStatData = new OS.Shared.Type.stat.implementation();
let gStatData = new Type.stat.implementation();
let gStatDataPtr = gStatData.address();
let MODE_MASK = 4095 /*= 07777*/;
File.Info = function Info(stat) {
let isDir = (stat.st_mode & OS.Constants.libc.S_IFMT) == OS.Constants.libc.S_IFDIR;
let isSymLink = (stat.st_mode & OS.Constants.libc.S_IFMT) == OS.Constants.libc.S_IFLNK;
let size = exports.OS.Shared.Type.size_t.importFromC(stat.st_size);
let isDir = (stat.st_mode & Const.S_IFMT) == Const.S_IFDIR;
let isSymLink = (stat.st_mode & Const.S_IFMT) == Const.S_IFLNK;
let size = Type.size_t.importFromC(stat.st_size);
let lastAccessDate = new Date(stat.st_atime * 1000);
let lastModificationDate = new Date(stat.st_mtime * 1000);
let unixLastStatusChangeDate = new Date(stat.st_ctime * 1000);
let unixOwner = exports.OS.Shared.Type.uid_t.importFromC(stat.st_uid);
let unixGroup = exports.OS.Shared.Type.gid_t.importFromC(stat.st_gid);
let unixMode = exports.OS.Shared.Type.mode_t.importFromC(stat.st_mode & MODE_MASK);
let unixOwner = Type.uid_t.importFromC(stat.st_uid);
let unixGroup = Type.gid_t.importFromC(stat.st_gid);
let unixMode = Type.mode_t.importFromC(stat.st_mode & MODE_MASK);
exports.OS.Shared.Unix.AbstractInfo.call(this, isDir, isSymLink, size, lastAccessDate,
lastModificationDate, unixLastStatusChangeDate,
unixOwner, unixGroup, unixMode);
SysAll.AbstractInfo.call(this, isDir, isSymLink, size, lastAccessDate,
lastModificationDate, unixLastStatusChangeDate,
unixOwner, unixGroup, unixMode);
// Some platforms (e.g. MacOS X, some BSDs) store a file creation date
if ("OSFILE_OFFSETOF_STAT_ST_BIRTHTIME" in OS.Constants.libc) {
if ("OSFILE_OFFSETOF_STAT_ST_BIRTHTIME" in Const) {
let date = new Date(stat.st_birthtime * 1000);
/**
@ -773,7 +774,7 @@
this.macBirthDate = date;
}
};
File.Info.prototype = Object.create(exports.OS.Shared.Unix.AbstractInfo.prototype);
File.Info.prototype = Object.create(SysAll.AbstractInfo.prototype);
// Deprecated, use macBirthDate/winBirthDate instead
Object.defineProperty(File.Info.prototype, "creationDate", {
@ -824,6 +825,7 @@
File.read = exports.OS.Shared.AbstractFile.read;
File.writeAtomic = exports.OS.Shared.AbstractFile.writeAtomic;
File.openUnique = exports.OS.Shared.AbstractFile.openUnique;
File.removeDir = exports.OS.Shared.AbstractFile.removeDir;
/**
@ -894,11 +896,12 @@
}
File.Unix = exports.OS.Unix.File;
File.Error = exports.OS.Shared.Unix.Error;
File.Error = SysAll.Error;
exports.OS.File = File;
exports.OS.Shared.Type = Type;
Object.defineProperty(File, "POS_START", { value: OS.Shared.POS_START });
Object.defineProperty(File, "POS_CURRENT", { value: OS.Shared.POS_CURRENT });
Object.defineProperty(File, "POS_END", { value: OS.Shared.POS_END });
Object.defineProperty(File, "POS_START", { value: SysAll.POS_START });
Object.defineProperty(File, "POS_CURRENT", { value: SysAll.POS_CURRENT });
Object.defineProperty(File, "POS_END", { value: SysAll.POS_END });
})(this);
}

View File

@ -8,354 +8,371 @@
* of OS.File.
*
* It serves the following purposes:
* - open libc;
* - open kernel32;
* - define OS.Shared.Win.Error;
* - define a few constants and types that need to be defined on all platforms.
*
* This module can be:
* - opened from the main thread as a jsm module;
* - opened from a chrome worker through importScripts.
* - opened from a chrome worker through require().
*/
"use strict";
let SharedAll;
if (typeof Components != "undefined") {
let Cu = Components.utils;
// Module is opened as a jsm module
this.EXPORTED_SYMBOLS = ["OS"];
Components.utils.import("resource://gre/modules/ctypes.jsm");
Cu.import("resource://gre/modules/ctypes.jsm", this);
SharedAll = {};
Components.utils.import("resource://gre/modules/osfile/osfile_shared_allthreads.jsm", SharedAll);
} else {
Cu.import("resource://gre/modules/osfile/osfile_shared_allthreads.jsm", SharedAll);
this.exports = {};
} else if (typeof "module" != "undefined" && typeof "require" != "undefined") {
// Module is loaded with require()
SharedAll = require("resource://gre/modules/osfile/osfile_shared_allthreads.jsm");
} else {
throw new Error("Please open this module with Component.utils.import or with require()");
}
(function(exports) {
"use strict";
if (exports.OS && exports.OS.Shared && exports.OS.Shared.Win) {
// Avoid double inclusion
return;
}
exports.OS = SharedAll.OS;
exports.OS.Shared.Win = {};
let LOG = SharedAll.LOG.bind(SharedAll, "Win", "allthreads");
let Const = SharedAll.Constants.Win;
let LOG = OS.Shared.LOG.bind(OS.Shared, "Win", "allthreads");
// Open libc
let libc;
try {
libc = ctypes.open("kernel32.dll");
} catch (ex) {
// Note: If you change the string here, please adapt consumers and
// tests accordingly
throw new Error("Could not open system library: " + ex.message);
}
exports.libc = libc;
// Open libc
let libc;
try {
libc = ctypes.open("kernel32.dll");
} catch (ex) {
// Note: If you change the string here, please adapt consumers and
// tests accordingly
throw new Error("Could not open system library: " + ex.message);
}
exports.OS.Shared.Win.libc = libc;
// Define declareFFI
let declareFFI = SharedAll.declareFFI.bind(null, libc);
exports.declareFFI = declareFFI;
// Define declareFFI
let declareFFI = OS.Shared.declareFFI.bind(null, libc);
exports.OS.Shared.Win.declareFFI = declareFFI;
// Define Error
let FormatMessage = libc.declare("FormatMessageW", ctypes.winapi_abi,
/*return*/ ctypes.uint32_t,
/*flags*/ ctypes.uint32_t,
/*source*/ ctypes.voidptr_t,
/*msgid*/ ctypes.uint32_t,
/*langid*/ ctypes.uint32_t,
/*buf*/ ctypes.jschar.ptr,
/*size*/ ctypes.uint32_t,
/*Arguments*/ctypes.voidptr_t
);
// Define Error
let FormatMessage = libc.declare("FormatMessageW", ctypes.winapi_abi,
/*return*/ ctypes.uint32_t,
/*flags*/ ctypes.uint32_t,
/*source*/ ctypes.voidptr_t,
/*msgid*/ ctypes.uint32_t,
/*langid*/ ctypes.uint32_t,
/*buf*/ ctypes.jschar.ptr,
/*size*/ ctypes.uint32_t,
/*Arguments*/ctypes.voidptr_t
/**
* A File-related error.
*
* To obtain a human-readable error message, use method |toString|.
* To determine the cause of the error, use the various |becauseX|
* getters. To determine the operation that failed, use field
* |operation|.
*
* Additionally, this implementation offers a field
* |winLastError|, which holds the OS-specific error
* constant. If you need this level of detail, you may match the value
* of this field against the error constants of |OS.Constants.Win|.
*
* @param {string=} operation The operation that failed. If unspecified,
* the name of the calling function is taken to be the operation that
* failed.
* @param {number=} lastError The OS-specific constant detailing the
* reason of the error. If unspecified, this is fetched from the system
* status.
*
* @constructor
* @extends {OS.Shared.Error}
*/
let OSError = function OSError(operation, lastError) {
operation = operation || "unknown operation";
SharedAll.OSError.call(this, operation);
this.winLastError = lastError || ctypes.winLastError;
};
OSError.prototype = Object.create(SharedAll.OSError.prototype);
OSError.prototype.toString = function toString() {
let buf = new (ctypes.ArrayType(ctypes.jschar, 1024))();
let result = FormatMessage(
Const.FORMAT_MESSAGE_FROM_SYSTEM |
Const.FORMAT_MESSAGE_IGNORE_INSERTS,
null,
/* The error number */ this.winLastError,
/* Default language */ 0,
/* Output buffer*/ buf,
/* Minimum size of buffer */ 1024,
/* Format args*/ null
);
if (!result) {
buf = "additional error " +
ctypes.winLastError +
" while fetching system error message";
}
return "Win error " + this.winLastError + " during operation "
+ this.operation + " (" + buf.readString() + ")";
};
/**
* |true| if the error was raised because a file or directory
* already exists, |false| otherwise.
*/
Object.defineProperty(OSError.prototype, "becauseExists", {
get: function becauseExists() {
return this.winLastError == Const.ERROR_FILE_EXISTS ||
this.winLastError == Const.ERROR_ALREADY_EXISTS;
}
});
/**
* |true| if the error was raised because a file or directory
* does not exist, |false| otherwise.
*/
Object.defineProperty(OSError.prototype, "becauseNoSuchFile", {
get: function becauseNoSuchFile() {
return this.winLastError == Const.ERROR_FILE_NOT_FOUND;
}
});
/**
* |true| if the error was raised because a directory is not empty
* does not exist, |false| otherwise.
*/
Object.defineProperty(OSError.prototype, "becauseNotEmpty", {
get: function becauseNotEmpty() {
return this.winLastError == Const.ERROR_DIR_NOT_EMPTY;
}
});
/**
* |true| if the error was raised because a file or directory
* is closed, |false| otherwise.
*/
Object.defineProperty(OSError.prototype, "becauseClosed", {
get: function becauseClosed() {
return this.winLastError == Const.ERROR_INVALID_HANDLE;
}
});
/**
* |true| if the error was raised because permission is denied to
* access a file or directory, |false| otherwise.
*/
Object.defineProperty(OSError.prototype, "becauseAccessDenied", {
get: function becauseAccessDenied() {
return this.winLastError == Const.ERROR_ACCESS_DENIED;
}
});
/**
* Serialize an instance of OSError to something that can be
* transmitted across threads (not necessarily a string).
*/
OSError.toMsg = function toMsg(error) {
return {
operation: error.operation,
winLastError: error.winLastError
};
};
/**
* Deserialize a message back to an instance of OSError
*/
OSError.fromMsg = function fromMsg(msg) {
return new OSError(msg.operation, msg.winLastError);
};
exports.Error = OSError;
/**
* Code shared by implementation of File.Info on Windows
*
* @constructor
*/
let AbstractInfo = function AbstractInfo(isDir, isSymLink, size, winBirthDate,
lastAccessDate, lastWriteDate) {
this._isDir = isDir;
this._isSymLink = isSymLink;
this._size = size;
this._winBirthDate = winBirthDate;
this._lastAccessDate = lastAccessDate;
this._lastModificationDate = lastWriteDate;
};
AbstractInfo.prototype = {
/**
* A File-related error.
* |true| if this file is a directory, |false| otherwise
*/
get isDir() {
return this._isDir;
},
/**
* |true| if this file is a symbolic link, |false| otherwise
*/
get isSymLink() {
return this._isSymLink;
},
/**
* The size of the file, in bytes.
*
* To obtain a human-readable error message, use method |toString|.
* To determine the cause of the error, use the various |becauseX|
* getters. To determine the operation that failed, use field
* |operation|.
* Note that the result may be |NaN| if the size of the file cannot be
* represented in JavaScript.
*
* Additionally, this implementation offers a field
* |winLastError|, which holds the OS-specific error
* constant. If you need this level of detail, you may match the value
* of this field against the error constants of |OS.Constants.Win|.
* @type {number}
*/
get size() {
return this._size;
},
// Deprecated
get creationDate() {
return this._winBirthDate;
},
/**
* The date of creation of this file.
*
* @param {string=} operation The operation that failed. If unspecified,
* the name of the calling function is taken to be the operation that
* failed.
* @param {number=} lastError The OS-specific constant detailing the
* reason of the error. If unspecified, this is fetched from the system
* status.
* @type {Date}
*/
get winBirthDate() {
return this._winBirthDate;
},
/**
* The date of last access to this file.
*
* @constructor
* @extends {OS.Shared.Error}
*/
let OSError = function OSError(operation, lastError) {
operation = operation || "unknown operation";
exports.OS.Shared.Error.call(this, operation);
this.winLastError = lastError || ctypes.winLastError;
};
OSError.prototype = new exports.OS.Shared.Error();
OSError.prototype.toString = function toString() {
let buf = new (ctypes.ArrayType(ctypes.jschar, 1024))();
let result = FormatMessage(
exports.OS.Constants.Win.FORMAT_MESSAGE_FROM_SYSTEM |
exports.OS.Constants.Win.FORMAT_MESSAGE_IGNORE_INSERTS,
null,
/* The error number */ this.winLastError,
/* Default language */ 0,
/* Output buffer*/ buf,
/* Minimum size of buffer */ 1024,
/* Format args*/ null
);
if (!result) {
buf = "additional error " +
ctypes.winLastError +
" while fetching system error message";
}
return "Win error " + this.winLastError + " during operation "
+ this.operation + " (" + buf.readString() + ")";
};
/**
* |true| if the error was raised because a file or directory
* already exists, |false| otherwise.
*/
Object.defineProperty(OSError.prototype, "becauseExists", {
get: function becauseExists() {
return this.winLastError == exports.OS.Constants.Win.ERROR_FILE_EXISTS ||
this.winLastError == exports.OS.Constants.Win.ERROR_ALREADY_EXISTS;
}
});
/**
* |true| if the error was raised because a file or directory
* does not exist, |false| otherwise.
*/
Object.defineProperty(OSError.prototype, "becauseNoSuchFile", {
get: function becauseNoSuchFile() {
return this.winLastError == exports.OS.Constants.Win.ERROR_FILE_NOT_FOUND;
}
});
/**
* |true| if the error was raised because a directory is not empty
* does not exist, |false| otherwise.
*/
Object.defineProperty(OSError.prototype, "becauseNotEmpty", {
get: function becauseNotEmpty() {
return this.winLastError == OS.Constants.Win.ERROR_DIR_NOT_EMPTY;
}
});
/**
* |true| if the error was raised because a file or directory
* is closed, |false| otherwise.
*/
Object.defineProperty(OSError.prototype, "becauseClosed", {
get: function becauseClosed() {
return this.winLastError == exports.OS.Constants.Win.ERROR_INVALID_HANDLE;
}
});
/**
* |true| if the error was raised because permission is denied to
* access a file or directory, |false| otherwise.
*/
Object.defineProperty(OSError.prototype, "becauseAccessDenied", {
get: function becauseAccessDenied() {
return this.winLastError == exports.OS.Constants.Win.ERROR_ACCESS_DENIED;
}
});
/**
* Serialize an instance of OSError to something that can be
* transmitted across threads (not necessarily a string).
*/
OSError.toMsg = function toMsg(error) {
return {
operation: error.operation,
winLastError: error.winLastError
};
};
/**
* Deserialize a message back to an instance of OSError
*/
OSError.fromMsg = function fromMsg(msg) {
return new OSError(msg.operation, msg.winLastError);
};
exports.OS.Shared.Win.Error = OSError;
/**
* Code shared by implementation of File.Info on Windows
* Note that the definition of last access may depend on the underlying
* operating system and file system.
*
* @constructor
* @type {Date}
*/
let AbstractInfo = function AbstractInfo(isDir, isSymLink, size, winBirthDate,
lastAccessDate, lastWriteDate) {
this._isDir = isDir;
this._isSymLink = isSymLink;
this._size = size;
this._winBirthDate = winBirthDate;
this._lastAccessDate = lastAccessDate;
this._lastModificationDate = lastWriteDate;
};
AbstractInfo.prototype = {
/**
* |true| if this file is a directory, |false| otherwise
*/
get isDir() {
return this._isDir;
},
/**
* |true| if this file is a symbolic link, |false| otherwise
*/
get isSymLink() {
return this._isSymLink;
},
/**
* The size of the file, in bytes.
*
* Note that the result may be |NaN| if the size of the file cannot be
* represented in JavaScript.
*
* @type {number}
*/
get size() {
return this._size;
},
// Deprecated
get creationDate() {
return this._winBirthDate;
},
/**
* The date of creation of this file.
*
* @type {Date}
*/
get winBirthDate() {
return this._winBirthDate;
},
/**
* The date of last access to this file.
*
* Note that the definition of last access may depend on the underlying
* operating system and file system.
*
* @type {Date}
*/
get lastAccessDate() {
return this._lastAccessDate;
},
/**
* The date of last modification of this file.
*
* Note that the definition of last access may depend on the underlying
* operating system and file system.
*
* @type {Date}
*/
get lastModificationDate() {
return this._lastModificationDate;
}
};
exports.OS.Shared.Win.AbstractInfo = AbstractInfo;
get lastAccessDate() {
return this._lastAccessDate;
},
/**
* Code shared by implementation of File.DirectoryIterator.Entry on Windows
* The date of last modification of this file.
*
* @constructor
* Note that the definition of last access may depend on the underlying
* operating system and file system.
*
* @type {Date}
*/
let AbstractEntry = function AbstractEntry(isDir, isSymLink, name,
winCreationDate, winLastWriteDate,
winLastAccessDate, path) {
this._isDir = isDir;
this._isSymLink = isSymLink;
this._name = name;
this._winCreationDate = winCreationDate;
this._winLastWriteDate = winLastWriteDate;
this._winLastAccessDate = winLastAccessDate;
this._path = path;
};
get lastModificationDate() {
return this._lastModificationDate;
}
};
exports.AbstractInfo = AbstractInfo;
AbstractEntry.prototype = {
/**
* |true| if the entry is a directory, |false| otherwise
*/
get isDir() {
return this._isDir;
},
/**
* |true| if the entry is a symbolic link, |false| otherwise
*/
get isSymLink() {
return this._isSymLink;
},
/**
* The name of the entry.
* @type {string}
*/
get name() {
return this._name;
},
/**
* The creation time of this file.
* @type {Date}
*/
get winCreationDate() {
return this._winCreationDate;
},
/**
* The last modification time of this file.
* @type {Date}
*/
get winLastWriteDate() {
return this._winLastWriteDate;
},
/**
* The last access time of this file.
* @type {Date}
*/
get winLastAccessDate() {
return this._winLastAccessDate;
},
/**
* The full path of the entry
* @type {string}
*/
get path() {
return this._path;
}
};
exports.OS.Shared.Win.AbstractEntry = AbstractEntry;
// Special constants that need to be defined on all platforms
Object.defineProperty(exports.OS.Shared, "POS_START", { value: exports.OS.Constants.Win.FILE_BEGIN });
Object.defineProperty(exports.OS.Shared, "POS_CURRENT", { value: exports.OS.Constants.Win.FILE_CURRENT });
Object.defineProperty(exports.OS.Shared, "POS_END", { value: exports.OS.Constants.Win.FILE_END });
// Special types that need to be defined for communication
// between threads
let Types = exports.OS.Shared.Type;
/**
* Code shared by implementation of File.DirectoryIterator.Entry on Windows
*
* @constructor
*/
let AbstractEntry = function AbstractEntry(isDir, isSymLink, name,
winCreationDate, winLastWriteDate,
winLastAccessDate, path) {
this._isDir = isDir;
this._isSymLink = isSymLink;
this._name = name;
this._winCreationDate = winCreationDate;
this._winLastWriteDate = winLastWriteDate;
this._winLastAccessDate = winLastAccessDate;
this._path = path;
};
AbstractEntry.prototype = {
/**
* Native paths
*
* Under Windows, expressed as wide strings
* |true| if the entry is a directory, |false| otherwise
*/
Types.path = Types.wstring.withName("[in] path");
Types.out_path = Types.out_wstring.withName("[out] path");
get isDir() {
return this._isDir;
},
/**
* |true| if the entry is a symbolic link, |false| otherwise
*/
get isSymLink() {
return this._isSymLink;
},
/**
* The name of the entry.
* @type {string}
*/
get name() {
return this._name;
},
/**
* The creation time of this file.
* @type {Date}
*/
get winCreationDate() {
return this._winCreationDate;
},
/**
* The last modification time of this file.
* @type {Date}
*/
get winLastWriteDate() {
return this._winLastWriteDate;
},
/**
* The last access time of this file.
* @type {Date}
*/
get winLastAccessDate() {
return this._winLastAccessDate;
},
/**
* The full path of the entry
* @type {string}
*/
get path() {
return this._path;
}
};
exports.AbstractEntry = AbstractEntry;
// Special constructors that need to be defined on all threads
OSError.closed = function closed(operation) {
return new OSError(operation, exports.OS.Constants.Win.ERROR_INVALID_HANDLE);
};
// Special constants that need to be defined on all platforms
OSError.exists = function exists(operation) {
return new OSError(operation, exports.OS.Constants.Win.ERROR_FILE_EXISTS);
};
exports.POS_START = Const.FILE_BEGIN;
exports.POS_CURRENT = Const.FILE_CURRENT;
exports.POS_END = Const.FILE_END;
OSError.noSuchFile = function noSuchFile(operation) {
return new OSError(operation, exports.OS.Constants.Win.ERROR_FILE_NOT_FOUND);
};
})(this);
// Special types that need to be defined for communication
// between threads
let Type = Object.create(SharedAll.Type);
exports.Type = Type;
/**
* Native paths
*
* Under Windows, expressed as wide strings
*/
Type.path = Type.wstring.withName("[in] path");
Type.out_path = Type.out_wstring.withName("[out] path");
// Special constructors that need to be defined on all threads
OSError.closed = function closed(operation) {
return new OSError(operation, Const.ERROR_INVALID_HANDLE);
};
OSError.exists = function exists(operation) {
return new OSError(operation, Const.ERROR_FILE_EXISTS);
};
OSError.noSuchFile = function noSuchFile(operation) {
return new OSError(operation, Const.ERROR_FILE_NOT_FOUND);
};
let EXPORTED_SYMBOLS = [
"declareFFI",
"libc",
"Error",
"AbstractInfo",
"AbstractEntry",
"Type",
"POS_START",
"POS_CURRENT",
"POS_END"
];
//////////// Boilerplate
if (typeof Components != "undefined") {
this.EXPORTED_SYMBOLS = EXPORTED_SYMBOLS;
for (let symbol of EXPORTED_SYMBOLS) {
this[symbol] = exports[symbol];
}
}

View File

@ -34,11 +34,12 @@
if (exports.OS && exports.OS.Win && exports.OS.Win.File) {
return; // Avoid double initialization
}
exports.OS = require("resource://gre/modules/osfile/osfile_shared_allthreads.jsm").OS;
exports.OS.Win.File = {};
let LOG = OS.Shared.LOG.bind(OS.Shared, "Win", "back");
let libc = exports.OS.Shared.Win.libc;
let SharedAll = require("resource://gre/modules/osfile/osfile_shared_allthreads.jsm");
let SysAll = require("resource://gre/modules/osfile/osfile_win_allthreads.jsm");
let LOG = SharedAll.LOG.bind(SharedAll, "Unix", "back");
let libc = SysAll.libc;
let Const = SharedAll.Constants.Win;
/**
* Initialize the Windows module.
@ -51,17 +52,14 @@
if (aDeclareFFI) {
declareFFI = aDeclareFFI.bind(null, libc);
} else {
declareFFI = exports.OS.Shared.Win.declareFFI;
declareFFI = SysAll.declareFFI;
}
// Shorthands
let OSWin = exports.OS.Win;
let WinFile = exports.OS.Win.File;
if (!exports.OS.Types) {
exports.OS.Types = {};
}
let Type = exports.OS.Shared.Type;
let Types = Type;
// Initialize types that require additional OS-specific
// support - either finalization or matching against
// OS-specific constants.
let Type = Object.create(SysAll.Type);
let SysFile = exports.OS.Win.File = { Type: Type };
// Initialize types
@ -69,10 +67,10 @@
* A C integer holding INVALID_HANDLE_VALUE in case of error or
* a file descriptor in case of success.
*/
Types.HANDLE =
Types.voidptr_t.withName("HANDLE");
Types.HANDLE.importFromC = function importFromC(maybe) {
if (Types.int.cast(maybe).value == INVALID_HANDLE) {
Type.HANDLE =
Type.voidptr_t.withName("HANDLE");
Type.HANDLE.importFromC = function importFromC(maybe) {
if (Type.int.cast(maybe).value == INVALID_HANDLE) {
// Ensure that API clients can effectively compare against
// Const.INVALID_HANDLE_VALUE. Without this cast,
// == would always return |false|.
@ -80,88 +78,88 @@
}
return ctypes.CDataFinalizer(maybe, this.finalizeHANDLE);
};
Types.HANDLE.finalizeHANDLE = function placeholder() {
Type.HANDLE.finalizeHANDLE = function placeholder() {
throw new Error("finalizeHANDLE should be implemented");
};
let INVALID_HANDLE = exports.OS.Constants.Win.INVALID_HANDLE_VALUE;
let INVALID_HANDLE = Const.INVALID_HANDLE_VALUE;
Types.file_HANDLE = Types.HANDLE.withName("file HANDLE");
exports.OS.Shared.defineLazyGetter(Types.file_HANDLE,
Type.file_HANDLE = Type.HANDLE.withName("file HANDLE");
SharedAll.defineLazyGetter(Type.file_HANDLE,
"finalizeHANDLE",
function() {
return _CloseHandle;
});
Types.find_HANDLE = Types.HANDLE.withName("find HANDLE");
exports.OS.Shared.defineLazyGetter(Types.find_HANDLE,
Type.find_HANDLE = Type.HANDLE.withName("find HANDLE");
SharedAll.defineLazyGetter(Type.find_HANDLE,
"finalizeHANDLE",
function() {
return _FindClose;
});
Types.DWORD = Types.int32_t.withName("DWORD");
Type.DWORD = Type.int32_t.withName("DWORD");
/**
* A C integer holding -1 in case of error or a positive integer
* in case of success.
*/
Types.negative_or_DWORD =
Types.DWORD.withName("negative_or_DWORD");
Type.negative_or_DWORD =
Type.DWORD.withName("negative_or_DWORD");
/**
* A C integer holding 0 in case of error or a positive integer
* in case of success.
*/
Types.zero_or_DWORD =
Types.DWORD.withName("zero_or_DWORD");
Type.zero_or_DWORD =
Type.DWORD.withName("zero_or_DWORD");
/**
* A C integer holding 0 in case of error, any other value in
* case of success.
*/
Types.zero_or_nothing =
Types.int.withName("zero_or_nothing");
Type.zero_or_nothing =
Type.int.withName("zero_or_nothing");
Types.SECURITY_ATTRIBUTES =
Types.void_t.withName("SECURITY_ATTRIBUTES");
Type.SECURITY_ATTRIBUTES =
Type.void_t.withName("SECURITY_ATTRIBUTES");
Types.FILETIME =
new Type("FILETIME",
Type.FILETIME =
new SharedAll.Type("FILETIME",
ctypes.StructType("FILETIME", [
{ lo: Types.DWORD.implementation },
{ hi: Types.DWORD.implementation }]));
{ lo: Type.DWORD.implementation },
{ hi: Type.DWORD.implementation }]));
Types.FindData =
new Type("FIND_DATA",
Type.FindData =
new SharedAll.Type("FIND_DATA",
ctypes.StructType("FIND_DATA", [
{ dwFileAttributes: ctypes.uint32_t },
{ ftCreationTime: Types.FILETIME.implementation },
{ ftLastAccessTime: Types.FILETIME.implementation },
{ ftLastWriteTime: Types.FILETIME.implementation },
{ nFileSizeHigh: Types.DWORD.implementation },
{ nFileSizeLow: Types.DWORD.implementation },
{ dwReserved0: Types.DWORD.implementation },
{ dwReserved1: Types.DWORD.implementation },
{ cFileName: ctypes.ArrayType(ctypes.jschar, exports.OS.Constants.Win.MAX_PATH) },
{ ftCreationTime: Type.FILETIME.implementation },
{ ftLastAccessTime: Type.FILETIME.implementation },
{ ftLastWriteTime: Type.FILETIME.implementation },
{ nFileSizeHigh: Type.DWORD.implementation },
{ nFileSizeLow: Type.DWORD.implementation },
{ dwReserved0: Type.DWORD.implementation },
{ dwReserved1: Type.DWORD.implementation },
{ cFileName: ctypes.ArrayType(ctypes.jschar, Const.MAX_PATH) },
{ cAlternateFileName: ctypes.ArrayType(ctypes.jschar, 14) }
]));
Types.FILE_INFORMATION =
new Type("FILE_INFORMATION",
Type.FILE_INFORMATION =
new SharedAll.Type("FILE_INFORMATION",
ctypes.StructType("FILE_INFORMATION", [
{ dwFileAttributes: ctypes.uint32_t },
{ ftCreationTime: Types.FILETIME.implementation },
{ ftLastAccessTime: Types.FILETIME.implementation },
{ ftLastWriteTime: Types.FILETIME.implementation },
{ ftCreationTime: Type.FILETIME.implementation },
{ ftLastAccessTime: Type.FILETIME.implementation },
{ ftLastWriteTime: Type.FILETIME.implementation },
{ dwVolumeSerialNumber: ctypes.uint32_t },
{ nFileSizeHigh: Types.DWORD.implementation },
{ nFileSizeLow: Types.DWORD.implementation },
{ nFileSizeHigh: Type.DWORD.implementation },
{ nFileSizeLow: Type.DWORD.implementation },
{ nNumberOfLinks: ctypes.uint32_t },
{ nFileIndex: ctypes.uint64_t }
]));
Types.SystemTime =
new Type("SystemTime",
Type.SystemTime =
new SharedAll.Type("SystemTime",
ctypes.StructType("SystemTime", [
{ wYear: ctypes.int16_t },
{ wMonth: ctypes.int16_t },
@ -175,12 +173,12 @@
// Special case: these functions are used by the
// finalizer
let _CloseHandle = WinFile._CloseHandle =
let _CloseHandle = SysFile._CloseHandle =
libc.declare("CloseHandle", ctypes.winapi_abi,
/*return */ctypes.bool,
/*handle*/ ctypes.voidptr_t);
WinFile.CloseHandle = function(fd) {
SysFile.CloseHandle = function(fd) {
if (fd == INVALID_HANDLE) {
return true;
} else {
@ -193,7 +191,7 @@
/*return */ctypes.bool,
/*handle*/ ctypes.voidptr_t);
WinFile.FindClose = function(handle) {
SysFile.FindClose = function(handle) {
if (handle == INVALID_HANDLE) {
return true;
} else {
@ -203,135 +201,140 @@
// Declare libc functions as functions of |OS.Win.File|
WinFile.CopyFile =
SysFile.CopyFile =
declareFFI("CopyFileW", ctypes.winapi_abi,
/*return*/ Types.zero_or_nothing,
/*sourcePath*/ Types.path,
/*destPath*/ Types.path,
/*bailIfExist*/Types.bool);
/*return*/ Type.zero_or_nothing,
/*sourcePath*/ Type.path,
/*destPath*/ Type.path,
/*bailIfExist*/Type.bool);
WinFile.CreateDirectory =
SysFile.CreateDirectory =
declareFFI("CreateDirectoryW", ctypes.winapi_abi,
/*return*/ Types.zero_or_nothing,
/*name*/ Types.jschar.in_ptr,
/*security*/Types.SECURITY_ATTRIBUTES.in_ptr);
/*return*/ Type.zero_or_nothing,
/*name*/ Type.jschar.in_ptr,
/*security*/Type.SECURITY_ATTRIBUTES.in_ptr);
WinFile.CreateFile =
SysFile.CreateFile =
declareFFI("CreateFileW", ctypes.winapi_abi,
/*return*/ Types.file_HANDLE,
/*name*/ Types.path,
/*access*/ Types.DWORD,
/*share*/ Types.DWORD,
/*security*/Types.SECURITY_ATTRIBUTES.in_ptr,
/*creation*/Types.DWORD,
/*flags*/ Types.DWORD,
/*template*/Types.HANDLE);
/*return*/ Type.file_HANDLE,
/*name*/ Type.path,
/*access*/ Type.DWORD,
/*share*/ Type.DWORD,
/*security*/Type.SECURITY_ATTRIBUTES.in_ptr,
/*creation*/Type.DWORD,
/*flags*/ Type.DWORD,
/*template*/Type.HANDLE);
WinFile.DeleteFile =
SysFile.DeleteFile =
declareFFI("DeleteFileW", ctypes.winapi_abi,
/*return*/ Types.zero_or_nothing,
/*path*/ Types.path);
/*return*/ Type.zero_or_nothing,
/*path*/ Type.path);
WinFile.FileTimeToSystemTime =
SysFile.FileTimeToSystemTime =
declareFFI("FileTimeToSystemTime", ctypes.winapi_abi,
/*return*/ Types.zero_or_nothing,
/*filetime*/Types.FILETIME.in_ptr,
/*systime*/ Types.SystemTime.out_ptr);
/*return*/ Type.zero_or_nothing,
/*filetime*/Type.FILETIME.in_ptr,
/*systime*/ Type.SystemTime.out_ptr);
WinFile.FindFirstFile =
SysFile.FindFirstFile =
declareFFI("FindFirstFileW", ctypes.winapi_abi,
/*return*/ Types.find_HANDLE,
/*pattern*/Types.path,
/*data*/ Types.FindData.out_ptr);
/*return*/ Type.find_HANDLE,
/*pattern*/Type.path,
/*data*/ Type.FindData.out_ptr);
WinFile.FindNextFile =
SysFile.FindNextFile =
declareFFI("FindNextFileW", ctypes.winapi_abi,
/*return*/ Types.zero_or_nothing,
/*prev*/ Types.find_HANDLE,
/*data*/ Types.FindData.out_ptr);
/*return*/ Type.zero_or_nothing,
/*prev*/ Type.find_HANDLE,
/*data*/ Type.FindData.out_ptr);
WinFile.FormatMessage =
SysFile.FormatMessage =
declareFFI("FormatMessageW", ctypes.winapi_abi,
/*return*/ Types.DWORD,
/*flags*/ Types.DWORD,
/*source*/ Types.void_t.in_ptr,
/*msgid*/ Types.DWORD,
/*langid*/ Types.DWORD,
/*buf*/ Types.out_wstring,
/*size*/ Types.DWORD,
/*Arguments*/Types.void_t.in_ptr
/*return*/ Type.DWORD,
/*flags*/ Type.DWORD,
/*source*/ Type.void_t.in_ptr,
/*msgid*/ Type.DWORD,
/*langid*/ Type.DWORD,
/*buf*/ Type.out_wstring,
/*size*/ Type.DWORD,
/*Arguments*/Type.void_t.in_ptr
);
WinFile.GetCurrentDirectory =
SysFile.GetCurrentDirectory =
declareFFI("GetCurrentDirectoryW", ctypes.winapi_abi,
/*return*/ Types.zero_or_DWORD,
/*length*/ Types.DWORD,
/*buf*/ Types.out_path
/*return*/ Type.zero_or_DWORD,
/*length*/ Type.DWORD,
/*buf*/ Type.out_path
);
WinFile.GetFileInformationByHandle =
SysFile.GetFileInformationByHandle =
declareFFI("GetFileInformationByHandle", ctypes.winapi_abi,
/*return*/ Types.zero_or_nothing,
/*handle*/ Types.HANDLE,
/*info*/ Types.FILE_INFORMATION.out_ptr);
/*return*/ Type.zero_or_nothing,
/*handle*/ Type.HANDLE,
/*info*/ Type.FILE_INFORMATION.out_ptr);
WinFile.MoveFileEx =
SysFile.MoveFileEx =
declareFFI("MoveFileExW", ctypes.winapi_abi,
/*return*/ Types.zero_or_nothing,
/*sourcePath*/ Types.path,
/*destPath*/ Types.path,
/*flags*/ Types.DWORD
/*return*/ Type.zero_or_nothing,
/*sourcePath*/ Type.path,
/*destPath*/ Type.path,
/*flags*/ Type.DWORD
);
WinFile.ReadFile =
SysFile.ReadFile =
declareFFI("ReadFile", ctypes.winapi_abi,
/*return*/ Types.zero_or_nothing,
/*file*/ Types.HANDLE,
/*buffer*/ Types.voidptr_t,
/*nbytes*/ Types.DWORD,
/*nbytes_read*/Types.DWORD.out_ptr,
/*overlapped*/Types.void_t.inout_ptr // FIXME: Implement?
/*return*/ Type.zero_or_nothing,
/*file*/ Type.HANDLE,
/*buffer*/ Type.voidptr_t,
/*nbytes*/ Type.DWORD,
/*nbytes_read*/Type.DWORD.out_ptr,
/*overlapped*/Type.void_t.inout_ptr // FIXME: Implement?
);
WinFile.RemoveDirectory =
SysFile.RemoveDirectory =
declareFFI("RemoveDirectoryW", ctypes.winapi_abi,
/*return*/ Types.zero_or_nothing,
/*path*/ Types.path);
/*return*/ Type.zero_or_nothing,
/*path*/ Type.path);
WinFile.SetCurrentDirectory =
SysFile.SetCurrentDirectory =
declareFFI("SetCurrentDirectoryW", ctypes.winapi_abi,
/*return*/ Types.zero_or_nothing,
/*path*/ Types.path
/*return*/ Type.zero_or_nothing,
/*path*/ Type.path
);
WinFile.SetEndOfFile =
SysFile.SetEndOfFile =
declareFFI("SetEndOfFile", ctypes.winapi_abi,
/*return*/ Types.zero_or_nothing,
/*file*/ Types.HANDLE);
/*return*/ Type.zero_or_nothing,
/*file*/ Type.HANDLE);
WinFile.SetFilePointer =
SysFile.SetFilePointer =
declareFFI("SetFilePointer", ctypes.winapi_abi,
/*return*/ Types.negative_or_DWORD,
/*file*/ Types.HANDLE,
/*distlow*/Types.long,
/*disthi*/ Types.long.in_ptr,
/*method*/ Types.DWORD);
/*return*/ Type.negative_or_DWORD,
/*file*/ Type.HANDLE,
/*distlow*/Type.long,
/*disthi*/ Type.long.in_ptr,
/*method*/ Type.DWORD);
WinFile.WriteFile =
SysFile.WriteFile =
declareFFI("WriteFile", ctypes.winapi_abi,
/*return*/ Types.zero_or_nothing,
/*file*/ Types.HANDLE,
/*buffer*/ Types.voidptr_t,
/*nbytes*/ Types.DWORD,
/*nbytes_wr*/Types.DWORD.out_ptr,
/*overlapped*/Types.void_t.inout_ptr // FIXME: Implement?
/*return*/ Type.zero_or_nothing,
/*file*/ Type.HANDLE,
/*buffer*/ Type.voidptr_t,
/*nbytes*/ Type.DWORD,
/*nbytes_wr*/Type.DWORD.out_ptr,
/*overlapped*/Type.void_t.inout_ptr // FIXME: Implement?
);
WinFile.FlushFileBuffers =
SysFile.FlushFileBuffers =
declareFFI("FlushFileBuffers", ctypes.winapi_abi,
/*return*/ Types.zero_or_nothing,
/*file*/ Types.HANDLE);
/*return*/ Type.zero_or_nothing,
/*file*/ Type.HANDLE);
};
exports.OS.Win = {
File: {
_init: init
}
};
exports.OS.Win.File._init = init;
})(this);
}

View File

@ -19,18 +19,19 @@
(function(exports) {
"use strict";
exports.OS = require("resource://gre/modules/osfile/osfile_shared_allthreads.jsm").OS;
let Path = require("resource://gre/modules/osfile/ospath.jsm");
// exports.OS.Win is created by osfile_win_back.jsm
if (exports.OS && exports.OS.File) {
return; // Avoid double-initialization
}
let SharedAll = require("resource://gre/modules/osfile/osfile_shared_allthreads.jsm");
let Path = require("resource://gre/modules/osfile/ospath.jsm");
let SysAll = require("resource://gre/modules/osfile/osfile_win_allthreads.jsm");
exports.OS.Win.File._init();
let Const = exports.OS.Constants.Win;
let WinFile = exports.OS.Win.File;
let LOG = OS.Shared.LOG.bind(OS.Shared, "Win front-end");
let Type = WinFile.Type;
// Mutable thread-global data
// In the Windows implementation, methods |read| and |write|
@ -47,7 +48,7 @@
let gBytesWrittenPtr = gBytesWritten.address();
// Same story for GetFileInformationByHandle
let gFileInfo = new OS.Shared.Type.FILE_INFORMATION.implementation();
let gFileInfo = new Type.FILE_INFORMATION.implementation();
let gFileInfoPtr = gFileInfo.address();
/**
@ -388,7 +389,7 @@
let result = WinFile.CreateDirectory(path, security);
if (result ||
options.ignoreExisting &&
ctypes.winLastError == OS.Constants.Win.ERROR_ALREADY_EXISTS) {
ctypes.winLastError == Const.ERROR_ALREADY_EXISTS) {
return;
}
throw new File.Error("makeDir");
@ -465,7 +466,7 @@
/**
* A global value used to receive data during time conversions.
*/
let gSystemTime = new OS.Shared.Type.SystemTime.implementation();
let gSystemTime = new Type.SystemTime.implementation();
let gSystemTimePtr = gSystemTime.address();
/**
@ -514,7 +515,7 @@
// Pre-open the first item.
this._first = true;
this._findData = new OS.Shared.Type.FindData.implementation();
this._findData = new Type.FindData.implementation();
this._findDataPtr = this._findData.address();
this._handle = WinFile.FindFirstFile(this._pattern, this._findDataPtr);
if (this._handle == Const.INVALID_HANDLE_VALUE) {
@ -523,12 +524,12 @@
this._findDataPtr = null;
if (error == Const.ERROR_FILE_NOT_FOUND) {
// Directory is empty, let's behave as if it were closed
LOG("Directory is empty");
SharedAll.LOG("Directory is empty");
this._closed = true;
this._exists = true;
} else if (error == Const.ERROR_PATH_NOT_FOUND) {
// Directory does not exist, let's throw if we attempt to walk it
LOG("Directory does not exist");
SharedAll.LOG("Directory does not exist");
this._closed = true;
this._exists = false;
} else {
@ -650,11 +651,11 @@
let path = Path.join(this._parent, name);
exports.OS.Shared.Win.AbstractEntry.call(this, isDir, isSymLink, name,
winCreationDate, winLastWriteDate,
winLastAccessDate, path);
SysAll.AbstractEntry.call(this, isDir, isSymLink, name,
winCreationDate, winLastWriteDate,
winLastAccessDate, path);
};
File.DirectoryIterator.Entry.prototype = Object.create(exports.OS.Shared.Win.AbstractEntry.prototype);
File.DirectoryIterator.Entry.prototype = Object.create(SysAll.AbstractEntry.prototype);
/**
* Return a version of an instance of
@ -695,13 +696,13 @@
let lastWriteDate = FILETIME_to_Date(stat.ftLastWriteTime);
let value = ctypes.UInt64.join(stat.nFileSizeHigh, stat.nFileSizeLow);
let size = exports.OS.Shared.Type.uint64_t.importFromC(value);
let size = Type.uint64_t.importFromC(value);
exports.OS.Shared.Win.AbstractInfo.call(this, isDir, isSymLink, size,
winBirthDate, lastAccessDate,
lastWriteDate);
SysAll.AbstractInfo.call(this, isDir, isSymLink, size,
winBirthDate, lastAccessDate,
lastWriteDate);
};
File.Info.prototype = Object.create(exports.OS.Shared.Win.AbstractInfo.prototype);
File.Info.prototype = Object.create(SysAll.AbstractInfo.prototype);
/**
* Return a version of an instance of File.Info that can be sent
@ -744,53 +745,54 @@
// All of the following is required to ensure that File.stat
// also works on directories.
const FILE_STAT_MODE = {
read:true
read: true
};
const FILE_STAT_OPTIONS = {
// Directories can be opened neither for reading(!) nor for writing
winAccess: 0,
// Directories can only be opened with backup semantics(!)
winFlags: OS.Constants.Win.FILE_FLAG_BACKUP_SEMANTICS,
winDisposition: OS.Constants.Win.OPEN_EXISTING
winFlags: Const.FILE_FLAG_BACKUP_SEMANTICS,
winDisposition: Const.OPEN_EXISTING
};
File.read = exports.OS.Shared.AbstractFile.read;
File.writeAtomic = exports.OS.Shared.AbstractFile.writeAtomic;
File.openUnique = exports.OS.Shared.AbstractFile.openUnique;
File.removeDir = exports.OS.Shared.AbstractFile.removeDir;
/**
* Get the current directory by getCurrentDirectory.
*/
File.getCurrentDirectory = function getCurrentDirectory() {
// This function is more complicated than one could hope.
//
// This is due to two facts:
// - the maximal length of a path under Windows is not completely
// specified (there is a constant MAX_PATH, but it is quite possible
// to create paths that are much larger, see bug 744413);
// - if we attempt to call |GetCurrentDirectory| with a buffer that
// is too short, it returns the length of the current directory, but
// this length might be insufficient by the time we can call again
// the function with a larger buffer, in the (unlikely byt possible)
// case in which the process changes directory to a directory with
// a longer name between both calls.
let buffer_size = 4096;
while (true) {
let array = new (ctypes.ArrayType(ctypes.jschar, buffer_size))();
// This function is more complicated than one could hope.
//
// This is due to two facts:
// - the maximal length of a path under Windows is not completely
// specified (there is a constant MAX_PATH, but it is quite possible
// to create paths that are much larger, see bug 744413);
// - if we attempt to call |GetCurrentDirectory| with a buffer that
// is too short, it returns the length of the current directory, but
// this length might be insufficient by the time we can call again
// the function with a larger buffer, in the (unlikely but possible)
// case in which the process changes directory to a directory with
// a longer name between both calls.
//
let buffer_size = 4096;
while (true) {
let array = new (ctypes.ArrayType(ctypes.jschar, buffer_size))();
let expected_size = throw_on_zero("getCurrentDirectory",
WinFile.GetCurrentDirectory(buffer_size, array)
);
if (expected_size <= buffer_size) {
return array.readString();
}
// At this point, we are in a case in which our buffer was not
// large enough to hold the name of the current directory.
// Consequently
// Note that, even in crazy scenarios, the loop will eventually
// converge, as the length of the paths cannot increase infinitely.
buffer_size = expected_size;
}
WinFile.GetCurrentDirectory(buffer_size, array)
);
if (expected_size <= buffer_size) {
return array.readString();
}
// At this point, we are in a case in which our buffer was not
// large enough to hold the name of the current directory.
// Consequently, we need to increase the size of the buffer.
// Note that, even in crazy scenarios, the loop will eventually
// converge, as the length of the paths cannot increase infinitely.
buffer_size = expected_size + 1 /* to store \0 */;
}
};
/**
@ -816,7 +818,7 @@
// Utility functions, used for error-handling
function error_or_file(maybe) {
if (maybe == exports.OS.Constants.Win.INVALID_HANDLE_VALUE) {
if (maybe == Const.INVALID_HANDLE_VALUE) {
throw new File.Error("open");
}
return new File(maybe);
@ -841,13 +843,12 @@
}
File.Win = exports.OS.Win.File;
File.Error = exports.OS.Shared.Win.Error;
File.Error = SysAll.Error;
exports.OS.File = File;
exports.OS.Shared.Type = Type;
exports.OS.Path = exports.Path;
Object.defineProperty(File, "POS_START", { value: OS.Shared.POS_START });
Object.defineProperty(File, "POS_CURRENT", { value: OS.Shared.POS_CURRENT });
Object.defineProperty(File, "POS_END", { value: OS.Shared.POS_END });
Object.defineProperty(File, "POS_START", { value: SysAll.POS_START });
Object.defineProperty(File, "POS_CURRENT", { value: SysAll.POS_CURRENT });
Object.defineProperty(File, "POS_END", { value: SysAll.POS_END });
})(this);
}

View File

@ -16,7 +16,6 @@ if (typeof Components != "undefined") {
#ifdef XP_WIN
importScripts(
"resource://gre/modules/workers/require.js",
"resource://gre/modules/osfile/osfile_win_allthreads.jsm",
"resource://gre/modules/osfile/osfile_win_back.jsm",
"resource://gre/modules/osfile/osfile_shared_front.jsm",
"resource://gre/modules/osfile/osfile_win_front.jsm"
@ -24,7 +23,6 @@ if (typeof Components != "undefined") {
#else
importScripts(
"resource://gre/modules/workers/require.js",
"resource://gre/modules/osfile/osfile_unix_allthreads.jsm",
"resource://gre/modules/osfile/osfile_unix_back.jsm",
"resource://gre/modules/osfile/osfile_shared_front.jsm",
"resource://gre/modules/osfile/osfile_unix_front.jsm"

View File

@ -61,6 +61,9 @@ let maketest = function(prefix, test) {
utils.info("Complete");
}, function catch_uncaught_errors(err) {
utils.fail("Uncaught error " + err);
if (err && typeof err == "object" && "message" in err) {
utils.fail("(" + err.message + ")");
}
if (err && typeof err == "object" && "stack" in err) {
utils.fail("at " + err.stack);
}
@ -924,12 +927,9 @@ let test_duration = maketest("duration", function duration(test) {
test.ok(copyOptions.outExecutionDuration >= backupDuration, "duration has increased 3");
OS.File.remove(pathDest);
OS.Shared.TEST = true;
// Testing an operation that doesn't take arguments at all
let file = yield OS.File.open(pathSource);
yield file.stat();
yield file.close();
Services.prefs.setBoolPref("toolkit.osfile.log", false);
});
});

View File

@ -4,7 +4,7 @@
function worker_handler(worker) {
worker.onerror = function(error) {
error.preventDefault();
ok(false, "error "+error);
ok(false, "Worker error " + error.message);
}
worker.onmessage = function(msg) {
ok(true, "MAIN: onmessage " + JSON.stringify(msg.data));

View File

@ -2,6 +2,10 @@
* http://creativecommons.org/publicdomain/zero/1.0/ */
importScripts('worker_test_osfile_shared.js');
importScripts("resource://gre/modules/workers/require.js");
let SharedAll = require("resource://gre/modules/osfile/osfile_shared_allthreads.jsm");
SharedAll.Config.DEBUG = true;
function should_throw(f) {
try {
@ -59,9 +63,9 @@ function test_offsetby() {
}
// Walk through the array with offsetBy by 8 bits
let uint8 = OS.Shared.Type.uint8_t.in_ptr.implementation(buf);
let uint8 = SharedAll.Type.uint8_t.in_ptr.implementation(buf);
for (i = 0; i < LENGTH; ++i) {
let value = OS.Shared.offsetBy(uint8, i).contents;
let value = SharedAll.offsetBy(uint8, i).contents;
if (value != i%256) {
is(value, i % 256, "test_offsetby: Walking through array with offsetBy (8 bits)");
break;
@ -69,10 +73,10 @@ function test_offsetby() {
}
// Walk again by 16 bits
let uint16 = OS.Shared.Type.uint16_t.in_ptr.implementation(buf);
let uint16 = SharedAll.Type.uint16_t.in_ptr.implementation(buf);
let view2 = new Uint16Array(buf);
for (i = 0; i < LENGTH/2; ++i) {
let value = OS.Shared.offsetBy(uint16, i).contents;
let value = SharedAll.offsetBy(uint16, i).contents;
if (value != view2[i]) {
is(value, view2[i], "test_offsetby: Walking through array with offsetBy (16 bits)");
break;
@ -80,15 +84,15 @@ function test_offsetby() {
}
// Ensure that offsetBy(..., 0) is idempotent
let startptr = OS.Shared.offsetBy(uint8, 0);
let startptr2 = OS.Shared.offsetBy(startptr, 0);
let startptr = SharedAll.offsetBy(uint8, 0);
let startptr2 = SharedAll.offsetBy(startptr, 0);
is(startptr.toString(), startptr2.toString(), "test_offsetby: offsetBy(..., 0) is idmpotent");
// Ensure that offsetBy(ptr, ...) does not work if ptr is a void*
let ptr = ctypes.voidptr_t(0);
let exn;
try {
OS.Shared.Utils.offsetBy(ptr, 1);
SharedAll.offsetBy(ptr, 1);
} catch (x) {
exn = x;
}

View File

@ -145,6 +145,10 @@ function run_test()
do_print("Testing the presence of ospath.jsm");
let Scope = {};
Components.utils.import("resource://gre/modules/osfile/ospath.jsm", Scope);
try {
Components.utils.import("resource://gre/modules/osfile/ospath.jsm", Scope);
} catch (ex) {
// Can't load ospath
}
do_check_true(!!Scope.basename);
}

View File

@ -0,0 +1,90 @@
"use strict";
Components.utils.import("resource://gre/modules/osfile.jsm");
Components.utils.import("resource://gre/modules/Task.jsm");
function run_test() {
run_next_test();
}
function testFiles(filename) {
return Task.spawn(function() {
const MAX_TRIES = 10;
let currentDir = yield OS.File.getCurrentDirectory();
let path = OS.Path.join(currentDir, filename);
let exists = yield OS.File.exists(path);
// Check a file with the same name doesn't exist already
do_check_false(exists);
// Ensure that openUnique() uses the file name if there is no file with that name already.
let openedFile = yield OS.File.openUnique(path);
do_print("\nCreate new file: " + openedFile.path);
yield openedFile.file.close();
exists = yield OS.File.exists(openedFile.path);
do_check_true(exists);
do_check_eq(path, openedFile.path);
let fileInfo = yield OS.File.stat(openedFile.path);
do_check_true(fileInfo.size == 0);
// Ensure that openUnique() creates a new file name using a HEX number, as the original name is already taken.
openedFile = yield OS.File.openUnique(path);
do_print("\nCreate unique HEX file: " + openedFile.path);
yield openedFile.file.close();
exists = yield OS.File.exists(openedFile.path);
do_check_true(exists);
let fileInfo = yield OS.File.stat(openedFile.path);
do_check_true(fileInfo.size == 0);
// Ensure that openUnique() generates different file names each time, using the HEX number algorithm
let filenames = new Set();
for (let i=0; i < MAX_TRIES; i++) {
openedFile = yield OS.File.openUnique(path);
yield openedFile.file.close();
filenames.add(openedFile.path);
}
do_check_eq(filenames.size, MAX_TRIES);
// Ensure that openUnique() creates a new human readable file name using, as the original name is already taken.
openedFile = yield OS.File.openUnique(path, {humanReadable : true});
do_print("\nCreate unique Human Readable file: " + openedFile.path);
yield openedFile.file.close();
exists = yield OS.File.exists(openedFile.path);
do_check_true(exists);
let fileInfo = yield OS.File.stat(openedFile.path);
do_check_true(fileInfo.size == 0);
// Ensure that openUnique() generates different human readable file names each time
filenames = new Set();
for (let i=0; i < MAX_TRIES; i++) {
openedFile = yield OS.File.openUnique(path, {humanReadable : true});
yield openedFile.file.close();
filenames.add(openedFile.path);
}
do_check_eq(filenames.size, MAX_TRIES);
let exn;
try {
for (let i=0; i < 100; i++) {
openedFile = yield OS.File.openUnique(path, {humanReadable : true});
yield openedFile.file.close();
}
} catch (ex) {
exn = ex;
}
do_print("Ensure that this raises the correct error");
do_check_true(!!exn);
do_check_true(exn instanceof OS.File.Error);
do_check_true(exn.becauseExists);
});
}
add_task(function test_unique() {
OS.Shared.DEBUG = true;
// Tests files with extension
yield testFiles("dummy_unique_file.txt");
// Tests files with no extension
yield testFiles("dummy_unique_file_no_ext");
});

View File

@ -12,3 +12,4 @@ tail =
[test_exception.js]
[test_path_constants.js]
[test_removeDir.js]
[test_unique.js]

View File

@ -1138,6 +1138,29 @@
]]></body>
</method>
<!--
- This handler may cancel a request to focus content by returning |false|
- explicitly.
-->
<method name="shouldFocusContent">
<body><![CDATA[
const fm = Components.classes["@mozilla.org/focus-manager;1"]
.getService(Components.interfaces.nsIFocusManager);
if (fm.focusedWindow != window)
return false;
let focusedElement = fm.focusedElement;
if (!focusedElement)
return false;
let bindingParent = document.getBindingParent(focusedElement);
if (bindingParent != this && bindingParent != this._findField)
return false;
return true;
]]></body>
</method>
</implementation>
<handlers>

View File

@ -120,6 +120,7 @@ var SrcdirProvider = {
"devtools/toolkit/webconsole": webconsoleURI,
"devtools/app-actor-front": appActorURI,
"devtools/styleinspector/css-logic": cssLogicURI,
"devtools/css-color": cssColorURI,
"devtools/touch-events": touchEventsURI,
"devtools/client": clientURI,
"escodegen": escodegenURI,

View File

@ -116,14 +116,22 @@ Finder.prototype = {
},
focusContent: function() {
let fastFind = this._fastFind;
// Allow Finder listeners to cancel focusing the content.
for (let l of this._listeners) {
if (!l.shouldFocusContent())
return;
}
let fastFind = this._fastFind;
const fm = Cc["@mozilla.org/focus-manager;1"].getService(Ci.nsIFocusManager);
try {
// Try to find the best possible match that should receive focus.
// Try to find the best possible match that should receive focus and
// block scrolling on focus since find already scrolls. Further
// scrolling is due to user action, so don't override this.
if (fastFind.foundLink) {
fastFind.foundLink.focus();
fm.setFocus(fastFind.foundLink, fm.FLAG_NOSCROLL);
} else if (fastFind.foundEditable) {
fastFind.foundEditable.focus();
fm.setFocus(fastFind.foundEditable, fm.FLAG_NOSCROLL);
fastFind.collapseSelection();
} else {
this._getWindow().focus()
@ -136,8 +144,18 @@ Finder.prototype = {
switch (aEvent.keyCode) {
case Ci.nsIDOMKeyEvent.DOM_VK_RETURN:
if (this._fastFind.foundLink) // Todo: Handle ctrl click.
this._fastFind.foundLink.click();
if (this._fastFind.foundLink) {
let view = this._fastFind.foundLink.ownerDocument.defaultView;
this._fastFind.foundLink.dispatchEvent(new view.MouseEvent("click", {
view: view,
cancelable: true,
bubbles: true,
ctrlKey: aEvent.ctrlKey,
altKey: aEvent.altKey,
shiftKey: aEvent.shiftKey,
metaKey: aEvent.metaKey
}));
}
break;
case Ci.nsIDOMKeyEvent.DOM_VK_TAB:
let direction = Services.focus.MOVEFOCUS_FORWARD;

View File

@ -114,6 +114,12 @@ RemoteFinderListener.prototype = {
this._global.sendAsyncMessage("Finder:Result", data);
},
//XXXmikedeboer-20131016: implement |shouldFocusContent| here to mitigate
// issues like bug 921338 and bug 921308.
shouldFocusContent: function () {
return true;
},
receiveMessage: function (aMessage) {
let data = aMessage.data;

View File

@ -10,27 +10,26 @@ support-files =
[test_0015_check_incompat_basic_addons.xul]
[test_0016_check_incompat_basic_license_addons.xul]
[test_0017_check_staging_basic.xul]
skip-if = os == 'linux'
reason = Bug 918029 - timeout caused by copying too many files.
[test_0021_check_billboard.xul]
[test_0022_check_billboard_license.xul]
[test_0023_check_incompat_billboard.xul]
[test_0024_check_incompat_billboard_license.xul]
[test_0025_check_incompat_billboard_addons.xul]
[test_0026_check_incompat_billboard_license_addons.xul]
[test_0027_check_staging_billboard.xul]
[test_0031_available_basic.xul]
[test_0032_available_basic_license.xul]
[test_0033_available_incompat_basic.xul]
[test_0034_available_incompat_basic_license.xul]
[test_0035_available_incompat_basic_addons.xul]
[test_0036_available_incompat_basic_license_addons.xul]
[test_0037_available_staging_basic.xul]
[test_0041_available_billboard.xul]
[test_0042_available_billboard_license.xul]
[test_0043_available_incompat_billboard.xul]
[test_0044_available_incompat_billboard_license.xul]
[test_0045_available_incompat_billboard_addons.xul]
[test_0046_available_incompat_billboard_license_addons.xul]
[test_0047_available_staging_billboard.xul]
[test_0051_check_error_xml_malformed.xul]
[test_0052_check_no_updates.xul]
[test_0053_check_billboard_license_noAttr.xul]

View File

@ -1,62 +0,0 @@
<?xml version="1.0"?>
<!--
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/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 title="Update Wizard pages: update check, billboard, download with staging, and finished"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
onload="runTestDefault();">
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
<script type="application/javascript"
src="utils.js"/>
<script type="application/javascript">
<![CDATA[
const TESTS = [ {
pageid: PAGEID_CHECKING
}, {
pageid: PAGEID_FOUND_BILLBOARD,
extraDelayedCheckFunction: checkRemoteContentState,
expectedRemoteContentState: "loading",
extraDelayedFinishFunction: addRemoteContentLoadListener
}, {
pageid: PAGEID_FOUND_BILLBOARD,
extraStartFunction: waitForRemoteContentLoaded,
expectedRemoteContentState: "loaded",
buttonClick: "next"
}, {
pageid: PAGEID_DOWNLOADING
}, {
pageid: PAGEID_FINISHED,
buttonClick: "extra1"
} ];
function runTest() {
debugDump("entering");
Services.prefs.setBoolPref(PREF_APP_UPDATE_STAGING_ENABLED, true);
let url = URL_UPDATE + "?showBillboard=1&showDetails=1" + getVersionParams();
setUpdateURLOverride(url);
setupTimer(180000); // 180 seconds
gUP.checkForUpdates();
}
]]>
</script>
<body xmlns="http://www.w3.org/1999/xhtml">
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test"></pre>
</body>
</window>

View File

@ -1,53 +0,0 @@
<?xml version="1.0"?>
<!--
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/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 title="Update Wizard pages: basic, download with staging, and finished"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
onload="runTestDefault();">
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
<script type="application/javascript"
src="utils.js"/>
<script type="application/javascript">
<![CDATA[
const TESTS = [ {
pageid: PAGEID_FOUND_BASIC,
buttonClick: "next"
}, {
pageid: PAGEID_DOWNLOADING
}, {
pageid: PAGEID_FINISHED,
buttonClick: "extra1"
} ];
function runTest() {
debugDump("entering");
Services.prefs.setBoolPref(PREF_APP_UPDATE_STAGING_ENABLED, true);
let url = URL_UPDATE + "?showDetails=1&showPrompt=1" + getVersionParams();
setUpdateURLOverride(url);
setupTimer(180000); // 180 seconds
gAUS.checkForBackgroundUpdates();
}
]]>
</script>
<body xmlns="http://www.w3.org/1999/xhtml">
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test"></pre>
</body>
</window>

View File

@ -1,61 +0,0 @@
<?xml version="1.0"?>
<!--
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/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 title="Update Wizard pages: billboard, download with staging, and finished"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
onload="runTestDefault();">
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
<script type="application/javascript"
src="utils.js"/>
<script type="application/javascript">
<![CDATA[
const TESTS = [ {
pageid: PAGEID_FOUND_BILLBOARD,
extraDelayedCheckFunction: checkRemoteContentState,
expectedRemoteContentState: "loading",
extraDelayedFinishFunction: addRemoteContentLoadListener
}, {
pageid: PAGEID_FOUND_BILLBOARD,
extraStartFunction: waitForRemoteContentLoaded,
expectedRemoteContentState: "loaded",
buttonClick: "next"
}, {
pageid: PAGEID_DOWNLOADING,
}, {
pageid: PAGEID_FINISHED,
buttonClick: "extra1"
} ];
function runTest() {
debugDump("entering");
Services.prefs.setBoolPref(PREF_APP_UPDATE_STAGING_ENABLED, true);
let url = URL_UPDATE + "?showBillboard=1&showDetails=1&showPrompt=1" +
getVersionParams();
setUpdateURLOverride(url);
setupTimer(180000); // 180 seconds
gAUS.notify(null);
}
]]>
</script>
<body xmlns="http://www.w3.org/1999/xhtml">
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test"></pre>
</body>
</window>

View File

@ -157,11 +157,13 @@ HwcComposer2D::PrepareLayerList(Layer* aLayer,
return true;
}
float opacity = aLayer->GetEffectiveOpacity();
if (opacity < 1) {
uint8_t opacity = std::min(0xFF, (int)(aLayer->GetEffectiveOpacity() * 256.0));
#if ANDROID_VERSION < 18
if (opacity < 0xFF) {
LOGD("%s Layer has planar semitransparency which is unsupported", aLayer->Name());
return false;
}
#endif
nsIntRect clip;
if (!HwcUtils::CalculateClipRect(aParentTransform * aGLWorldTransform,
@ -276,7 +278,7 @@ HwcComposer2D::PrepareLayerList(Layer* aLayer,
hwcLayer.acquireFenceFd = -1;
hwcLayer.releaseFenceFd = -1;
hwcLayer.planeAlpha = 0xFF; // Until plane alpha is enabled
hwcLayer.planeAlpha = opacity;
#else
hwcLayer.compositionType = HwcUtils::HWC_USE_COPYBIT;
#endif
@ -434,6 +436,7 @@ HwcComposer2D::PrepareLayerList(Layer* aLayer,
hwcLayer.transform = colorLayer->GetColor().Packed();
}
mHwcLayerMap.AppendElement(static_cast<LayerComposite*>(aLayer->ImplData()));
mList->numHwLayers++;
return true;
}
@ -461,13 +464,29 @@ HwcComposer2D::TryHwComposition()
Prepare(fbsurface->lastHandle, -1);
bool fullHwcComposite = true;
for (int j = 0; j < idx; j++) {
if (mList->hwLayers[j].compositionType == HWC_FRAMEBUFFER) {
// After prepare, if there is an HWC_FRAMEBUFFER layer,
// it means full HWC Composition is not possible this time
LOGD("GPU or Partial HWC Composition");
return false;
fullHwcComposite = false;
break;
}
}
if (!fullHwcComposite) {
for (int k=0; k < idx; k++) {
if (mList->hwLayers[k].compositionType == HWC_OVERLAY) {
// HWC will compose HWC_OVERLAY layers in partial
// HWC Composition, so set layer composition flag
// on mapped LayerComposite to skip GPU composition
mHwcLayerMap[k]->SetLayerComposited(true);
}
}
return false;
}
// Full HWC Composition
Commit();
@ -554,28 +573,26 @@ HwcComposer2D::Commit()
int err = mHwc->set(mHwc, HWC_NUM_DISPLAY_TYPES, displays);
for (int i = 0; i <= MAX_HWC_LAYERS; i++) {
if (mPrevRelFd[i] <= 0) {
break;
if (!mPrevReleaseFds.IsEmpty()) {
// Wait for previous retire Fence to signal.
// Denotes contents on display have been replaced.
// For buffer-sync, framework should not over-write
// prev buffers until we close prev releaseFenceFds
sp<Fence> fence = new Fence(mPrevReleaseFds[0]);
if (fence->wait(1000) == -ETIME) {
LOGE("Wait timed-out for retireFenceFd %d", mPrevReleaseFds[0]);
}
if (!i) {
// Wait for previous retire Fence to signal.
// Denotes contents on display have been replaced.
// For buffer-sync, framework should not over-write
// prev buffers until we close prev releaseFenceFds
sp<Fence> fence = new Fence(mPrevRelFd[i]);
if (fence->wait(1000) == -ETIME) {
LOGE("Wait timed-out for retireFenceFd %d", mPrevRelFd[i]);
}
for (int i = 0; i < mPrevReleaseFds.Length(); i++) {
close(mPrevReleaseFds[i]);
}
close(mPrevRelFd[i]);
mPrevRelFd[i] = -1;
mPrevReleaseFds.Clear();
}
mPrevRelFd[0] = mList->retireFenceFd;
for (uint32_t j = 0; j < (mList->numHwLayers - 1); j++) {
mPrevReleaseFds.AppendElement(mList->retireFenceFd);
for (uint32_t j=0; j < (mList->numHwLayers - 1); j++) {
if (mList->hwLayers[j].compositionType == HWC_OVERLAY) {
mPrevRelFd[j + 1] = mList->hwLayers[j].releaseFenceFd;
mPrevReleaseFds.AppendElement(mList->hwLayers[j].releaseFenceFd);
mList->hwLayers[j].releaseFenceFd = -1;
}
}
@ -609,12 +626,14 @@ HwcComposer2D::TryRender(Layer* aRoot,
MOZ_ASSERT(Initialized());
if (mList) {
mList->numHwLayers = 0;
mHwcLayerMap.Clear();
}
// XXX: The clear() below means all rect vectors will be have to be
// reallocated. We may want to avoid this if possible
mVisibleRegions.clear();
MOZ_ASSERT(mHwcLayerMap.IsEmpty());
if (!PrepareLayerList(aRoot,
mScreenRect,
gfxMatrix(),

View File

@ -24,8 +24,6 @@
#include <hardware/hwcomposer.h>
#define MAX_HWC_LAYERS 15
namespace mozilla {
namespace layers {
@ -83,7 +81,8 @@ private:
//Holds all the dynamically allocated RectVectors needed
//to render the current frame
std::list<RectVector> mVisibleRegions;
int mPrevRelFd[MAX_HWC_LAYERS + 1];
nsTArray<int> mPrevReleaseFds;
nsTArray<layers::LayerComposite*> mHwcLayerMap;
};
} // namespace mozilla

View File

@ -206,6 +206,7 @@ MetroInput::MetroInput(MetroWidget* aWidget,
UI::Core::ICoreWindow* aWindow)
: mWidget(aWidget),
mChromeHitTestCacheForTouch(false),
mCurrentInputLevel(LEVEL_IMPRECISE),
mWindow(aWindow)
{
LogFunction();
@ -240,6 +241,51 @@ MetroInput::~MetroInput()
UnregisterInputEvents();
}
/**
* Tracks the current input level (precise/imprecise) and fires an observer
* when the mode changes.
*/
void
MetroInput::UpdateInputLevel(InputPrecisionLevel aInputLevel)
{
// ignore mouse input if we have active touch input.
if (aInputLevel == LEVEL_PRECISE && mTouches.Count() > 0) {
return;
}
if (mCurrentInputLevel != aInputLevel) {
mCurrentInputLevel = aInputLevel;
MetroUtils::FireObserver(mCurrentInputLevel == LEVEL_PRECISE ?
"metro_precise_input" : "metro_imprecise_input");
}
}
/**
* Processes an IEdgeGestureEventArgs and returns the input source type
* for the event. Also updates input level via UpdateInputLevel.
*/
uint16_t
MetroInput::ProcessInputTypeForGesture(UI::Input::IEdgeGestureEventArgs* aArgs)
{
MOZ_ASSERT(aArgs);
UI::Input::EdgeGestureKind kind;
aArgs->get_Kind(&kind);
switch(kind) {
case UI::Input::EdgeGestureKind::EdgeGestureKind_Touch:
UpdateInputLevel(LEVEL_PRECISE);
return nsIDOMMouseEvent::MOZ_SOURCE_TOUCH;
break;
case UI::Input::EdgeGestureKind::EdgeGestureKind_Keyboard:
return nsIDOMMouseEvent::MOZ_SOURCE_KEYBOARD;
break;
case UI::Input::EdgeGestureKind::EdgeGestureKind_Mouse:
UpdateInputLevel(LEVEL_IMPRECISE);
return nsIDOMMouseEvent::MOZ_SOURCE_MOUSE;
break;
}
return nsIDOMMouseEvent::MOZ_SOURCE_UNKNOWN;
}
/**
* When the user swipes her/his finger in from the top of the screen,
* we receive this event.
@ -263,8 +309,7 @@ MetroInput::OnEdgeGestureStarted(UI::Input::IEdgeGesture* sender,
mModifierKeyState.Update();
mModifierKeyState.InitInputEvent(geckoEvent);
geckoEvent.time = ::GetMessageTime();
geckoEvent.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH;
geckoEvent.inputSource = ProcessInputTypeForGesture(aArgs);
// Safe
DispatchEventIgnoreStatus(&geckoEvent);
@ -295,8 +340,7 @@ MetroInput::OnEdgeGestureCanceled(UI::Input::IEdgeGesture* sender,
mModifierKeyState.Update();
mModifierKeyState.InitInputEvent(geckoEvent);
geckoEvent.time = ::GetMessageTime();
geckoEvent.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH;
geckoEvent.inputSource = ProcessInputTypeForGesture(aArgs);
// Safe
DispatchEventIgnoreStatus(&geckoEvent);
@ -326,15 +370,7 @@ MetroInput::OnEdgeGestureCompleted(UI::Input::IEdgeGesture* sender,
mModifierKeyState.Update();
mModifierKeyState.InitInputEvent(geckoEvent);
geckoEvent.time = ::GetMessageTime();
UI::Input::EdgeGestureKind value;
aArgs->get_Kind(&value);
if (value == UI::Input::EdgeGestureKind::EdgeGestureKind_Keyboard) {
geckoEvent.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_KEYBOARD;
} else {
geckoEvent.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH;
}
geckoEvent.inputSource = ProcessInputTypeForGesture(aArgs);
// Safe
DispatchEventIgnoreStatus(&geckoEvent);
@ -391,6 +427,7 @@ MetroInput::OnPointerNonTouch(UI::Input::IPointerPoint* aPoint) {
event->message = NS_MOUSE_BUTTON_UP;
break;
}
UpdateInputLevel(LEVEL_PRECISE);
InitGeckoMouseEventFromPointerPoint(event, aPoint);
DispatchAsyncEventIgnoreStatus(event);
}
@ -430,6 +467,8 @@ MetroInput::OnPointerPressed(UI::Core::ICoreWindow* aSender,
}
// This is touch input.
UpdateInputLevel(LEVEL_IMPRECISE);
// Create the new touch point and add it to our event.
uint32_t pointerId;
currentPoint->get_PointerId(&pointerId);
@ -517,6 +556,8 @@ MetroInput::OnPointerMoved(UI::Core::ICoreWindow* aSender,
}
// This is touch input.
UpdateInputLevel(LEVEL_IMPRECISE);
// Get the touch associated with this touch point.
uint32_t pointerId;
currentPoint->get_PointerId(&pointerId);
@ -614,6 +655,8 @@ MetroInput::OnPointerReleased(UI::Core::ICoreWindow* aSender,
}
// This is touch input.
UpdateInputLevel(LEVEL_IMPRECISE);
// Get the touch associated with this touch point.
uint32_t pointerId;
currentPoint->get_PointerId(&pointerId);
@ -748,9 +791,11 @@ MetroInput::OnPointerEntered(UI::Core::ICoreWindow* aSender,
WidgetMouseEvent* event =
new WidgetMouseEvent(true, NS_MOUSE_ENTER, mWidget.Get(),
WidgetMouseEvent::eReal, WidgetMouseEvent::eNormal);
UpdateInputLevel(LEVEL_PRECISE);
InitGeckoMouseEventFromPointerPoint(event, currentPoint.Get());
DispatchAsyncEventIgnoreStatus(event);
}
UpdateInputLevel(LEVEL_IMPRECISE);
return S_OK;
}
@ -779,9 +824,11 @@ MetroInput::OnPointerExited(UI::Core::ICoreWindow* aSender,
WidgetMouseEvent* event =
new WidgetMouseEvent(true, NS_MOUSE_EXIT, mWidget.Get(),
WidgetMouseEvent::eReal, WidgetMouseEvent::eNormal);
UpdateInputLevel(LEVEL_PRECISE);
InitGeckoMouseEventFromPointerPoint(event, currentPoint.Get());
DispatchAsyncEventIgnoreStatus(event);
}
UpdateInputLevel(LEVEL_IMPRECISE);
return S_OK;
}

View File

@ -155,6 +155,14 @@ private:
ModifierKeyState mModifierKeyState;
// Tracking input level
enum InputPrecisionLevel {
LEVEL_PRECISE,
LEVEL_IMPRECISE
};
InputPrecisionLevel mCurrentInputLevel;
void UpdateInputLevel(InputPrecisionLevel aInputLevel);
// Initialization/Uninitialization helpers
void RegisterInputEvents();
void UnregisterInputEvents();
@ -174,6 +182,7 @@ private:
Point const& aPosition,
uint32_t aMagEventType,
uint32_t aRotEventType);
uint16_t ProcessInputTypeForGesture(IEdgeGestureEventArgs* aArgs);
// The W3C spec states that "whether preventDefault has been called" should
// be tracked on a per-touchpoint basis, but it also states that touchstart