зеркало из https://github.com/mozilla/gecko-dev.git
Merge last PGO-green changeset of mozilla-inbound to mozilla-central
This commit is contained in:
Коммит
aac68a2eb6
|
@ -16,7 +16,6 @@ var gPrevCharset = null;
|
|||
var gProxyFavIcon = null;
|
||||
var gLastValidURLStr = "";
|
||||
var gInPrintPreviewMode = false;
|
||||
var gDownloadMgr = null;
|
||||
var gContextMenu = null; // nsContextMenu instance
|
||||
var gStartupRan = false;
|
||||
|
||||
|
@ -1339,8 +1338,7 @@ var gBrowserInit = {
|
|||
// If the user manually opens the download manager before the timeout, the
|
||||
// downloads will start right away, and getting the service again won't hurt.
|
||||
setTimeout(function() {
|
||||
gDownloadMgr = Cc["@mozilla.org/download-manager;1"].
|
||||
getService(Ci.nsIDownloadManager);
|
||||
Cc["@mozilla.org/download-manager;1"].getService(Ci.nsIDownloadManager);
|
||||
|
||||
#ifdef XP_WIN
|
||||
if (Win7Features) {
|
||||
|
@ -6871,140 +6869,6 @@ var gIdentityHandler = {
|
|||
}
|
||||
};
|
||||
|
||||
let DownloadMonitorPanel = {
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//// DownloadMonitorPanel Member Variables
|
||||
|
||||
_panel: null,
|
||||
_activeStr: null,
|
||||
_pausedStr: null,
|
||||
_lastTime: Infinity,
|
||||
_listening: false,
|
||||
|
||||
get DownloadUtils() {
|
||||
delete this.DownloadUtils;
|
||||
Cu.import("resource://gre/modules/DownloadUtils.jsm", this);
|
||||
return this.DownloadUtils;
|
||||
},
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//// DownloadMonitorPanel Public Methods
|
||||
|
||||
/**
|
||||
* Initialize the status panel and member variables
|
||||
*/
|
||||
init: function DMP_init() {
|
||||
// Initialize "private" member variables
|
||||
this._panel = document.getElementById("download-monitor");
|
||||
|
||||
// Cache the status strings
|
||||
this._activeStr = gNavigatorBundle.getString("activeDownloads1");
|
||||
this._pausedStr = gNavigatorBundle.getString("pausedDownloads1");
|
||||
|
||||
gDownloadMgr.addListener(this);
|
||||
this._listening = true;
|
||||
|
||||
this.updateStatus();
|
||||
},
|
||||
|
||||
uninit: function DMP_uninit() {
|
||||
if (this._listening)
|
||||
gDownloadMgr.removeListener(this);
|
||||
},
|
||||
|
||||
inited: function DMP_inited() {
|
||||
return this._panel != null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Update status based on the number of active and paused downloads
|
||||
*/
|
||||
updateStatus: function DMP_updateStatus() {
|
||||
if (!this.inited())
|
||||
return;
|
||||
|
||||
let numActive = gDownloadMgr.activeDownloadCount;
|
||||
|
||||
// Hide the panel and reset the "last time" if there's no downloads
|
||||
if (numActive == 0) {
|
||||
this._panel.hidden = true;
|
||||
this._lastTime = Infinity;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Find the download with the longest remaining time
|
||||
let numPaused = 0;
|
||||
let maxTime = -Infinity;
|
||||
let dls = gDownloadMgr.activeDownloads;
|
||||
while (dls.hasMoreElements()) {
|
||||
let dl = dls.getNext();
|
||||
if (dl.state == gDownloadMgr.DOWNLOAD_DOWNLOADING) {
|
||||
// Figure out if this download takes longer
|
||||
if (dl.speed > 0 && dl.size > 0)
|
||||
maxTime = Math.max(maxTime, (dl.size - dl.amountTransferred) / dl.speed);
|
||||
else
|
||||
maxTime = -1;
|
||||
}
|
||||
else if (dl.state == gDownloadMgr.DOWNLOAD_PAUSED)
|
||||
numPaused++;
|
||||
}
|
||||
|
||||
// Get the remaining time string and last sec for time estimation
|
||||
let timeLeft;
|
||||
[timeLeft, this._lastTime] =
|
||||
this.DownloadUtils.getTimeLeft(maxTime, this._lastTime);
|
||||
|
||||
// Figure out how many downloads are currently downloading
|
||||
let numDls = numActive - numPaused;
|
||||
let status = this._activeStr;
|
||||
|
||||
// If all downloads are paused, show the paused message instead
|
||||
if (numDls == 0) {
|
||||
numDls = numPaused;
|
||||
status = this._pausedStr;
|
||||
}
|
||||
|
||||
// Get the correct plural form and insert the number of downloads and time
|
||||
// left message if necessary
|
||||
status = PluralForm.get(numDls, status);
|
||||
status = status.replace("#1", numDls);
|
||||
status = status.replace("#2", timeLeft);
|
||||
|
||||
// Update the panel and show it
|
||||
this._panel.label = status;
|
||||
this._panel.hidden = false;
|
||||
},
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//// nsIDownloadProgressListener
|
||||
|
||||
/**
|
||||
* Update status for download progress changes
|
||||
*/
|
||||
onProgressChange: function() {
|
||||
this.updateStatus();
|
||||
},
|
||||
|
||||
/**
|
||||
* Update status for download state changes
|
||||
*/
|
||||
onDownloadStateChange: function() {
|
||||
this.updateStatus();
|
||||
},
|
||||
|
||||
onStateChange: function(aWebProgress, aRequest, aStateFlags, aStatus, aDownload) {
|
||||
},
|
||||
|
||||
onSecurityChange: function(aWebProgress, aRequest, aState, aDownload) {
|
||||
},
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//// nsISupports
|
||||
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIDownloadProgressListener]),
|
||||
};
|
||||
|
||||
function getNotificationBox(aWindow) {
|
||||
var foundBrowser = gBrowser.getBrowserForDocument(aWindow.document);
|
||||
if (foundBrowser)
|
||||
|
|
|
@ -24,10 +24,8 @@ MOCHITEST_BROWSER_FILES = \
|
|||
browser_privatebrowsing_searchbar.js \
|
||||
browser_privatebrowsing_sslsite_transition.js \
|
||||
$(filter disabled-since-it-no-longer-makes-sense, browser_privatebrowsing_transition.js) \
|
||||
$(filter disabled--bug-564934, browser_privatebrowsing_downloadmonitor.js) \
|
||||
browser_privatebrowsing_urlbarundo.js \
|
||||
browser_privatebrowsing_viewsource.js \
|
||||
staller.sjs \
|
||||
$(NULL)
|
||||
|
||||
# Turn off private browsing tests that perma-timeout on Linux.
|
||||
|
|
|
@ -1,153 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
// This test makes sure that the download monitor status bar panel is correctly
|
||||
// cleared when switching the private browsing mode on or off.
|
||||
|
||||
function test() {
|
||||
// initialization
|
||||
let pb = Cc["@mozilla.org/privatebrowsing;1"].
|
||||
getService(Ci.nsIPrivateBrowsingService);
|
||||
let dm = Cc["@mozilla.org/download-manager;1"].
|
||||
getService(Ci.nsIDownloadManager);
|
||||
if (!gDownloadMgr)
|
||||
gDownloadMgr = dm;
|
||||
let panel = document.getElementById("download-monitor");
|
||||
waitForExplicitFinish();
|
||||
|
||||
let acceptDialog = 0;
|
||||
let confirmCalls = 0;
|
||||
function promptObserver(aSubject, aTopic, aData) {
|
||||
let dialogWin = aSubject.QueryInterface(Ci.nsIDOMWindow);
|
||||
confirmCalls++;
|
||||
if (acceptDialog-- > 0)
|
||||
dialogWin.document.documentElement.getButton("accept").click();
|
||||
}
|
||||
|
||||
Services.obs.addObserver(promptObserver, "common-dialog-loaded", false);
|
||||
|
||||
// Add a new download
|
||||
let [file, persist] = addDownload(dm, {
|
||||
isPrivate: PrivateBrowsingUtils.isWindowPrivate(window),
|
||||
resultFileName: "pbtest-1",
|
||||
downloadName: "PB Test 1"
|
||||
});
|
||||
|
||||
// Make sure that the download is being displayed in the monitor panel
|
||||
if (!DownloadMonitorPanel.inited())
|
||||
DownloadMonitorPanel.init();
|
||||
else
|
||||
DownloadMonitorPanel.updateStatus();
|
||||
ok(!panel.hidden, "The download panel should be successfully added initially");
|
||||
|
||||
// Enter the private browsing mode
|
||||
acceptDialog = 1;
|
||||
pb.privateBrowsingEnabled = true;
|
||||
is(confirmCalls, 1, "One prompt was accepted");
|
||||
ok(pb.privateBrowsingEnabled, "The private browsing transition was successful");
|
||||
|
||||
executeSoon(function () {
|
||||
ok(panel.hidden, "The download panel should be hidden when entering the private browsing mode");
|
||||
|
||||
// Add a new download
|
||||
let [file2, persist2] = addDownload(dm, {
|
||||
isPrivate: PrivateBrowsingUtils.isWindowPrivate(window),
|
||||
resultFileName: "pbtest-2",
|
||||
downloadName: "PB Test 2"
|
||||
});
|
||||
|
||||
// Update the panel
|
||||
DownloadMonitorPanel.updateStatus();
|
||||
|
||||
// Make sure that the panel is visible
|
||||
ok(!panel.hidden, "The download panel should show up when a new download is added");
|
||||
|
||||
// Exit the private browsing mode
|
||||
acceptDialog = 1;
|
||||
pb.privateBrowsingEnabled = false;
|
||||
is(confirmCalls, 2, "One prompt was accepted");
|
||||
ok(!pb.privateBrowsingEnabled, "The private browsing transition was successful");
|
||||
|
||||
executeSoon(function () {
|
||||
ok(panel.hidden, "The download panel should be hidden when leaving the private browsing mode");
|
||||
|
||||
// cleanup
|
||||
let dls = dm.activeDownloads;
|
||||
while (dls.hasMoreElements()) {
|
||||
let dl = dls.getNext().QueryInterface(Ci.nsIDownload);
|
||||
dm.removeDownload(dl.id);
|
||||
let file = dl.targetFile;
|
||||
if (file.exists())
|
||||
file.remove(false);
|
||||
}
|
||||
if (file.exists())
|
||||
file.remove(false);
|
||||
|
||||
Services.obs.removeObserver(promptObserver, "common-dialog-loaded", false);
|
||||
finish();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a download to the DM, and starts it.
|
||||
* (Copied from toolkit/componentns/downloads/test/unit/head_download_manager.js)
|
||||
* @param aParams (optional): an optional object which contains the function
|
||||
* parameters:
|
||||
* resultFileName: leaf node for the target file
|
||||
* targetFile: nsIFile for the target (overrides resultFileName)
|
||||
* sourceURI: the download source URI
|
||||
* downloadName: the display name of the download
|
||||
* runBeforeStart: a function to run before starting the download
|
||||
* isPrivate: whether the download is private
|
||||
*/
|
||||
function addDownload(dm, aParams)
|
||||
{
|
||||
if (!aParams)
|
||||
aParams = {};
|
||||
if (!("resultFileName" in aParams))
|
||||
aParams.resultFileName = "download.result";
|
||||
if (!("targetFile" in aParams)) {
|
||||
let dirSvc = Cc["@mozilla.org/file/directory_service;1"].
|
||||
getService(Ci.nsIProperties);
|
||||
aParams.targetFile = dirSvc.get("ProfD", Ci.nsIFile);
|
||||
aParams.targetFile.append(aParams.resultFileName);
|
||||
}
|
||||
if (!("sourceURI" in aParams))
|
||||
aParams.sourceURI = "http://mochi.test:8888/browser/browser/components/privatebrowsing/test/browser/global/staller.sjs";
|
||||
if (!("downloadName" in aParams))
|
||||
aParams.downloadName = null;
|
||||
if (!("runBeforeStart" in aParams))
|
||||
aParams.runBeforeStart = function () {};
|
||||
|
||||
const nsIWBP = Ci.nsIWebBrowserPersist;
|
||||
let persist = Cc["@mozilla.org/embedding/browser/nsWebBrowserPersist;1"]
|
||||
.createInstance(Ci.nsIWebBrowserPersist);
|
||||
persist.persistFlags = nsIWBP.PERSIST_FLAGS_REPLACE_EXISTING_FILES |
|
||||
nsIWBP.PERSIST_FLAGS_BYPASS_CACHE |
|
||||
nsIWBP.PERSIST_FLAGS_AUTODETECT_APPLY_CONVERSION;
|
||||
|
||||
let dl = dm.addDownload(Ci.nsIDownloadManager.DOWNLOAD_TYPE_DOWNLOAD,
|
||||
createURI(aParams.sourceURI),
|
||||
createURI(aParams.targetFile), aParams.downloadName, null,
|
||||
Math.round(Date.now() * 1000), null, persist, aParams.isPrivate);
|
||||
|
||||
// This will throw if it isn't found, and that would mean test failure, so no
|
||||
// try catch block
|
||||
let test = dm.getDownload(dl.id);
|
||||
|
||||
aParams.runBeforeStart.call(undefined, dl);
|
||||
|
||||
persist.progressListener = dl.QueryInterface(Ci.nsIWebProgressListener);
|
||||
persist.savePrivacyAwareURI(dl.source, null, null, null, null, dl.targetFile,
|
||||
aParams.isPrivate);
|
||||
|
||||
return [dl.targetFile, persist];
|
||||
}
|
||||
|
||||
function createURI(aObj) {
|
||||
let ios = Services.io;
|
||||
return (aObj instanceof Ci.nsIFile) ? ios.newFileURI(aObj) :
|
||||
ios.newURI(aObj, null, null);
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
// This provides the tests with a download URL which never finishes.
|
||||
|
||||
var timer;
|
||||
|
||||
function handleRequest(request, response) {
|
||||
response.setStatusLine(request.httpVersion, 200, "OK");
|
||||
response.processAsync();
|
||||
|
||||
const nsITimer = Components.interfaces.nsITimer;
|
||||
|
||||
function stall() {
|
||||
timer = null;
|
||||
// This write will throw if the connection has been closed by the browser.
|
||||
response.write("stalling...\n");
|
||||
timer = Components.classes["@mozilla.org/timer;1"]
|
||||
.createInstance(nsITimer);
|
||||
timer.initWithCallback(stall, 500, nsITimer.TYPE_ONE_SHOT);
|
||||
}
|
||||
|
||||
response.setHeader("Content-Type", "text/plain", false);
|
||||
response.setHeader("Accept-Ranges", "none", false);
|
||||
stall();
|
||||
}
|
|
@ -18,7 +18,7 @@ XPCOMUtils.defineLazyModuleGetter(this, "CommandUtils",
|
|||
|
||||
// DO NOT put Require.jsm or gcli.jsm into lazy getters as this breaks the
|
||||
// requisition import a few lines down.
|
||||
Cu.import("resource://gre/modules/devtools/gcli.jsm");
|
||||
Cu.import("resource:///modules/devtools/gcli.jsm");
|
||||
Cu.import("resource://gre/modules/devtools/Require.jsm");
|
||||
|
||||
let Requisition = require('gcli/cli').Requisition;
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
let tempScope = {};
|
||||
Components.utils.import("resource:///modules/devtools/Target.jsm", tempScope);
|
||||
let TargetFactory = tempScope.TargetFactory;
|
||||
Components.utils.import("resource:///modules/devtools/Console.jsm", tempScope);
|
||||
Components.utils.import("resource://gre/modules/devtools/Console.jsm", tempScope);
|
||||
let console = tempScope.console;
|
||||
|
||||
/**
|
||||
|
|
|
@ -13,7 +13,7 @@ Cu.import("resource://gre/modules/Services.jsm");
|
|||
Cu.import("resource:///modules/devtools/EventEmitter.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "MarkupView",
|
||||
"resource://gre/modules/devtools/MarkupView.jsm");
|
||||
"resource:///modules/devtools/MarkupView.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Selection",
|
||||
"resource:///modules/devtools/Selection.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "HTMLBreadcrumbs",
|
||||
|
|
|
@ -586,8 +586,6 @@ just addresses the organization to follow, e.g. "This site is run by " -->
|
|||
|
||||
<!ENTITY identity.moreInfoLinkText "More Information…">
|
||||
|
||||
<!ENTITY downloadMonitor2.tooltip "Click to open downloads window">
|
||||
|
||||
<!ENTITY allTabs.filter.emptyText "Search Tabs">
|
||||
<!-- Name for the tabs toolbar as spoken by screen readers.
|
||||
The word "toolbar" is appended automatically and should not be contained below! -->
|
||||
|
|
|
@ -232,14 +232,6 @@ identity.unknown.tooltip=This website does not supply identity information.
|
|||
|
||||
identity.ownerUnknown2=(unknown)
|
||||
|
||||
# Downloads Monitor Panel
|
||||
# LOCALIZATION NOTE (activeDownloads1, pausedDownloads1): Semi-colon list of plural
|
||||
# forms. See: http://developer.mozilla.org/en/docs/Localization_and_Plurals
|
||||
# #1 number of downloads; #2 time left
|
||||
# examples: 1 active download (2 minutes remaining); 11 paused downloads
|
||||
activeDownloads1=1 active download (#2);#1 active downloads (#2)
|
||||
pausedDownloads1=1 paused download;#1 paused downloads
|
||||
|
||||
# Edit Bookmark UI
|
||||
editBookmarkPanel.pageBookmarkedTitle=Page Bookmarked
|
||||
editBookmarkPanel.pageBookmarkedDescription=%S will always remember this page for you.
|
||||
|
|
|
@ -1791,12 +1791,6 @@ toolbar[mode="text"] toolbarbutton.chevron > .toolbarbutton-icon {
|
|||
display: -moz-box; /* display chevron icon in text mode */
|
||||
}
|
||||
|
||||
#download-monitor {
|
||||
list-style-image: url("chrome://browser/skin/Toolbar-small.png");
|
||||
-moz-image-region: rect(0px 16px 16px 0px);
|
||||
}
|
||||
|
||||
|
||||
/* ::::: Keyboard UI Panel ::::: */
|
||||
|
||||
.KUI-panel-closebutton {
|
||||
|
|
|
@ -3130,10 +3130,6 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker {
|
|||
@hudButtonPressed@
|
||||
}
|
||||
|
||||
#download-monitor {
|
||||
list-style-image: url("chrome://mozapps/skin/downloads/downloadStatusIcon.png");
|
||||
}
|
||||
|
||||
/* ::::: Keyboard UI Panel ::::: */
|
||||
|
||||
.KUI-panel {
|
||||
|
|
|
@ -2408,11 +2408,6 @@ toolbarbutton.bookmark-item[dragover="true"][open="true"] {
|
|||
min-width: 280px;
|
||||
}
|
||||
|
||||
#download-monitor {
|
||||
list-style-image: url("chrome://browser/skin/Toolbar.png");
|
||||
-moz-image-region: rect(0, 108px, 18px, 90px);
|
||||
}
|
||||
|
||||
/* Bookmarks roots menu-items */
|
||||
#appmenu_subscribeToPage:not([disabled]),
|
||||
#appmenu_subscribeToPageMenu,
|
||||
|
|
|
@ -5284,6 +5284,7 @@ dnl enable once PeerConnection lands
|
|||
fi
|
||||
|
||||
AC_SUBST(MOZ_WEBRTC)
|
||||
AC_SUBST(MOZ_WEBRTC_LEAKING_TESTS)
|
||||
AC_SUBST(MOZ_WEBRTC_SIGNALING)
|
||||
AC_SUBST(MOZ_PEERCONNECTION)
|
||||
AC_SUBST(MOZ_WEBRTC_IN_LIBXUL)
|
||||
|
|
|
@ -222,7 +222,8 @@ static uint32_t CountNewlinesInNativeLength(nsIContent* aContent,
|
|||
}
|
||||
#endif
|
||||
|
||||
static uint32_t GetNativeTextLength(nsIContent* aContent, uint32_t aMaxLength = UINT32_MAX)
|
||||
/* static */ uint32_t
|
||||
nsContentEventHandler::GetNativeTextLength(nsIContent* aContent, uint32_t aMaxLength)
|
||||
{
|
||||
if (aContent->IsNodeOfType(nsINode::eTEXT)) {
|
||||
uint32_t textLengthDifference =
|
||||
|
@ -369,7 +370,7 @@ nsContentEventHandler::SetRangeFromFlatTextOffset(
|
|||
uint32_t aNativeLength,
|
||||
bool aExpandToClusterBoundaries)
|
||||
{
|
||||
nsCOMPtr<nsIContentIterator> iter = NS_NewContentIterator();
|
||||
nsCOMPtr<nsIContentIterator> iter = NS_NewPreContentIterator();
|
||||
nsresult rv = iter->Init(mRootContent);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
|
|
|
@ -80,6 +80,9 @@ public:
|
|||
static nsresult GetFlatTextOffsetOfRange(nsIContent* aRootContent,
|
||||
nsRange* aRange,
|
||||
uint32_t* aOffset);
|
||||
// Get the native text length of a content node excluding any children
|
||||
static uint32_t GetNativeTextLength(nsIContent* aContent,
|
||||
uint32_t aMaxLength = UINT32_MAX);
|
||||
protected:
|
||||
// Make the DOM range from the offset of FlatText and the text length.
|
||||
// If aExpandToClusterBoundaries is true, the start offset and the end one are
|
||||
|
|
|
@ -62,6 +62,8 @@ public:
|
|||
NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
|
||||
NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
|
||||
NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
|
||||
NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTEWILLCHANGE
|
||||
NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED
|
||||
|
||||
void Init(nsIWidget* aWidget,
|
||||
nsPresContext* aPresContext,
|
||||
|
@ -79,6 +81,7 @@ private:
|
|||
void ObserveEditableNode();
|
||||
|
||||
bool mObserving;
|
||||
uint32_t mPreAttrChangeLength;
|
||||
};
|
||||
|
||||
/******************************************************************/
|
||||
|
@ -976,6 +979,50 @@ nsTextStateManager::ContentRemoved(nsIDocument* aDocument,
|
|||
new TextChangeEvent(this, offset, offset + childOffset, offset));
|
||||
}
|
||||
|
||||
static nsIContent*
|
||||
GetContentBR(mozilla::dom::Element *aElement) {
|
||||
if (!aElement->IsNodeOfType(nsINode::eCONTENT)) {
|
||||
return nullptr;
|
||||
}
|
||||
nsIContent *content = static_cast<nsIContent*>(aElement);
|
||||
return content->IsHTML(nsGkAtoms::br) ? content : nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
nsTextStateManager::AttributeWillChange(nsIDocument* aDocument,
|
||||
mozilla::dom::Element* aElement,
|
||||
int32_t aNameSpaceID,
|
||||
nsIAtom* aAttribute,
|
||||
int32_t aModType)
|
||||
{
|
||||
nsIContent *content = GetContentBR(aElement);
|
||||
mPreAttrChangeLength = content ?
|
||||
nsContentEventHandler::GetNativeTextLength(content) : 0;
|
||||
}
|
||||
|
||||
void
|
||||
nsTextStateManager::AttributeChanged(nsIDocument* aDocument,
|
||||
mozilla::dom::Element* aElement,
|
||||
int32_t aNameSpaceID,
|
||||
nsIAtom* aAttribute,
|
||||
int32_t aModType)
|
||||
{
|
||||
nsIContent *content = GetContentBR(aElement);
|
||||
if (!content) {
|
||||
return;
|
||||
}
|
||||
uint32_t postAttrChangeLength =
|
||||
nsContentEventHandler::GetNativeTextLength(content);
|
||||
if (postAttrChangeLength != mPreAttrChangeLength) {
|
||||
uint32_t start;
|
||||
if (NS_SUCCEEDED(nsContentEventHandler::GetFlatTextOffsetOfRange(
|
||||
mRootContent, content, 0, &start))) {
|
||||
nsContentUtils::AddScriptRunner(new TextChangeEvent(this, start,
|
||||
start + mPreAttrChangeLength, start + postAttrChangeLength));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
nsIMEStateManager::IsEditable(nsINode* node)
|
||||
{
|
||||
|
|
|
@ -43,7 +43,7 @@ MOCHITEST_FILES = test_bug1682.html \
|
|||
test_viewport.html \
|
||||
test_documentAll.html \
|
||||
test_document-element-inserted.html \
|
||||
test_bug445004.html \
|
||||
$(filter disabled-temporarily--bug-559932, test_bug445004.html) \
|
||||
bug445004-inner.js \
|
||||
bug445004-outer-rel.html \
|
||||
bug445004-outer-abs.html \
|
||||
|
|
|
@ -1087,7 +1087,7 @@ nsSVGSVGElement::GetCurrentViewElement() const
|
|||
nsIDocument* doc = GetCurrentDoc();
|
||||
if (doc) {
|
||||
Element *element = doc->GetElementById(*mCurrentViewID);
|
||||
if (element && element->Tag() == nsGkAtoms::view) {
|
||||
if (element && element->IsSVG(nsGkAtoms::view)) {
|
||||
return static_cast<nsSVGViewElement*>(element);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,6 +44,11 @@ XPCOMUtils.defineLazyGetter(this, "msgmgr", function() {
|
|||
.getService(Ci.nsISystemMessagesInternal);
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "updateSvc", function() {
|
||||
return Cc["@mozilla.org/offlinecacheupdate-service;1"]
|
||||
.getService(Ci.nsIOfflineCacheUpdateService);
|
||||
});
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
const DIRECTORY_NAME = "webappsDir";
|
||||
#elifdef ANDROID
|
||||
|
@ -931,8 +936,6 @@ this.DOMApplicationRegistry = {
|
|||
// if the manifest has an appcache_path property, use it to populate the appcache
|
||||
if (aManifest.appcache_path) {
|
||||
let appcacheURI = Services.io.newURI(aManifest.fullAppcachePath(), null, null);
|
||||
let updateService = Cc["@mozilla.org/offlinecacheupdate-service;1"]
|
||||
.getService(Ci.nsIOfflineCacheUpdateService);
|
||||
let docURI = Services.io.newURI(aManifest.fullLaunchPath(), null, null);
|
||||
// We determine the app's 'installState' according to its previous
|
||||
// state. Cancelled download should remain as 'pending'. Successfully
|
||||
|
@ -943,8 +946,9 @@ this.DOMApplicationRegistry = {
|
|||
// We set the 'downloading' flag right before starting the app
|
||||
// download/update.
|
||||
aApp.downloading = true;
|
||||
let cacheUpdate = aProfileDir ? updateService.scheduleCustomProfileUpdate(appcacheURI, docURI, aProfileDir)
|
||||
: updateService.scheduleAppUpdate(appcacheURI, docURI, aApp.localId, false);
|
||||
let cacheUpdate = aProfileDir
|
||||
? updateSvc.scheduleCustomProfileUpdate(appcacheURI, docURI, aProfileDir)
|
||||
: updateSvc.scheduleAppUpdate(appcacheURI, docURI, aApp.localId, false);
|
||||
cacheUpdate.addObserver(new AppcacheObserver(aApp), false);
|
||||
if (aOfflineCacheObserver) {
|
||||
cacheUpdate.addObserver(aOfflineCacheObserver, false);
|
||||
|
@ -1038,9 +1042,23 @@ this.DOMApplicationRegistry = {
|
|||
|
||||
this._saveApps(function() {
|
||||
aData.app = app;
|
||||
aData.event = manifest.appcache_path ? "downloadavailable"
|
||||
: "downloadapplied";
|
||||
aMm.sendAsyncMessage("Webapps:CheckForUpdate:Return:OK", aData);
|
||||
if (!manifest.appcache_path) {
|
||||
aData.event = "downloadapplied";
|
||||
aMm.sendAsyncMessage("Webapps:CheckForUpdate:Return:OK", aData);
|
||||
} else {
|
||||
// Check if the appcache is updatable, and send "downloadavailable" or
|
||||
// "downloadapplied".
|
||||
let updateObserver = {
|
||||
observe: function(aSubject, aTopic, aData) {
|
||||
aData.event =
|
||||
aTopic == "offline-cache-update-available" ? "downloadavailable"
|
||||
: "downloadapplied";
|
||||
aMm.sendAsyncMessage("Webapps:CheckForUpdate:Return:OK", aData);
|
||||
}
|
||||
}
|
||||
updateSvc.checkForUpdate(Services.io.newURI(aData.manifestURL, null, null),
|
||||
app.localId, false, updateObserver);
|
||||
}
|
||||
});
|
||||
|
||||
// Update the permissions for this app.
|
||||
|
|
|
@ -10,14 +10,20 @@ relativesrcdir = @relativesrcdir@
|
|||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
# TODO: When bug 814718 and bug 814721 are fixed, add the following files:
|
||||
# test_getUserMedia_basicVideo.html
|
||||
# test_getUserMedia_basicAudio.thml
|
||||
# test_getUserMedia_basicVideoAudio.html
|
||||
# mediaStreamPlayback.js
|
||||
MOCHITEST_FILES = \
|
||||
test_getUserMedia_exceptions.html \
|
||||
head.js \
|
||||
$(NULL)
|
||||
|
||||
# The following tests are leaking and cannot be run by default yet
|
||||
ifdef MOZ_WEBRTC_LEAKING_TESTS
|
||||
MOCHITEST_FILES += \
|
||||
# Bug 814718 and bug 818466 prevent us from running the following tests:
|
||||
# test_getUserMedia_basicVideo.html \
|
||||
# test_getUserMedia_basicAudio.html \
|
||||
# test_getUserMedia_basicVideoAudio.html \
|
||||
# mediaStreamPlayback.js \
|
||||
$(NULL)
|
||||
endif
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
|
|
@ -1417,6 +1417,17 @@ RadioInterfaceLayer.prototype = {
|
|||
timestamp,
|
||||
true);
|
||||
|
||||
gSystemMessenger.broadcastMessage("sms-sent",
|
||||
{id: id,
|
||||
delivery: DOM_SMS_DELIVERY_SENT,
|
||||
deliveryStatus: RIL.GECKO_SMS_DELIVERY_STATUS_PENDING,
|
||||
sender: message.sender || null,
|
||||
receiver: options.number,
|
||||
body: options.fullBody,
|
||||
messageClass: messageClass,
|
||||
timestamp: timestamp,
|
||||
read: true});
|
||||
|
||||
if (!options.requestStatusReport) {
|
||||
// No more used if STATUS-REPORT not requested.
|
||||
delete this._sentSmsEnvelopes[message.envelopeId];
|
||||
|
|
|
@ -135,9 +135,11 @@ bool ImageContainerChild::CopyDataIntoSharedImage(Image* src, SharedImage* dest)
|
|||
|
||||
ShmemYCbCrImage shmemImage(yuv.data(), yuv.offset());
|
||||
|
||||
MOZ_ASSERT(data->mCbSkip == data->mCrSkip);
|
||||
if (!shmemImage.CopyData(data->mYChannel, data->mCbChannel, data->mCrChannel,
|
||||
data->mYSize, data->mYStride,
|
||||
data->mCbCrSize, data->mCbCrStride)) {
|
||||
data->mCbCrSize, data->mCbCrStride,
|
||||
data->mYSkip, data->mCbSkip)) {
|
||||
NS_WARNING("Failed to copy image data!");
|
||||
return false;
|
||||
}
|
||||
|
@ -515,10 +517,11 @@ public:
|
|||
mSize = mData.mPicSize;
|
||||
|
||||
ShmemYCbCrImage shmImg(mShmem);
|
||||
|
||||
MOZ_ASSERT(aData.mCbSkip == aData.mCrSkip);
|
||||
if (!shmImg.CopyData(aData.mYChannel, aData.mCbChannel, aData.mCrChannel,
|
||||
aData.mYSize, aData.mYStride,
|
||||
aData.mCbCrSize, aData.mCbCrStride)) {
|
||||
aData.mCbCrSize, aData.mCbCrStride,
|
||||
aData.mYSkip, aData.mCbSkip)) {
|
||||
NS_WARNING("Failed to copy image data!");
|
||||
}
|
||||
mData.mYChannel = shmImg.GetYData();
|
||||
|
|
|
@ -150,25 +150,54 @@ bool ShmemYCbCrImage::IsValid()
|
|||
return true;
|
||||
}
|
||||
|
||||
bool ShmemYCbCrImage::CopyData(uint8_t* aYData, uint8_t* aCbData, uint8_t* aCrData,
|
||||
static void CopyLineWithSkip(const uint8_t* src, uint8_t* dst, uint32_t len, uint32_t skip) {
|
||||
for (uint32_t i = 0; i < len; ++i) {
|
||||
*dst = *src;
|
||||
src += 1 + skip;
|
||||
++dst;
|
||||
}
|
||||
}
|
||||
|
||||
bool ShmemYCbCrImage::CopyData(const uint8_t* aYData,
|
||||
const uint8_t* aCbData, const uint8_t* aCrData,
|
||||
gfxIntSize aYSize, uint32_t aYStride,
|
||||
gfxIntSize aCbCrSize, uint32_t aCbCrStride)
|
||||
gfxIntSize aCbCrSize, uint32_t aCbCrStride,
|
||||
uint32_t aYSkip, uint32_t aCbCrSkip)
|
||||
{
|
||||
if (!IsValid() || GetYSize() != aYSize || GetCbCrSize() != aCbCrSize) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < aYSize.height; i++) {
|
||||
memcpy(GetYData() + i * GetYStride(),
|
||||
aYData + i * aYStride,
|
||||
aYSize.width);
|
||||
for (int i = 0; i < aYSize.height; ++i) {
|
||||
if (aYSkip == 0) {
|
||||
// fast path
|
||||
memcpy(GetYData() + i * GetYStride(),
|
||||
aYData + i * aYStride,
|
||||
aYSize.width);
|
||||
} else {
|
||||
// slower path
|
||||
CopyLineWithSkip(aYData + i * aYStride,
|
||||
GetYData() + i * GetYStride(),
|
||||
aYSize.width, aYSkip);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < aCbCrSize.height; i++) {
|
||||
memcpy(GetCbData() + i * GetCbCrStride(),
|
||||
aCbData + i * aCbCrStride,
|
||||
aCbCrSize.width);
|
||||
memcpy(GetCrData() + i * GetCbCrStride(),
|
||||
aCrData + i * aCbCrStride,
|
||||
aCbCrSize.width);
|
||||
for (int i = 0; i < aCbCrSize.height; ++i) {
|
||||
if (aCbCrSkip == 0) {
|
||||
// fast path
|
||||
memcpy(GetCbData() + i * GetCbCrStride(),
|
||||
aCbData + i * aCbCrStride,
|
||||
aCbCrSize.width);
|
||||
memcpy(GetCrData() + i * GetCbCrStride(),
|
||||
aCrData + i * aCbCrStride,
|
||||
aCbCrSize.width);
|
||||
} else {
|
||||
// slower path
|
||||
CopyLineWithSkip(aCbData + i * aCbCrStride,
|
||||
GetCbData() + i * GetCbCrStride(),
|
||||
aCbCrSize.width, aCbCrSkip);
|
||||
CopyLineWithSkip(aCrData + i * aCbCrStride,
|
||||
GetCrData() + i * GetCbCrStride(),
|
||||
aCbCrSize.width, aCbCrSkip);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -96,9 +96,11 @@ public:
|
|||
/**
|
||||
* Copies the data passed in parameter into the shmem.
|
||||
*/
|
||||
bool CopyData(uint8_t* aYData, uint8_t* aCbData, uint8_t* aCrData,
|
||||
bool CopyData(const uint8_t* aYData,
|
||||
const uint8_t* aCbData, const uint8_t* aCrData,
|
||||
gfxIntSize aYSize, uint32_t aYStride,
|
||||
gfxIntSize aCbCrSize, uint32_t aCbCrStride);
|
||||
gfxIntSize aCbCrSize, uint32_t aCbCrStride,
|
||||
uint32_t aYSkip, uint32_t aCbCrSkip);
|
||||
|
||||
private:
|
||||
bool Open(Shmem& aShmem, size_t aOffset = 0);
|
||||
|
|
|
@ -1183,7 +1183,7 @@ SequentialCompileContext::compile(IonBuilder *builder, MIRGraph *graph,
|
|||
// incremental read barriers.
|
||||
if (js_IonOptions.parallelCompilation &&
|
||||
OffThreadCompilationAvailable(cx) &&
|
||||
!IsIncrementalGCInProgress(cx->runtime))
|
||||
cx->runtime->gcIncrementalState == gc::NO_INCREMENTAL)
|
||||
{
|
||||
builder->script()->ion = ION_COMPILING_SCRIPT;
|
||||
|
||||
|
|
|
@ -107,7 +107,7 @@ SVGViewFrame::AttributeChanged(int32_t aNameSpaceID,
|
|||
aAttribute == nsGkAtoms::viewTarget)) {
|
||||
|
||||
nsSVGOuterSVGFrame *outerSVGFrame = nsSVGUtils::GetOuterSVGFrame(this);
|
||||
NS_ASSERTION(outerSVGFrame->GetContent()->Tag() == nsGkAtoms::svg,
|
||||
NS_ASSERTION(outerSVGFrame->GetContent()->IsSVG(nsGkAtoms::svg),
|
||||
"Expecting an <svg> element");
|
||||
|
||||
nsSVGSVGElement* svgElement =
|
||||
|
|
|
@ -364,13 +364,13 @@ public class AwesomeBar extends GeckoActivity {
|
|||
private void cancelAndFinish() {
|
||||
setResult(Activity.RESULT_CANCELED);
|
||||
finish();
|
||||
overridePendingTransition(0, 0);
|
||||
overridePendingTransition(R.anim.awesomebar_hold_still, R.anim.awesomebar_fade_out);
|
||||
}
|
||||
|
||||
private void finishWithResult(Intent intent) {
|
||||
setResult(Activity.RESULT_OK, intent);
|
||||
finish();
|
||||
overridePendingTransition(0, 0);
|
||||
overridePendingTransition(R.anim.awesomebar_hold_still, R.anim.awesomebar_fade_out);
|
||||
}
|
||||
|
||||
private void openUrlAndFinish(String url) {
|
||||
|
|
|
@ -12,6 +12,7 @@ import android.text.Spannable;
|
|||
import android.text.SpannableString;
|
||||
import android.text.SpannableStringBuilder;
|
||||
import android.text.Selection;
|
||||
import android.text.TextUtils;
|
||||
import android.text.style.UnderlineSpan;
|
||||
import android.text.style.ForegroundColorSpan;
|
||||
import android.text.style.BackgroundColorSpan;
|
||||
|
@ -71,6 +72,7 @@ final class GeckoEditable
|
|||
private InputFilter[] mFilters;
|
||||
|
||||
private final SpannableStringBuilder mText;
|
||||
private final SpannableStringBuilder mChangedText;
|
||||
private final Editable mProxy;
|
||||
private GeckoEditableListener mListener;
|
||||
private final ActionQueue mActionQueue;
|
||||
|
@ -244,6 +246,7 @@ final class GeckoEditable
|
|||
mUpdateGecko = true;
|
||||
|
||||
mText = new SpannableStringBuilder();
|
||||
mChangedText = new SpannableStringBuilder();
|
||||
|
||||
final Class<?>[] PROXY_INTERFACES = { Editable.class };
|
||||
mProxy = (Editable)Proxy.newProxyInstance(
|
||||
|
@ -531,6 +534,15 @@ final class GeckoEditable
|
|||
}
|
||||
final int seqnoWhenPosted = ++mGeckoUpdateSeqno;
|
||||
|
||||
/* An event (keypress, etc.) has potentially changed the selection,
|
||||
synchronize the selection here. There is not a race with the UI thread
|
||||
because the UI thread should be blocked on the event action */
|
||||
if (!mActionQueue.isEmpty() &&
|
||||
mActionQueue.peek().mType == Action.TYPE_EVENT) {
|
||||
Selection.setSelection(mText, start, end);
|
||||
return;
|
||||
}
|
||||
|
||||
geckoPostToUI(new Runnable() {
|
||||
public void run() {
|
||||
mActionQueue.syncWithGecko();
|
||||
|
@ -551,6 +563,13 @@ final class GeckoEditable
|
|||
});
|
||||
}
|
||||
|
||||
private void geckoReplaceText(int start, int oldEnd, CharSequence newText) {
|
||||
// Don't use replace() because Gingerbread has a bug where if the replaced text
|
||||
// has the same spans as the original text, the spans will end up being deleted
|
||||
mText.delete(start, oldEnd);
|
||||
mText.insert(start, newText);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextChange(final String text, final int start,
|
||||
final int unboundedOldEnd, final int unboundedNewEnd) {
|
||||
|
@ -565,24 +584,61 @@ final class GeckoEditable
|
|||
number to denote "end of the text". Fix that here */
|
||||
final int oldEnd = unboundedOldEnd > mText.length() ? mText.length() : unboundedOldEnd;
|
||||
// new end should always match text
|
||||
if (unboundedNewEnd < (start + text.length())) {
|
||||
if (start != 0 && unboundedNewEnd != (start + text.length())) {
|
||||
throw new IllegalArgumentException("newEnd does not match text");
|
||||
}
|
||||
final int newEnd = start + text.length();
|
||||
|
||||
/* Text changes affect the selection as well, and we may not receive another selection
|
||||
update as a result of selection notification masking on the Gecko side; therefore,
|
||||
in order to prevent previous stale selection notifications from occurring, we need
|
||||
to increment the seqno here as well */
|
||||
++mGeckoUpdateSeqno;
|
||||
|
||||
mChangedText.clearSpans();
|
||||
mChangedText.replace(0, mChangedText.length(), text);
|
||||
// Preserve as many spans as possible
|
||||
TextUtils.copySpansFrom(mText, start, Math.min(oldEnd, newEnd),
|
||||
Object.class, mChangedText, 0);
|
||||
|
||||
if (!mActionQueue.isEmpty()) {
|
||||
final Action action = mActionQueue.peek();
|
||||
if (action.mType == Action.TYPE_REPLACE_TEXT &&
|
||||
action.mStart == start &&
|
||||
text.equals(action.mSequence.toString())) {
|
||||
// Replace using saved text to preserve spans
|
||||
mText.replace(start, oldEnd, action.mSequence,
|
||||
0, action.mSequence.length());
|
||||
start <= action.mStart &&
|
||||
action.mStart + action.mSequence.length() <= newEnd) {
|
||||
|
||||
// actionNewEnd is the new end of the original replacement action
|
||||
final int actionNewEnd = action.mStart + action.mSequence.length();
|
||||
int selStart = Selection.getSelectionStart(mText);
|
||||
int selEnd = Selection.getSelectionEnd(mText);
|
||||
|
||||
// Replace old spans with new spans
|
||||
mChangedText.replace(action.mStart - start, actionNewEnd - start,
|
||||
action.mSequence);
|
||||
geckoReplaceText(start, oldEnd, mChangedText);
|
||||
|
||||
// delete/insert above might have moved our selection to somewhere else
|
||||
// this happens when the Gecko text change covers a larger range than
|
||||
// the original replacement action. Fix selection here
|
||||
if (selStart >= start && selStart <= oldEnd) {
|
||||
selStart = selStart < action.mStart ? selStart :
|
||||
selStart < action.mEnd ? actionNewEnd :
|
||||
selStart + actionNewEnd - action.mEnd;
|
||||
mText.setSpan(Selection.SELECTION_START, selStart, selStart,
|
||||
Spanned.SPAN_POINT_POINT);
|
||||
}
|
||||
if (selEnd >= start && selEnd <= oldEnd) {
|
||||
selEnd = selEnd < action.mStart ? selEnd :
|
||||
selEnd < action.mEnd ? actionNewEnd :
|
||||
selEnd + actionNewEnd - action.mEnd;
|
||||
mText.setSpan(Selection.SELECTION_END, selEnd, selEnd,
|
||||
Spanned.SPAN_POINT_POINT);
|
||||
}
|
||||
} else {
|
||||
mText.replace(start, oldEnd, text, 0, text.length());
|
||||
geckoReplaceText(start, oldEnd, mChangedText);
|
||||
}
|
||||
} else {
|
||||
mText.replace(start, oldEnd, text, 0, text.length());
|
||||
geckoReplaceText(start, oldEnd, mChangedText);
|
||||
}
|
||||
geckoPostToUI(new Runnable() {
|
||||
public void run() {
|
||||
|
|
|
@ -29,8 +29,6 @@ import android.view.inputmethod.InputMethodManager;
|
|||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
class GeckoInputConnection
|
||||
extends BaseInputConnection
|
||||
|
@ -41,8 +39,6 @@ class GeckoInputConnection
|
|||
|
||||
private static final int INLINE_IME_MIN_DISPLAY_SIZE = 480;
|
||||
|
||||
private static final Timer mIMETimer = new Timer("GeckoInputConnection Timer");
|
||||
|
||||
private static int mIMEState;
|
||||
private static String mIMETypeHint = "";
|
||||
private static String mIMEModeHint = "";
|
||||
|
@ -172,12 +168,6 @@ class GeckoInputConnection
|
|||
return extract;
|
||||
}
|
||||
|
||||
private static void postToUiThread(Runnable runnable) {
|
||||
// postToUiThread() is called by the Gecko and TimerTask threads.
|
||||
// The UI thread does not need to post Runnables to itself.
|
||||
GeckoApp.mAppContext.mMainHandler.post(runnable);
|
||||
}
|
||||
|
||||
private static View getView() {
|
||||
return GeckoApp.mAppContext.getLayerView();
|
||||
}
|
||||
|
@ -191,6 +181,35 @@ class GeckoInputConnection
|
|||
return InputMethods.getInputMethodManager(context);
|
||||
}
|
||||
|
||||
private static void showSoftInput() {
|
||||
final InputMethodManager imm = getInputMethodManager();
|
||||
if (imm != null) {
|
||||
final View v = getView();
|
||||
imm.showSoftInput(v, 0);
|
||||
}
|
||||
}
|
||||
|
||||
private static void hideSoftInput() {
|
||||
final InputMethodManager imm = getInputMethodManager();
|
||||
if (imm != null) {
|
||||
final View v = getView();
|
||||
imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
private void restartInput() {
|
||||
final InputMethodManager imm = getInputMethodManager();
|
||||
if (imm != null) {
|
||||
final View v = getView();
|
||||
final Editable editable = getEditable();
|
||||
// Fake a selection change, so that when we restart the input,
|
||||
// the IME will make sure that any old composition string is cleared
|
||||
notifySelectionChange(Selection.getSelectionStart(editable),
|
||||
Selection.getSelectionEnd(editable));
|
||||
imm.restartInput(v);
|
||||
}
|
||||
}
|
||||
|
||||
public void onTextChange(String text, int start, int oldEnd, int newEnd) {
|
||||
|
||||
if (mUpdateRequest == null) {
|
||||
|
@ -251,17 +270,6 @@ class GeckoInputConnection
|
|||
getComposingSpanEnd(editable));
|
||||
}
|
||||
|
||||
protected void resetCompositionState() {
|
||||
if (mBatchEditCount > 0) {
|
||||
Log.d(LOGTAG, "resetCompositionState: resetting mBatchEditCount "
|
||||
+ mBatchEditCount + " -> 0");
|
||||
mBatchEditCount = 0;
|
||||
}
|
||||
|
||||
removeComposingSpans(getEditable());
|
||||
mUpdateRequest = null;
|
||||
}
|
||||
|
||||
public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
|
||||
outAttrs.inputType = InputType.TYPE_CLASS_TEXT;
|
||||
outAttrs.imeOptions = EditorInfo.IME_ACTION_NONE;
|
||||
|
@ -342,7 +350,9 @@ class GeckoInputConnection
|
|||
}
|
||||
}
|
||||
|
||||
resetCompositionState();
|
||||
// We don't know the selection
|
||||
outAttrs.initialSelStart = -1;
|
||||
outAttrs.initialSelEnd = -1;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -450,41 +460,23 @@ class GeckoInputConnection
|
|||
}
|
||||
|
||||
public void notifyIME(final int type, final int state) {
|
||||
|
||||
final View v = getView();
|
||||
if (v == null)
|
||||
return;
|
||||
|
||||
switch (type) {
|
||||
case NOTIFY_IME_RESETINPUTSTATE:
|
||||
if (DEBUG) Log.d(LOGTAG, ". . . notifyIME: reset");
|
||||
|
||||
resetCompositionState();
|
||||
|
||||
// Don't use IMEStateUpdater for reset.
|
||||
// Because IME may not work showSoftInput()
|
||||
// after calling restartInput() immediately.
|
||||
// So we have to call showSoftInput() delay.
|
||||
InputMethodManager imm = getInputMethodManager();
|
||||
if (imm == null) {
|
||||
// no way to reset IME status directly
|
||||
IMEStateUpdater.resetIME();
|
||||
} else {
|
||||
imm.restartInput(v);
|
||||
}
|
||||
|
||||
// keep current enabled state
|
||||
IMEStateUpdater.enableIME();
|
||||
break;
|
||||
|
||||
case NOTIFY_IME_CANCELCOMPOSITION:
|
||||
if (DEBUG) Log.d(LOGTAG, ". . . notifyIME: cancel");
|
||||
removeComposingSpans(getEditable());
|
||||
// Set composition to empty and end composition
|
||||
setComposingText("", 0);
|
||||
// Fall through
|
||||
|
||||
case NOTIFY_IME_RESETINPUTSTATE:
|
||||
// Commit and end composition
|
||||
finishComposingText();
|
||||
restartInput();
|
||||
break;
|
||||
|
||||
case NOTIFY_IME_FOCUSCHANGE:
|
||||
if (DEBUG) Log.d(LOGTAG, ". . . notifyIME: focus");
|
||||
IMEStateUpdater.resetIME();
|
||||
// Showing/hiding vkb is done in notifyIMEEnabled
|
||||
mBatchEditCount = 0;
|
||||
mUpdateRequest = null;
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -497,82 +489,34 @@ class GeckoInputConnection
|
|||
|
||||
public void notifyIMEEnabled(final int state, final String typeHint,
|
||||
final String modeHint, final String actionHint) {
|
||||
// For some input type we will use a widget to display the ui, for those we must not
|
||||
// For some input type we will use a widget to display the ui, for those we must not
|
||||
// display the ime. We can display a widget for date and time types and, if the sdk version
|
||||
// is greater than 11, for datetime/month/week as well.
|
||||
if (typeHint.equals("date") || typeHint.equals("time") ||
|
||||
(Build.VERSION.SDK_INT > 10 &&
|
||||
(typeHint.equals("datetime") || typeHint.equals("month") ||
|
||||
typeHint.equals("week") || typeHint.equals("datetime-local")))) {
|
||||
mIMEState = IME_STATE_DISABLED;
|
||||
return;
|
||||
}
|
||||
|
||||
final View v = getView();
|
||||
if (v == null)
|
||||
return;
|
||||
|
||||
/* When IME is 'disabled', IME processing is disabled.
|
||||
In addition, the IME UI is hidden */
|
||||
mIMEState = state;
|
||||
mIMETypeHint = (typeHint == null) ? "" : typeHint;
|
||||
mIMEModeHint = (modeHint == null) ? "" : modeHint;
|
||||
mIMEActionHint = (actionHint == null) ? "" : actionHint;
|
||||
IMEStateUpdater.enableIME();
|
||||
}
|
||||
|
||||
/* Delay updating IME states (see bug 573800) */
|
||||
private static final class IMEStateUpdater extends TimerTask {
|
||||
private static IMEStateUpdater instance;
|
||||
private boolean mEnable;
|
||||
private boolean mReset;
|
||||
|
||||
private static IMEStateUpdater getInstance() {
|
||||
if (instance == null) {
|
||||
instance = new IMEStateUpdater();
|
||||
mIMETimer.schedule(instance, 200);
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
public static synchronized void enableIME() {
|
||||
getInstance().mEnable = true;
|
||||
}
|
||||
|
||||
public static synchronized void resetIME() {
|
||||
getInstance().mReset = true;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
if (DEBUG) Log.d(LOGTAG, "IME: IMEStateUpdater.run()");
|
||||
synchronized (IMEStateUpdater.class) {
|
||||
instance = null;
|
||||
}
|
||||
|
||||
// TimerTask.run() is running on a random background thread, so post to UI thread.
|
||||
postToUiThread(new Runnable() {
|
||||
public void run() {
|
||||
final View v = getView();
|
||||
if (v == null)
|
||||
return;
|
||||
|
||||
final InputMethodManager imm = getInputMethodManager();
|
||||
if (imm == null)
|
||||
return;
|
||||
|
||||
if (mReset)
|
||||
imm.restartInput(v);
|
||||
|
||||
if (!mEnable)
|
||||
return;
|
||||
|
||||
if (mIMEState != IME_STATE_DISABLED) {
|
||||
imm.showSoftInput(v, 0);
|
||||
} else if (imm.isActive(v)) {
|
||||
imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
|
||||
}
|
||||
restartInput();
|
||||
GeckoApp.mAppContext.mMainHandler.postDelayed(new Runnable() {
|
||||
public void run() {
|
||||
if (mIMEState == IME_STATE_DISABLED) {
|
||||
hideSoftInput();
|
||||
} else {
|
||||
showSoftInput();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}, 200); // Delay 200ms to prevent repeated IME showing/hiding
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -486,6 +486,7 @@ RES_XML = \
|
|||
|
||||
RES_ANIM = \
|
||||
res/anim/awesomebar_fade_in.xml \
|
||||
res/anim/awesomebar_fade_out.xml \
|
||||
res/anim/awesomebar_hold_still.xml \
|
||||
res/anim/grow_fade_in.xml \
|
||||
res/anim/grow_fade_in_center.xml \
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
|
||||
<set xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<alpha android:interpolator="@android:anim/accelerate_interpolator"
|
||||
android:fromAlpha="1.0"
|
||||
android:toAlpha="0.0"
|
||||
android:duration="200"/>
|
||||
|
||||
</set>
|
|
@ -120,6 +120,7 @@
|
|||
"content/xul/content/test/test_bug486990.xul": "TIMED_OUT",
|
||||
"docshell/test/navigation/test_bug13871.html": "RANDOM",
|
||||
"docshell/test/navigation/test_bug430723.html": "TIMED_OUT",
|
||||
"docshell/test/navigation/test_popup-navigates-children.html": "bug 783589",
|
||||
"docshell/test/navigation/test_sessionhistory.html": "RANDOM",
|
||||
"docshell/test/test_bug344861.html": "",
|
||||
"docshell/test/test_bug94514.html": "TIMED_OUT",
|
||||
|
@ -127,6 +128,7 @@
|
|||
"docshell/test/test_bug598895.html": "",
|
||||
"docshell/test/test_bug637644.html": "",
|
||||
"docshell/test/test_bug668513.html": "RANDOM",
|
||||
"docshell/test/test_framedhistoryframes.html": "bug 784321",
|
||||
"dom/browser-element/mochitest/test_browserElement_oop_SecurityChange.html": "TIMED_OUT, bug 766586",
|
||||
"dom/browser-element/mochitest/test_browserElement_inproc_AppFramePermission.html": "",
|
||||
"dom/browser-element/mochitest/test_browserElement_inproc_AppWindowNamespace.html": "TIMED_OUT, bug 783509",
|
||||
|
|
Двоичный файл не отображается.
До Ширина: | Высота: | Размер: 544 B |
|
@ -6,7 +6,6 @@ toolkit.jar:
|
|||
% skin mozapps classic/1.0 %skin/classic/mozapps/
|
||||
skin/classic/mozapps/downloads/buttons.png (downloads/buttons.png)
|
||||
skin/classic/mozapps/downloads/downloadIcon.png (downloads/downloadIcon.png)
|
||||
skin/classic/mozapps/downloads/downloadStatusIcon.png (downloads/downloadStatusIcon.png)
|
||||
* skin/classic/mozapps/downloads/downloads.css (downloads/downloads.css)
|
||||
skin/classic/mozapps/downloads/unknownContentType.css (downloads/unknownContentType.css)
|
||||
skin/classic/mozapps/extensions/category-search.png (extensions/category-search.png)
|
||||
|
|
|
@ -665,6 +665,13 @@ AndroidGeckoEvent::Init(int aType)
|
|||
mType = aType;
|
||||
}
|
||||
|
||||
void
|
||||
AndroidGeckoEvent::Init(int aType, int aAction)
|
||||
{
|
||||
mType = aType;
|
||||
mAction = aAction;
|
||||
}
|
||||
|
||||
void
|
||||
AndroidGeckoEvent::Init(int x1, int y1, int x2, int y2)
|
||||
{
|
||||
|
|
|
@ -633,6 +633,9 @@ public:
|
|||
AndroidGeckoEvent(int aType) {
|
||||
Init(aType);
|
||||
}
|
||||
AndroidGeckoEvent(int aType, int aAction) {
|
||||
Init(aType, aAction);
|
||||
}
|
||||
AndroidGeckoEvent(int x1, int y1, int x2, int y2) {
|
||||
Init(x1, y1, x2, y2);
|
||||
}
|
||||
|
@ -648,6 +651,7 @@ public:
|
|||
|
||||
void Init(JNIEnv *jenv, jobject jobj);
|
||||
void Init(int aType);
|
||||
void Init(int aType, int aAction);
|
||||
void Init(int x1, int y1, int x2, int y2);
|
||||
void Init(int aType, const nsIntRect &aRect);
|
||||
void Init(AndroidGeckoEvent *aResizeEvent);
|
||||
|
@ -816,7 +820,8 @@ public:
|
|||
IME_ADD_COMPOSITION_RANGE = 3,
|
||||
IME_UPDATE_COMPOSITION = 4,
|
||||
IME_REMOVE_COMPOSITION = 5,
|
||||
IME_ACKNOWLEDGE_FOCUS = 6
|
||||
IME_ACKNOWLEDGE_FOCUS = 6,
|
||||
IME_FLUSH_CHANGES = 7
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -1763,8 +1763,14 @@ nsWindow::OnIMEEvent(AndroidGeckoEvent *ae)
|
|||
return;
|
||||
}
|
||||
switch (ae->Action()) {
|
||||
case AndroidGeckoEvent::IME_FLUSH_CHANGES:
|
||||
{
|
||||
FlushIMEChanges();
|
||||
}
|
||||
break;
|
||||
case AndroidGeckoEvent::IME_SYNCHRONIZE:
|
||||
{
|
||||
FlushIMEChanges();
|
||||
AndroidBridge::NotifyIME(AndroidBridge::NOTIFY_IME_REPLY_EVENT, 0);
|
||||
}
|
||||
break;
|
||||
|
@ -1807,6 +1813,7 @@ nsWindow::OnIMEEvent(AndroidGeckoEvent *ae)
|
|||
event.data = ae->Characters();
|
||||
DispatchEvent(&event);
|
||||
}
|
||||
FlushIMEChanges();
|
||||
AndroidBridge::NotifyIME(AndroidBridge::NOTIFY_IME_REPLY_EVENT, 0);
|
||||
}
|
||||
break;
|
||||
|
@ -2046,13 +2053,18 @@ nsWindow::OnIMEFocusChange(bool aFocus)
|
|||
ALOGIME("IME: OnIMEFocusChange: f=%d", aFocus);
|
||||
|
||||
if (aFocus) {
|
||||
mIMETextChanges.Clear();
|
||||
mIMESelectionChange = IMEChange();
|
||||
// OnIMETextChange also notifies selection
|
||||
OnIMETextChange(0, INT32_MAX, INT32_MAX);
|
||||
OnIMESelectionChange();
|
||||
FlushIMEChanges();
|
||||
} else {
|
||||
// Mask events because we lost focus. On the next focus event, Gecko will notify
|
||||
// Java, and Java will send an acknowledge focus event back to Gecko. That is
|
||||
// where we unmask event handling
|
||||
mIMEMaskEventsCount++;
|
||||
mIMEComposing = false;
|
||||
mIMEComposingText.Truncate();
|
||||
}
|
||||
|
||||
AndroidBridge::NotifyIME(AndroidBridge::NOTIFY_IME_FOCUSCHANGE,
|
||||
|
@ -2061,6 +2073,51 @@ nsWindow::OnIMEFocusChange(bool aFocus)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsWindow::PostFlushIMEChanges()
|
||||
{
|
||||
if (!mIMETextChanges.IsEmpty() || !mIMESelectionChange.IsEmpty()) {
|
||||
// Already posted
|
||||
return;
|
||||
}
|
||||
AndroidGeckoEvent *event = new AndroidGeckoEvent(
|
||||
AndroidGeckoEvent::IME_EVENT, AndroidGeckoEvent::IME_FLUSH_CHANGES);
|
||||
nsAppShell::gAppShell->PostEvent(event);
|
||||
}
|
||||
|
||||
void
|
||||
nsWindow::FlushIMEChanges()
|
||||
{
|
||||
nsRefPtr<nsWindow> kungFuDeathGrip(this);
|
||||
for (uint32_t i = 0; i < mIMETextChanges.Length(); i++) {
|
||||
IMEChange &change = mIMETextChanges[i];
|
||||
MOZ_ASSERT(change.IsTextChange());
|
||||
|
||||
nsQueryContentEvent event(true, NS_QUERY_TEXT_CONTENT, this);
|
||||
InitEvent(event, nullptr);
|
||||
event.InitForQueryTextContent(change.mStart,
|
||||
change.mNewEnd - change.mStart);
|
||||
DispatchEvent(&event);
|
||||
if (!event.mSucceeded)
|
||||
return;
|
||||
|
||||
AndroidBridge::NotifyIMEChange(event.mReply.mString.get(),
|
||||
event.mReply.mString.Length(),
|
||||
change.mStart,
|
||||
change.mOldEnd,
|
||||
change.mNewEnd);
|
||||
}
|
||||
mIMETextChanges.Clear();
|
||||
|
||||
if (!mIMESelectionChange.IsEmpty()) {
|
||||
MOZ_ASSERT(!mIMESelectionChange.IsTextChange());
|
||||
AndroidBridge::NotifyIMEChange(nullptr, 0,
|
||||
mIMESelectionChange.mStart,
|
||||
mIMESelectionChange.mOldEnd, -1);
|
||||
mIMESelectionChange = IMEChange();
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsWindow::OnIMETextChange(uint32_t aStart, uint32_t aOldEnd, uint32_t aNewEnd)
|
||||
{
|
||||
|
@ -2070,21 +2127,67 @@ nsWindow::OnIMETextChange(uint32_t aStart, uint32_t aOldEnd, uint32_t aNewEnd)
|
|||
ALOGIME("IME: OnIMETextChange: s=%d, oe=%d, ne=%d",
|
||||
aStart, aOldEnd, aNewEnd);
|
||||
|
||||
nsRefPtr<nsWindow> kungFuDeathGrip(this);
|
||||
nsQueryContentEvent event(true, NS_QUERY_TEXT_CONTENT, this);
|
||||
InitEvent(event, nullptr);
|
||||
event.InitForQueryTextContent(aStart, aNewEnd - aStart);
|
||||
|
||||
DispatchEvent(&event);
|
||||
if (!event.mSucceeded)
|
||||
return NS_OK;
|
||||
|
||||
AndroidBridge::NotifyIMEChange(event.mReply.mString.get(),
|
||||
event.mReply.mString.Length(),
|
||||
aStart, aOldEnd, aNewEnd);
|
||||
|
||||
/* Make sure Java's selection is up-to-date */
|
||||
mIMESelectionChange = IMEChange();
|
||||
OnIMESelectionChange();
|
||||
PostFlushIMEChanges();
|
||||
|
||||
mIMETextChanges.AppendElement(IMEChange(aStart, aOldEnd, aNewEnd));
|
||||
// Now that we added a new range we need to go back and
|
||||
// update all the ranges before that.
|
||||
// Ranges that have offsets which follow this new range
|
||||
// need to be updated to reflect new offsets
|
||||
int32_t delta = (int32_t)(aNewEnd - aOldEnd);
|
||||
for (int32_t i = mIMETextChanges.Length() - 2; i >= 0; i--) {
|
||||
IMEChange &previousChange = mIMETextChanges[i];
|
||||
if (previousChange.mStart > (int32_t)aOldEnd) {
|
||||
previousChange.mStart += delta;
|
||||
previousChange.mOldEnd += delta;
|
||||
previousChange.mNewEnd += delta;
|
||||
}
|
||||
}
|
||||
|
||||
// Now go through all ranges to merge any ranges that are connected
|
||||
// srcIndex is the index of the range to merge from
|
||||
// dstIndex is the index of the range to potentially merge into
|
||||
int32_t srcIndex = mIMETextChanges.Length() - 1;
|
||||
int32_t dstIndex = srcIndex;
|
||||
|
||||
while (--dstIndex >= 0) {
|
||||
IMEChange &src = mIMETextChanges[srcIndex];
|
||||
IMEChange &dst = mIMETextChanges[dstIndex];
|
||||
// When merging a more recent change into an older
|
||||
// change, we need to compare recent change's (start, oldEnd)
|
||||
// range to the older change's (start, newEnd)
|
||||
if (src.mOldEnd < dst.mStart || dst.mNewEnd < src.mStart) {
|
||||
// No overlap between ranges
|
||||
continue;
|
||||
}
|
||||
// When merging two ranges, there are generally four posibilities:
|
||||
// [----(----]----), (----[----]----),
|
||||
// [----(----)----], (----[----)----]
|
||||
// where [----] is the first range and (----) is the second range
|
||||
// As seen above, the start of the merged range is always the lesser
|
||||
// of the two start offsets. OldEnd and NewEnd then need to be
|
||||
// adjusted separately depending on the case. In any case, the change
|
||||
// in text length of the merged range should be the sum of text length
|
||||
// changes of the two original ranges, i.e.,
|
||||
// newNewEnd - newOldEnd == newEnd1 - oldEnd1 + newEnd2 - oldEnd2
|
||||
dst.mStart = std::min(dst.mStart, src.mStart);
|
||||
if (src.mOldEnd < dst.mNewEnd) {
|
||||
// New range overlaps or is within previous range; merge
|
||||
dst.mNewEnd += src.mNewEnd - src.mOldEnd;
|
||||
} else { // src.mOldEnd >= dst.mNewEnd
|
||||
// New range overlaps previous range; merge
|
||||
dst.mOldEnd += src.mOldEnd - dst.mNewEnd;
|
||||
dst.mNewEnd = src.mNewEnd;
|
||||
}
|
||||
// src merged to dst; delete src.
|
||||
mIMETextChanges.RemoveElementAt(srcIndex);
|
||||
// Any ranges that we skip over between src and dst are not mergeable
|
||||
// so we can safely continue the merge starting at dst
|
||||
srcIndex = dstIndex;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -2104,8 +2207,9 @@ nsWindow::OnIMESelectionChange(void)
|
|||
if (!event.mSucceeded)
|
||||
return NS_OK;
|
||||
|
||||
AndroidBridge::NotifyIMEChange(nullptr, 0, int(event.GetSelectionStart()),
|
||||
int(event.GetSelectionEnd()), -1);
|
||||
PostFlushIMEChanges();
|
||||
mIMESelectionChange = IMEChange((int32_t)event.GetSelectionStart(),
|
||||
(int32_t)event.GetSelectionEnd());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -167,6 +167,8 @@ protected:
|
|||
bool DrawTo(gfxASurface *targetSurface, const nsIntRect &aRect);
|
||||
bool IsTopLevel();
|
||||
void RemoveIMEComposition();
|
||||
void PostFlushIMEChanges();
|
||||
void FlushIMEChanges();
|
||||
|
||||
// Call this function when the users activity is the direct cause of an
|
||||
// event (like a keypress or mouse click).
|
||||
|
@ -188,6 +190,33 @@ protected:
|
|||
nsString mIMEComposingText;
|
||||
nsAutoTArray<nsTextRange, 4> mIMERanges;
|
||||
|
||||
struct IMEChange {
|
||||
int32_t mStart, mOldEnd, mNewEnd;
|
||||
|
||||
IMEChange() :
|
||||
mStart(-1), mOldEnd(-1), mNewEnd(-1)
|
||||
{
|
||||
}
|
||||
IMEChange(int32_t start, int32_t oldEnd, int32_t newEnd) :
|
||||
mStart(start), mOldEnd(oldEnd), mNewEnd(newEnd)
|
||||
{
|
||||
}
|
||||
IMEChange(int32_t start, int32_t end) :
|
||||
mStart(start), mOldEnd(end), mNewEnd(-1)
|
||||
{
|
||||
}
|
||||
bool IsEmpty()
|
||||
{
|
||||
return mStart < 0;
|
||||
}
|
||||
bool IsTextChange()
|
||||
{
|
||||
return mNewEnd >= 0;
|
||||
}
|
||||
};
|
||||
nsAutoTArray<IMEChange, 4> mIMETextChanges;
|
||||
IMEChange mIMESelectionChange;
|
||||
|
||||
InputContext mInputContext;
|
||||
|
||||
static void DumpWindows();
|
||||
|
|
Загрузка…
Ссылка в новой задаче