mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 22:01:30 +00:00
Merging cedar with mozilla-central.
This commit is contained in:
commit
ba98c26241
@ -2032,7 +2032,7 @@ let GroupItems = {
|
||||
if (UI.shouldLoadFavIcon(xulTab.linkedBrowser))
|
||||
iconUrl = UI.getFavIconUrlForTab(xulTab);
|
||||
else
|
||||
iconUrl = Utils.defaultFaviconURL;
|
||||
iconUrl = gFavIconService.defaultFavicon.spec;
|
||||
|
||||
return iconUrl;
|
||||
},
|
||||
|
@ -490,8 +490,6 @@ Subscribable.prototype = {
|
||||
// Class: Utils
|
||||
// Singelton with common utility functions.
|
||||
let Utils = {
|
||||
defaultFaviconURL: "chrome://mozapps/skin/places/defaultFavicon.png",
|
||||
|
||||
// ----------
|
||||
// Function: toString
|
||||
// Prints [Utils] for debug use
|
||||
|
@ -47,8 +47,6 @@ let Storage = {
|
||||
GROUPS_DATA_IDENTIFIER: "tabview-groups",
|
||||
TAB_DATA_IDENTIFIER: "tabview-tab",
|
||||
UI_DATA_IDENTIFIER: "tabview-ui",
|
||||
CACHE_CLIENT_IDENTIFIER: "tabview-cache",
|
||||
CACHE_PREFIX: "moz-panorama:",
|
||||
|
||||
// ----------
|
||||
// Function: toString
|
||||
@ -64,28 +62,12 @@ let Storage = {
|
||||
this._sessionStore =
|
||||
Cc["@mozilla.org/browser/sessionstore;1"].
|
||||
getService(Ci.nsISessionStore);
|
||||
|
||||
// Create stream-based cache session for tabview
|
||||
let cacheService =
|
||||
Cc["@mozilla.org/network/cache-service;1"].
|
||||
getService(Ci.nsICacheService);
|
||||
this._cacheSession = cacheService.createSession(
|
||||
this.CACHE_CLIENT_IDENTIFIER, Ci.nsICache.STORE_ON_DISK, true);
|
||||
this.StringInputStream = Components.Constructor(
|
||||
"@mozilla.org/io/string-input-stream;1", "nsIStringInputStream",
|
||||
"setData");
|
||||
this.StorageStream = Components.Constructor(
|
||||
"@mozilla.org/storagestream;1", "nsIStorageStream",
|
||||
"init");
|
||||
},
|
||||
|
||||
// ----------
|
||||
// Function: uninit
|
||||
uninit: function Storage_uninit () {
|
||||
this._sessionStore = null;
|
||||
this._cacheSession = null;
|
||||
this.StringInputStream = null;
|
||||
this.StorageStream = null;
|
||||
},
|
||||
|
||||
// ----------
|
||||
@ -114,137 +96,6 @@ let Storage = {
|
||||
}
|
||||
},
|
||||
|
||||
// ----------
|
||||
// Function: _openCacheEntry
|
||||
// Opens a cache entry for the given <url> and requests access <access>.
|
||||
// Calls <successCallback>(entry) when the entry was successfully opened with
|
||||
// requested access rights. Otherwise calls <errorCallback>().
|
||||
_openCacheEntry: function Storage__openCacheEntry(url, access, successCallback, errorCallback) {
|
||||
let onCacheEntryAvailable = function (entry, accessGranted, status) {
|
||||
if (entry && access == accessGranted && Components.isSuccessCode(status)) {
|
||||
successCallback(entry);
|
||||
} else {
|
||||
entry && entry.close();
|
||||
errorCallback();
|
||||
}
|
||||
}
|
||||
|
||||
let key = this.CACHE_PREFIX + url;
|
||||
|
||||
// switch to synchronous mode if parent window is about to close
|
||||
if (UI.isDOMWindowClosing) {
|
||||
let entry = this._cacheSession.openCacheEntry(key, access, true);
|
||||
let status = Components.results.NS_OK;
|
||||
onCacheEntryAvailable(entry, entry.accessGranted, status);
|
||||
} else {
|
||||
let listener = new CacheListener(onCacheEntryAvailable);
|
||||
this._cacheSession.asyncOpenCacheEntry(key, access, listener);
|
||||
}
|
||||
},
|
||||
|
||||
// ----------
|
||||
// Function: saveThumbnail
|
||||
// Saves the <imageData> to the cache using the given <url> as key.
|
||||
// Calls <callback>(status) when finished (passing true or false indicating
|
||||
// whether the operation succeeded).
|
||||
saveThumbnail: function Storage_saveThumbnail(url, imageData, callback) {
|
||||
Utils.assert(url, "url");
|
||||
Utils.assert(imageData, "imageData");
|
||||
Utils.assert(typeof callback == "function", "callback arg must be a function");
|
||||
|
||||
let self = this;
|
||||
let StringInputStream = this.StringInputStream;
|
||||
|
||||
let onCacheEntryAvailable = function (entry) {
|
||||
let outputStream = entry.openOutputStream(0);
|
||||
|
||||
let cleanup = function () {
|
||||
outputStream.close();
|
||||
entry.close();
|
||||
}
|
||||
|
||||
// switch to synchronous mode if parent window is about to close
|
||||
if (UI.isDOMWindowClosing) {
|
||||
outputStream.write(imageData, imageData.length);
|
||||
cleanup();
|
||||
callback(true);
|
||||
return;
|
||||
}
|
||||
|
||||
// asynchronous mode
|
||||
let inputStream = new StringInputStream(imageData, imageData.length);
|
||||
gNetUtil.asyncCopy(inputStream, outputStream, function (result) {
|
||||
cleanup();
|
||||
inputStream.close();
|
||||
callback(Components.isSuccessCode(result));
|
||||
});
|
||||
}
|
||||
|
||||
let onCacheEntryUnavailable = function () {
|
||||
callback(false);
|
||||
}
|
||||
|
||||
this._openCacheEntry(url, Ci.nsICache.ACCESS_WRITE,
|
||||
onCacheEntryAvailable, onCacheEntryUnavailable);
|
||||
},
|
||||
|
||||
// ----------
|
||||
// Function: loadThumbnail
|
||||
// Asynchrously loads image data from the cache using the given <url> as key.
|
||||
// Calls <callback>(status, data) when finished, passing true or false
|
||||
// (indicating whether the operation succeeded) and the retrieved image data.
|
||||
loadThumbnail: function Storage_loadThumbnail(url, callback) {
|
||||
Utils.assert(url, "url");
|
||||
Utils.assert(typeof callback == "function", "callback arg must be a function");
|
||||
|
||||
let self = this;
|
||||
|
||||
let onCacheEntryAvailable = function (entry) {
|
||||
let imageChunks = [];
|
||||
let nativeInputStream = entry.openInputStream(0);
|
||||
|
||||
const CHUNK_SIZE = 0x10000; // 65k
|
||||
const PR_UINT32_MAX = 0xFFFFFFFF;
|
||||
let storageStream = new self.StorageStream(CHUNK_SIZE, PR_UINT32_MAX, null);
|
||||
let storageOutStream = storageStream.getOutputStream(0);
|
||||
|
||||
let cleanup = function () {
|
||||
nativeInputStream.close();
|
||||
storageStream.close();
|
||||
storageOutStream.close();
|
||||
entry.close();
|
||||
}
|
||||
|
||||
gNetUtil.asyncCopy(nativeInputStream, storageOutStream, function (result) {
|
||||
// cancel if parent window has already been closed
|
||||
if (typeof UI == "undefined") {
|
||||
cleanup();
|
||||
return;
|
||||
}
|
||||
|
||||
let imageData = null;
|
||||
let isSuccess = Components.isSuccessCode(result);
|
||||
|
||||
if (isSuccess) {
|
||||
let storageInStream = storageStream.newInputStream(0);
|
||||
imageData = gNetUtil.readInputStreamToString(storageInStream,
|
||||
storageInStream.available());
|
||||
storageInStream.close();
|
||||
}
|
||||
|
||||
cleanup();
|
||||
callback(isSuccess, imageData);
|
||||
});
|
||||
}
|
||||
|
||||
let onCacheEntryUnavailable = function () {
|
||||
callback(false);
|
||||
}
|
||||
|
||||
this._openCacheEntry(url, Ci.nsICache.ACCESS_READ,
|
||||
onCacheEntryAvailable, onCacheEntryUnavailable);
|
||||
},
|
||||
|
||||
// ----------
|
||||
// Function: saveTab
|
||||
// Saves the data for a single tab.
|
||||
@ -255,16 +106,9 @@ let Storage = {
|
||||
let imageData = data.imageData;
|
||||
// Remove imageData from payload
|
||||
delete data.imageData;
|
||||
if (imageData != null) {
|
||||
this.saveThumbnail(data.url, imageData, function (status) {
|
||||
if (status) {
|
||||
// Notify subscribers
|
||||
tab._tabViewTabItem._sendToSubscribers("savedCachedImageData");
|
||||
} else {
|
||||
Utils.log("Error while saving thumbnail: " + e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (imageData != null)
|
||||
ThumbnailStorage.saveThumbnail(tab, imageData);
|
||||
}
|
||||
|
||||
this._sessionStore.setTabValue(tab, this.TAB_DATA_IDENTIFIER,
|
||||
@ -292,18 +136,13 @@ let Storage = {
|
||||
}
|
||||
|
||||
if (existingData) {
|
||||
this.loadThumbnail(existingData.url, function (status, imageData) {
|
||||
if (status) {
|
||||
ThumbnailStorage.loadThumbnail(
|
||||
tab, existingData.url,
|
||||
function(status, imageData) {
|
||||
callback(imageData);
|
||||
|
||||
// Notify subscribers
|
||||
tab._tabViewTabItem._sendToSubscribers("loadedCachedImageData");
|
||||
} else {
|
||||
Utils.log("Error while loading thumbnail");
|
||||
}
|
||||
});
|
||||
);
|
||||
}
|
||||
|
||||
return existingData;
|
||||
},
|
||||
|
||||
@ -409,26 +248,3 @@ let Storage = {
|
||||
}
|
||||
};
|
||||
|
||||
// ##########
|
||||
// Class: CacheListener
|
||||
// Generic CacheListener for feeding to asynchronous cache calls.
|
||||
// Calls <callback>(entry, access, status) when the requested cache entry
|
||||
// is available.
|
||||
function CacheListener(callback) {
|
||||
Utils.assert(typeof callback == "function", "callback arg must be a function");
|
||||
this.callback = callback;
|
||||
};
|
||||
|
||||
CacheListener.prototype = {
|
||||
// ----------
|
||||
// Function: toString
|
||||
// Prints [CacheListener] for debug use
|
||||
toString: function CacheListener_toString() {
|
||||
return "[CacheListener]";
|
||||
},
|
||||
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsICacheListener]),
|
||||
onCacheEntryAvailable: function (entry, access, status) {
|
||||
this.callback(entry, access, status);
|
||||
}
|
||||
};
|
||||
|
@ -1,6 +1,7 @@
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cu = Components.utils;
|
||||
const Cr = Components.results;
|
||||
|
||||
Cu.import("resource:///modules/tabview/AllTabs.jsm");
|
||||
Cu.import("resource:///modules/tabview/utils.jsm");
|
||||
@ -50,5 +51,6 @@ var gTabViewFrame = gWindow.document.getElementById("tab-view");
|
||||
#include tabitems.js
|
||||
#include drag.js
|
||||
#include trench.js
|
||||
#include thumbnailStorage.js
|
||||
#include ui.js
|
||||
#include search.js
|
||||
|
373
browser/base/content/tabview/thumbnailStorage.js
Normal file
373
browser/base/content/tabview/thumbnailStorage.js
Normal file
@ -0,0 +1,373 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is thumbnailStorage.js.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* the Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Raymond Lee <raymond@appcoast.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
// **********
|
||||
// Title: thumbnailStorage.js
|
||||
|
||||
// ##########
|
||||
// Class: ThumbnailStorage
|
||||
// Singleton for persistent storage of thumbnail data.
|
||||
let ThumbnailStorage = {
|
||||
CACHE_CLIENT_IDENTIFIER: "tabview-cache",
|
||||
CACHE_PREFIX: "moz-panorama:",
|
||||
PREF_DISK_CACHE_SSL: "browser.cache.disk_cache_ssl",
|
||||
|
||||
// Holds the cache session reference
|
||||
_cacheSession: null,
|
||||
|
||||
// Holds the string input stream reference
|
||||
_stringInputStream: null,
|
||||
|
||||
// Holds the storage stream reference
|
||||
_storageStream: null,
|
||||
|
||||
// Holds the progress listener reference
|
||||
_progressListener: null,
|
||||
|
||||
// Used to keep track of disk_cache_ssl preference
|
||||
enablePersistentHttpsCaching: null,
|
||||
|
||||
// Used to keep track of browsers whose thumbs we shouldn't save
|
||||
excludedBrowsers: [],
|
||||
|
||||
// ----------
|
||||
// Function: toString
|
||||
// Prints [ThumbnailStorage] for debug use.
|
||||
toString: function ThumbnailStorage_toString() {
|
||||
return "[ThumbnailStorage]";
|
||||
},
|
||||
|
||||
// ----------
|
||||
// Function: init
|
||||
// Should be called when UI is initialized.
|
||||
init: function ThumbnailStorage_init() {
|
||||
// Create stream-based cache session for tabview
|
||||
let cacheService =
|
||||
Cc["@mozilla.org/network/cache-service;1"].
|
||||
getService(Ci.nsICacheService);
|
||||
this._cacheSession = cacheService.createSession(
|
||||
this.CACHE_CLIENT_IDENTIFIER, Ci.nsICache.STORE_ON_DISK, true);
|
||||
this._stringInputStream = Components.Constructor(
|
||||
"@mozilla.org/io/string-input-stream;1", "nsIStringInputStream",
|
||||
"setData");
|
||||
this._storageStream = Components.Constructor(
|
||||
"@mozilla.org/storagestream;1", "nsIStorageStream",
|
||||
"init");
|
||||
|
||||
// store the preference value
|
||||
this.enablePersistentHttpsCaching =
|
||||
Services.prefs.getBoolPref(this.PREF_DISK_CACHE_SSL);
|
||||
|
||||
Services.prefs.addObserver(this.PREF_DISK_CACHE_SSL, this, false);
|
||||
|
||||
let self = this;
|
||||
// tabs are already loaded before UI is initialized so cache-control
|
||||
// values are unknown. We add browsers with https to the list for now.
|
||||
gBrowser.browsers.forEach(function(browser) {
|
||||
let checkAndAddToList = function(browserObj) {
|
||||
if (!self.enablePersistentHttpsCaching &&
|
||||
browserObj.currentURI.schemeIs("https"))
|
||||
self.excludedBrowsers.push(browserObj);
|
||||
};
|
||||
if (browser.contentDocument.readyState != "complete" ||
|
||||
browser.webProgress.isLoadingDocument) {
|
||||
browser.addEventListener("load", function() {
|
||||
browser.removeEventListener("load", arguments.callee, true);
|
||||
checkAndAddToList(browser);
|
||||
}, true);
|
||||
} else {
|
||||
checkAndAddToList(browser);
|
||||
}
|
||||
});
|
||||
gBrowser.addTabsProgressListener(this);
|
||||
},
|
||||
|
||||
// Function: uninit
|
||||
// Should be called when window is unloaded.
|
||||
uninit: function ThumbnailStorage_uninit() {
|
||||
gBrowser.removeTabsProgressListener(this);
|
||||
Services.prefs.removeObserver(this.PREF_DISK_CACHE_SSL, this);
|
||||
},
|
||||
|
||||
// ----------
|
||||
// Function: _openCacheEntry
|
||||
// Opens a cache entry for the given <url> and requests access <access>.
|
||||
// Calls <successCallback>(entry) when the entry was successfully opened with
|
||||
// requested access rights. Otherwise calls <errorCallback>().
|
||||
_openCacheEntry: function ThumbnailStorage__openCacheEntry(url, access, successCallback, errorCallback) {
|
||||
let onCacheEntryAvailable = function(entry, accessGranted, status) {
|
||||
if (entry && access == accessGranted && Components.isSuccessCode(status)) {
|
||||
successCallback(entry);
|
||||
} else {
|
||||
entry && entry.close();
|
||||
errorCallback();
|
||||
}
|
||||
}
|
||||
|
||||
let key = this.CACHE_PREFIX + url;
|
||||
|
||||
// switch to synchronous mode if parent window is about to close
|
||||
if (UI.isDOMWindowClosing) {
|
||||
let entry = this._cacheSession.openCacheEntry(key, access, true);
|
||||
let status = Cr.NS_OK;
|
||||
onCacheEntryAvailable(entry, entry.accessGranted, status);
|
||||
} else {
|
||||
let listener = new CacheListener(onCacheEntryAvailable);
|
||||
this._cacheSession.asyncOpenCacheEntry(key, access, listener);
|
||||
}
|
||||
},
|
||||
|
||||
// Function: _shouldSaveThumbnail
|
||||
// Checks whether to save tab's thumbnail or not.
|
||||
_shouldSaveThumbnail : function ThumbnailStorage__shouldSaveThumbnail(tab) {
|
||||
return (this.excludedBrowsers.indexOf(tab.linkedBrowser) == -1);
|
||||
},
|
||||
|
||||
// ----------
|
||||
// Function: saveThumbnail
|
||||
// Saves the <imageData> to the cache using the given <url> as key.
|
||||
// Calls <callback>(status, data) when finished, passing true or false
|
||||
// (indicating whether the operation succeeded).
|
||||
saveThumbnail: function ThumbnailStorage_saveThumbnail(tab, imageData, callback) {
|
||||
Utils.assert(tab, "tab");
|
||||
Utils.assert(imageData, "imageData");
|
||||
|
||||
if (!this._shouldSaveThumbnail(tab)) {
|
||||
tab._tabViewTabItem._sendToSubscribers("deniedToCacheImageData");
|
||||
if (callback)
|
||||
callback(false);
|
||||
return;
|
||||
}
|
||||
|
||||
let self = this;
|
||||
|
||||
let completed = function(status) {
|
||||
if (callback)
|
||||
callback(status);
|
||||
|
||||
if (status) {
|
||||
// Notify subscribers
|
||||
tab._tabViewTabItem._sendToSubscribers("savedCachedImageData");
|
||||
} else {
|
||||
Utils.log("Error while saving thumbnail: " + e);
|
||||
}
|
||||
};
|
||||
|
||||
let onCacheEntryAvailable = function(entry) {
|
||||
let outputStream = entry.openOutputStream(0);
|
||||
|
||||
let cleanup = function() {
|
||||
outputStream.close();
|
||||
entry.close();
|
||||
}
|
||||
|
||||
// switch to synchronous mode if parent window is about to close
|
||||
if (UI.isDOMWindowClosing) {
|
||||
outputStream.write(imageData, imageData.length);
|
||||
cleanup();
|
||||
completed(true);
|
||||
return;
|
||||
}
|
||||
|
||||
// asynchronous mode
|
||||
let inputStream = new self._stringInputStream(imageData, imageData.length);
|
||||
gNetUtil.asyncCopy(inputStream, outputStream, function (result) {
|
||||
cleanup();
|
||||
inputStream.close();
|
||||
completed(Components.isSuccessCode(result));
|
||||
});
|
||||
}
|
||||
|
||||
let onCacheEntryUnavailable = function() {
|
||||
completed(false);
|
||||
}
|
||||
|
||||
this._openCacheEntry(tab.linkedBrowser.currentURI.spec,
|
||||
Ci.nsICache.ACCESS_WRITE, onCacheEntryAvailable,
|
||||
onCacheEntryUnavailable);
|
||||
},
|
||||
|
||||
// ----------
|
||||
// Function: loadThumbnail
|
||||
// Asynchrously loads image data from the cache using the given <url> as key.
|
||||
// Calls <callback>(status, data) when finished, passing true or false
|
||||
// (indicating whether the operation succeeded) and the retrieved image data.
|
||||
loadThumbnail: function ThumbnailStorage_loadThumbnail(tab, url, callback) {
|
||||
Utils.assert(tab, "tab");
|
||||
Utils.assert(url, "url");
|
||||
Utils.assert(typeof callback == "function", "callback arg must be a function");
|
||||
|
||||
let self = this;
|
||||
|
||||
let completed = function(status, imageData) {
|
||||
callback(status, imageData);
|
||||
|
||||
if (status) {
|
||||
// Notify subscribers
|
||||
tab._tabViewTabItem._sendToSubscribers("loadedCachedImageData");
|
||||
} else {
|
||||
Utils.log("Error while loading thumbnail");
|
||||
}
|
||||
}
|
||||
|
||||
let onCacheEntryAvailable = function(entry) {
|
||||
let imageChunks = [];
|
||||
let nativeInputStream = entry.openInputStream(0);
|
||||
|
||||
const CHUNK_SIZE = 0x10000; // 65k
|
||||
const PR_UINT32_MAX = 0xFFFFFFFF;
|
||||
let storageStream = new self._storageStream(CHUNK_SIZE, PR_UINT32_MAX, null);
|
||||
let storageOutStream = storageStream.getOutputStream(0);
|
||||
|
||||
let cleanup = function () {
|
||||
nativeInputStream.close();
|
||||
storageStream.close();
|
||||
storageOutStream.close();
|
||||
entry.close();
|
||||
}
|
||||
|
||||
gNetUtil.asyncCopy(nativeInputStream, storageOutStream, function (result) {
|
||||
// cancel if parent window has already been closed
|
||||
if (typeof UI == "undefined") {
|
||||
cleanup();
|
||||
return;
|
||||
}
|
||||
|
||||
let imageData = null;
|
||||
let isSuccess = Components.isSuccessCode(result);
|
||||
|
||||
if (isSuccess) {
|
||||
let storageInStream = storageStream.newInputStream(0);
|
||||
imageData = gNetUtil.readInputStreamToString(storageInStream,
|
||||
storageInStream.available());
|
||||
storageInStream.close();
|
||||
}
|
||||
|
||||
cleanup();
|
||||
completed(isSuccess, imageData);
|
||||
});
|
||||
}
|
||||
|
||||
let onCacheEntryUnavailable = function() {
|
||||
completed(false);
|
||||
}
|
||||
|
||||
this._openCacheEntry(url, Ci.nsICache.ACCESS_READ,
|
||||
onCacheEntryAvailable, onCacheEntryUnavailable);
|
||||
},
|
||||
|
||||
// ----------
|
||||
// Function: observe
|
||||
// Implements the observer interface.
|
||||
observe: function ThumbnailStorage_observe(subject, topic, data) {
|
||||
this.enablePersistentHttpsCaching =
|
||||
Services.prefs.getBoolPref(this.PREF_DISK_CACHE_SSL);
|
||||
},
|
||||
|
||||
// ----------
|
||||
// Implements progress listener interface.
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener,
|
||||
Ci.nsISupportsWeakReference,
|
||||
Ci.nsISupports]),
|
||||
|
||||
onStateChange: function ThumbnailStorage_onStateChange(
|
||||
browser, webProgress, request, flag, status) {
|
||||
if (flag & Ci.nsIWebProgressListener.STATE_START &&
|
||||
flag & Ci.nsIWebProgressListener.STATE_IS_WINDOW) {
|
||||
// ensure the dom window is the top one
|
||||
if (webProgress.DOMWindow.parent == webProgress.DOMWindow) {
|
||||
let index = this.excludedBrowsers.indexOf(browser);
|
||||
if (index != -1)
|
||||
this.excludedBrowsers.splice(index, 1);
|
||||
}
|
||||
}
|
||||
if (flag & Ci.nsIWebProgressListener.STATE_STOP &&
|
||||
flag & Ci.nsIWebProgressListener.STATE_IS_WINDOW) {
|
||||
// ensure the dom window is the top one
|
||||
if (webProgress.DOMWindow.parent == webProgress.DOMWindow &&
|
||||
request && request instanceof Ci.nsIHttpChannel) {
|
||||
request.QueryInterface(Ci.nsIHttpChannel);
|
||||
|
||||
let inhibitPersistentThumb = false;
|
||||
if (request.isNoStoreResponse()) {
|
||||
inhibitPersistentThumb = true;
|
||||
} else if (!this.enablePersistentHttpsCaching &&
|
||||
request.URI.schemeIs("https")) {
|
||||
let cacheControlHeader;
|
||||
try {
|
||||
cacheControlHeader = request.getResponseHeader("Cache-Control");
|
||||
} catch(e) {
|
||||
// this error would occur when "Cache-Control" doesn't exist in
|
||||
// the eaders
|
||||
}
|
||||
if (cacheControlHeader && !(/public/i).test(cacheControlHeader))
|
||||
inhibitPersistentThumb = true;
|
||||
}
|
||||
|
||||
if (inhibitPersistentThumb &&
|
||||
this.excludedBrowsers.indexOf(browser) == -1)
|
||||
this.excludedBrowsers.push(browser);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ##########
|
||||
// Class: CacheListener
|
||||
// Generic CacheListener for feeding to asynchronous cache calls.
|
||||
// Calls <callback>(entry, access, status) when the requested cache entry
|
||||
// is available.
|
||||
function CacheListener(callback) {
|
||||
Utils.assert(typeof callback == "function", "callback arg must be a function");
|
||||
this.callback = callback;
|
||||
};
|
||||
|
||||
CacheListener.prototype = {
|
||||
// ----------
|
||||
// Function: toString
|
||||
// Prints [CacheListener] for debug use
|
||||
toString: function CacheListener_toString() {
|
||||
return "[CacheListener]";
|
||||
},
|
||||
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsICacheListener]),
|
||||
onCacheEntryAvailable: function CacheListener_onCacheEntryAvailable(
|
||||
entry, access, status) {
|
||||
this.callback(entry, access, status);
|
||||
}
|
||||
};
|
||||
|
@ -157,6 +157,9 @@ let UI = {
|
||||
// initialize the direction of the page
|
||||
this._initPageDirection();
|
||||
|
||||
// ___ thumbnail storage
|
||||
ThumbnailStorage.init();
|
||||
|
||||
// ___ storage
|
||||
Storage.init();
|
||||
let data = Storage.readUIData(gWindow);
|
||||
@ -278,7 +281,7 @@ let UI = {
|
||||
// initialized.
|
||||
let event = document.createEvent("Events");
|
||||
event.initEvent("tabviewframeinitialized", true, false);
|
||||
dispatchEvent(event);
|
||||
dispatchEvent(event);
|
||||
} catch(e) {
|
||||
Utils.log(e);
|
||||
} finally {
|
||||
@ -286,6 +289,8 @@ let UI = {
|
||||
}
|
||||
},
|
||||
|
||||
// Function: uninit
|
||||
// Should be called when window is unloaded.
|
||||
uninit: function UI_uninit() {
|
||||
// call our cleanup functions
|
||||
this._cleanupFunctions.forEach(function(func) {
|
||||
@ -297,6 +302,7 @@ let UI = {
|
||||
TabItems.uninit();
|
||||
GroupItems.uninit();
|
||||
Storage.uninit();
|
||||
ThumbnailStorage.uninit();
|
||||
|
||||
this._removeTabActionHandlers();
|
||||
this._currentTab = null;
|
||||
@ -680,22 +686,22 @@ let UI = {
|
||||
// don't reenter Panorama due to all of the session restore tab
|
||||
// manipulation (which otherwise we might). When transitioning away from
|
||||
// PB, we reenter Panorama if we had been there directly before PB.
|
||||
function pbObserver(aSubject, aTopic, aData) {
|
||||
if (aTopic == "private-browsing") {
|
||||
function pbObserver(subject, topic, data) {
|
||||
if (topic == "private-browsing") {
|
||||
// We could probably do this in private-browsing-change-granted, but
|
||||
// this seems like a nicer spot, right in the middle of the process.
|
||||
if (aData == "enter") {
|
||||
if (data == "enter") {
|
||||
// If we are in Tab View, exit.
|
||||
self._privateBrowsing.wasInTabView = self.isTabViewVisible();
|
||||
if (self.isTabViewVisible())
|
||||
self.goToTab(gBrowser.selectedTab);
|
||||
}
|
||||
} else if (aTopic == "private-browsing-change-granted") {
|
||||
if (aData == "enter" || aData == "exit") {
|
||||
self._privateBrowsing.transitionMode = aData;
|
||||
} else if (topic == "private-browsing-change-granted") {
|
||||
if (data == "enter" || data == "exit") {
|
||||
self._privateBrowsing.transitionMode = data;
|
||||
self.storageBusy();
|
||||
}
|
||||
} else if (aTopic == "private-browsing-transition-complete") {
|
||||
} else if (topic == "private-browsing-transition-complete") {
|
||||
// We use .transitionMode here, as aData is empty.
|
||||
if (self._privateBrowsing.transitionMode == "exit" &&
|
||||
self._privateBrowsing.wasInTabView)
|
||||
@ -990,21 +996,28 @@ let UI = {
|
||||
[
|
||||
#ifdef XP_UNIX
|
||||
"quitApplication",
|
||||
#else
|
||||
"redo",
|
||||
#endif
|
||||
#ifdef XP_MACOSX
|
||||
"preferencesCmdMac", "minimizeWindow",
|
||||
#endif
|
||||
"newNavigator", "newNavigatorTab", "undo", "cut", "copy", "paste",
|
||||
"selectAll", "find"
|
||||
].forEach(function(key) {
|
||||
].forEach(function(key) {
|
||||
let element = gWindow.document.getElementById("key_" + key);
|
||||
keys[key] = element.getAttribute("key").toLocaleLowerCase().charCodeAt(0);
|
||||
});
|
||||
|
||||
// for key combinations with shift key, the charCode of upper case letters
|
||||
// are different to the lower case ones so need to handle them differently.
|
||||
["closeWindow", "tabview", "undoCloseTab", "undoCloseWindow",
|
||||
"privatebrowsing", "redo"].forEach(function(key) {
|
||||
[
|
||||
#ifdef XP_UNIX
|
||||
"redo",
|
||||
#endif
|
||||
"closeWindow", "tabview", "undoCloseTab", "undoCloseWindow",
|
||||
"privatebrowsing"
|
||||
].forEach(function(key) {
|
||||
let element = gWindow.document.getElementById("key_" + key);
|
||||
keys[key] = element.getAttribute("key").toLocaleUpperCase().charCodeAt(0);
|
||||
});
|
||||
@ -1039,22 +1052,33 @@ let UI = {
|
||||
let preventDefault = true;
|
||||
if (evt.shiftKey) {
|
||||
switch (evt.charCode) {
|
||||
case self._browserKeys.privatebrowsing:
|
||||
case self._browserKeys.undoCloseTab:
|
||||
case self._browserKeys.undoCloseWindow:
|
||||
case self._browserKeys.closeWindow:
|
||||
case self._browserKeys.redo:
|
||||
preventDefault = false;
|
||||
break;
|
||||
case self._browserKeys.tabview:
|
||||
self.exit();
|
||||
break;
|
||||
#ifdef XP_UNIX
|
||||
case self._browserKeys.redo:
|
||||
#endif
|
||||
case self._browserKeys.closeWindow:
|
||||
case self._browserKeys.undoCloseTab:
|
||||
case self._browserKeys.undoCloseWindow:
|
||||
case self._browserKeys.privatebrowsing:
|
||||
preventDefault = false;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (evt.charCode) {
|
||||
case self._browserKeys.find:
|
||||
self.enableSearch();
|
||||
break;
|
||||
#ifdef XP_UNIX
|
||||
case self._browserKeys.quitApplication:
|
||||
#else
|
||||
case self._browserKeys.redo:
|
||||
#endif
|
||||
#ifdef XP_MACOSX
|
||||
case self._browserKeys.preferencesCmdMac:
|
||||
case self._browserKeys.minimizeWindow:
|
||||
#endif
|
||||
case self._browserKeys.newNavigator:
|
||||
case self._browserKeys.newNavigatorTab:
|
||||
case self._browserKeys.undo:
|
||||
@ -1064,17 +1088,6 @@ let UI = {
|
||||
case self._browserKeys.selectAll:
|
||||
preventDefault = false;
|
||||
break;
|
||||
#ifdef XP_UNIX
|
||||
case self._browserKeys.quitApplication:
|
||||
preventDefault = false;
|
||||
break;
|
||||
#endif
|
||||
#ifdef XP_MACOSX
|
||||
case self._browserKeys.preferencesCmdMac:
|
||||
case self._browserKeys.minimizeWindow:
|
||||
preventDefault = false;
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
if (preventDefault) {
|
||||
|
@ -113,6 +113,7 @@ _BROWSER_FILES = \
|
||||
browser_tabview_bug626368.js \
|
||||
browser_tabview_bug626525.js \
|
||||
browser_tabview_bug626791.js \
|
||||
browser_tabview_bug627239.js \
|
||||
browser_tabview_bug627288.js \
|
||||
browser_tabview_bug627736.js \
|
||||
browser_tabview_bug628061.js \
|
||||
|
@ -1,6 +1,9 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
const fi = Cc["@mozilla.org/browser/favicon-service;1"].
|
||||
getService(Ci.nsIFaviconService);
|
||||
|
||||
let newTab;
|
||||
|
||||
function test() {
|
||||
@ -27,7 +30,7 @@ function onTabViewWindowLoaded() {
|
||||
is($icon.data("xulTab"), newTab,
|
||||
"The app tab icon has the right tab reference")
|
||||
// check to see whether it's showing the default one or not.
|
||||
is($icon.attr("src"), contentWindow.Utils.defaultFaviconURL,
|
||||
is($icon.attr("src"), fi.defaultFavicon.spec,
|
||||
"The icon is showing the default fav icon for blank tab");
|
||||
|
||||
let errorHandler = function(event) {
|
||||
@ -37,7 +40,7 @@ function onTabViewWindowLoaded() {
|
||||
// fired, a delay is used here to avoid the test code run before the browser
|
||||
// code.
|
||||
executeSoon(function() {
|
||||
is($icon.attr("src"), contentWindow.Utils.defaultFaviconURL,
|
||||
is($icon.attr("src"), fi.defaultFavicon.spec,
|
||||
"The icon is showing the default fav icon");
|
||||
|
||||
// clean up
|
||||
|
@ -2,8 +2,9 @@
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
function test() {
|
||||
let url = "http://non.existant/url";
|
||||
let url = "http://www.example.com/";
|
||||
let cw;
|
||||
let tab = gBrowser.tabs[0];
|
||||
|
||||
let finishTest = function () {
|
||||
is(1, gBrowser.tabs.length, "there is one tab, only");
|
||||
@ -14,7 +15,7 @@ function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
let testErroneousLoading = function () {
|
||||
cw.Storage.loadThumbnail(url, function (status, data) {
|
||||
cw.ThumbnailStorage.loadThumbnail(tab, url, function (status, data) {
|
||||
ok(!status, "thumbnail entry failed to load");
|
||||
is(null, data, "no thumbnail data received");
|
||||
next();
|
||||
@ -25,11 +26,11 @@ function test() {
|
||||
let saved = false;
|
||||
let data = "thumbnail-data-asynchronous";
|
||||
|
||||
cw.Storage.saveThumbnail(url, data, function (status) {
|
||||
cw.ThumbnailStorage.saveThumbnail(tab, data, function (status) {
|
||||
ok(status, "thumbnail entry was saved");
|
||||
ok(saved, "thumbnail was saved asynchronously");
|
||||
|
||||
cw.Storage.loadThumbnail(url, function (status, imageData) {
|
||||
cw.ThumbnailStorage.loadThumbnail(tab, url, function (status, imageData) {
|
||||
ok(status, "thumbnail entry was loaded");
|
||||
is(imageData, data, "valid thumbnail data received");
|
||||
next();
|
||||
@ -46,11 +47,11 @@ function test() {
|
||||
cw.UI.isDOMWindowClosing = true;
|
||||
registerCleanupFunction(function () cw.UI.isDOMWindowClosing = false);
|
||||
|
||||
cw.Storage.saveThumbnail(url, data, function (status) {
|
||||
cw.ThumbnailStorage.saveThumbnail(tab, data, function (status) {
|
||||
ok(status, "thumbnail entry was saved");
|
||||
ok(!saved, "thumbnail was saved synchronously");
|
||||
|
||||
cw.Storage.loadThumbnail(url, function (status, imageData) {
|
||||
cw.ThumbnailStorage.loadThumbnail(tab, url, function (status, imageData) {
|
||||
ok(status, "thumbnail entry was loaded");
|
||||
is(imageData, data, "valid thumbnail data received");
|
||||
|
||||
@ -72,10 +73,13 @@ function test() {
|
||||
hideTabView(finishTest);
|
||||
}
|
||||
|
||||
showTabView(function () {
|
||||
registerCleanupFunction(function () TabView.hide());
|
||||
cw = TabView.getContentWindow();
|
||||
tab.linkedBrowser.loadURI(url);
|
||||
afterAllTabsLoaded(function() {
|
||||
showTabView(function () {
|
||||
registerCleanupFunction(function () TabView.hide());
|
||||
cw = TabView.getContentWindow();
|
||||
|
||||
next();
|
||||
next();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
156
browser/base/content/test/tabview/browser_tabview_bug627239.js
Normal file
156
browser/base/content/test/tabview/browser_tabview_bug627239.js
Normal file
@ -0,0 +1,156 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
let contentWindow;
|
||||
let enablePersistentHttpsCaching;
|
||||
let newTab;
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
newTab = gBrowser.addTab();
|
||||
|
||||
HttpRequestObserver.register();
|
||||
|
||||
registerCleanupFunction(function () {
|
||||
HttpRequestObserver.unregister();
|
||||
if (gBrowser.tabs[1])
|
||||
gBrowser.removeTab(gBrowser.tabs[1]);
|
||||
hideTabView(function () {});
|
||||
|
||||
contentWindow.ThumbnailStorage.enablePersistentHttpsCaching =
|
||||
enablePersistentHttpsCaching;
|
||||
});
|
||||
|
||||
showTabView(function() {
|
||||
contentWindow = TabView.getContentWindow();
|
||||
test1();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function test1() {
|
||||
// page with cache-control: no-store, should not save thumbnail
|
||||
HttpRequestObserver.cacheControlValue = "no-store";
|
||||
newTab.linkedBrowser.loadURI("http://www.example.com/browser/browser/base/content/test/tabview/dummy_page.html");
|
||||
|
||||
afterAllTabsLoaded(function() {
|
||||
let tabItem = newTab._tabViewTabItem;
|
||||
|
||||
ok(!contentWindow.ThumbnailStorage._shouldSaveThumbnail(newTab),
|
||||
"Should not save the thumbnail for tab");
|
||||
|
||||
tabItem.addSubscriber(tabItem, "deniedToCacheImageData", function() {
|
||||
tabItem.removeSubscriber(tabItem, "deniedToCacheImageData");
|
||||
test2();
|
||||
});
|
||||
tabItem.save(true);
|
||||
HttpRequestObserver.cacheControlValue = null;
|
||||
});
|
||||
}
|
||||
|
||||
function test2() {
|
||||
// page with cache-control: private, should save thumbnail
|
||||
HttpRequestObserver.cacheControlValue = "private";
|
||||
|
||||
newTab.linkedBrowser.loadURI("http://www.example.com/");
|
||||
afterAllTabsLoaded(function() {
|
||||
let tabItem = newTab._tabViewTabItem;
|
||||
|
||||
ok(contentWindow.ThumbnailStorage._shouldSaveThumbnail(newTab),
|
||||
"Should save the thumbnail for tab");
|
||||
|
||||
tabItem.addSubscriber(tabItem, "savedCachedImageData", function() {
|
||||
tabItem.removeSubscriber(tabItem, "savedCachedImageData");
|
||||
test3();
|
||||
});
|
||||
tabItem.save(true);
|
||||
});
|
||||
}
|
||||
|
||||
function test3() {
|
||||
// page with cache-control: private with https caching enabled, should save thumbnail
|
||||
HttpRequestObserver.cacheControlValue = "private";
|
||||
|
||||
enablePersistentHttpsCaching =
|
||||
contentWindow.ThumbnailStorage.enablePersistentHttpsCaching;
|
||||
contentWindow.ThumbnailStorage.enablePersistentHttpsCaching = true;
|
||||
|
||||
newTab.linkedBrowser.loadURI("https://example.com/browser/browser/base/content/test/tabview/dummy_page.html");
|
||||
afterAllTabsLoaded(function() {
|
||||
let tabItem = newTab._tabViewTabItem;
|
||||
|
||||
ok(contentWindow.ThumbnailStorage._shouldSaveThumbnail(newTab),
|
||||
"Should save the thumbnail for tab");
|
||||
|
||||
tabItem.addSubscriber(tabItem, "savedCachedImageData", function() {
|
||||
tabItem.removeSubscriber(tabItem, "savedCachedImageData");
|
||||
|
||||
test4();
|
||||
});
|
||||
tabItem.save(true);
|
||||
});
|
||||
}
|
||||
|
||||
function test4() {
|
||||
// page with cache-control: public with https caching disabled, should save thumbnail
|
||||
HttpRequestObserver.cacheControlValue = "public";
|
||||
|
||||
contentWindow.ThumbnailStorage.enablePersistentHttpsCaching = false;
|
||||
|
||||
newTab.linkedBrowser.loadURI("https://example.com/browser/browser/base/content/test/tabview/");
|
||||
afterAllTabsLoaded(function() {
|
||||
let tabItem = newTab._tabViewTabItem;
|
||||
|
||||
ok(contentWindow.ThumbnailStorage._shouldSaveThumbnail(newTab),
|
||||
"Should save the thumbnail for tab");
|
||||
|
||||
tabItem.addSubscriber(tabItem, "savedCachedImageData", function() {
|
||||
tabItem.removeSubscriber(tabItem, "savedCachedImageData");
|
||||
|
||||
test5();
|
||||
});
|
||||
tabItem.save(true);
|
||||
});
|
||||
}
|
||||
|
||||
function test5() {
|
||||
// page with cache-control: private with https caching disabled, should not save thumbnail
|
||||
HttpRequestObserver.cacheControlValue = "private";
|
||||
|
||||
newTab.linkedBrowser.loadURI("https://example.com/");
|
||||
afterAllTabsLoaded(function() {
|
||||
let tabItem = newTab._tabViewTabItem;
|
||||
|
||||
ok(!contentWindow.ThumbnailStorage._shouldSaveThumbnail(newTab),
|
||||
"Should not the thumbnail for tab");
|
||||
|
||||
tabItem.addSubscriber(tabItem, "deniedToCacheImageData", function() {
|
||||
tabItem.removeSubscriber(tabItem, "deniedToCacheImageData");
|
||||
|
||||
hideTabView(function () {
|
||||
gBrowser.removeTab(gBrowser.tabs[1]);
|
||||
finish();
|
||||
});
|
||||
});
|
||||
tabItem.save(true);
|
||||
});
|
||||
}
|
||||
|
||||
let HttpRequestObserver = {
|
||||
cacheControlValue: null,
|
||||
|
||||
observe: function(subject, topic, data) {
|
||||
if (topic == "http-on-examine-response" && this.cacheControlValue) {
|
||||
let httpChannel = subject.QueryInterface(Ci.nsIHttpChannel);
|
||||
httpChannel.setResponseHeader("Cache-Control", this.cacheControlValue, false);
|
||||
}
|
||||
},
|
||||
|
||||
register: function() {
|
||||
Services.obs.addObserver(this, "http-on-examine-response", false);
|
||||
},
|
||||
|
||||
unregister: function() {
|
||||
Services.obs.removeObserver(this, "http-on-examine-response");
|
||||
}
|
||||
};
|
@ -7,17 +7,18 @@ var prefsBranch = Cc["@mozilla.org/preferences-service;1"].
|
||||
|
||||
function animateZoom() prefsBranch.getBoolPref("animate_zoom");
|
||||
|
||||
function registerCleanupFunction() {
|
||||
prefsBranch.setUserPref("animate_zoom", true);
|
||||
}
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
let charsetArg = "charset=" + window.content.document.characterSet;
|
||||
let win = window.openDialog(getBrowserURL(), "_blank", "chrome,all,dialog=no",
|
||||
"about:blank", charsetArg, null, null, true);
|
||||
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
prefsBranch.setBoolPref("animate_zoom", true);
|
||||
win.close();
|
||||
});
|
||||
|
||||
ok(animateZoom(), "By default, we animate on zoom.");
|
||||
prefsBranch.setBoolPref("animate_zoom", false);
|
||||
ok(!animateZoom(), "animate_zoom = false");
|
||||
@ -29,27 +30,24 @@ function test() {
|
||||
let tabViewWindow = null;
|
||||
let transitioned = 0;
|
||||
|
||||
let onShown = function() {
|
||||
win.removeEventListener("tabviewshown", onShown, false);
|
||||
|
||||
ok(!transitioned, "There should be no transitions");
|
||||
win.close();
|
||||
|
||||
finish();
|
||||
};
|
||||
|
||||
let initCallback = function() {
|
||||
tabViewWindow = win.TabView._window;
|
||||
function onTransitionEnd(event) {
|
||||
transitioned++;
|
||||
tabViewWindow.Utils.log(transitioned);
|
||||
info(transitioned);
|
||||
}
|
||||
tabViewWindow.document.addEventListener("transitionend", onTransitionEnd, false);
|
||||
|
||||
win.TabView.show();
|
||||
showTabView(function() {
|
||||
ok(!transitioned, "There should be no transitions");
|
||||
|
||||
tabViewWindow.document.removeEventListener(
|
||||
"transitionend", onTransitionEnd, false);
|
||||
|
||||
finish();
|
||||
}, win);
|
||||
};
|
||||
|
||||
win.addEventListener("tabviewshown", onShown, false);
|
||||
win.TabView._initFrame(initCallback);
|
||||
}
|
||||
win.addEventListener("load", onLoad, false);
|
||||
|
@ -31,7 +31,9 @@ function onTabViewWindowLoaded() {
|
||||
|
||||
is(groupItem.getChildren().length, 1, "The new group has a tab item");
|
||||
// start the tests
|
||||
testUndoGroup(contentWindow, groupItem);
|
||||
waitForFocus(function() {
|
||||
testUndoGroup(contentWindow, groupItem);
|
||||
}, contentWindow);
|
||||
};
|
||||
window.addEventListener("tabviewhidden", onTabViewHidden, false);
|
||||
window.addEventListener("tabviewshown", onTabViewShown, false);
|
||||
@ -80,7 +82,7 @@ function testUndoGroup(contentWindow, groupItem) {
|
||||
});
|
||||
|
||||
let closeButton = groupItem.container.getElementsByClassName("close");
|
||||
ok(closeButton, "Group item close button exists");
|
||||
ok(closeButton[0], "Group item close button exists");
|
||||
EventUtils.sendMouseEvent({ type: "click" }, closeButton[0], contentWindow);
|
||||
}
|
||||
|
||||
@ -129,6 +131,6 @@ function testCloseUndoGroup(contentWindow, groupItem) {
|
||||
});
|
||||
|
||||
let closeButton = groupItem.container.getElementsByClassName("close");
|
||||
ok(closeButton, "Group item close button exists");
|
||||
ok(closeButton[0], "Group item close button exists");
|
||||
EventUtils.sendMouseEvent({ type: "click" }, closeButton[0], contentWindow);
|
||||
}
|
||||
|
@ -42,9 +42,9 @@
|
||||
xmlns:xbl="http://www.mozilla.org/xbl">
|
||||
<binding id="site" extends="chrome://global/content/bindings/richlistbox.xml#richlistitem">
|
||||
<content>
|
||||
<xul:hbox class="site-container" align="center">
|
||||
<xul:hbox class="site-container" align="center" flex="1">
|
||||
<xul:image xbl:inherits="src=favicon" class="site-favicon"/>
|
||||
<xul:label xbl:inherits="value,selected" class="site-domain" crop="end"/>
|
||||
<xul:label xbl:inherits="value,selected" class="site-domain" crop="end" flex="1"/>
|
||||
</xul:hbox>
|
||||
</content>
|
||||
</binding>
|
||||
|
@ -19,11 +19,10 @@
|
||||
|
||||
#sites-box {
|
||||
padding: 10px;
|
||||
width: 25em;
|
||||
}
|
||||
|
||||
.site {
|
||||
width: 250px;
|
||||
overflow-x: hidden;
|
||||
padding: 4px;
|
||||
border-bottom: 1px solid ThreeDLightShadow;
|
||||
}
|
||||
@ -39,10 +38,6 @@
|
||||
list-style-image: none;
|
||||
}
|
||||
|
||||
.site-domain {
|
||||
max-width: 200px; /* crop set in XBL will ellipsize the domain if it's too long */
|
||||
}
|
||||
|
||||
/* permissions box */
|
||||
|
||||
#permissions-box {
|
||||
|
@ -21,11 +21,10 @@
|
||||
|
||||
#sites-box {
|
||||
padding: 10px;
|
||||
width: 25em;
|
||||
}
|
||||
|
||||
.site {
|
||||
width: 250px;
|
||||
overflow-x: hidden;
|
||||
padding: 4px;
|
||||
border-bottom: 1px solid ThreeDLightShadow;
|
||||
}
|
||||
@ -41,10 +40,6 @@
|
||||
list-style-image: none;
|
||||
}
|
||||
|
||||
.site-domain {
|
||||
max-width: 200px; /* crop set in XBL will ellipsize the domain if it's too long */
|
||||
}
|
||||
|
||||
/* permissions box */
|
||||
|
||||
#permissions-box {
|
||||
|
@ -24,11 +24,10 @@
|
||||
|
||||
#sites-box {
|
||||
padding: 10px;
|
||||
width: 25em;
|
||||
}
|
||||
|
||||
.site {
|
||||
width: 250px;
|
||||
overflow-x: hidden;
|
||||
padding: 4px;
|
||||
border-bottom: 1px solid ThreeDLightShadow;
|
||||
}
|
||||
@ -44,10 +43,6 @@
|
||||
list-style-image: none;
|
||||
}
|
||||
|
||||
.site-domain {
|
||||
max-width: 200px; /* crop set in XBL will ellipsize the domain if it's too long */
|
||||
}
|
||||
|
||||
/* permissions box */
|
||||
|
||||
#permissions-box {
|
||||
|
@ -1326,6 +1326,31 @@ nsHTMLInputElement::SetFiles(const nsCOMArray<nsIDOMFile>& aFiles,
|
||||
mFiles.Clear();
|
||||
mFiles.AppendObjects(aFiles);
|
||||
|
||||
AfterSetFiles(aSetValueChanged);
|
||||
}
|
||||
|
||||
void
|
||||
nsHTMLInputElement::SetFiles(nsIDOMFileList* aFiles,
|
||||
bool aSetValueChanged)
|
||||
{
|
||||
mFiles.Clear();
|
||||
|
||||
if (aFiles) {
|
||||
PRUint32 listLength;
|
||||
aFiles->GetLength(&listLength);
|
||||
for (PRUint32 i = 0; i < listLength; i++) {
|
||||
nsCOMPtr<nsIDOMFile> file;
|
||||
aFiles->Item(i, getter_AddRefs(file));
|
||||
mFiles.AppendObject(file);
|
||||
}
|
||||
}
|
||||
|
||||
AfterSetFiles(aSetValueChanged);
|
||||
}
|
||||
|
||||
void
|
||||
nsHTMLInputElement::AfterSetFiles(bool aSetValueChanged)
|
||||
{
|
||||
// No need to flush here, if there's no frame at this point we
|
||||
// don't need to force creation of one just to tell it about this
|
||||
// new value. We just want the display to update as needed.
|
||||
|
@ -145,11 +145,11 @@ public:
|
||||
{
|
||||
return nsGenericHTMLElement::GetEditor(aEditor);
|
||||
}
|
||||
|
||||
// Forward nsIDOMHTMLElement
|
||||
NS_FORWARD_NSIDOMHTMLELEMENT_NOFOCUSCLICK(nsGenericHTMLFormElement::)
|
||||
NS_IMETHOD Focus();
|
||||
NS_IMETHOD Click();
|
||||
|
||||
// Forward nsIDOMHTMLElement
|
||||
NS_FORWARD_NSIDOMHTMLELEMENT_NOFOCUSCLICK(nsGenericHTMLFormElement::)
|
||||
NS_IMETHOD Focus();
|
||||
NS_IMETHOD Click();
|
||||
|
||||
NS_IMETHOD SetUserInput(const nsAString& aInput);
|
||||
|
||||
@ -218,6 +218,7 @@ public:
|
||||
void GetDisplayFileName(nsAString& aFileName) const;
|
||||
const nsCOMArray<nsIDOMFile>& GetFiles() const;
|
||||
void SetFiles(const nsCOMArray<nsIDOMFile>& aFiles, bool aSetValueChanged);
|
||||
void SetFiles(nsIDOMFileList* aFiles, bool aSetValueChanged);
|
||||
|
||||
void SetCheckedChangedInternal(PRBool aCheckedChanged);
|
||||
PRBool GetCheckedChanged() const {
|
||||
@ -457,6 +458,11 @@ protected:
|
||||
*/
|
||||
nsresult UpdateFileList();
|
||||
|
||||
/**
|
||||
* Called after calling one of the SetFiles() functions.
|
||||
*/
|
||||
void AfterSetFiles(bool aSetValueChanged);
|
||||
|
||||
/**
|
||||
* Determine whether the editor needs to be initialized explicitly for
|
||||
* a particular event.
|
||||
|
@ -79,6 +79,7 @@ EXPORTS = \
|
||||
nsPluginTags.h \
|
||||
nsPluginDirServiceProvider.h \
|
||||
nsPluginHost.h \
|
||||
nsPluginInstanceOwner.h \
|
||||
$(NULL)
|
||||
|
||||
EXPORTS_mozilla = \
|
||||
@ -95,6 +96,7 @@ CPPSRCS = \
|
||||
nsJSNPRuntime.cpp \
|
||||
nsPluginTags.cpp \
|
||||
PluginPRLibrary.cpp \
|
||||
nsPluginInstanceOwner.cpp \
|
||||
$(NULL)
|
||||
|
||||
ifeq ($(OS_ARCH),WINNT)
|
||||
@ -127,6 +129,7 @@ endif
|
||||
|
||||
LOCAL_INCLUDES = \
|
||||
-I$(topsrcdir)/xpcom/base/ \
|
||||
$(MOZ_CAIRO_CFLAGS) \
|
||||
$(NULL)
|
||||
|
||||
ifneq (,$(filter WINNT Darwin,$(OS_ARCH)))
|
||||
@ -146,6 +149,7 @@ ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT))
|
||||
EXTRA_DSO_LDOPTS += $(TK_LIBS)
|
||||
endif
|
||||
|
||||
include $(topsrcdir)/dom/dom-config.mk
|
||||
include $(topsrcdir)/config/config.mk
|
||||
include $(topsrcdir)/ipc/chromium/chromium-config.mk
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
3402
dom/plugins/base/nsPluginInstanceOwner.cpp
Normal file
3402
dom/plugins/base/nsPluginInstanceOwner.cpp
Normal file
File diff suppressed because it is too large
Load Diff
407
dom/plugins/base/nsPluginInstanceOwner.h
Normal file
407
dom/plugins/base/nsPluginInstanceOwner.h
Normal file
@ -0,0 +1,407 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
// vim:set ts=2 sts=2 sw=2 et cin:
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1998
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Pierre Phaneuf <pp@ludusdesign.com>
|
||||
* Jacek Piskozub <piskozub@iopan.gda.pl>
|
||||
* Leon Sha <leon.sha@sun.com>
|
||||
* Roland Mainz <roland.mainz@informatik.med.uni-giessen.de>
|
||||
* Robert O'Callahan <roc+moz@cs.cmu.edu>
|
||||
* Christian Biesinger <cbiesinger@web.de>
|
||||
* Josh Aas <josh@mozilla.com>
|
||||
* Mats Palmgren <matspal@gmail.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef nsPluginInstanceOwner_h_
|
||||
#define nsPluginInstanceOwner_h_
|
||||
|
||||
#include "prtypes.h"
|
||||
#include "npapi.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIPluginInstanceOwner.h"
|
||||
#include "nsIPluginTagInfo.h"
|
||||
#include "nsIDOMMouseListener.h"
|
||||
#include "nsIDOMMouseMotionListener.h"
|
||||
#include "nsIDOMKeyListener.h"
|
||||
#include "nsIDOMFocusListener.h"
|
||||
#include "nsIScrollPositionListener.h"
|
||||
#include "nsPluginHost.h"
|
||||
#include "nsPluginNativeWindow.h"
|
||||
#include "gfxRect.h"
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
#include "nsCoreAnimationSupport.h"
|
||||
#include <ApplicationServices/ApplicationServices.h>
|
||||
#endif
|
||||
|
||||
class nsIInputStream;
|
||||
class nsIntRect;
|
||||
class nsPluginDOMContextMenuListener;
|
||||
class nsObjectFrame;
|
||||
class nsDisplayListBuilder;
|
||||
|
||||
#ifdef MOZ_X11
|
||||
class gfxXlibSurface;
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_WIDGET_GTK2
|
||||
#include "gfxXlibNativeRenderer.h"
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_WIDGET_QT
|
||||
#include "gfxQtNativeRenderer.h"
|
||||
#endif
|
||||
|
||||
class nsPluginInstanceOwner : public nsIPluginInstanceOwner,
|
||||
public nsIPluginTagInfo,
|
||||
public nsIDOMMouseListener,
|
||||
public nsIDOMMouseMotionListener,
|
||||
public nsIDOMKeyListener,
|
||||
public nsIDOMFocusListener,
|
||||
public nsIScrollPositionListener
|
||||
{
|
||||
public:
|
||||
nsPluginInstanceOwner();
|
||||
virtual ~nsPluginInstanceOwner();
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIPLUGININSTANCEOWNER
|
||||
|
||||
NS_IMETHOD GetURL(const char *aURL, const char *aTarget,
|
||||
nsIInputStream *aPostStream,
|
||||
void *aHeadersData, PRUint32 aHeadersDataLen);
|
||||
|
||||
NS_IMETHOD ShowStatus(const PRUnichar *aStatusMsg);
|
||||
|
||||
NPError ShowNativeContextMenu(NPMenu* menu, void* event);
|
||||
|
||||
NPBool ConvertPoint(double sourceX, double sourceY, NPCoordinateSpace sourceSpace,
|
||||
double *destX, double *destY, NPCoordinateSpace destSpace);
|
||||
|
||||
//nsIPluginTagInfo interface
|
||||
NS_DECL_NSIPLUGINTAGINFO
|
||||
|
||||
// nsIDOMMouseListener interfaces
|
||||
NS_IMETHOD MouseDown(nsIDOMEvent* aMouseEvent);
|
||||
NS_IMETHOD MouseUp(nsIDOMEvent* aMouseEvent);
|
||||
NS_IMETHOD MouseClick(nsIDOMEvent* aMouseEvent);
|
||||
NS_IMETHOD MouseDblClick(nsIDOMEvent* aMouseEvent);
|
||||
NS_IMETHOD MouseOver(nsIDOMEvent* aMouseEvent);
|
||||
NS_IMETHOD MouseOut(nsIDOMEvent* aMouseEvent);
|
||||
NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent);
|
||||
|
||||
// nsIDOMMouseMotionListener interfaces
|
||||
NS_IMETHOD MouseMove(nsIDOMEvent* aMouseEvent);
|
||||
NS_IMETHOD DragMove(nsIDOMEvent* aMouseEvent) { return NS_OK; }
|
||||
|
||||
// nsIDOMKeyListener interfaces
|
||||
NS_IMETHOD KeyDown(nsIDOMEvent* aKeyEvent);
|
||||
NS_IMETHOD KeyUp(nsIDOMEvent* aKeyEvent);
|
||||
NS_IMETHOD KeyPress(nsIDOMEvent* aKeyEvent);
|
||||
|
||||
// nsIDOMFocusListener interfaces
|
||||
NS_IMETHOD Focus(nsIDOMEvent * aFocusEvent);
|
||||
NS_IMETHOD Blur(nsIDOMEvent * aFocusEvent);
|
||||
|
||||
nsresult Destroy();
|
||||
|
||||
void PrepareToStop(PRBool aDelayedStop);
|
||||
|
||||
#ifdef XP_WIN
|
||||
void Paint(const RECT& aDirty, HDC aDC);
|
||||
#elif defined(XP_MACOSX)
|
||||
void Paint(const gfxRect& aDirtyRect, CGContextRef cgContext);
|
||||
void RenderCoreAnimation(CGContextRef aCGContext, int aWidth, int aHeight);
|
||||
void DoCocoaEventDrawRect(const gfxRect& aDrawRect, CGContextRef cgContext);
|
||||
#elif defined(MOZ_X11)
|
||||
void Paint(gfxContext* aContext,
|
||||
const gfxRect& aFrameRect,
|
||||
const gfxRect& aDirtyRect);
|
||||
#elif defined(XP_OS2)
|
||||
void Paint(const nsRect& aDirtyRect, HPS aHPS);
|
||||
#endif
|
||||
|
||||
#ifdef MAC_CARBON_PLUGINS
|
||||
void CancelTimer();
|
||||
void StartTimer(PRBool isVisible);
|
||||
#endif
|
||||
void SendIdleEvent();
|
||||
|
||||
// nsIScrollPositionListener interface
|
||||
virtual void ScrollPositionWillChange(nscoord aX, nscoord aY);
|
||||
virtual void ScrollPositionDidChange(nscoord aX, nscoord aY);
|
||||
|
||||
//locals
|
||||
|
||||
nsresult Init(nsPresContext* aPresContext, nsObjectFrame* aFrame,
|
||||
nsIContent* aContent);
|
||||
|
||||
void* GetPluginPortFromWidget();
|
||||
void ReleasePluginPort(void* pluginPort);
|
||||
|
||||
void SetPluginHost(nsIPluginHost* aHost);
|
||||
|
||||
nsEventStatus ProcessEvent(const nsGUIEvent & anEvent);
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
enum { ePluginPaintEnable, ePluginPaintDisable };
|
||||
|
||||
NPDrawingModel GetDrawingModel();
|
||||
PRBool IsRemoteDrawingCoreAnimation();
|
||||
NPEventModel GetEventModel();
|
||||
static void CARefresh(nsITimer *aTimer, void *aClosure);
|
||||
static void AddToCARefreshTimer(nsPluginInstanceOwner *aPluginInstance);
|
||||
static void RemoveFromCARefreshTimer(nsPluginInstanceOwner *aPluginInstance);
|
||||
void SetupCARefresh();
|
||||
void* FixUpPluginWindow(PRInt32 inPaintState);
|
||||
void HidePluginWindow();
|
||||
// Set a flag that (if true) indicates the plugin port info has changed and
|
||||
// SetWindow() needs to be called.
|
||||
void SetPluginPortChanged(PRBool aState) { mPluginPortChanged = aState; }
|
||||
// Return a pointer to the internal nsPluginPort structure that's used to
|
||||
// store a copy of plugin port info and to detect when it's been changed.
|
||||
void* GetPluginPortCopy();
|
||||
// Set plugin port info in the plugin (in the 'window' member of the
|
||||
// NPWindow structure passed to the plugin by SetWindow()) and set a
|
||||
// flag (mPluginPortChanged) to indicate whether or not this info has
|
||||
// changed, and SetWindow() needs to be called again.
|
||||
void* SetPluginPortAndDetectChange();
|
||||
// Flag when we've set up a Thebes (and CoreGraphics) context in
|
||||
// nsObjectFrame::PaintPlugin(). We need to know this in
|
||||
// FixUpPluginWindow() (i.e. we need to know when FixUpPluginWindow() has
|
||||
// been called from nsObjectFrame::PaintPlugin() when we're using the
|
||||
// CoreGraphics drawing model).
|
||||
void BeginCGPaint();
|
||||
void EndCGPaint();
|
||||
#else // XP_MACOSX
|
||||
void UpdateWindowPositionAndClipRect(PRBool aSetWindow);
|
||||
void CallSetWindow();
|
||||
void UpdateWindowVisibility(PRBool aVisible);
|
||||
#endif // XP_MACOSX
|
||||
|
||||
void SetOwner(nsObjectFrame *aOwner)
|
||||
{
|
||||
mObjectFrame = aOwner;
|
||||
}
|
||||
nsObjectFrame* GetOwner() {
|
||||
return mObjectFrame;
|
||||
}
|
||||
|
||||
PRUint32 GetLastEventloopNestingLevel() const {
|
||||
return mLastEventloopNestingLevel;
|
||||
}
|
||||
|
||||
static PRUint32 GetEventloopNestingLevel();
|
||||
|
||||
void ConsiderNewEventloopNestingLevel() {
|
||||
PRUint32 currentLevel = GetEventloopNestingLevel();
|
||||
|
||||
if (currentLevel < mLastEventloopNestingLevel) {
|
||||
mLastEventloopNestingLevel = currentLevel;
|
||||
}
|
||||
}
|
||||
|
||||
const char* GetPluginName()
|
||||
{
|
||||
if (mInstance && mPluginHost) {
|
||||
const char* name = NULL;
|
||||
if (NS_SUCCEEDED(mPluginHost->GetPluginName(mInstance, &name)) && name)
|
||||
return name;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
#ifdef MOZ_X11
|
||||
void GetPluginDescription(nsACString& aDescription)
|
||||
{
|
||||
aDescription.Truncate();
|
||||
if (mInstance && mPluginHost) {
|
||||
nsCOMPtr<nsIPluginTag> pluginTag;
|
||||
|
||||
mPluginHost->GetPluginTagForInstance(mInstance,
|
||||
getter_AddRefs(pluginTag));
|
||||
if (pluginTag) {
|
||||
pluginTag->GetDescription(aDescription);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
PRBool SendNativeEvents()
|
||||
{
|
||||
#ifdef XP_WIN
|
||||
// XXX we should remove the plugin name check
|
||||
return mPluginWindow->type == NPWindowTypeDrawable &&
|
||||
(MatchPluginName("Shockwave Flash") ||
|
||||
MatchPluginName("Test Plug-in"));
|
||||
#elif defined(MOZ_X11) || defined(XP_MACOSX)
|
||||
return PR_TRUE;
|
||||
#else
|
||||
return PR_FALSE;
|
||||
#endif
|
||||
}
|
||||
|
||||
PRBool MatchPluginName(const char *aPluginName)
|
||||
{
|
||||
return strncmp(GetPluginName(), aPluginName, strlen(aPluginName)) == 0;
|
||||
}
|
||||
|
||||
void NotifyPaintWaiter(nsDisplayListBuilder* aBuilder);
|
||||
// Return true if we set image with valid surface
|
||||
PRBool SetCurrentImage(ImageContainer* aContainer);
|
||||
/**
|
||||
* Returns the bounds of the current async-rendered surface. This can only
|
||||
* change in response to messages received by the event loop (i.e. not during
|
||||
* painting).
|
||||
*/
|
||||
nsIntSize GetCurrentImageSize();
|
||||
|
||||
// Methods to update the background image we send to async plugins.
|
||||
// The eventual target of these operations is PluginInstanceParent,
|
||||
// but it takes several hops to get there.
|
||||
void SetBackgroundUnknown();
|
||||
already_AddRefed<gfxContext> BeginUpdateBackground(const nsIntRect& aRect);
|
||||
void EndUpdateBackground(gfxContext* aContext, const nsIntRect& aRect);
|
||||
|
||||
PRBool UseAsyncRendering()
|
||||
{
|
||||
PRBool useAsyncRendering;
|
||||
return (mInstance &&
|
||||
NS_SUCCEEDED(mInstance->UseAsyncPainting(&useAsyncRendering)) &&
|
||||
useAsyncRendering &&
|
||||
(!mPluginWindow ||
|
||||
mPluginWindow->type == NPWindowTypeDrawable));
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
// return FALSE if LayerSurface dirty (newly created and don't have valid plugin content yet)
|
||||
PRBool IsUpToDate()
|
||||
{
|
||||
nsIntSize size;
|
||||
return NS_SUCCEEDED(mInstance->GetImageSize(&size)) &&
|
||||
size == nsIntSize(mPluginWindow->width, mPluginWindow->height);
|
||||
}
|
||||
|
||||
void FixUpURLS(const nsString &name, nsAString &value);
|
||||
|
||||
nsPluginNativeWindow *mPluginWindow;
|
||||
nsRefPtr<nsNPAPIPluginInstance> mInstance;
|
||||
nsObjectFrame *mObjectFrame; // owns nsPluginInstanceOwner
|
||||
nsCOMPtr<nsIContent> mContent;
|
||||
nsCString mDocumentBase;
|
||||
char *mTagText;
|
||||
nsCOMPtr<nsIWidget> mWidget;
|
||||
nsRefPtr<nsPluginHost> mPluginHost;
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
NP_CGContext mCGPluginPortCopy;
|
||||
#ifndef NP_NO_QUICKDRAW
|
||||
NP_Port mQDPluginPortCopy;
|
||||
#endif
|
||||
PRInt32 mInCGPaintLevel;
|
||||
nsIOSurface *mIOSurface;
|
||||
nsCARenderer mCARenderer;
|
||||
CGColorSpaceRef mColorProfile;
|
||||
static nsCOMPtr<nsITimer> *sCATimer;
|
||||
static nsTArray<nsPluginInstanceOwner*> *sCARefreshListeners;
|
||||
PRBool mSentInitialTopLevelWindowEvent;
|
||||
#endif
|
||||
|
||||
// Initially, the event loop nesting level we were created on, it's updated
|
||||
// if we detect the appshell is on a lower level as long as we're not stopped.
|
||||
// We delay DoStopPlugin() until the appshell reaches this level or lower.
|
||||
PRUint32 mLastEventloopNestingLevel;
|
||||
PRPackedBool mContentFocused;
|
||||
PRPackedBool mWidgetVisible; // used on Mac to store our widget's visible state
|
||||
#ifdef XP_MACOSX
|
||||
PRPackedBool mPluginPortChanged;
|
||||
#endif
|
||||
#ifdef MOZ_X11
|
||||
// Used with windowless plugins only, initialized in CreateWidget().
|
||||
PRPackedBool mFlash10Quirks;
|
||||
#endif
|
||||
PRPackedBool mPluginWindowVisible;
|
||||
|
||||
// If true, destroy the widget on destruction. Used when plugin stop
|
||||
// is being delayed to a safer point in time.
|
||||
PRPackedBool mDestroyWidget;
|
||||
PRUint16 mNumCachedAttrs;
|
||||
PRUint16 mNumCachedParams;
|
||||
char **mCachedAttrParamNames;
|
||||
char **mCachedAttrParamValues;
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
NPEventModel mEventModel;
|
||||
#endif
|
||||
|
||||
// pointer to wrapper for nsIDOMContextMenuListener
|
||||
nsRefPtr<nsPluginDOMContextMenuListener> mCXMenuListener;
|
||||
|
||||
nsresult DispatchKeyToPlugin(nsIDOMEvent* aKeyEvent);
|
||||
nsresult DispatchMouseToPlugin(nsIDOMEvent* aMouseEvent);
|
||||
nsresult DispatchFocusToPlugin(nsIDOMEvent* aFocusEvent);
|
||||
|
||||
nsresult EnsureCachedAttrParamArrays();
|
||||
|
||||
#ifdef MOZ_X11
|
||||
class Renderer
|
||||
#if defined(MOZ_WIDGET_GTK2)
|
||||
: public gfxXlibNativeRenderer
|
||||
#elif defined(MOZ_WIDGET_QT)
|
||||
: public gfxQtNativeRenderer
|
||||
#endif
|
||||
{
|
||||
public:
|
||||
Renderer(NPWindow* aWindow, nsPluginInstanceOwner* aInstanceOwner,
|
||||
const nsIntSize& aPluginSize, const nsIntRect& aDirtyRect)
|
||||
: mWindow(aWindow), mInstanceOwner(aInstanceOwner),
|
||||
mPluginSize(aPluginSize), mDirtyRect(aDirtyRect)
|
||||
{}
|
||||
virtual nsresult DrawWithXlib(gfxXlibSurface* surface, nsIntPoint offset,
|
||||
nsIntRect* clipRects, PRUint32 numClipRects);
|
||||
private:
|
||||
NPWindow* mWindow;
|
||||
nsPluginInstanceOwner* mInstanceOwner;
|
||||
const nsIntSize& mPluginSize;
|
||||
const nsIntRect& mDirtyRect;
|
||||
};
|
||||
#endif
|
||||
|
||||
PRPackedBool mWaitingForPaint;
|
||||
};
|
||||
|
||||
#endif // nsPluginInstanceOwner_h_
|
||||
|
@ -99,94 +99,6 @@
|
||||
function(){new Effect.Highlight('nothing-to-see-here')});
|
||||
}},
|
||||
|
||||
testCallbacks: function() { with(this) {
|
||||
tmp = tmp2 = 0;
|
||||
var e1 = new Effect.Opacity('sandbox',{from:1.0,to:0.5,duration:0.5,
|
||||
beforeStart: function() { tmp++ },
|
||||
beforeStartInternal: function() { tmp++ },
|
||||
beforeSetup: function() { tmp++ },
|
||||
beforeSetupInternal: function() { tmp++ },
|
||||
afterSetup: function() { tmp++ },
|
||||
afterSetupInternal: function() { tmp++ },
|
||||
beforeUpdate: function() { tmp2++ },
|
||||
beforeUpdateInternal: function() { tmp2++ },
|
||||
beforeFinish: function() { tmp++ },
|
||||
beforeFinishInternal: function() { tmp++ },
|
||||
afterFinish: function() { tmp++ },
|
||||
afterFinishInternal: function() { tmp++ }
|
||||
});
|
||||
wait(1000, function() {
|
||||
assertEqual(10, tmp);
|
||||
assert(tmp2 > 0);
|
||||
});
|
||||
}},
|
||||
|
||||
testEvent: function() { with(this) {
|
||||
tmp = 0;
|
||||
new Effect.Event({ afterFinish:function(){ tmp++ }, position:'end'});
|
||||
wait(100, function() {
|
||||
assertEqual(1, tmp);
|
||||
});
|
||||
}},
|
||||
|
||||
testTransition: function() { with(this) {
|
||||
// false implies linear
|
||||
var e = new Effect.Opacity('sandbox',{transition:false,from:0.0,to:0.25,duration:0.5});
|
||||
assert(e.options.transition == Effect.Transitions.linear);
|
||||
|
||||
wait(1000, function() {
|
||||
assertEqual(0.25, $('sandbox').getStyle('opacity'));
|
||||
// default to sinoidal
|
||||
var e = new Effect.Opacity('sandbox',{from:0.0,to:0.25,duration:0.5});
|
||||
assert(e.options.transition == Effect.Transitions.sinoidal);
|
||||
wait(1000, function() {
|
||||
assertEqual(0.25, $('sandbox').getStyle('opacity'));
|
||||
|
||||
var transitions = [
|
||||
{ transition: Effect.Transitions.linear, expected: 1 },
|
||||
{ transition: Effect.Transitions.sinoidal, expected: 1 },
|
||||
{ transition: Effect.Transitions.reverse, expected: 0 },
|
||||
{ transition: Effect.Transitions.flicker, expected: 1 },
|
||||
{ transition: Effect.Transitions.wobble, expected: 1 },
|
||||
{ transition: Effect.Transitions.pulse, expected: 1 },
|
||||
{ transition: Effect.Transitions.none, expected: 0 }
|
||||
];
|
||||
|
||||
transitions.each(function(t){
|
||||
var e = new Effect.Opacity('sandbox',{sync:true, from:0, to: 1, transition:t.transition});
|
||||
assert(e.options.transition == t.transition);
|
||||
e.render(1.0);
|
||||
assertEqual(t.expected, e.position, t.transition);
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
}},
|
||||
|
||||
testInspect: function() { with(this) {
|
||||
var e1 = new Effect.Opacity('sandbox',{from:1.0,to:0.5,duration:0.5});
|
||||
info( e1.inspect() );
|
||||
assertEqual(0, e1.inspect().indexOf('#<Effect:'));
|
||||
assert(e1.inspect().indexOf('idle')>0);
|
||||
wait(1000, function() {
|
||||
assert(e1.inspect().indexOf('finished')>0);
|
||||
});
|
||||
}},
|
||||
|
||||
testDefaultOptions: function() { with(this) {
|
||||
var oldDefaultOptions = Object.extend({},Effect.DefaultOptions);
|
||||
|
||||
assertEqual(1.0, Effect.DefaultOptions.duration);
|
||||
Effect.DefaultOptions.duration = 0.5;
|
||||
var e1 = new Effect.Opacity('sandbox');
|
||||
assertEqual(0.5, e1.options.duration);
|
||||
|
||||
wait(750, function() {
|
||||
assertEqual('finished', e1.state);
|
||||
Effect.DefaultOptions = oldDefaultOptions;
|
||||
});
|
||||
}},
|
||||
|
||||
testEffectsQueue: function() { with(this) {
|
||||
var e1 = new Effect.Highlight('sandbox');
|
||||
var e2 = new Effect.Appear('sandbox');
|
||||
@ -330,177 +242,6 @@
|
||||
});
|
||||
}},
|
||||
|
||||
testSynchronizedEffects: function() { with(this) {
|
||||
var e1 = new Effect.Fade('sandbox',{sync:true});
|
||||
wait(250, function() {
|
||||
// effect should still be at frame 0
|
||||
assertEqual(0, e1.currentFrame);
|
||||
assertEqual('idle', e1.state);
|
||||
e1.render(0.01);
|
||||
|
||||
// no frame count for sync effects
|
||||
assertEqual(0, e1.currentFrame);
|
||||
assertEqual('running', e1.state);
|
||||
});
|
||||
}},
|
||||
|
||||
testEffectPosition: function() { with(this) {
|
||||
var testeffect = new Effect.Opacity('sandbox',{
|
||||
afterSetup: function(effect) { effect.frames = 0; },
|
||||
afterUpdate: function(effect) { effect.frames++; $('sandbox').update(effect.position); },
|
||||
duration: 0.5, from: 1.0, to: 0.5
|
||||
});
|
||||
assertNull(testeffect.position);
|
||||
assertEqual('idle', testeffect.state);
|
||||
wait(1000, function() {
|
||||
info('Rendered ' + testeffect.frames + ' frames in .5 seconds ' +
|
||||
'(~' + (testeffect.frames/0.5) + 'fps of a possible 60fps, ' +
|
||||
'note that this can exceed 60fps because of additional last frame rendering)');
|
||||
assertEqual('0.5', $('sandbox').innerHTML);
|
||||
assertEqual(0.5, testeffect.position);
|
||||
assertEqual('finished', testeffect.state);
|
||||
});
|
||||
}},
|
||||
|
||||
testRenderPerformance: function() { with(this) {
|
||||
info('The render() method is generated on a per-effect basis')
|
||||
var e = new Effect.Opacity('sandbox',{sync:true});
|
||||
benchmark(function(){
|
||||
e.render(0.5);
|
||||
},1000, 'Without events');
|
||||
var e = new Effect.Opacity('sandbox',{sync:true,afterUpdate:function(){return}});
|
||||
benchmark(function(){
|
||||
e.render(0.5);
|
||||
},1000, 'With afterUpdate event');
|
||||
}},
|
||||
|
||||
testElementMorph: function() { with(this) {
|
||||
$('error_test_ul').morph('font-size:40px', {duration: 0.5}).setStyle({marginRight:'17px'});
|
||||
$('error_message_2').morph({
|
||||
fontSize: '20px',
|
||||
color: '#f00',
|
||||
backgroundColor: '#ffffff'
|
||||
},
|
||||
{
|
||||
duration:0.5
|
||||
});
|
||||
$('error_message_3').morph('final', {duration:0.5});
|
||||
wait(2000,function(){
|
||||
assertEqual('17px', $('error_test_ul').getStyle('margin-right'));
|
||||
assertEqual('40px', $('error_test_ul').getStyle('font-size'));
|
||||
assertEqual('#ffffff', $('error_message_2').getStyle('background-color').parseColor());
|
||||
assertEqual('20px', $('error_message_2').getStyle('font-size'));
|
||||
assertEqual('italic', $('error_message_3').getStyle('font-style'));
|
||||
assertEqual('20px', $('error_message_3').getStyle('font-size'));
|
||||
assertEqual(.5, $('error_message_3').getStyle('opacity'));
|
||||
assertEqual('', $('error_message_3').style.fontSize);
|
||||
});
|
||||
}},
|
||||
|
||||
testElementMorphChaining: function() { with(this) {
|
||||
$('error_message').morph('font-size:17px').morph('opacity:0',{delay:3});
|
||||
wait(4100,function(){ // 3000ms delay + 1000ms default duration
|
||||
assertEqual(0, $('error_message').getOpacity());
|
||||
});
|
||||
}},
|
||||
|
||||
testTransformBySelector: function() { with(this) {
|
||||
new Effect.Transform([
|
||||
{ 'ul.error-list li': 'font-size:20px;text-indent:40pt' }
|
||||
],{ duration: 0.5 }).play();
|
||||
|
||||
wait(700,function(){
|
||||
var idx = 0;
|
||||
$A($('error_test_ul').cleanWhitespace().childNodes).each(function(node){
|
||||
assertEqual('20px', $(node).getStyle('font-size'));
|
||||
assertEqual('40pt', $(node).getStyle('text-indent'));
|
||||
idx++;
|
||||
});
|
||||
assertEqual(5, idx);
|
||||
});
|
||||
}},
|
||||
|
||||
testTransformUsesCSSClassPresets: function() { with(this) {
|
||||
assertEqual('40px', $('rotfl').getStyle('font-size'));
|
||||
|
||||
// Render the effect at half-way through, font-size should be
|
||||
// exactly half-way between original and target
|
||||
new Effect.Transform([
|
||||
{ 'rotfl': 'font-size:20px;text-indent:40pt;background-color:#888' }
|
||||
],{ sync:true }).play().render(0.5);
|
||||
|
||||
wait(1100,function(){
|
||||
// shoould be 30px = 40px + (20px-40px)/2
|
||||
assertEqual('30px', $('rotfl').getStyle('font-size'));
|
||||
});
|
||||
}},
|
||||
|
||||
testTransformMultiple: function() { with(this) {
|
||||
var transformation = new Effect.Transform([
|
||||
{ 'div.morphing': 'font-size:20px;padding-left:40em;opacity:0.5' },
|
||||
{ 'blah' :
|
||||
'width:480px;border-width:10px;border-right-width:20px;' +
|
||||
'margin:20px;margin-bottom:-20px;font-size:30px;' +
|
||||
'background:#954' }
|
||||
],{ duration: 0.5 });
|
||||
|
||||
var generatedEffect = transformation.play();
|
||||
|
||||
assertEqual(3, generatedEffect.effects.length);
|
||||
|
||||
wait(700, function(){
|
||||
// have a look at the generated color transforms for the 3rd found element
|
||||
// which is the "blah" div
|
||||
assertEqual('blah', generatedEffect.effects[2].element.id);
|
||||
assertEnumEqual([255,255,255],
|
||||
generatedEffect.effects[2].transforms.detect( function(transform){
|
||||
return (transform.style == 'backgroundColor')
|
||||
}).originalValue);
|
||||
assertEnumEqual([153,85,68],
|
||||
generatedEffect.effects[2].transforms.detect( function(transform){
|
||||
return (transform.style == 'backgroundColor')
|
||||
}).targetValue);
|
||||
|
||||
assertEqual('20px', $$('div.morphing').first().getStyle('font-size'));
|
||||
assertEqual('20px', $$('div.morphing').last().getStyle('font-size'));
|
||||
assertEqual('30px', $('blah').getStyle('font-size'));
|
||||
|
||||
// border-width/border-right-width should be set independently
|
||||
assertEqual('10px', $('blah').getStyle('border-top-width'));
|
||||
assertEqual('10px', $('blah').getStyle('border-bottom-width'));
|
||||
assertEqual('10px', $('blah').getStyle('border-left-width'));
|
||||
assertEqual('20px', $('blah').getStyle('border-right-width'));
|
||||
|
||||
// colors should assume transition from
|
||||
// #ffffff (white) if original was transparent
|
||||
// we now should have arrived at the given color
|
||||
assertEqual('#995544', $('blah').getStyle('background-color').parseColor());
|
||||
|
||||
// play again = should have same values
|
||||
transformation.play();
|
||||
wait(700, function(){
|
||||
assertEqual('20px', $$('div.morphing').first().getStyle('font-size'));
|
||||
assertEqual('20px', $$('div.morphing').last().getStyle('font-size'));
|
||||
assertEqual('30px', $('blah').getStyle('font-size'));
|
||||
|
||||
$('blah').setStyle({'font-size':'100px'});
|
||||
assertEqual('100px', $('blah').getStyle('font-size'));
|
||||
transformation.play();
|
||||
wait(700, function(){
|
||||
assertEqual('30px', $('blah').getStyle('font-size'));
|
||||
|
||||
new Effect.Transform([
|
||||
{ 'blah': 'color: #80d980; background: #208020' }
|
||||
],{ duration: 1.1 }).play();
|
||||
wait(1500, function(){
|
||||
assertEqual('#80d980', $('blah').getStyle('color').parseColor());
|
||||
assertEqual('#208020', $('blah').getStyle('background-color').parseColor());
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}}
|
||||
|
||||
});
|
||||
|
||||
// ]]>
|
||||
|
@ -148,7 +148,7 @@ bool
|
||||
ShadowLayersParent::RecvUpdate(const InfallibleTArray<Edit>& cset,
|
||||
InfallibleTArray<EditReply>* reply)
|
||||
{
|
||||
MOZ_LAYERS_LOG(("[ParentSide] recieved txn with %d edits", cset.Length()));
|
||||
MOZ_LAYERS_LOG(("[ParentSide] received txn with %d edits", cset.Length()));
|
||||
|
||||
if (mDestroyed || layer_manager()->IsDestroyed()) {
|
||||
return true;
|
||||
|
@ -462,6 +462,10 @@ static JS_ALWAYS_INLINE jsval_layout
|
||||
BOOLEAN_TO_JSVAL_IMPL(JSBool b)
|
||||
{
|
||||
jsval_layout l;
|
||||
|
||||
// Happens if XPConnect hands out an illegal value (constructed from C++ through a PRBool, for
|
||||
// instance).
|
||||
JS_ASSERT(b == JS_TRUE || b == JS_FALSE);
|
||||
l.s.tag = JSVAL_TAG_BOOLEAN;
|
||||
l.s.payload.boo = b;
|
||||
return l;
|
||||
@ -654,6 +658,10 @@ static JS_ALWAYS_INLINE jsval_layout
|
||||
BOOLEAN_TO_JSVAL_IMPL(JSBool b)
|
||||
{
|
||||
jsval_layout l;
|
||||
|
||||
// Happens if XPConnect hands out an illegal value (constructed from C++ through a PRBool, for
|
||||
// instance).
|
||||
JS_ASSERT(b == JS_TRUE || b == JS_FALSE);
|
||||
l.asBits = ((uint64)(uint32)b) | JSVAL_SHIFTED_TAG_BOOLEAN;
|
||||
return l;
|
||||
}
|
||||
|
@ -1199,7 +1199,9 @@ DocumentViewerImpl::PermitUnload(PRBool aCallerClosesWindow, PRBool *aPermitUnlo
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
PRBool dummy;
|
||||
// Although the exact value is ignored, we must not pass invalid
|
||||
// PRBool values through XPConnect.
|
||||
PRBool dummy = PR_FALSE;
|
||||
PRInt32 buttonPressed = 0;
|
||||
PRUint32 buttonFlags = (nsIPrompt::BUTTON_POS_0_DEFAULT |
|
||||
(nsIPrompt::BUTTON_TITLE_IS_STRING * nsIPrompt::BUTTON_POS_0) |
|
||||
|
@ -93,6 +93,9 @@
|
||||
#include "nsDOMFile.h"
|
||||
#include "nsEventStates.h"
|
||||
|
||||
#include "nsIDOMDOMStringList.h"
|
||||
#include "nsIDOMDragEvent.h"
|
||||
|
||||
namespace dom = mozilla::dom;
|
||||
|
||||
#define SYNC_TEXT 0x1
|
||||
@ -136,6 +139,15 @@ nsFileControlFrame::DestroyFrom(nsIFrame* aDestructRoot)
|
||||
mTextFrame = nsnull;
|
||||
ENSURE_TRUE(mContent);
|
||||
|
||||
// Remove the drag events
|
||||
nsCOMPtr<nsIDOMEventTarget> dragTarget = do_QueryInterface(mContent);
|
||||
if (dragTarget) {
|
||||
dragTarget->RemoveEventListener(NS_LITERAL_STRING("drop"),
|
||||
mMouseListener, PR_FALSE);
|
||||
dragTarget->RemoveEventListener(NS_LITERAL_STRING("dragover"),
|
||||
mMouseListener, PR_FALSE);
|
||||
}
|
||||
|
||||
// remove mMouseListener as a mouse event listener (bug 40533, bug 355931)
|
||||
NS_NAMED_LITERAL_STRING(click, "click");
|
||||
|
||||
@ -258,6 +270,14 @@ nsFileControlFrame::CreateAnonymousContent(nsTArray<ContentInfo>& aElements)
|
||||
if (!aElements.AppendElement(mTextContent))
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
// Register the whole frame as an event listener of drag events
|
||||
nsCOMPtr<nsIDOMEventTarget> dragTarget = do_QueryInterface(mContent);
|
||||
NS_ENSURE_STATE(dragTarget);
|
||||
dragTarget->AddEventListener(NS_LITERAL_STRING("drop"),
|
||||
mMouseListener, PR_FALSE);
|
||||
dragTarget->AddEventListener(NS_LITERAL_STRING("dragover"),
|
||||
mMouseListener, PR_FALSE);
|
||||
|
||||
NS_NAMED_LITERAL_STRING(click, "click");
|
||||
nsCOMPtr<nsIDOMEventGroup> systemGroup;
|
||||
mContent->GetSystemEventGroup(getter_AddRefs(systemGroup));
|
||||
@ -498,6 +518,74 @@ nsFileControlFrame::BrowseMouseListener::MouseClick(nsIDOMEvent* aMouseEvent)
|
||||
return input ? input->FireAsyncClickHandler() : NS_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is called when we receive any registered events on the control.
|
||||
* We've only registered for drop, dragover and click events, and click events
|
||||
* already call MouseClick() for us. Here, we handle file drops.
|
||||
*/
|
||||
NS_IMETHODIMP
|
||||
nsFileControlFrame::BrowseMouseListener::HandleEvent(nsIDOMEvent* aEvent)
|
||||
{
|
||||
NS_ASSERTION(mFrame, "We should have been unregistered");
|
||||
nsCOMPtr<nsIDOMNSUIEvent> uiEvent = do_QueryInterface(aEvent);
|
||||
NS_ENSURE_STATE(uiEvent);
|
||||
PRBool defaultPrevented = PR_FALSE;
|
||||
uiEvent->GetPreventDefault(&defaultPrevented);
|
||||
if (defaultPrevented) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMDragEvent> dragEvent = do_QueryInterface(aEvent);
|
||||
if (!dragEvent || !IsValidDropData(dragEvent)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsAutoString eventType;
|
||||
aEvent->GetType(eventType);
|
||||
if (eventType.EqualsLiteral("dragover")) {
|
||||
// Prevent default if we can accept this drag data
|
||||
aEvent->PreventDefault();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (eventType.EqualsLiteral("drop")) {
|
||||
aEvent->StopPropagation();
|
||||
aEvent->PreventDefault();
|
||||
|
||||
nsIContent* content = mFrame->GetContent();
|
||||
NS_ASSERTION(content, "The frame has no content???");
|
||||
|
||||
nsHTMLInputElement* inputElement = nsHTMLInputElement::FromContent(content);
|
||||
NS_ASSERTION(inputElement, "No input element for this file upload control frame!");
|
||||
|
||||
nsCOMPtr<nsIDOMDataTransfer> dataTransfer;
|
||||
dragEvent->GetDataTransfer(getter_AddRefs(dataTransfer));
|
||||
|
||||
nsCOMPtr<nsIDOMFileList> fileList;
|
||||
dataTransfer->GetFiles(getter_AddRefs(fileList));
|
||||
inputElement->SetFiles(fileList, true);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* static */ PRBool
|
||||
nsFileControlFrame::BrowseMouseListener::IsValidDropData(nsIDOMDragEvent* aEvent)
|
||||
{
|
||||
nsCOMPtr<nsIDOMDataTransfer> dataTransfer;
|
||||
aEvent->GetDataTransfer(getter_AddRefs(dataTransfer));
|
||||
NS_ENSURE_TRUE(dataTransfer, PR_FALSE);
|
||||
|
||||
nsCOMPtr<nsIDOMDOMStringList> types;
|
||||
dataTransfer->GetTypes(getter_AddRefs(types));
|
||||
NS_ENSURE_TRUE(types, PR_FALSE);
|
||||
|
||||
// We only support dropping files onto a file upload control
|
||||
PRBool typeSupported;
|
||||
types->Contains(NS_LITERAL_STRING("Files"), &typeSupported);
|
||||
return typeSupported;
|
||||
}
|
||||
|
||||
nscoord
|
||||
nsFileControlFrame::GetMinWidth(nsRenderingContext *aRenderingContext)
|
||||
{
|
||||
|
@ -48,6 +48,8 @@
|
||||
#include "nsTextControlFrame.h"
|
||||
typedef nsTextControlFrame nsNewFrame;
|
||||
|
||||
class nsIDOMDragEvent;
|
||||
|
||||
class nsFileControlFrame : public nsBlockFrame,
|
||||
public nsIFormControlFrame,
|
||||
public nsIAnonymousContentCreator
|
||||
@ -169,6 +171,9 @@ protected:
|
||||
public:
|
||||
BrowseMouseListener(nsFileControlFrame* aFrame) : MouseListener(aFrame) {};
|
||||
NS_IMETHOD MouseClick(nsIDOMEvent* aMouseEvent);
|
||||
NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent);
|
||||
|
||||
static PRBool IsValidDropData(nsIDOMDragEvent* aEvent);
|
||||
};
|
||||
|
||||
virtual PRBool IsFrameOfType(PRUint32 aFlags) const
|
||||
|
@ -68,6 +68,7 @@ EXPORTS = \
|
||||
nsIStatefulFrame.h \
|
||||
nsFrameSelection.h \
|
||||
nsSubDocumentFrame.h \
|
||||
nsObjectFrame.h \
|
||||
$(NULL)
|
||||
|
||||
ifdef IBMBIDI
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -44,6 +44,7 @@
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#include "nsPluginInstanceOwner.h"
|
||||
#include "nsIObjectFrame.h"
|
||||
#include "nsFrame.h"
|
||||
#include "nsRegion.h"
|
||||
@ -56,11 +57,9 @@
|
||||
class nsIAccessible;
|
||||
#endif
|
||||
|
||||
class nsPluginInstanceOwner;
|
||||
class nsPluginHost;
|
||||
class nsPresContext;
|
||||
class nsDisplayPlugin;
|
||||
class nsIDOMElement;
|
||||
class nsIOSurface;
|
||||
class PluginBackgroundSink;
|
||||
|
||||
|
@ -1392,7 +1392,7 @@ var FullScreenVideo = {
|
||||
this._dispatchMouseEvent("Browser:MouseDown", aEvent.clientX, aEvent.clientY);
|
||||
break;
|
||||
case "TapSingle":
|
||||
this._dispatchMouseEvent("Browser:MouseUp", aEvent.clientX, aEvent.clientY);
|
||||
this._dispatchMouseEvent("Browser:MouseClick", aEvent.clientX, aEvent.clientY);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
@ -13,13 +13,15 @@
|
||||
|
||||
<binding id="stacked-notificationbox" extends="chrome://global/content/bindings/notification.xml#notificationbox">
|
||||
<content>
|
||||
<xul:stack xbl:inherits="hidden=notificationshidden">
|
||||
<xul:spacer/>
|
||||
<children includes="notification"/>
|
||||
</xul:stack>
|
||||
<xul:stack flex="1">
|
||||
<children/>
|
||||
<html:div flex="1" class="input-overlay" anonid="input-overlay"/>
|
||||
<xul:stack>
|
||||
<xul:stack top="0">
|
||||
<children/>
|
||||
<html:div flex="1" class="input-overlay" anonid="input-overlay"/>
|
||||
</xul:stack>
|
||||
<xul:stack top="0" xbl:inherits="hidden=notificationshidden">
|
||||
<xul:spacer/>
|
||||
<children includes="notification"/>
|
||||
</xul:stack>
|
||||
</xul:stack>
|
||||
</content>
|
||||
<implementation>
|
||||
|
@ -75,7 +75,7 @@ toolbarbutton.urlbar-button {
|
||||
}
|
||||
|
||||
#tool-app-switch:hover:active {
|
||||
background-color: #8db8d8 !important;
|
||||
background-color: @color_background_highlight@ !important;
|
||||
-moz-border-radius-bottomright: @border_radius_small@;
|
||||
}
|
||||
|
||||
@ -96,7 +96,7 @@ toolbarbutton.urlbar-button {
|
||||
}
|
||||
|
||||
#tool-app-close:hover:active {
|
||||
background-color: #8db8d8 !important;
|
||||
background-color: @color_background_highlight@ !important;
|
||||
}
|
||||
|
||||
#tool-app-close:hover:active:-moz-locale-dir(ltr) {
|
||||
@ -202,7 +202,7 @@ toolbarbutton.urlbar-button {
|
||||
}
|
||||
|
||||
#urlbar-title.placeholder {
|
||||
color: gray;
|
||||
color: @color_text_placeholder@;
|
||||
}
|
||||
|
||||
#urlbar-edit,
|
||||
@ -349,7 +349,7 @@ toolbarbutton.button-control:not([disabled="true"]):hover:active {
|
||||
}
|
||||
|
||||
.panel-close:hover:active {
|
||||
background-color: #8db8d8 !important;
|
||||
background-color: @color_background_highlight@ !important;
|
||||
}
|
||||
|
||||
.panel-close:hover:active:-moz-locale-dir(ltr) {
|
||||
@ -395,7 +395,7 @@ remotetabslist > hbox.remotetabs-throbber-box {
|
||||
|
||||
historylist[loading="true"] > hbox.history-throbber-box,
|
||||
remotetabslist[loading="true"] > hbox.remotetabs-throbber-box {
|
||||
background-color: white;
|
||||
background-color: white; /* force */
|
||||
display: -moz-box;
|
||||
}
|
||||
|
||||
@ -515,12 +515,9 @@ remotetabslist[loading="true"] > richlistbox.remotetabs-list-children {
|
||||
-moz-margin-end: @margin_normal@;
|
||||
}
|
||||
|
||||
richlistitem[isDisabled="true"] .title {
|
||||
color: gray;
|
||||
}
|
||||
|
||||
richlistitem[isDisabled="true"] .title,
|
||||
richlistitem[isDisabled="true"] .normal {
|
||||
color: lightgray;
|
||||
color: @color_text_disabled@;
|
||||
}
|
||||
|
||||
richlistitem[isDisabled="true"] image {
|
||||
@ -550,7 +547,7 @@ richlistitem[isDisabled="true"] image {
|
||||
|
||||
#dl-empty-message > label {
|
||||
text-align: center;
|
||||
color: grey;
|
||||
color: @color_text_placeholder@;
|
||||
}
|
||||
|
||||
/* console panel UI ------------------------------------------------------ */
|
||||
@ -588,7 +585,7 @@ placelabel {
|
||||
background-repeat: no-repeat, repeat-x;
|
||||
background-position: 98% 50%, top left;
|
||||
background-size: auto auto, auto 100%;
|
||||
color: #000;
|
||||
color: black; /* force */
|
||||
min-height: @touch_row@; /* row size */
|
||||
}
|
||||
|
||||
@ -598,7 +595,8 @@ placelabel:-moz-locale-dir(rtl) {
|
||||
|
||||
placelabel:hover:active {
|
||||
background-image: url(images/arrowup-16.png);
|
||||
background-color: #8db8d8;
|
||||
background-color: @color_background_highlight@;
|
||||
color: @color_text_highlight@;
|
||||
}
|
||||
|
||||
/* folder bookmarks row */
|
||||
@ -648,16 +646,19 @@ placeitem[ui="manage"] > .bookmark-manage textbox[anonid="uri"]:-moz-locale-dir(
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
/* autocomplete-items */
|
||||
.autocomplete-items {
|
||||
background-color: white;
|
||||
/* force the richlistboxes to have a white background */
|
||||
.autocomplete-items,
|
||||
.place-list-children,
|
||||
.history-list-children,
|
||||
.remotetabs-list-children {
|
||||
background-color: white; /* force */
|
||||
}
|
||||
|
||||
autocompleteresult,
|
||||
placeitem {
|
||||
-moz-user-focus: ignore;
|
||||
color: black;
|
||||
background-color: white;
|
||||
color: black; /* force */
|
||||
background-color: white; /* force */
|
||||
padding: @padding_xsmall@ @padding_small@;
|
||||
border-bottom: @border_width_tiny@ solid rgb(207,207,207);
|
||||
min-height: @touch_row@; /* row size */
|
||||
@ -668,7 +669,8 @@ placelist placeitem:hover:active:not([selected="true"]),
|
||||
historylist autocompleteresult:hover:active:not([selected="true"]):not([class="history-item-title"]),
|
||||
remotetabslist autocompleteresult:hover:active:not([selected="true"]):not([class="remotetabs-item-title"]),
|
||||
.autocompleteresult-selected {
|
||||
background-color: #8db8d8;
|
||||
background-color: @color_background_highlight@;
|
||||
color: @color_text_highlight@;
|
||||
}
|
||||
|
||||
.autocomplete-item-container,
|
||||
@ -747,7 +749,7 @@ placeitem[src=""] .bookmark-item-container > image {
|
||||
|
||||
.autocomplete-item-subtitle,
|
||||
.bookmark-item-url {
|
||||
color: blue;
|
||||
color: blue; /* force */
|
||||
font-size: @font_small@ !important;
|
||||
-moz-margin-end: @autocomplete_item_subtitle_margin@;
|
||||
}
|
||||
@ -759,8 +761,7 @@ placeitem[src=""] .bookmark-item-container > image {
|
||||
}
|
||||
|
||||
.autocomplete-item-container[search="true"] .autocomplete-item-subtitle {
|
||||
color: black;
|
||||
font-size: smaller;
|
||||
color: black; /* force */
|
||||
}
|
||||
|
||||
.autocomplete-item-tags,
|
||||
@ -853,12 +854,12 @@ autocompleteresult.noresults {
|
||||
}
|
||||
|
||||
autocompleteresult.noresults:hover:active {
|
||||
background-color: white !important;
|
||||
background-color: white !important; /* force */
|
||||
}
|
||||
|
||||
autocompleteresult.noresults > .autocomplete-item-container {
|
||||
text-align: center;
|
||||
color: grey;
|
||||
color: @color_text_placeholder@;
|
||||
}
|
||||
|
||||
/* Left sidebar (tabs) ---------------------------------------------------- */
|
||||
@ -1053,6 +1054,7 @@ documenttab[reload="true"] > stack > .documenttab-reload {
|
||||
.action-button,
|
||||
.context-command,
|
||||
pageaction {
|
||||
color: black; /* force */
|
||||
-moz-border-top-colors: white;
|
||||
-moz-border-right-colors: rgb(175,175,175);
|
||||
-moz-border-bottom-colors: rgb(175,175,175);
|
||||
@ -1078,7 +1080,7 @@ pageaction {
|
||||
.action-button[disabled="true"],
|
||||
.context-command[disabled="true"] {
|
||||
pointer-events: none;
|
||||
color: #aaa !important;
|
||||
color: @color_text_disabled@ !important;
|
||||
}
|
||||
|
||||
.action-button[selected="true"],
|
||||
@ -1117,7 +1119,9 @@ pageaction {
|
||||
.action-button:not([disabled]):hover:active,
|
||||
.context-command:not([disabled]):hover:active,
|
||||
pageaction:not([disabled]):hover:active {
|
||||
background: url("chrome://browser/skin/images/popup-selected-item-hdpi.png") repeat-x !important;
|
||||
color: @color_text_highlight@;
|
||||
background-color: @color_background_highlight@;
|
||||
background-image: none !important;
|
||||
background-origin: border-box !important;
|
||||
background-clip: border-box !important;
|
||||
-moz-border-top-colors: transparent;
|
||||
@ -1138,12 +1142,11 @@ pageaction:not([image]) > hbox >.pageaction-image {
|
||||
.context-command,
|
||||
.pageaction-title {
|
||||
font-size: @font_normal@ !important;
|
||||
color: #414141 !important;
|
||||
}
|
||||
|
||||
.pageaction-desc {
|
||||
font-size: @font_tiny@ !important;
|
||||
color: #414141;
|
||||
color: @color_subtext_inverse@;
|
||||
}
|
||||
|
||||
.pageaction-desc[value=""] {
|
||||
@ -1243,12 +1246,12 @@ pageaction:not([image]) > hbox >.pageaction-image {
|
||||
/* XXX should be a richlistitem description.normal */
|
||||
.prefdesc {
|
||||
font-size: @font_small@ !important;
|
||||
color: grey;
|
||||
color: @color_subtext_default@;
|
||||
}
|
||||
|
||||
/* alerts popup ----------------------------------------------------------- */
|
||||
#alerts-container {
|
||||
color: white;
|
||||
color: @color_text_default@;
|
||||
background-color: #5e6166;
|
||||
border: @border_width_small@ solid #767973;
|
||||
border-radius: @border_radius_normal@;
|
||||
@ -1412,8 +1415,8 @@ pageaction:not([image]) > hbox >.pageaction-image {
|
||||
}
|
||||
|
||||
.syncsetup-code {
|
||||
color: #000;
|
||||
background-color: #fff;
|
||||
color: @color_text_inverse@;
|
||||
background-color: @color_background_inverse@;
|
||||
font-size: @font_xlarge@ !important;
|
||||
padding: 0.2em 0.4em;
|
||||
-moz-padding-end: 0.2em;
|
||||
@ -1427,7 +1430,7 @@ pageaction:not([image]) > hbox >.pageaction-image {
|
||||
}
|
||||
|
||||
.syncsetup-label {
|
||||
color: #fff;
|
||||
color: @color_text_default@;
|
||||
}
|
||||
|
||||
#syncsetup-customserver {
|
||||
|
@ -44,7 +44,7 @@
|
||||
|
||||
/* make clicking on links stand out a bit (bug 532206) */
|
||||
* > *:not(embed):focus, * > *:focus > font {
|
||||
outline: 2px solid #8db8d8 !important;
|
||||
outline: 2px solid @color_background_highlight@ !important;
|
||||
/*
|
||||
XXX How do I preserve mac focusring without blowing focus color on other platforms?
|
||||
outline-color: -moz-mac-focusring !important;
|
||||
@ -344,7 +344,7 @@ option:active,
|
||||
select:active,
|
||||
label:active,
|
||||
textarea:active {
|
||||
background-color: rgba(141, 184, 216, 0.5) !important;
|
||||
background-color: @color_background_highlight_overlay@ !important;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -11,10 +11,18 @@
|
||||
%define color_background_header #292929
|
||||
%define color_text_header #999999
|
||||
%define color_background_scroller #9a9a9a
|
||||
|
||||
%define color_background_inverse #fff
|
||||
%define color_text_inverse #000
|
||||
%define color_text_gray #808080
|
||||
%define color_text_button #000
|
||||
%define color_text_disabled #808080
|
||||
%define color_text_placeholder #808080
|
||||
|
||||
%define color_background_highlight #febc2b
|
||||
%define color_background_highlight_overlay rgba(254, 188, 43, 0.8)
|
||||
%define color_text_highlight #000
|
||||
|
||||
%define color_subtext_default lightgray
|
||||
%define color_subtext_inverse #414141
|
||||
|
||||
%ifdef ANDROID
|
||||
%define font_xlarge 5.08mozmm
|
||||
|
@ -48,8 +48,8 @@
|
||||
}
|
||||
|
||||
::-moz-selection {
|
||||
background-color: #8db8d8;
|
||||
color: black;
|
||||
background-color: @color_background_highlight@;
|
||||
color: @color_text_highlight@;
|
||||
}
|
||||
|
||||
menu,
|
||||
@ -82,7 +82,7 @@ textbox:not([type="number"]) {
|
||||
}
|
||||
|
||||
textbox[isempty="true"] {
|
||||
color: @color_text_gray@;
|
||||
color: @color_text_placeholder@;
|
||||
}
|
||||
|
||||
textbox.search-bar {
|
||||
@ -146,7 +146,7 @@ button {
|
||||
-moz-appearance: none;
|
||||
min-width: @touch_button_minwidth@ !important;
|
||||
min-height: @touch_button_small@ !important; /* button size */
|
||||
color: #000;
|
||||
color: @color_text_button@;
|
||||
margin: @margin_normal@;
|
||||
padding: @padding_xnormal@;
|
||||
background-image: url("chrome://browser/skin/images/button-bg.png");
|
||||
@ -155,7 +155,7 @@ button {
|
||||
}
|
||||
|
||||
button[disabled="true"] {
|
||||
color: #aaa !important;
|
||||
color: @color_text_disabled@ !important;
|
||||
border: @border_width_tiny@ solid @color_button_border@ !important;
|
||||
}
|
||||
|
||||
@ -207,7 +207,7 @@ spinbuttons {
|
||||
-moz-appearance: none !important;
|
||||
min-width: @touch_button_small@ !important; /* button size */
|
||||
min-height: @touch_button_small@ !important; /* button size */
|
||||
color: #000;
|
||||
color: @color_text_button@;
|
||||
margin: @margin_normal@;
|
||||
padding: @padding_xnormal@;
|
||||
background-image: url("chrome://browser/skin/images/button-bg.png");
|
||||
@ -261,7 +261,7 @@ toolbarbutton[open="true"] {
|
||||
background: none !important;
|
||||
border: none !important;
|
||||
-moz-border-image: none !important;
|
||||
color: white;
|
||||
color: @color_text_default@;
|
||||
-moz-box-align: center;
|
||||
font-size: @font_small@;
|
||||
-moz-box-align: center;
|
||||
@ -302,7 +302,7 @@ radio {
|
||||
-moz-appearance: none;
|
||||
min-width: @touch_button_small@ !important; /* button size */
|
||||
min-height: @touch_button_small@ !important; /* button size */
|
||||
color: #000;
|
||||
color: @color_text_button@;
|
||||
padding: @padding_xnormal@;
|
||||
margin: 0;
|
||||
background-image: url("chrome://browser/skin/images/button-bg.png");
|
||||
@ -395,7 +395,7 @@ richlistitem description.title {
|
||||
|
||||
richlistitem label.normal,
|
||||
richlistitem description.normal {
|
||||
color: gray;
|
||||
color: @color_subtext_default@;
|
||||
font-size: @font_small@ !important;
|
||||
white-space: pre-wrap;
|
||||
word-wrap: break-word;
|
||||
@ -421,8 +421,11 @@ richlistitem[selected="true"] {
|
||||
background-color: @color_background_default@;
|
||||
}
|
||||
|
||||
richlistitem:hover:active:not([selected="true"]):not([nohighlight="true"]) {
|
||||
background-color: #8db8d8;
|
||||
richlistitem:hover:active:not([selected="true"]):not([nohighlight="true"]),
|
||||
richlistitem:hover:active:not([selected="true"]):not([nohighlight="true"]) label.normal,
|
||||
richlistitem:hover:active:not([selected="true"]):not([nohighlight="true"]) description.normal {
|
||||
background-color: @color_background_highlight@;
|
||||
color: @color_text_highlight@;
|
||||
}
|
||||
|
||||
richlistitem.section-header,
|
||||
@ -485,7 +488,7 @@ menulist {
|
||||
-moz-user-focus: ignore;
|
||||
min-width: @touch_button_minwidth@ !important;
|
||||
min-height: @touch_button_small@ !important; /* button size */
|
||||
color: #000 !important;
|
||||
color: @color_text_button@ !important;
|
||||
margin: @margin_normal@;
|
||||
padding: @padding_small@ @padding_xnormal@;
|
||||
background-image: url("chrome://browser/skin/images/button-bg.png");
|
||||
@ -494,7 +497,7 @@ menulist {
|
||||
}
|
||||
|
||||
menulist[disabled="true"] {
|
||||
color: #aaa !important;
|
||||
color: @color_text_disabled@ !important;
|
||||
border: @border_width_tiny@ solid @color_button_border@ !important;
|
||||
}
|
||||
|
||||
@ -532,7 +535,7 @@ progressmeter {
|
||||
}
|
||||
|
||||
.progress-bar {
|
||||
background-color: #8db8d8;
|
||||
background-color: @color_background_highlight@;
|
||||
}
|
||||
|
||||
/* panels / arrowboxes------------------------------------------------------ */
|
||||
@ -687,7 +690,7 @@ dialog {
|
||||
}
|
||||
|
||||
.panel-row-button[disabled="true"] .toolbarbutton-text {
|
||||
color: #aaa;
|
||||
color: @color_text_disabled@;
|
||||
}
|
||||
|
||||
.panel-row-button[checked="true"] {
|
||||
|
@ -680,19 +680,23 @@ RasterImage::GetFrame(PRUint32 aWhichFrame,
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
PRUint32 desiredDecodeFlags = aFlags & DECODE_FLAGS_MASK;
|
||||
if (desiredDecodeFlags != mFrameDecodeFlags) {
|
||||
// if we can't discard, then we're screwed; we have no way
|
||||
// to re-decode. Similarly if we aren't allowed to do a sync
|
||||
// decode.
|
||||
if (!(aFlags & FLAG_SYNC_DECODE))
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
if (!CanForciblyDiscard() || mDecoder || mAnim)
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
ForceDiscard();
|
||||
|
||||
mFrameDecodeFlags = desiredDecodeFlags;
|
||||
if (mDecoded) {
|
||||
// If we have decoded data, and it is not a perfect match for what we are
|
||||
// looking for, we must discard to be able to generate the proper data.
|
||||
PRUint32 desiredDecodeFlags = aFlags & DECODE_FLAGS_MASK;
|
||||
if (desiredDecodeFlags != mFrameDecodeFlags) {
|
||||
// if we can't discard, then we're screwed; we have no way
|
||||
// to re-decode. Similarly if we aren't allowed to do a sync
|
||||
// decode.
|
||||
if (!(aFlags & FLAG_SYNC_DECODE))
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
if (!CanForciblyDiscard() || mDecoder || mAnim)
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
ForceDiscard();
|
||||
|
||||
mFrameDecodeFlags = desiredDecodeFlags;
|
||||
}
|
||||
}
|
||||
|
||||
// If the caller requested a synchronous decode, do it
|
||||
|
@ -144,6 +144,14 @@
|
||||
#define NS_ERROR_INVALID_CONTENT_ENCODING \
|
||||
NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_NETWORK, 27)
|
||||
|
||||
/**
|
||||
* A transport level corruption was found in the source document. for example
|
||||
* a document with a calculated checksum that does not match the Content-MD5
|
||||
* http header.
|
||||
*/
|
||||
#define NS_ERROR_CORRUPTED_CONTENT \
|
||||
NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_NETWORK, 29)
|
||||
|
||||
/******************************************************************************
|
||||
* Connectivity error codes:
|
||||
*/
|
||||
|
@ -137,7 +137,8 @@ nsHttpChunkedDecoder::ParseChunkRemaining(char *buf,
|
||||
LOG(("got trailer: %s\n", buf));
|
||||
// allocate a header array for the trailers on demand
|
||||
if (!mTrailers) {
|
||||
mTrailers = new nsHttpHeaderArray();
|
||||
mTrailers = new nsHttpHeaderArray
|
||||
(nsHttpHeaderArray::HTTP_RESPONSE_HEADERS);
|
||||
if (!mTrailers)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
@ -85,8 +85,11 @@ nsHttpHeaderArray::SetHeader(nsHttpAtom header,
|
||||
entry->value.Append(value);
|
||||
}
|
||||
// Replace the existing string with the new value
|
||||
else
|
||||
else if (CanOverwriteHeader(header))
|
||||
entry->value = value;
|
||||
else if (!entry->value.Equals(value))
|
||||
return NS_ERROR_CORRUPTED_CONTENT;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -129,7 +132,7 @@ nsHttpHeaderArray::VisitHeaders(nsIHttpHeaderVisitor *visitor)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsresult
|
||||
nsHttpHeaderArray::ParseHeaderLine(const char *line,
|
||||
nsHttpAtom *hdr,
|
||||
char **val)
|
||||
@ -151,13 +154,13 @@ nsHttpHeaderArray::ParseHeaderLine(const char *line,
|
||||
char *p = (char *) strchr(line, ':');
|
||||
if (!p) {
|
||||
LOG(("malformed header [%s]: no colon\n", line));
|
||||
return;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// make sure we have a valid token for the field-name
|
||||
if (!nsHttp::IsValidToken(line, p)) {
|
||||
LOG(("malformed header [%s]: field-name not a token\n", line));
|
||||
return;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
*p = 0; // null terminate field-name
|
||||
@ -165,7 +168,7 @@ nsHttpHeaderArray::ParseHeaderLine(const char *line,
|
||||
nsHttpAtom atom = nsHttp::ResolveAtom(line);
|
||||
if (!atom) {
|
||||
LOG(("failed to resolve atom [%s]\n", line));
|
||||
return;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// skip over whitespace
|
||||
@ -183,7 +186,7 @@ nsHttpHeaderArray::ParseHeaderLine(const char *line,
|
||||
if (val) *val = p;
|
||||
|
||||
// assign response header
|
||||
SetHeader(atom, nsDependentCString(p, p2 - p), PR_TRUE);
|
||||
return SetHeader(atom, nsDependentCString(p, p2 - p), PR_TRUE);
|
||||
}
|
||||
|
||||
void
|
||||
@ -247,3 +250,11 @@ nsHttpHeaderArray::CanAppendToHeader(nsHttpAtom header)
|
||||
header != nsHttp::Location &&
|
||||
header != nsHttp::Max_Forwards;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsHttpHeaderArray::CanOverwriteHeader(nsHttpAtom header)
|
||||
{
|
||||
if (mType != HTTP_RESPONSE_HEADERS)
|
||||
return PR_TRUE;
|
||||
return header != nsHttp::Content_Length;
|
||||
}
|
||||
|
@ -49,7 +49,12 @@
|
||||
class nsHttpHeaderArray
|
||||
{
|
||||
public:
|
||||
nsHttpHeaderArray() {}
|
||||
enum nsHttpHeaderType {
|
||||
HTTP_REQUEST_HEADERS,
|
||||
HTTP_RESPONSE_HEADERS
|
||||
};
|
||||
|
||||
nsHttpHeaderArray(nsHttpHeaderType headerType) : mType(headerType) {}
|
||||
~nsHttpHeaderArray() { Clear(); }
|
||||
|
||||
const char *PeekHeader(nsHttpAtom header);
|
||||
@ -73,9 +78,9 @@ public:
|
||||
|
||||
// parse a header line, return the header atom and a pointer to the
|
||||
// header value (the substring of the header line -- do not free).
|
||||
void ParseHeaderLine(const char *line,
|
||||
nsHttpAtom *header=nsnull,
|
||||
char **value=nsnull);
|
||||
nsresult ParseHeaderLine(const char *line,
|
||||
nsHttpAtom *header=nsnull,
|
||||
char **value=nsnull);
|
||||
|
||||
void Flatten(nsACString &, PRBool pruneProxyHeaders=PR_FALSE);
|
||||
|
||||
@ -104,8 +109,10 @@ public:
|
||||
private:
|
||||
PRInt32 LookupEntry(nsHttpAtom header, nsEntry **);
|
||||
PRBool CanAppendToHeader(nsHttpAtom header);
|
||||
PRBool CanOverwriteHeader(nsHttpAtom header);
|
||||
|
||||
nsTArray<nsEntry> mHeaders;
|
||||
nsHttpHeaderType mType;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -52,8 +52,10 @@
|
||||
class nsHttpRequestHead
|
||||
{
|
||||
public:
|
||||
nsHttpRequestHead() : mMethod(nsHttp::Get), mVersion(NS_HTTP_VERSION_1_1) {}
|
||||
~nsHttpRequestHead() {}
|
||||
nsHttpRequestHead() : mHeaders(nsHttpHeaderArray::HTTP_REQUEST_HEADERS)
|
||||
, mMethod(nsHttp::Get)
|
||||
, mVersion(NS_HTTP_VERSION_1_1) {}
|
||||
~nsHttpRequestHead() {}
|
||||
|
||||
void SetMethod(nsHttpAtom method) { mMethod = method; }
|
||||
void SetVersion(nsHttpVersion version) { mVersion = version; }
|
||||
|
@ -197,23 +197,30 @@ nsHttpResponseHead::ParseStatusLine(const char *line)
|
||||
PRUintn(mVersion), PRUintn(mStatus), mStatusText.get()));
|
||||
}
|
||||
|
||||
void
|
||||
nsresult
|
||||
nsHttpResponseHead::ParseHeaderLine(const char *line)
|
||||
{
|
||||
nsHttpAtom hdr = {0};
|
||||
char *val;
|
||||
|
||||
mHeaders.ParseHeaderLine(line, &hdr, &val);
|
||||
nsresult rv;
|
||||
|
||||
rv = mHeaders.ParseHeaderLine(line, &hdr, &val);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
// leading and trailing LWS has been removed from |val|
|
||||
|
||||
// handle some special case headers...
|
||||
if (hdr == nsHttp::Content_Length) {
|
||||
PRInt64 len;
|
||||
// permit only a single value here.
|
||||
if (nsHttp::ParseInt64(val, &len))
|
||||
if (nsHttp::ParseInt64(val, &len)) {
|
||||
mContentLength = len;
|
||||
else
|
||||
}
|
||||
else {
|
||||
LOG(("invalid content-length!\n"));
|
||||
return NS_ERROR_CORRUPTED_CONTENT;
|
||||
}
|
||||
}
|
||||
else if (hdr == nsHttp::Content_Type) {
|
||||
LOG(("ParseContentType [type=%s]\n", val));
|
||||
@ -225,6 +232,7 @@ nsHttpResponseHead::ParseHeaderLine(const char *line)
|
||||
ParseCacheControl(val);
|
||||
else if (hdr == nsHttp::Pragma)
|
||||
ParsePragma(val);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// From section 13.2.3 of RFC2616, we compute the current age of a cached
|
||||
|
@ -51,13 +51,14 @@
|
||||
class nsHttpResponseHead
|
||||
{
|
||||
public:
|
||||
nsHttpResponseHead() : mVersion(NS_HTTP_VERSION_1_1)
|
||||
nsHttpResponseHead() : mHeaders(nsHttpHeaderArray::HTTP_RESPONSE_HEADERS)
|
||||
, mVersion(NS_HTTP_VERSION_1_1)
|
||||
, mStatus(200)
|
||||
, mContentLength(LL_MAXUINT)
|
||||
, mCacheControlNoStore(PR_FALSE)
|
||||
, mCacheControlNoCache(PR_FALSE)
|
||||
, mPragmaNoCache(PR_FALSE) {}
|
||||
~nsHttpResponseHead()
|
||||
~nsHttpResponseHead()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
@ -104,7 +105,7 @@ public:
|
||||
void ParseStatusLine(const char *line);
|
||||
|
||||
// parse a header line. line must be null terminated. parsing is destructive.
|
||||
void ParseHeaderLine(const char *line);
|
||||
nsresult ParseHeaderLine(const char *line);
|
||||
|
||||
// cache validation support methods
|
||||
nsresult ComputeFreshnessLifetime(PRUint32 *);
|
||||
|
@ -784,12 +784,12 @@ nsHttpTransaction::LocateHttpStart(char *buf, PRUint32 len,
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
nsresult
|
||||
nsHttpTransaction::ParseLine(char *line)
|
||||
{
|
||||
LOG(("nsHttpTransaction::ParseLine [%s]\n", line));
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
if (!mHaveStatusLine) {
|
||||
mResponseHead->ParseStatusLine(line);
|
||||
mHaveStatusLine = PR_TRUE;
|
||||
@ -797,8 +797,10 @@ nsHttpTransaction::ParseLine(char *line)
|
||||
if (mResponseHead->Version() == NS_HTTP_VERSION_0_9)
|
||||
mHaveAllHeaders = PR_TRUE;
|
||||
}
|
||||
else
|
||||
mResponseHead->ParseHeaderLine(line);
|
||||
else {
|
||||
rv = mResponseHead->ParseHeaderLine(line);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
@ -813,8 +815,11 @@ nsHttpTransaction::ParseLineSegment(char *segment, PRUint32 len)
|
||||
// of mLineBuf.
|
||||
mLineBuf.Truncate(mLineBuf.Length() - 1);
|
||||
if (!mHaveStatusLine || (*segment != ' ' && *segment != '\t')) {
|
||||
ParseLine(mLineBuf.BeginWriting());
|
||||
nsresult rv = ParseLine(mLineBuf.BeginWriting());
|
||||
mLineBuf.Truncate();
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -141,7 +141,7 @@ private:
|
||||
nsresult Restart();
|
||||
char *LocateHttpStart(char *buf, PRUint32 len,
|
||||
PRBool aAllowPartialMatch);
|
||||
void ParseLine(char *line);
|
||||
nsresult ParseLine(char *line);
|
||||
nsresult ParseLineSegment(char *seg, PRUint32 len);
|
||||
nsresult ParseHead(char *, PRUint32 count, PRUint32 *countRead);
|
||||
nsresult HandleContentStart();
|
||||
|
@ -807,7 +807,9 @@ PK11PasswordPrompt(PK11SlotInfo* slot, PRBool retry, void* arg) {
|
||||
rv = NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
else {
|
||||
PRBool checkState;
|
||||
// Although the exact value is ignored, we must not pass invalid
|
||||
// PRBool values through XPConnect.
|
||||
PRBool checkState = PR_FALSE;
|
||||
rv = proxyPrompt->PromptPassword(nsnull, promptString.get(),
|
||||
&password, nsnull, &checkState, &value);
|
||||
}
|
||||
|
@ -7217,7 +7217,7 @@ DirectoryInstallLocation.prototype = {
|
||||
linkedDirectory.initWithPath(line.value);
|
||||
}
|
||||
catch (e) {
|
||||
linkedDirectory.setRelativeDescriptor(file.parent, line.value);
|
||||
linkedDirectory.setRelativeDescriptor(aFile.parent, line.value);
|
||||
}
|
||||
|
||||
if (!linkedDirectory.exists()) {
|
||||
|
@ -64,6 +64,25 @@ function writePointer(aId, aName) {
|
||||
fos.close();
|
||||
}
|
||||
|
||||
function writeRelativePointer(aId, aName) {
|
||||
let file = profileDir.clone();
|
||||
file.append(aName ? aName : aId);
|
||||
|
||||
let absTarget = sourceDir.clone();
|
||||
absTarget.append(do_get_expected_addon_name(aId));
|
||||
|
||||
var relTarget = absTarget.QueryInterface(Ci.nsILocalFile)
|
||||
.getRelativeDescriptor(profileDir);
|
||||
|
||||
var fos = AM_Cc["@mozilla.org/network/file-output-stream;1"].
|
||||
createInstance(AM_Ci.nsIFileOutputStream);
|
||||
fos.init(file,
|
||||
FileUtils.MODE_WRONLY | FileUtils.MODE_CREATE | FileUtils.MODE_TRUNCATE,
|
||||
FileUtils.PERMS_FILE, 0);
|
||||
fos.write(relTarget, relTarget.length);
|
||||
fos.close();
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
// pointer files only work with unpacked directories
|
||||
if (Services.prefs.getBoolPref("extensions.alwaysUnpack") == false)
|
||||
@ -352,7 +371,33 @@ function run_test_9() {
|
||||
pointer.append(addon1.id);
|
||||
do_check_false(pointer.exists());
|
||||
|
||||
end_test();
|
||||
run_test_10();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Tests that installing a new add-on by pointer with a relative path works
|
||||
function run_test_10() {
|
||||
writeInstallRDFForExtension(addon1, sourceDir);
|
||||
writeRelativePointer(addon1.id);
|
||||
|
||||
restartManager();
|
||||
|
||||
AddonManager.getAddonByID(addon1.id, function(a1) {
|
||||
do_check_neq(a1, null);
|
||||
do_check_eq(a1.version, "1.0");
|
||||
|
||||
let file = a1.getResourceURI().QueryInterface(AM_Ci.nsIFileURL).file;
|
||||
do_check_eq(file.parent.path, sourceDir.path);
|
||||
|
||||
let rootUri = do_get_addon_root_uri(sourceDir, addon1.id);
|
||||
let uri = a1.getResourceURI("/");
|
||||
do_check_eq(uri.spec, rootUri);
|
||||
uri = a1.getResourceURI("install.rdf");
|
||||
do_check_eq(uri.spec, rootUri + "install.rdf");
|
||||
|
||||
// Check that upgrade is disabled for addons installed by file-pointers.
|
||||
do_check_eq(a1.permissions & AddonManager.PERM_CAN_UPGRADE, 0);
|
||||
end_test();
|
||||
});
|
||||
}
|
||||
|
@ -619,7 +619,7 @@ else
|
||||
endif # DMG
|
||||
endif # MOZ_PKG_MANIFEST
|
||||
endif # UNIVERSAL_BINARY
|
||||
$(OPTIMIZE_JARS_CMD) --optimize $(JARLOG_DIR) $(DIST)/bin/chrome $(DIST)/$(STAGEPATH)$(MOZ_PKG_DIR)/chrome
|
||||
$(OPTIMIZE_JARS_CMD) --optimize $(JARLOG_DIR) $(DIST)/bin/chrome $(DIST)/$(STAGEPATH)$(MOZ_PKG_DIR)$(_BINPATH)/chrome
|
||||
ifndef PKG_SKIP_STRIP
|
||||
ifeq ($(OS_ARCH),OS2)
|
||||
@echo "Stripping package directory..."
|
||||
|
@ -56,7 +56,7 @@ notification[type="critical"] .messageImage {
|
||||
/* Popup notification */
|
||||
|
||||
.popup-notification-description {
|
||||
max-width: 248px;
|
||||
max-width: 24em;
|
||||
}
|
||||
|
||||
.popup-notification-button-container {
|
||||
|
@ -91,7 +91,7 @@ notification[type="warning"] .messageCloseButton {
|
||||
/* Popup notification */
|
||||
|
||||
.popup-notification-description {
|
||||
max-width: 248px;
|
||||
max-width: 24em;
|
||||
}
|
||||
|
||||
.popup-notification-button-container {
|
||||
|
@ -60,7 +60,7 @@ notification[type="critical"] .messageImage {
|
||||
/* Popup notification */
|
||||
|
||||
.popup-notification-description {
|
||||
max-width: 248px;
|
||||
max-width: 24em;
|
||||
}
|
||||
|
||||
.popup-notification-button-container {
|
||||
|
Loading…
Reference in New Issue
Block a user