Merge the last PGO-green inbound changeset to m-c.

This commit is contained in:
Ryan VanderMeulen 2013-02-25 14:16:48 -05:00
Родитель 0b968f5ce7 6598183003
Коммит 8612caaf5c
97 изменённых файлов: 3275 добавлений и 1257 удалений

Просмотреть файл

@ -635,6 +635,8 @@ pref("memory.free_dirty_pages", true);
pref("wap.UAProf.url", "");
pref("wap.UAProf.tagname", "x-wap-profile");
pref("layout.imagevisibility.enabled", false);
// Enable native identity (persona/browserid)
pref("dom.identity.enabled", true);

Просмотреть файл

@ -155,6 +155,11 @@ SettingsListener.observe('language.current', 'en-US', function(value) {
});
});
SettingsListener.observe('ril.mms.retrieval_mode', 'manual',
function(value) {
Services.prefs.setCharPref('dom.mms.retrieval_mode', value);
});
SettingsListener.observe('ril.sms.strict7BitEncoding.enabled', false,
function(value) {
Services.prefs.setBoolPref('dom.sms.strict7BitEncoding', value);

Просмотреть файл

@ -31,7 +31,20 @@ let SocialUI = {
SocialChatBar.update();
});
Social.init(this._providerReady.bind(this));
SocialChatBar.init();
SocialShareButton.init();
SocialMenu.init();
SocialToolbar.init();
SocialSidebar.init();
Social.init();
// If social was previously initialized it isn't going to notify observers
// about the provider being set or the list of providers changing, so
// handle those now.
if (Social.provider) {
this.observe(null, "social:provider-set", Social.provider.origin);
this.observe(null, "social:providers-changed", null);
}
},
// Called on window unload
@ -48,18 +61,6 @@ let SocialUI = {
Services.prefs.removeObserver("social.toast-notifications.enabled", this);
},
// Called once, after window load, once Social.jsm's provider has been set.
_providerReady: function SocialUI_providerReady() {
this._updateActiveUI();
this._updateMenuItems();
SocialChatBar.update();
SocialShareButton.init();
SocialMenu.populate();
SocialToolbar.init();
SocialSidebar.init();
},
// Social.provider has changed, update any state that depends on it.
// Note: this method is not called when Social.provider is first set, during
// the first window load.
@ -335,6 +336,8 @@ let SocialUI = {
}
let SocialChatBar = {
init: function() {
},
get chatbar() {
return document.getElementById("pinnedchats");
},
@ -556,7 +559,6 @@ let SocialFlyout = {
let SocialShareButton = {
// Called once, after window load, when the Social.provider object is initialized
init: function SSB_init() {
this.updateProvider();
},
// Called when the Social.provider changes
@ -703,6 +705,9 @@ let SocialShareButton = {
};
var SocialMenu = {
init: function SocialMenu_init() {
},
populate: function SocialMenu_populate() {
let submenu = document.getElementById("menu_social-statusarea-popup");
let ambientMenuItems = submenu.getElementsByClassName("ambient-menuitem");
@ -740,8 +745,6 @@ var SocialToolbar = {
let accesskey = gNavigatorBundle.getString("social.removeProvider.accesskey");
let removeCommand = document.getElementById("Social:Remove");
removeCommand.setAttribute("accesskey", accesskey);
this.updateProvider();
this._dynamicResizer = new DynamicResizeWatcher();
},
@ -1073,7 +1076,6 @@ var SocialSidebar = {
Social.setErrorListener(sbrowser, this.setSidebarErrorMessage.bind(this));
// setting isAppTab causes clicks on untargeted links to open new tabs
sbrowser.docShell.isAppTab = true;
this.update();
},
// Whether the sidebar can be shown for this window.

Просмотреть файл

@ -13,43 +13,18 @@ var ContextMenuHandler = {
// Events we catch from content during the bubbling phase
addEventListener("contextmenu", this, false);
addEventListener("pagehide", this, false);
addEventListener("select", this, false);
// Messages we receive from browser
// Command sent over from browser that only we can handle.
addMessageListener("Browser:ContextCommand", this, false);
// InvokeContextAtPoint is sent to us from browser's selection
// overlay when it traps a contextmenu event. In response we
// should invoke context menu logic at the point specified.
addMessageListener("Browser:InvokeContextAtPoint", this, false);
this.popupNode = null;
},
_getLinkURL: function ch_getLinkURL(aLink) {
let href = aLink.href;
if (href)
return href;
href = aLink.getAttributeNS(kXLinkNamespace, "href");
if (!href || !href.match(/\S/)) {
// Without this we try to save as the current doc,
// for example, HTML case also throws if empty
throw "Empty href";
}
return Util.makeURLAbsolute(aLink.baseURI, href);
},
_getURI: function ch_getURI(aURL) {
try {
return Util.makeURI(aURL);
} catch (ex) { }
return null;
},
_getProtocol: function ch_getProtocol(aURI) {
if (aURI)
return aURI.scheme;
return null;
},
handleEvent: function ch_handleEvent(aEvent) {
switch (aEvent.type) {
case "contextmenu":
@ -58,12 +33,25 @@ var ContextMenuHandler = {
case "pagehide":
this.reset();
break;
case "select":
break;
}
},
receiveMessage: function ch_receiveMessage(aMessage) {
switch (aMessage.name) {
case "Browser:ContextCommand":
this._onContextCommand(aMessage);
break;
case "Browser:InvokeContextAtPoint":
this._onContextAtPoint(aMessage);
break;
}
},
/*
* Handler for commands send over from browser's ContextCommands.js
* in response to certain context menu actions only we can handle.
*/
_onContextCommand: function _onContextCommand(aMessage) {
let node = this.popupNode;
let command = aMessage.json.command;
@ -97,6 +85,17 @@ var ContextMenuHandler = {
}
},
/*
* Handler for selection overlay context menu events.
*/
_onContextAtPoint: function _onContextCommand(aMessage) {
// we need to find popupNode as if the context menu were
// invoked on underlying content.
let elem = elementFromPoint(aMessage.json.xPos, aMessage.json.yPos);
this._processPopupNode(elem, aMessage.json.xPos, aMessage.json.yPos,
Ci.nsIDOMMouseEvent.MOZ_SOURCE_TOUCH);
},
/******************************************************
* Event handlers
*/
@ -106,7 +105,7 @@ var ContextMenuHandler = {
this._target = null;
},
// content contextmenu
// content contextmenu handler
_onContentContextMenu: function _onContentContextMenu(aEvent) {
if (aEvent.defaultPrevented)
return;
@ -115,6 +114,80 @@ var ContextMenuHandler = {
aEvent.stopPropagation();
aEvent.preventDefault();
this._processPopupNode(aEvent.originalTarget, aEvent.clientX,
aEvent.clientY, aEvent.mozInputSource);
},
/******************************************************
* ContextCommand handlers
*/
_onSelectAll: function _onSelectAll() {
if (this._isTextInput(this._target)) {
// select all text in the input control
this._target.select();
} else {
// select the entire document
content.getSelection().selectAllChildren(content.document);
}
this.reset();
},
_onPaste: function _onPaste() {
// paste text if this is an input control
if (this._isTextInput(this._target)) {
let edit = this._target.QueryInterface(Ci.nsIDOMNSEditableElement);
if (edit) {
edit.editor.paste(Ci.nsIClipboard.kGlobalClipboard);
} else {
Util.dumpLn("error: target element does not support nsIDOMNSEditableElement");
}
}
this.reset();
},
_onCopyImage: function _onCopyImage() {
Util.copyImageToClipboard(this._target);
},
/******************************************************
* Utility routines
*/
/*
* _translateToTopLevelWindow - Given a potential coordinate set within
* a subframe, translate up to the parent window which is what front
* end code expect.
*/
_translateToTopLevelWindow: function _translateToTopLevelWindow(aPopupNode) {
let offsetX = 0;
let offsetY = 0;
let element = aPopupNode;
while (element &&
element.ownerDocument &&
element.ownerDocument.defaultView != content) {
element = element.ownerDocument.defaultView.frameElement;
let rect = element.getBoundingClientRect();
offsetX += rect.left;
offsetY += rect.top;
}
return { offsetX: offsetX, offsetY: offsetY };
},
/*
* _processPopupNode - Generate and send a Content:ContextMenu message
* to browser detailing the underlying content types at this.popupNode.
* Note the event we receive targets the sub frame (if there is one) of
* the page.
*/
_processPopupNode: function _processPopupNode(aPopupNode, aX, aY, aInputSrc) {
if (!aPopupNode)
return;
let { offsetX: offsetX, offsetY: offsetY } =
this._translateToTopLevelWindow(aPopupNode);
let popupNode = this.popupNode = aPopupNode;
let imageUrl = "";
let state = {
types: [],
label: "",
@ -122,13 +195,8 @@ var ContextMenuHandler = {
linkTitle: "",
linkProtocol: null,
mediaURL: "",
x: aEvent.x,
y: aEvent.y
};
let popupNode = this.popupNode = aEvent.originalTarget;
let imageUrl = "";
// Do checks for nodes that never have children.
if (popupNode.nodeType == Ci.nsIDOMNode.ELEMENT_NODE) {
// See if the user clicked on an image.
@ -248,9 +316,9 @@ var ContextMenuHandler = {
}
// populate position and event source
state.xPos = aEvent.clientX;
state.yPos = aEvent.clientY;
state.source = aEvent.mozInputSource;
state.xPos = offsetX + aX;
state.yPos = offsetY + aY;
state.source = aInputSrc;
for (let i = 0; i < this._types.length; i++)
if (this._types[i].handler(state, popupNode))
@ -259,39 +327,6 @@ var ContextMenuHandler = {
sendAsyncMessage("Content:ContextMenu", state);
},
_onSelectAll: function _onSelectAll() {
if (this._isTextInput(this._target)) {
// select all text in the input control
this._target.select();
} else {
// select the entire document
content.getSelection().selectAllChildren(content.document);
}
this.reset();
},
_onPaste: function _onPaste() {
// paste text if this is an input control
if (this._isTextInput(this._target)) {
let edit = this._target.QueryInterface(Ci.nsIDOMNSEditableElement);
if (edit) {
edit.editor.paste(Ci.nsIClipboard.kGlobalClipboard);
} else {
Util.dumpLn("error: target element does not support nsIDOMNSEditableElement");
}
}
this.reset();
},
_onCopyImage: function _onCopyImage() {
Util.copyImageToClipboard(this._target);
},
/*
* Utility routines used in testing for various
* HTML element types.
*/
_isTextInput: function _isTextInput(element) {
return ((element instanceof Ci.nsIDOMHTMLInputElement &&
element.mozIsTextField(false)) ||
@ -315,6 +350,35 @@ var ContextMenuHandler = {
element instanceof Ci.nsIDOMHTMLBodyElement);
},
_getLinkURL: function ch_getLinkURL(aLink) {
let href = aLink.href;
if (href)
return href;
href = aLink.getAttributeNS(kXLinkNamespace, "href");
if (!href || !href.match(/\S/)) {
// Without this we try to save as the current doc,
// for example, HTML case also throws if empty
throw "Empty href";
}
return Util.makeURLAbsolute(aLink.baseURI, href);
},
_getURI: function ch_getURI(aURL) {
try {
return Util.makeURI(aURL);
} catch (ex) { }
return null;
},
_getProtocol: function ch_getProtocol(aURI) {
if (aURI)
return aURI.scheme;
return null;
},
/**
* For add-ons to add new types and data to the ContextMenu message.
*

Просмотреть файл

@ -26,6 +26,8 @@ BROWSER_TESTS = \
browser_context_menu_tests.js \
browser_context_menu_tests_01.html \
browser_context_menu_tests_02.html \
browser_context_menu_tests_03.html \
text-block.html \
$(NULL)
BROWSER_TEST_RESOURCES = \

Просмотреть файл

@ -26,7 +26,6 @@ function emptyClipboard() {
.emptyClipboard(Ci.nsIClipboard.kGlobalClipboard);
}
// Image context menu tests
gTests.push({
desc: "text context menu",
run: function test() {
@ -397,6 +396,119 @@ gTests.push({
}
});
gTests.push({
desc: "tests for subframe positioning",
run: function test() {
info(chromeRoot + "browser_context_menu_tests_03.html");
yield addTab(chromeRoot + "browser_context_menu_tests_03.html");
let win = Browser.selectedTab.browser.contentWindow;
// Sometimes the context ui is visible, sometimes it isn't.
try {
yield waitForCondition(function () {
return ContextUI.isVisible;
}, 500, 50);
} catch (ex) {}
ContextUI.dismiss();
let frame1 = win.document.getElementById("frame1");
let link1 = frame1.contentDocument.getElementById("link1");
let promise = waitForEvent(document, "popupshown");
sendContextMenuClickToElement(frame1.contentDocument.defaultView, link1, 85, 10);
yield promise;
ok(promise && !(promise instanceof Error), "promise error");
// should be visible
ok(ContextMenuUI._menuPopup._visible, "is visible");
ok(ContextMenuUI._panel.left > 375 && ContextMenuUI._panel.left < 390, "position");
ok(ContextMenuUI._panel.top > 235 && ContextMenuUI._panel.top < 245, "position");
promise = waitForEvent(document, "popuphidden");
ContextMenuUI.hide();
yield promise;
ok(promise && !(promise instanceof Error), "promise error");
frame1.contentDocument.defaultView.scrollBy(0, 200);
promise = waitForEvent(document, "popupshown");
sendContextMenuClickToElement(frame1.contentDocument.defaultView, link1, 85, 10);
yield promise;
ok(promise && !(promise instanceof Error), "promise error");
// should be visible
ok(ContextMenuUI._menuPopup._visible, "is visible");
ok(ContextMenuUI._panel.left > 375 && ContextMenuUI._panel.left < 390, "position");
ok(ContextMenuUI._panel.top > 35 && ContextMenuUI._panel.top < 45, "position");
promise = waitForEvent(document, "popuphidden");
ContextMenuUI.hide();
yield promise;
ok(promise && !(promise instanceof Error), "promise error");
let rlink1 = win.document.getElementById("rlink1");
promise = waitForEvent(document, "popupshown");
sendContextMenuClickToElement(win, rlink1, 40, 10);
yield promise;
ok(promise && !(promise instanceof Error), "promise error");
// should be visible
ok(ContextMenuUI._menuPopup._visible, "is visible");
ok(ContextMenuUI._panel.left > 730 && ContextMenuUI._panel.left < 745, "position");
ok(ContextMenuUI._panel.top > 600 && ContextMenuUI._panel.top < 610, "position");
promise = waitForEvent(document, "popuphidden");
ContextMenuUI.hide();
yield promise;
ok(promise && !(promise instanceof Error), "promise error");
win.scrollBy(0, 200);
promise = waitForEvent(document, "popupshown");
sendContextMenuClickToElement(win, rlink1, 40, 10);
yield promise;
ok(promise && !(promise instanceof Error), "promise error");
// should be visible
ok(ContextMenuUI._menuPopup._visible, "is visible");
ok(ContextMenuUI._panel.left > 730 && ContextMenuUI._panel.left < 745, "position");
ok(ContextMenuUI._panel.top > 400 && ContextMenuUI._panel.top < 410, "position");
promise = waitForEvent(document, "popuphidden");
ContextMenuUI.hide();
yield promise;
ok(promise && !(promise instanceof Error), "promise error");
let link2 = frame1.contentDocument.getElementById("link2");
promise = waitForEvent(document, "popupshown");
sendContextMenuClickToElement(frame1.contentDocument.defaultView, link2, 85, 10);
yield promise;
ok(promise && !(promise instanceof Error), "promise error");
// should be visible
ok(ContextMenuUI._menuPopup._visible, "is visible");
info(ContextMenuUI._panel.left);
info(ContextMenuUI._panel.top);
ok(ContextMenuUI._panel.left > 380 && ContextMenuUI._panel.left < 390, "position");
ok(ContextMenuUI._panel.top > 170 && ContextMenuUI._panel.top < 185, "position");
promise = waitForEvent(document, "popuphidden");
ContextMenuUI.hide();
yield promise;
ok(promise && !(promise instanceof Error), "promise error");
}
});
function test() {
runTests();
}

Просмотреть файл

@ -0,0 +1,54 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="en"><head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<meta charset="utf-8">
</head>
<body bgcolor=white>
Hello there. <a href="#hello">hello there.</a>
<center>
<iframe id="frame1" width="800" height="600" src="text-block.html"></iframe>
<br />
<br />
Hello there. <a id="rlink1" href="#hello">hello there.</a>
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
</center>
</body></html>

Просмотреть файл

@ -0,0 +1,64 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
</head>
<body>
<div id="content">
<p>(start of paragraph)
Alice was beginning to get very (break)<br>
tired of sitting by her sister on the bank, and of having nothing to do: once or twice she (span)
<span>(start of span) had peeped into the book her sister was reading (end of span)</span>,
but it had no pictures or conversations in it, `and what is the use of a book,' thought Alice
`without pictures or conversation?' (break)<br>
(end of paragraph)</p>
(in between paragraphs)
<p>(start of paragraph)
Alice was beginning to get very
tired of sitting by her sister on the bank, and of having nothing to do: once or twice she
had peeped into the book her sister was reading, but it had no pictures or conversations
in it, `and what is the use of a book,' thought Alice `without pictures or conversation?'(break)<br>
(end of paragraph)</p>
<p><a id="link1" href="#hello">(start of paragraph)</a>
So she was considering in her own mind (as well as she could, for the hot day made her
feel very sleepy and stupid), whether the pleasure of making a daisy-chain would be worth
the trouble of getting up and picking the daisies, when suddenly a White Rabbit with pink
eyes ran close by her. <br>
</p>
<p>
There was nothing so VERY remarkable in that; nor did Alice think it so VERY much out of
the way to hear the Rabbit say to itself, `Oh dear! Oh dear! I shall be late!' (when she
thought it over afterwards, it occurred to her that she ought to have wondered at this,
but at the time it all seemed quite natural); but when the Rabbit actually TOOK A WATCH
OUT OF ITS WAISTCOAT- POCKET, and looked at it, and then hurried on, Alice started to her
feet, for it flashed across her mind that she had never before seen a rabbit with either a
waistcoat-pocket, or a watch to take out of it, and burning with curiosity, she ran across
the field after it, and fortunately was just in time to see it pop down a large
rabbit-hole under the hedge. <br>
<br>
In another moment down went Alice after it, never once considering how in the world she
was to get out again. <br>
<br>
The rabbit-hole went straight on like a tunnel for some way, and then dipped suddenly
down, so suddenly that Alice had not a moment to think about stopping herself before she
found herself falling down a very deep well. <br>
<br><a id="link2" href="#hello">(start of paragraph)</a>
Either the well was very deep, or she fell very slowly, for she had plenty of time as she
went down to look about her and to wonder what was going to happen next. First, she tried
to look down and make out what she was coming to, but it was too dark to see anything;
then she looked at the sides of the well, and noticed that they were filled with cupboards
and book-shelves; here and there she saw maps and pictures hung upon pegs. She took down a
jar from one of the shelves as she passed; it was labelled `ORANGE MARMALADE', but to her
great disappointment it was empty: she did not like to drop the jar for fear of killing
somebody, so managed to put it into one of the cupboards as she fell past it. <br>
<br>
`Well!' thought Alice to herself, `after such a fall as this, I shall think nothing of
tumbling down stairs! How brave they'll all think me at home! Why, I wouldn't say anything
about it, even if I fell off the top of the house!' (Which was very likely true.) <br>
<br>
Down, down, down.
<br>
</div>
</body></html>

Просмотреть файл

@ -57,13 +57,12 @@ this.Social = {
return this._provider;
},
set provider(val) {
// Changes triggered by the public setter should notify of an engine change.
this._setProvider(val, true);
this._setProvider(val);
},
// Sets the current provider and enables it. Also disables the
// previously set provider, and optionally notifies observers of the change.
_setProvider: function (provider, notify) {
// previously set provider, and notifies observers of the change.
_setProvider: function (provider) {
if (this._provider == provider)
return;
@ -84,10 +83,8 @@ this.Social = {
Services.prefs.setBoolPref("social.enabled", enabled);
}
if (notify) {
let origin = this._provider && this._provider.origin;
Services.obs.notifyObservers(null, "social:provider-set", origin);
}
let origin = this._provider && this._provider.origin;
Services.obs.notifyObservers(null, "social:provider-set", origin);
},
get defaultProvider() {
@ -97,41 +94,37 @@ this.Social = {
return provider || this.providers[0];
},
init: function Social_init(callback) {
init: function Social_init() {
this._disabledForSafeMode = Services.appinfo.inSafeMode && this.enabled;
if (this.providers) {
schedule(callback);
return;
}
// Retrieve the current set of providers, and set the current provider.
SocialService.getProviderList(function (providers) {
// We don't want to notify about a provider change when we're setting
// this.provider for the first time, so pass false here.
this._updateProviderCache(providers, false);
callback();
this._updateProviderCache(providers);
}.bind(this));
// Register an observer for changes to the provider list
SocialService.registerProviderListener(function providerListener(topic, data) {
// An engine change caused by adding/removing a provider should notify
if (topic == "provider-added" || topic == "provider-removed") {
this._updateProviderCache(data, true);
this._updateProviderCache(data);
Services.obs.notifyObservers(null, "social:providers-changed", null);
}
}.bind(this));
},
// Called to update our cache of providers and set the current provider
_updateProviderCache: function (providers, notifyProviderChange) {
_updateProviderCache: function (providers) {
this.providers = providers;
// If social is currently disabled there's nothing else to do.
if (!SocialService.enabled)
return;
// Otherwise set the provider.
this._setProvider(this.defaultProvider, notifyProviderChange);
this._setProvider(this.defaultProvider);
},
set enabled(val) {

Просмотреть файл

@ -825,6 +825,14 @@ user_pref("camino.use_system_proxy_settings", false); // Camino-only, harmless t
env['XRE_NO_WINDOWS_CRASH_DIALOG'] = '1'
env['NS_TRACE_MALLOC_DISABLE_STACKS'] = '1'
# Additional temporary logging while we try to debug some intermittent
# WebRTC conditions. This is necessary to troubleshoot bugs 841496,
# 841150, and 839677 (at least)
env['NSPR_LOG_MODULES'] = 'signaling:3,mtransport:3'
env['R_LOG_LEVEL'] = '5'
env['R_LOG_DESTINATION'] = 'stderr'
env['R_LOG_VERBOSE'] = '1'
# ASan specific environment stuff
if self.IS_ASAN and (self.IS_LINUX or self.IS_MAC):
try:

Просмотреть файл

@ -37,7 +37,7 @@ interface nsIFrame;
* Web IDL interfaces to mirror this interface when changing it.
*/
[scriptable, builtinclass, uuid(497bfb9b-d996-4d1e-a647-8137b0cfc876)]
[scriptable, builtinclass, uuid(e3968acd-b796-4ca3-aec0-e7f0880f2219)]
interface nsIImageLoadingContent : imgINotificationObserver
{
/**
@ -159,4 +159,12 @@ interface nsIImageLoadingContent : imgINotificationObserver
* as PR_FALSE to revert ImageState() to its original behaviour.
*/
void forceImageState(in boolean aForce, in unsigned long long aState);
/**
* A visible count is stored, if it is non-zero then this image is considered
* visible. These methods increment, decrement, or return the visible coount.
*/
[noscript, notxpcom] void IncrementVisibleCount();
[noscript, notxpcom] void DecrementVisibleCount();
[noscript, notxpcom] uint32_t GetVisibleCount();
};

Просмотреть файл

@ -86,7 +86,8 @@ nsImageLoadingContent::nsImageLoadingContent()
mNewRequestsWillNeedAnimationReset(false),
mStateChangerDepth(0),
mCurrentRequestRegistered(false),
mPendingRequestRegistered(false)
mPendingRequestRegistered(false),
mVisibleCount(0)
{
if (!nsContentUtils::GetImgLoaderForChannel(nullptr)) {
mLoadingEnabled = false;
@ -121,6 +122,11 @@ nsImageLoadingContent::Notify(imgIRequest* aRequest,
return OnImageIsAnimated(aRequest);
}
if (aType == imgINotificationObserver::UNLOCKED_DRAW) {
OnUnlockedDraw();
return NS_OK;
}
if (aType == imgINotificationObserver::LOAD_COMPLETE) {
// We should definitely have a request here
NS_ABORT_IF_FALSE(aRequest, "no request?");
@ -228,6 +234,25 @@ nsImageLoadingContent::OnStopRequest(imgIRequest* aRequest,
return NS_OK;
}
void
nsImageLoadingContent::OnUnlockedDraw()
{
if (mVisibleCount > 0) {
// We should already be marked as visible, there is nothing more we can do.
return;
}
nsPresContext* presContext = GetFramePresContext();
if (!presContext)
return;
nsIPresShell* presShell = presContext->PresShell();
if (!presShell)
return;
presShell->EnsureImageInVisibleList(this);
}
nsresult
nsImageLoadingContent::OnImageIsAnimated(imgIRequest *aRequest)
{
@ -375,25 +400,23 @@ nsImageLoadingContent::FrameCreated(nsIFrame* aFrame)
{
NS_ASSERTION(aFrame, "aFrame is null");
if (aFrame->HasAnyStateBits(NS_FRAME_IN_POPUP)) {
// Assume all images in popups are visible.
IncrementVisibleCount();
}
nsPresContext* presContext = aFrame->PresContext();
if (mVisibleCount == 0) {
presContext->PresShell()->EnsureImageInVisibleList(this);
}
// We pass the SKIP_FRAME_CHECK flag to TrackImage here because our primary
// frame pointer hasn't been setup yet when this is caled.
TrackImage(mCurrentRequest, SKIP_FRAME_CHECK);
TrackImage(mPendingRequest, SKIP_FRAME_CHECK);
// We need to make sure that our image request is registered, if it should
// be registered.
nsPresContext* presContext = aFrame->PresContext();
if (mCurrentRequest && !(mCurrentRequestFlags & REQUEST_IS_TRACKED)) {
nsIDocument* doc = GetOurCurrentDoc();
if (doc) {
mCurrentRequestFlags |= REQUEST_IS_TRACKED;
doc->AddImage(mCurrentRequest);
}
}
if (mPendingRequest && !(mPendingRequestFlags & REQUEST_IS_TRACKED)) {
nsIDocument* doc = GetOurCurrentDoc();
if (doc) {
mPendingRequestFlags |= REQUEST_IS_TRACKED;
doc->AddImage(mPendingRequest);
}
}
if (mCurrentRequest) {
nsLayoutUtils::RegisterImageRequestIfAnimated(presContext, mCurrentRequest,
&mCurrentRequestRegistered);
@ -423,19 +446,13 @@ nsImageLoadingContent::FrameDestroyed(nsIFrame* aFrame)
&mPendingRequestRegistered);
}
if (mCurrentRequest && (mCurrentRequestFlags & REQUEST_IS_TRACKED)) {
nsIDocument* doc = GetOurCurrentDoc();
if (doc) {
mCurrentRequestFlags &= ~REQUEST_IS_TRACKED;
doc->RemoveImage(mCurrentRequest);
}
}
if (mPendingRequest && (mPendingRequestFlags & REQUEST_IS_TRACKED)) {
nsIDocument* doc = GetOurCurrentDoc();
if (doc) {
mPendingRequestFlags &= ~REQUEST_IS_TRACKED;
doc->RemoveImage(mPendingRequest);
}
UntrackImage(mCurrentRequest);
UntrackImage(mPendingRequest);
if (aFrame->HasAnyStateBits(NS_FRAME_IN_POPUP)) {
// We assume all images in popups are visible, so this decrement balances
// out the increment in FrameCreated above.
DecrementVisibleCount();
}
}
@ -614,6 +631,34 @@ nsImageLoadingContent::UnblockOnload(imgIRequest* aRequest)
return NS_OK;
}
void
nsImageLoadingContent::IncrementVisibleCount()
{
mVisibleCount++;
if (mVisibleCount == 1) {
TrackImage(mCurrentRequest);
TrackImage(mPendingRequest);
}
}
void
nsImageLoadingContent::DecrementVisibleCount()
{
NS_ASSERTION(mVisibleCount > 0, "visible count should be positive here");
mVisibleCount--;
if (mVisibleCount == 0) {
UntrackImage(mCurrentRequest);
UntrackImage(mPendingRequest);
}
}
uint32_t
nsImageLoadingContent::GetVisibleCount()
{
return mVisibleCount;
}
/*
* Non-interface methods
*/
@ -1101,7 +1146,7 @@ nsImageLoadingContent::ClearCurrentRequest(nsresult aReason)
&mCurrentRequestRegistered);
// Clean up the request.
UntrackImage(mCurrentRequest);
UntrackImage(mCurrentRequest, REQUEST_DISCARD);
mCurrentRequest->CancelAndForgetObserver(aReason);
mCurrentRequest = nullptr;
mCurrentRequestFlags = 0;
@ -1124,7 +1169,7 @@ nsImageLoadingContent::ClearPendingRequest(nsresult aReason)
nsLayoutUtils::DeregisterImageRequest(GetFramePresContext(), mPendingRequest,
&mPendingRequestRegistered);
UntrackImage(mPendingRequest);
UntrackImage(mPendingRequest, REQUEST_DISCARD);
mPendingRequest->CancelAndForgetObserver(aReason);
mPendingRequest = nullptr;
mPendingRequestFlags = 0;
@ -1183,16 +1228,8 @@ nsImageLoadingContent::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
nsCxPusher pusher;
pusher.PushNull();
if (GetOurPrimaryFrame()) {
if (mCurrentRequest && !(mCurrentRequestFlags & REQUEST_IS_TRACKED)) {
mCurrentRequestFlags |= REQUEST_IS_TRACKED;
aDocument->AddImage(mCurrentRequest);
}
if (mPendingRequest && !(mPendingRequestFlags & REQUEST_IS_TRACKED)) {
mPendingRequestFlags |= REQUEST_IS_TRACKED;
aDocument->AddImage(mPendingRequest);
}
}
TrackImage(mCurrentRequest);
TrackImage(mPendingRequest);
if (mCurrentRequestFlags & REQUEST_BLOCKS_ONLOAD)
aDocument->BlockOnload();
@ -1211,21 +1248,15 @@ nsImageLoadingContent::UnbindFromTree(bool aDeep, bool aNullParent)
nsCxPusher pusher;
pusher.PushNull();
if (mCurrentRequest && (mCurrentRequestFlags & REQUEST_IS_TRACKED)) {
mCurrentRequestFlags &= ~REQUEST_IS_TRACKED;
doc->RemoveImage(mCurrentRequest);
}
if (mPendingRequest && (mPendingRequestFlags & REQUEST_IS_TRACKED)) {
mPendingRequestFlags &= ~REQUEST_IS_TRACKED;
doc->RemoveImage(mPendingRequest);
}
UntrackImage(mCurrentRequest);
UntrackImage(mPendingRequest);
if (mCurrentRequestFlags & REQUEST_BLOCKS_ONLOAD)
doc->UnblockOnload(false);
}
nsresult
nsImageLoadingContent::TrackImage(imgIRequest* aImage)
nsImageLoadingContent::TrackImage(imgIRequest* aImage, uint32_t aFlags /* = 0 */)
{
if (!aImage)
return NS_OK;
@ -1234,7 +1265,8 @@ nsImageLoadingContent::TrackImage(imgIRequest* aImage)
"Why haven't we heard of this request?");
nsIDocument* doc = GetOurCurrentDoc();
if (doc && GetOurPrimaryFrame()) {
if (doc && ((aFlags & SKIP_FRAME_CHECK) || GetOurPrimaryFrame()) &&
(mVisibleCount > 0)) {
if (aImage == mCurrentRequest && !(mCurrentRequestFlags & REQUEST_IS_TRACKED)) {
mCurrentRequestFlags |= REQUEST_IS_TRACKED;
doc->AddImage(mCurrentRequest);
@ -1248,7 +1280,7 @@ nsImageLoadingContent::TrackImage(imgIRequest* aImage)
}
nsresult
nsImageLoadingContent::UntrackImage(imgIRequest* aImage)
nsImageLoadingContent::UntrackImage(imgIRequest* aImage, uint32_t aFlags /* = 0 */)
{
if (!aImage)
return NS_OK;
@ -1263,11 +1295,13 @@ nsImageLoadingContent::UntrackImage(imgIRequest* aImage)
if (doc) {
if (aImage == mCurrentRequest && (mCurrentRequestFlags & REQUEST_IS_TRACKED)) {
mCurrentRequestFlags &= ~REQUEST_IS_TRACKED;
doc->RemoveImage(mCurrentRequest, nsIDocument::REQUEST_DISCARD);
doc->RemoveImage(mCurrentRequest,
(aFlags & REQUEST_DISCARD) ? nsIDocument::REQUEST_DISCARD : 0);
}
if (aImage == mPendingRequest && (mPendingRequestFlags & REQUEST_IS_TRACKED)) {
mPendingRequestFlags &= ~REQUEST_IS_TRACKED;
doc->RemoveImage(mPendingRequest, nsIDocument::REQUEST_DISCARD);
doc->RemoveImage(mPendingRequest,
(aFlags & REQUEST_DISCARD) ? nsIDocument::REQUEST_DISCARD : 0);
}
}
return NS_OK;

Просмотреть файл

@ -183,6 +183,7 @@ protected:
void UnbindFromTree(bool aDeep, bool aNullParent);
nsresult OnStopRequest(imgIRequest* aRequest, nsresult aStatus);
void OnUnlockedDraw();
nsresult OnImageIsAnimated(imgIRequest *aRequest);
private:
@ -326,9 +327,21 @@ protected:
* Adds/Removes a given imgIRequest from our document's tracker.
*
* No-op if aImage is null.
*
* SKIP_FRAME_CHECK passed to TrackImage means we skip the check if we have a
* frame, there is only one valid use of this: when calling from FrameCreated.
*
* REQUEST_DISCARD passed to UntrackImage means we request the discard of the
* decoded data of the image.
*/
nsresult TrackImage(imgIRequest* aImage);
nsresult UntrackImage(imgIRequest* aImage);
enum {
SKIP_FRAME_CHECK = 0x1
};
nsresult TrackImage(imgIRequest* aImage, uint32_t aFlags = 0);
enum {
REQUEST_DISCARD = 0x1
};
nsresult UntrackImage(imgIRequest* aImage, uint32_t aFlags = 0);
/* MEMBERS */
nsRefPtr<imgRequestProxy> mCurrentRequest;
@ -404,6 +417,8 @@ private:
// registered with the refresh driver.
bool mCurrentRequestRegistered;
bool mPendingRequestRegistered;
uint32_t mVisibleCount;
};
#endif // nsImageLoadingContent_h__

Просмотреть файл

@ -119,6 +119,31 @@ BluetoothOppManagerObserver::Observe(nsISupports* aSubject,
return NS_ERROR_UNEXPECTED;
}
class SendSocketDataTask : public nsRunnable
{
public:
SendSocketDataTask(uint8_t* aStream, uint32_t aSize)
: mStream(aStream)
, mSize(aSize)
{
MOZ_ASSERT(!NS_IsMainThread());
}
NS_IMETHOD Run()
{
MOZ_ASSERT(NS_IsMainThread());
sInstance->SendPutRequest(mStream, mSize);
sSentFileLength += mSize;
return NS_OK;
}
private:
nsAutoArrayPtr<uint8_t> mStream;
uint32_t mSize;
};
class ReadFileTask : public nsRunnable
{
public:
@ -135,13 +160,13 @@ public:
MOZ_ASSERT(!NS_IsMainThread());
uint32_t numRead;
nsAutoArrayPtr<char> buf;
buf = new char[mAvailablePacketSize];
char* buf = new char[mAvailablePacketSize];
// function inputstream->Read() only works on non-main thread
nsresult rv = mInputStream->Read(buf.get(), mAvailablePacketSize, &numRead);
nsresult rv = mInputStream->Read(buf, mAvailablePacketSize, &numRead);
if (NS_FAILED(rv)) {
// Needs error handling here
NS_WARNING("Failed to read from input stream");
return NS_ERROR_FAILURE;
}
@ -149,8 +174,13 @@ public:
if (sSentFileLength + numRead >= sFileLength) {
sWaitingToSendPutFinal = true;
}
sInstance->SendPutRequest((uint8_t*)buf.get(), numRead);
sSentFileLength += numRead;
nsRefPtr<SendSocketDataTask> task =
new SendSocketDataTask((uint8_t*)buf, numRead);
if (NS_FAILED(NS_DispatchToMainThread(task))) {
NS_WARNING("Failed to dispatch to main thread!");
return NS_ERROR_FAILURE;
}
}
return NS_OK;
@ -361,6 +391,7 @@ BluetoothOppManager::SendFile(BlobParent* aActor)
SendConnectRequest();
mTransferMode = false;
StartFileTransfer();
return true;
}
@ -797,24 +828,26 @@ BluetoothOppManager::ClientDataHandler(UnixSocketRawData* aMessage)
packetLength = (((int)aMessage->mData[1]) << 8) | aMessage->mData[2];
}
// Check response code
if (mLastCommand == ObexRequestCode::Put &&
opCode != ObexResponseCode::Continue) {
NS_WARNING("[OPP] Put(0x02) failed");
SendDisconnectRequest();
return;
} else if (mLastCommand == ObexRequestCode::Abort ||
mLastCommand == ObexRequestCode::Connect ||
mLastCommand == ObexRequestCode::Disconnect ||
mLastCommand == ObexRequestCode::PutFinal){
if (opCode != ObexResponseCode::Success) {
nsAutoCString str;
str += "[OPP] 0x";
str += mLastCommand;
str += " failed";
NS_WARNING(str.get());
return;
// Check response code and send out system message as finished if the reponse
// code is somehow incorrect.
uint8_t expectedOpCode = ObexResponseCode::Success;
if (mLastCommand == ObexRequestCode::Put) {
expectedOpCode = ObexResponseCode::Continue;
}
if (opCode != expectedOpCode) {
if (mLastCommand == ObexRequestCode::Put ||
mLastCommand == ObexRequestCode::Abort ||
mLastCommand == ObexRequestCode::PutFinal) {
SendDisconnectRequest();
}
nsAutoCString str;
str += "[OPP] 0x";
str.AppendInt(mLastCommand, 16);
str += " failed";
NS_WARNING(str.get());
FileTransferComplete();
return;
}
if (mLastCommand == ObexRequestCode::PutFinal) {
@ -849,7 +882,6 @@ BluetoothOppManager::ClientDataHandler(UnixSocketRawData* aMessage)
*/
if (ExtractBlobHeaders()) {
sInstance->SendPutHeaderRequest(sFileName, sFileLength);
StartFileTransfer();
}
} else if (mLastCommand == ObexRequestCode::Put) {

Просмотреть файл

@ -122,7 +122,7 @@ BluetoothScoManager::Init()
mSocketStatus = GetConnectionStatus();
sScoObserver = new BluetoothScoManagerObserver();
if (sScoObserver->Init()) {
if (!sScoObserver->Init()) {
NS_WARNING("Cannot set up SCO observers!");
}
return true;

Просмотреть файл

@ -2466,11 +2466,9 @@ BluetoothDBusService::Connect(const nsAString& aDeviceAddress,
errorStr.AssignLiteral("BluetoothOppManager has connected/is connecting!");
DispatchBluetoothReply(aRunnable, v, errorStr);
}
} else {
NS_WARNING("Unknown Profile");
}
#ifdef DEBUG
NS_WARNING("Unknown Profile");
#endif
}
void

Просмотреть файл

@ -21,7 +21,7 @@ function handlePrompt(e) {
alert('parent:ready');
}
else if (numPrompts > 3) {
else if (numPrompts == 4 || numPrompts == 5) {
alert(e.detail.message);
}
}

Просмотреть файл

@ -390,6 +390,14 @@ ContactManager.prototype = {
return contacts;
},
_fireSuccessOrDone: function(aCursor, aResult) {
if (aResult == null) {
Services.DOMRequest.fireDone(aCursor);
} else {
Services.DOMRequest.fireSuccess(aCursor, aResult);
}
},
receiveMessage: function(aMessage) {
if (DEBUG) debug("receiveMessage: " + aMessage.name);
let msg = aMessage.json;
@ -407,12 +415,15 @@ ContactManager.prototype = {
}
break;
case "Contacts:GetAll:Next":
let cursor = this._cursorData[msg.cursorId];
let data = this._cursorData[msg.cursorId];
let contact = msg.contact ? this._convertContact(msg.contact) : null;
if (contact == null) {
Services.DOMRequest.fireDone(cursor);
if (data.waitingForNext) {
if (DEBUG) debug("cursor waiting for contact, sending");
data.waitingForNext = false;
this._fireSuccessOrDone(data.cursor, contact);
} else {
Services.DOMRequest.fireSuccess(cursor, contact);
if (DEBUG) debug("cursor not waiting, saving");
data.cachedContacts.push(contact);
}
break;
case "Contacts:GetSimContacts:Return:OK":
@ -591,12 +602,16 @@ ContactManager.prototype = {
createCursor: function CM_createCursor(aRequest) {
let id = this._getRandomId();
let cursor = Services.DOMRequest.createCursor(this._window, function() {
this.handleContinue(id);
}.bind(this));
let data = {
cursor: Services.DOMRequest.createCursor(this._window, function() {
this.handleContinue(id);
}.bind(this)),
cachedContacts: [],
waitingForNext: true,
};
if (DEBUG) debug("saved cursor id: " + id);
this._cursorData[id] = cursor;
return [id, cursor];
this._cursorData[id] = data;
return [id, data.cursor];
},
getAll: function CM_getAll(aOptions) {
@ -612,9 +627,14 @@ ContactManager.prototype = {
handleContinue: function CM_handleContinue(aCursorId) {
if (DEBUG) debug("handleContinue: " + aCursorId);
cpmm.sendAsyncMessage("Contacts:GetAll:Continue", {
cursorId: aCursorId
});
let data = this._cursorData[aCursorId];
if (data.cachedContacts.length > 0) {
if (DEBUG) debug("contact in cache");
this._fireSuccessOrDone(data.cursor, data.cachedContacts.shift());
} else {
if (DEBUG) debug("waiting for contact");
data.waitingForNext = true;
}
},
remove: function removeContact(aRecord) {

Просмотреть файл

@ -30,8 +30,6 @@ this.ContactDB = function ContactDB(aGlobal) {
ContactDB.prototype = {
__proto__: IndexedDBHelper.prototype,
cursorData: {},
upgradeSchema: function upgradeSchema(aTransaction, aDb, aOldVersion, aNewVersion) {
if (DEBUG) debug("upgrade schema from: " + aOldVersion + " to " + aNewVersion + " called!");
let db = aDb;
@ -472,82 +470,81 @@ ContactDB.prototype = {
}, aSuccessCb, aErrorCb);
},
getObjectById: function CDB_getObjectById(aStore, aObjectId, aCallback) {
if (DEBUG) debug("getObjectById: " + aStore + ":" + aObjectId);
this.newTxn("readonly", aStore, function (txn, store) {
let req = store.get(aObjectId);
req.onsuccess = function (event) {
aCallback(event.target.result);
};
req.onerror = function (event) {
aCallback(null);
};
});
},
getCacheForQuery: function CDB_getCacheForQuery(aQuery, aCursorId, aSuccessCb) {
if (DEBUG) debug("getCacheForQuery");
// Here we try to get the cached results for query `aQuery'. If they don't
// exist, it means the cache was invalidated and needs to be recreated, so
// we do that. Otherwise, we just return the existing cache.
this.getObjectById(SAVED_GETALL_STORE_NAME, aQuery, function (aCache) {
if (!aCache) {
if (DEBUG) debug("creating cache for query " + aQuery);
this.createCacheForQuery(aQuery, aCursorId, aSuccessCb);
} else {
if (DEBUG) debug("cache exists");
if (!this.cursorData[aCursorId]) {
this.cursorData[aCursorId] = aCache;
}
aSuccessCb(aCache);
}
}.bind(this));
},
setCacheForQuery: function CDB_setCacheForQuery(aQuery, aCache, aCallback) {
this.newTxn("readwrite", SAVED_GETALL_STORE_NAME, function (txn, store) {
let req = store.put(aCache, aQuery);
if (!aCallback) {
return;
}
req.onsuccess = function () {
aCallback(true);
};
req.onerror = function () {
aCallback(false);
};
});
},
createCacheForQuery: function CDB_createCacheForQuery(aQuery, aCursorId, aSuccessCb, aFailureCb) {
createCacheForQuery: function CDB_createCacheForQuery(aQuery, aSuccessCb, aFailureCb) {
this.find(function (aContacts) {
if (aContacts) {
let contactsArray = [];
for (let i in aContacts) {
contactsArray.push(aContacts[i].id);
contactsArray.push(aContacts[i]);
}
this.setCacheForQuery(aQuery, contactsArray);
this.cursorData[aCursorId] = contactsArray;
aSuccessCb(contactsArray);
// save contact ids in cache
this.newTxn("readwrite", SAVED_GETALL_STORE_NAME, function(txn, store) {
store.put(contactsArray.map(function(el) el.id), aQuery);
});
// send full contacts
aSuccessCb(contactsArray, true);
} else {
aSuccessCb(null);
aSuccessCb([], true);
}
}.bind(this),
function (aErrorMsg) { aFailureCb(aErrorMsg); },
JSON.parse(aQuery));
},
getAll: function CDB_getAll(aSuccessCb, aFailureCb, aOptions, aCursorId) {
// Recreate the cache for this query if needed
getCacheForQuery: function CDB_getCacheForQuery(aQuery, aSuccessCb) {
if (DEBUG) debug("getCacheForQuery");
// Here we try to get the cached results for query `aQuery'. If they don't
// exist, it means the cache was invalidated and needs to be recreated, so
// we do that. Otherwise, we just return the existing cache.
this.newTxn("readonly", SAVED_GETALL_STORE_NAME, function(txn, store) {
let req = store.get(aQuery);
req.onsuccess = function(e) {
if (e.target.result) {
if (DEBUG) debug("cache exists");
debug("sending: " + JSON.stringify(e.target.result));
aSuccessCb(e.target.result, false);
} else {
if (DEBUG) debug("creating cache for query " + aQuery);
this.createCacheForQuery(aQuery, aSuccessCb);
}
}.bind(this);
req.onerror = function() {
};
}.bind(this));
},
getAll: function CDB_getAll(aSuccessCb, aFailureCb, aOptions) {
let optionStr = JSON.stringify(aOptions);
this.getCacheForQuery(optionStr, aCursorId, function (aCachedResults) {
this.getCacheForQuery(optionStr, function(aCachedResults, aFullContacts) {
// aFullContacts is true if the cache didn't exist and had to be created.
// In that case, we receive the full contacts since we already have them
// in memory to create the cache anyway. This allows us to avoid accessing
// the main object store again.
if (aCachedResults && aCachedResults.length > 0) {
if (DEBUG) debug("query returned at least one contact");
this.getObjectById(STORE_NAME, aCachedResults[0], function (aContact) {
this.cursorData[aCursorId].shift();
aSuccessCb(aContact);
}.bind(this));
if (aFullContacts) {
if (DEBUG) debug("full contacts: " + aCachedResults.length);
for (let i = 0; i < aCachedResults.length; ++i) {
aSuccessCb(aCachedResults[i]);
}
aSuccessCb(null);
} else {
let count = 0;
this.newTxn("readonly", STORE_NAME, function(txn, store) {
for (let i = 0; i < aCachedResults.length; ++i) {
store.get(aCachedResults[i]).onsuccess = function(e) {
aSuccessCb(e.target.result);
count++;
if (count == aCachedResults.length) {
aSuccessCb(null);
}
};
}
});
}
} else { // no contacts
if (DEBUG) debug("query returned no contacts");
aSuccessCb(null);
@ -555,34 +552,6 @@ ContactDB.prototype = {
}.bind(this));
},
getNext: function CDB_getNext(aSuccessCb, aFailureCb, aCursorId) {
if (DEBUG) debug("ContactDB:getNext: " + aCursorId);
let aCachedResults = this.cursorData[aCursorId];
if (DEBUG) debug("got transient cache");
if (aCachedResults.length > 0) {
this.getObjectById(STORE_NAME, aCachedResults[0], function(aContact) {
this.cursorData[aCursorId].shift();
if (aContact) {
aSuccessCb(aContact);
} else {
// If the contact ID in cache is invalid, it was removed recently and
// the cache hasn't been updated to reflect the change, so we skip it.
if (DEBUG) debug("invalid contact in cache: " + aCachedResults[0]);
return this.getNext(aSuccessCb, aFailureCb, aCursorId);
}
}.bind(this));
} else { // last contact
delete this.cursorData[aCursorId];
aSuccessCb(null);
}
},
releaseCursors: function CDB_releaseCursors(aCursors) {
for (let i of aCursors) {
delete this.cursorData[i];
}
},
/*
* Sorting the contacts by sortBy field. aSortBy can either be familyName or givenName.
* If 2 entries have the same sortyBy field or no sortBy field is present, we continue

Просмотреть файл

@ -37,12 +37,9 @@ XPCOMUtils.defineLazyGetter(this, "mRIL", function () {
let myGlobal = this;
this.DOMContactManager = {
// maps children to their live cursors so we can cleanup on shutdown/crash
_liveCursors: {},
init: function() {
if (DEBUG) debug("Init");
this._messages = ["Contacts:Find", "Contacts:GetAll", "Contacts:GetAll:Continue", "Contacts:Clear", "Contact:Save",
this._messages = ["Contacts:Find", "Contacts:GetAll", "Contacts:Clear", "Contact:Save",
"Contact:Remove", "Contacts:GetSimContacts",
"Contacts:RegisterForMessages", "child-process-shutdown"];
this._children = [];
@ -119,23 +116,6 @@ this.DOMContactManager = {
},
function(aErrorMsg) { mm.sendAsyncMessage("Contacts:Find:Return:KO", { errorMsg: aErrorMsg }); },
msg.findOptions, msg.cursorId);
if (Array.isArray(this._liveCursors[mm])) {
this._liveCursors[mm].push(msg.cursorId);
} else {
this._liveCursors[mm] = [msg.cursorId];
}
break;
case "Contacts:GetAll:Continue":
this._db.getNext(
function(aContact) {
if (aContact == null) { // last contact, release the cursor
let cursors = this._liveCursors[mm];
cursors.splice(cursors.indexOf(msg.cursorId), 1);
}
mm.sendAsyncMessage("Contacts:GetAll:Next", {cursorId: msg.cursorId, contact: aContact});
}.bind(this),
function(aErrorMsg) { mm.sendAsyncMessage("Contacts:Find:Return:KO", { errorMsg: aErrorMsg }); },
msg.cursorId);
break;
case "Contact:Save":
if (msg.options.reason === "create") {
@ -210,10 +190,6 @@ this.DOMContactManager = {
break;
case "child-process-shutdown":
if (DEBUG) debug("Unregister");
if (this._liveCursors[mm]) {
this._db.releaseCursors(this._liveCursors[mm]);
delete this._liveCursors[mm];
}
let index = this._children.indexOf(mm);
if (index != -1) {
if (DEBUG) debug("Unregister index: " + index);

Просмотреть файл

@ -266,7 +266,7 @@ let steps = [
add20Contacts,
function() {
ok(true, "Test cache invalidation between getAll and getNext");
ok(true, "Test cache consistency when deleting contact during getAll");
req = mozContacts.find({});
req.onsuccess = function(e) {
let lastContact = e.target.result[e.target.result.length-1];
@ -290,8 +290,7 @@ let steps = [
count++;
req.continue();
} else {
is(count, 19, "19 contacts returned");
ok(true, "last contact");
is(count, 20, "last contact - 20 contacts returned");
next();
}
}
@ -303,7 +302,7 @@ let steps = [
add20Contacts,
function() {
ok(true, "Delete the currect contact while iterating");
ok(true, "Delete the current contact while iterating");
req = mozContacts.getAll({});
let count = 0;
let previousId = null;

Просмотреть файл

@ -6,6 +6,7 @@
#include "SimToolKit.idl"
interface nsIDOMEventListener;
interface nsIDOMDOMRequest;
[scriptable, builtinclass, uuid(9d898c66-3485-4cd5-ab8d-92ef2988887b)]
interface nsIDOMMozIccManager : nsIDOMEventTarget
@ -272,4 +273,46 @@ interface nsIDOMMozIccManager : nsIDOMEventTarget
* ICC.
*/
[implicit_jscontext] attribute jsval onstksessionend;
// UICC Secure Element Interfaces
/**
* A secure element is a smart card chip that can hold
* several different applications with the necessary security.
* The most known secure element is the Universal Integrated Circuit Card (UICC)
*/
/**
* Send request to open a logical channel defined by its
* application identifier (AID)
*
* @param aid
* The Application Identifier of the Applet to be selected on this channel
* return value : An instance of Channel (channelID) if available or null.
*/
nsIDOMDOMRequest iccOpenChannel(in DOMString aid);
/**
* Interface, used to communicate with an applet through the
* Application Data Protocol Units (APDUs) and is
* used for all data that is exchanged between the UICC card and the terminal (ME).
*
* @param channel
* The Application Identifier of the Applet to which APDU is directed
* @param apdu
* Application Protocol Data Unit
* return value : Response APDU
*/
nsIDOMDOMRequest iccExchangeAPDU(in long channel, in jsval apdu);
/**
* Send request to close the selected logical channel identified by its
* application identifier (AID)
*
* @param aid
* The Application Identifier of the Applet , to be closed
*/
nsIDOMDOMRequest iccCloseChannel(in long channel);
// End of UICC Secure Element Interfaces
};

Просмотреть файл

@ -157,6 +157,37 @@ IccManager::SendStkEventDownload(const JS::Value& aEvent)
return NS_OK;
}
NS_IMETHODIMP
IccManager::IccOpenChannel(const nsAString& aAid, nsIDOMDOMRequest** aRequest)
{
if (!mProvider) {
return NS_ERROR_FAILURE;
}
return mProvider->IccOpenChannel(GetOwner(), aAid, aRequest);
}
NS_IMETHODIMP
IccManager::IccExchangeAPDU(int32_t aChannel, const jsval& aApdu, nsIDOMDOMRequest** aRequest)
{
if (!mProvider) {
return NS_ERROR_FAILURE;
}
return mProvider->IccExchangeAPDU(GetOwner(), aChannel, aApdu, aRequest);
}
NS_IMETHODIMP
IccManager::IccCloseChannel(int32_t aChannel, nsIDOMDOMRequest** aRequest)
{
if (!mProvider) {
return NS_ERROR_FAILURE;
}
return mProvider->IccCloseChannel(GetOwner(), aChannel, aRequest);
}
NS_IMPL_EVENT_HANDLER(IccManager, stkcommand)
NS_IMPL_EVENT_HANDLER(IccManager, stksessionend)

Просмотреть файл

@ -1580,6 +1580,9 @@ const MMS_PDU_TYPES = (function () {
"to",
"date",
"x-mms-status"]);
add(MMS_PDU_TYPE_ACKNOWLEDGE_IND, false, ["x-mms-message-type",
"x-mms-transaction-id",
"x-mms-mms-version"]);
return pdus;
})();

Просмотреть файл

@ -34,6 +34,12 @@ const CONFIG_SEND_REPORT_ALWAYS = 3;
const TIME_TO_BUFFER_MMS_REQUESTS = 30000;
const TIME_TO_RELEASE_MMS_CONNECTION = 30000;
const PREF_RETRIEVAL_MODE = 'dom.mms.retrieval_mode';
const RETRIEVAL_MODE_MANUAL = "manual";
const RETRIEVAL_MODE_AUTOMATIC = "automatic";
const RETRIEVAL_MODE_NEVER = "never";
XPCOMUtils.defineLazyServiceGetter(this, "gpps",
"@mozilla.org/network/protocol-proxy-service;1",
"nsIProtocolProxyService");
@ -683,6 +689,48 @@ SendTransaction.prototype = {
}
};
/**
* Send M-acknowledge.ind back to MMSC.
*
* @param transactionId
* X-Mms-Transaction-ID of the message.
* @param reportAllowed
* X-Mms-Report-Allowed of the response.
*
* @see OMA-TS-MMS_ENC-V1_3-20110913-A section 6.4
*/
function AcknowledgeTransaction(transactionId, reportAllowed) {
let headers = {};
// Mandatory fields
headers["x-mms-message-type"] = MMS.MMS_PDU_TYPE_ACKNOWLEDGE_IND;
headers["x-mms-transaction-id"] = transactionId;
headers["x-mms-mms-version"] = MMS.MMS_VERSION;
// Optional fields
headers["x-mms-report-allowed"] = reportAllowed;
this.istream = MMS.PduHelper.compose(null, {headers: headers});
}
AcknowledgeTransaction.prototype = {
/**
* @param callback [optional]
* A callback function that takes one argument -- the http status.
*/
run: function run(callback) {
let requestCallback;
if (callback) {
requestCallback = function (httpStatus, data) {
// `The MMS Client SHOULD ignore the associated HTTP POST response
// from the MMS Proxy-Relay.` ~ OMA-TS-MMS_CTR-V1_3-20110913-A
// section 8.2.3 "Retrieving an MM".
callback(httpStatus);
};
}
gMmsTransactionHelper.sendRequest("POST", gMmsConnection.mmsc,
this.istream, requestCallback);
}
};
/**
* MmsService
*/
@ -755,34 +803,53 @@ MmsService.prototype = {
*/
handleNotificationIndication: function handleNotificationIndication(notification) {
// TODO: bug 839436 - make DB be able to save MMS messages
// TODO: bug 810067 - support automatic/manual/never retrieval modes
let url = notification.headers["x-mms-content-location"].uri;
// TODO: bug 810091 - don't download message twice on receiving duplicated
// notification
this.retrieveMessage(url, (function (mmsStatus, retrievedMsg) {
debug("retrievedMsg = " + JSON.stringify(retrievedMsg));
if (this.isTransientError(mmsStatus)) {
// TODO: remove this check after bug 810097 is landed.
return;
}
let transactionId = notification.headers["x-mms-transaction-id"];
let retrievalMode = RETRIEVAL_MODE_MANUAL;
try {
retrievalMode = Services.prefs.getCharPref(PREF_RETRIEVAL_MODE);
} catch (e) {}
// For X-Mms-Report-Allowed
let wish = notification.headers["x-mms-delivery-report"];
// `The absence of the field does not indicate any default value.`
// So we go checking the same field in retrieved message instead.
if ((wish == null) && retrievedMsg) {
wish = retrievedMsg.headers["x-mms-delivery-report"];
}
let reportAllowed =
this.getReportAllowed(this.confSendDeliveryReport, wish);
if (RETRIEVAL_MODE_AUTOMATIC === retrievalMode) {
this.retrieveMessage(url, (function responseNotify(mmsStatus, retrievedMsg) {
debug("retrievedMsg = " + JSON.stringify(retrievedMsg));
if (this.isTransientError(mmsStatus)) {
// TODO: remove this check after bug 810097 is landed.
return;
}
let transaction =
new NotifyResponseTransaction(transactionId, mmsStatus, reportAllowed);
transaction.run();
}).bind(this));
let transactionId = notification.headers["x-mms-transaction-id"];
// For X-Mms-Report-Allowed
let wish = notification.headers["x-mms-delivery-report"];
// `The absence of the field does not indicate any default value.`
// So we go checking the same field in retrieved message instead.
if ((wish == null) && retrievedMsg) {
wish = retrievedMsg.headers["x-mms-delivery-report"];
}
let reportAllowed = this.getReportAllowed(this.confSendDeliveryReport, wish);
let transaction =
new NotifyResponseTransaction(transactionId, mmsStatus, reportAllowed);
transaction.run();
}).bind(this));
return;
}
let transactionId = notification.headers["x-mms-transaction-id"];
let mmsStatus = RETRIEVAL_MODE_NEVER === retrievalMode ?
MMS.MMS_PDU_STATUS_REJECTED : MMS.MMS_PDU_STATUS_DEFERRED;
// For X-Mms-Report-Allowed
let wish = notification.headers["x-mms-delivery-report"];
let reportAllowed = this.getReportAllowed(this.confSendDeliveryReport, wish);
let transaction = new NotifyResponseTransaction(transactionId,
mmsStatus,
reportAllowed);
transaction.run();
},
/**

Просмотреть файл

@ -60,4 +60,17 @@ interface nsIMobileConnectionProvider : nsISupports
in unsigned short reason);
nsIDOMDOMRequest setCallForwardingOption(in nsIDOMWindow window,
in nsIDOMMozMobileCFInfo CFInfo);
/**
* Secure Card Icc communication channel
*/
nsIDOMDOMRequest iccOpenChannel(in nsIDOMWindow window,
in DOMString aid);
nsIDOMDOMRequest iccExchangeAPDU(in nsIDOMWindow window,
in long channel,
in jsval apdu);
nsIDOMDOMRequest iccCloseChannel(in nsIDOMWindow window,
in long channel);
};

Просмотреть файл

@ -22,5 +22,7 @@ EXTRA_JS_MODULES += \
Payment.jsm \
$(NULL)
TEST_DIRS += tests
include $(topsrcdir)/config/config.mk
include $(topsrcdir)/config/rules.mk

Просмотреть файл

@ -0,0 +1,21 @@
# 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/.
DEPTH = @DEPTH@
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
relativesrcdir = @relativesrcdir@
include $(DEPTH)/config/autoconf.mk
DIRS = \
$(NULL)
MODULE = test_dom_payment
XPCSHELL_TESTS = unit
include $(topsrcdir)/config/rules.mk

Просмотреть файл

@ -0,0 +1,38 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
let subscriptLoader = Cc["@mozilla.org/moz/jssubscript-loader;1"]
.getService(Ci.mozIJSSubScriptLoader);
/**
* Start a new payment module.
*
* @param custom_ns
* Namespace with symbols to be injected into the new payment module
* namespace.
*
* @return an object that represents the payment module's namespace.
*/
function newPaymentModule(custom_ns) {
let payment_ns = {
importScripts: function fakeImportScripts() {
Array.slice(arguments).forEach(function (script) {
subscriptLoader.loadSubScript("resource://gre/modules/" + script, this);
}, this);
},
};
// Copy the custom definitions over.
for (let key in custom_ns) {
payment_ns[key] = custom_ns[key];
}
// Load the payment module itself.
payment_ns.importScripts("Payment.jsm");
return payment_ns;
}

Просмотреть файл

@ -0,0 +1,348 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
function getPaymentHelper() {
let error;
let paym = newPaymentModule();
paym.PaymentManager.paymentFailed = function paymentFailed(aRequestId,
errorMsg) {
error = errorMsg;
};
return {
get paymentModule() {
return paym;
},
get error() {
return error;
}
};
}
function run_test() {
run_next_test();
}
function testGetPaymentRequest(paymentProviders, test) {
let helper = getPaymentHelper();
let paym = helper.paymentModule;
paym.PaymentManager.registeredProviders = paymentProviders;
let ret = paym.PaymentManager.getPaymentRequestInfo("", test.jwt);
if (!test.result) {
test.ret ? do_check_true(ret) : do_check_false(ret);
}
if (test.error !== null) {
do_check_eq(helper.error, test.error);
} else {
do_check_eq(typeof ret, "object");
do_check_eq(ret.jwt, test.jwt);
do_check_eq(ret.type, test.result.type);
do_check_eq(ret.providerName, test.result.providerName);
}
}
add_test(function test_successfull_request() {
let providers = {};
let type = "mock/payments/inapp/v1";
providers[type] = {
name: "mockprovider",
description: "Mock Payment Provider",
uri: "https://mockpayprovider.phpfogapp.com/?req=",
requestMethod: "GET"
};
// Payload
// {
// "aud": "mockpayprovider.phpfogapp.com",
// "iss": "Enter you app key here!",
// "request": {
// "name": "Piece of Cake",
// "price": "10.50",
// "priceTier": 1,
// "productdata": "transaction_id=86",
// "currencyCode": "USD",
// "description": "Virtual chocolate cake to fill your virtual tummy"
// },
// "exp": 1352232792,
// "iat": 1352229192,
// "typ": "mock/payments/inapp/v1"
// }
let jwt = "eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9.eyJhdWQiOiAibW9j" +
"a3BheXByb3ZpZGVyLnBocGZvZ2FwcC5jb20iLCAiaXNzIjogIkVudGVyI" +
"HlvdSBhcHAga2V5IGhlcmUhIiwgInJlcXVlc3QiOiB7Im5hbWUiOiAiUG" +
"llY2Ugb2YgQ2FrZSIsICJwcmljZSI6ICIxMC41MCIsICJwcmljZVRpZXI" +
"iOiAxLCAicHJvZHVjdGRhdGEiOiAidHJhbnNhY3Rpb25faWQ9ODYiLCAi" +
"Y3VycmVuY3lDb2RlIjogIlVTRCIsICJkZXNjcmlwdGlvbiI6ICJWaXJ0d" +
"WFsIGNob2NvbGF0ZSBjYWtlIHRvIGZpbGwgeW91ciB2aXJ0dWFsIHR1bW" +
"15In0sICJleHAiOiAxMzUyMjMyNzkyLCAiaWF0IjogMTM1MjIyOTE5Miw" +
"gInR5cCI6ICJtb2NrL3BheW1lbnRzL2luYXBwL3YxIn0.QZxc62USCy4U" +
"IyKIC1TKelVhNklvk-Ou1l_daKntaFI";
testGetPaymentRequest(providers, {
jwt: jwt,
ret: true,
error: null,
result: {
type: type,
providerName: providers[type].name
}
});
run_next_test();
});
add_test(function test_successfull_request_html_description() {
let providers = {};
let type = "mozilla/payments/pay/v1";
providers[type] = {
name: "webpay",
description: "Mozilla Payment Provider",
uri: "https://marketplace.firefox.com/mozpay/?req=",
requestMethod: "GET"
};
// Payload
// {
// "aud": "marketplace.firefox.com",
// "iss": "marketplace-dev.allizom.org",
// "request": {
// "name": "Krupa's paid app 1",
// "chargebackURL": "http://localhost:8002/telefonica/services/webpay/"
// "chargeback",
// "postbackURL": "http://localhost:8002/telefonica/services/webpay/"
// "postback",
// "productData": "addon_id=85&seller_uuid=d4855df9-6ce0-45cd-81cb-"
// "cf8737e1e7aa&contrib_uuid=201868b7ac2cda410a99b3"
// "ed4c11a8ea",
// "pricePoint": 1,
// "id": "maude:85",
// "description": "This app has been automatically generated by <a href="
// "\"http://outgoing.mozilla.org/v1/ba7f373ae16789eff3ab"
// "fd95ca8d3c15d18dc9009afa204dc43f85a55b1f6ef1/http%3A/"
// "/testmanifest.com\" rel=\"nofollow\">testmanifest.com"
// "</a>"
// },
// "exp": 1358379147,
// "iat": 1358375547,
// "typ": "mozilla/payments/pay/v1"
// }
let jwt = "eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9.eyJhdWQiOiAibWFya2V0cGx" +
"hY2UuZmlyZWZveC5jb20iLCAiaXNzIjogIm1hcmtldHBsYWNlLWRldi5hbGxpem9" +
"tLm9yZyIsICJyZXF1ZXN0IjogeyJuYW1lIjogIktydXBhJ3MgcGFpZCBhcHAgMSI" +
"sICJjaGFyZ2ViYWNrVVJMIjogImh0dHA6Ly9sb2NhbGhvc3Q6ODAwMi90ZWxlZm9" +
"uaWNhL3NlcnZpY2VzL3dlYnBheS9jaGFyZ2ViYWNrIiwgInBvc3RiYWNrVVJMIjo" +
"gImh0dHA6Ly9sb2NhbGhvc3Q6ODAwMi90ZWxlZm9uaWNhL3NlcnZpY2VzL3dlYnB" +
"heS9wb3N0YmFjayIsICJwcm9kdWN0RGF0YSI6ICJhZGRvbl9pZD04NSZzZWxsZXJ" +
"fdXVpZD1kNDg1NWRmOS02Y2UwLTQ1Y2QtODFjYi1jZjg3MzdlMWU3YWEmY29udHJ" +
"pYl91dWlkPTIwMTg2OGI3YWMyY2RhNDEwYTk5YjNlZDRjMTFhOGVhIiwgInByaWN" +
"lUG9pbnQiOiAxLCAiaWQiOiAibWF1ZGU6ODUiLCAiZGVzY3JpcHRpb24iOiAiVGh" +
"pcyBhcHAgaGFzIGJlZW4gYXV0b21hdGljYWxseSBnZW5lcmF0ZWQgYnkgPGEgaHJ" +
"lZj1cImh0dHA6Ly9vdXRnb2luZy5tb3ppbGxhLm9yZy92MS9iYTdmMzczYWUxNjc" +
"4OWVmZjNhYmZkOTVjYThkM2MxNWQxOGRjOTAwOWFmYTIwNGRjNDNmODVhNTViMWY" +
"2ZWYxL2h0dHAlM0EvL3Rlc3RtYW5pZmVzdC5jb21cIiByZWw9XCJub2ZvbGxvd1w" +
"iPnRlc3RtYW5pZmVzdC5jb208L2E-In0sICJleHAiOiAxMzU4Mzc5MTQ3LCAiaWF" +
"0IjogMTM1ODM3NTU0NywgInR5cCI6ICJtb3ppbGxhL3BheW1lbnRzL3BheS92MSJ" +
"9.kgSt636OSRBezMGtm9QLeDxlEOevL4xcOoDj8VRJyD8";
testGetPaymentRequest(providers, {
jwt: jwt,
ret: true,
error: null,
result: {
type: type,
providerName: providers[type].name
}
});
run_next_test();
});
add_test(function test_empty_jwt() {
testGetPaymentRequest(null, {
jwt: "",
ret: true,
error: "INTERNAL_ERROR_CALL_WITH_MISSING_JWT"
});
run_next_test();
});
add_test(function test_wrong_segments_count() {
// 1 segment JWT
let OneSegJwt = "eyJhbGciOiJIUzI1NiJ9";
testGetPaymentRequest(null, {
jwt: OneSegJwt,
ret: true,
error: "PAY_REQUEST_ERROR_WRONG_SEGMENTS_COUNT"
});
// 2 segments JWT
let TwoSegJwt = "eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiIwNTg2NDkwMTM2NTY2N" +
"zU1ODY2MSIsImF1ZCI6Ikdvb2dsZSIsInR5cCI6Imdvb2dsZS9" +
"wYXltZW50cy9pbmFwcC9pdGVtL3YxIiwiaWF0IjoxMzUyMjIwM" +
"jEyLCJleHAiOjEzNTIzMDY2MTIsInJlcXVlc3QiOnsiY3VycmV" +
"uY3lDb2RlIjoiVVNEIiwicHJpY2UiOiIzLjAwIiwibmFtZSI6I" +
"kdvbGQgU3RhciIsInNlbGxlckRhdGEiOiJzb21lIG9wYXF1ZSB" +
"kYXRhIiwiZGVzY3JpcHRpb24iOiJBIHNoaW5pbmcgYmFkZ2Ugb" +
"2YgZGlzdGluY3Rpb24ifX0";
testGetPaymentRequest(null, {
jwt: TwoSegJwt,
ret: true,
error: "PAY_REQUEST_ERROR_WRONG_SEGMENTS_COUNT"
});
run_next_test();
});
add_test(function test_empty_payload() {
let EmptyPayloadJwt = "eyJhbGciOiJIUzI1NiJ9..eyJpc3MiOiIwNTg2NDkwMTM2NTY2N";
testGetPaymentRequest(null, {
jwt: EmptyPayloadJwt,
ret: true,
error: "PAY_REQUEST_ERROR_EMPTY_PAYLOAD"
});
run_next_test();
});
add_test(function test_missing_typ_parameter() {
// Payload
// {
// "iss": "640ae477-df33-45cd-83b8-6f1f910a6494",
// "iat": 1361203745,
// "request": {
// "description": "detailed description",
// "id": "799db970-7afa-4028-bdb7-8b045eb8babc",
// "postbackURL": "http://inapp-pay-test.farmdev.com/postback",
// "productData": "transaction_id=58",
// "pricePoint": 1,
// "chargebackURL": "http://inapp-pay-test.farmdev.com/chargeback",
// "name": "The Product"
// },
// "aud": "marketplace-dev.allizom.org",
// "exp": 1361207345
// }
let missingTypJwt = "eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9." +
"eyJpc3MiOiAiNjQwYWU0NzctZGYzMy00NWNkLTgzY" +
"jgtNmYxZjkxMGE2NDk0IiwgImlhdCI6IDEzNjEyMD" +
"M3NDUsICJyZXF1ZXN0IjogeyJkZXNjcmlwdGlvbiI" +
"6ICJkZXRhaWxlZCBkZXNjcmlwdGlvbiIsICJpZCI6" +
"ICI3OTlkYjk3MC03YWZhLTQwMjgtYmRiNy04YjA0N" +
"WViOGJhYmMiLCAicG9zdGJhY2tVUkwiOiAiaHR0cD" +
"ovL2luYXBwLXBheS10ZXN0LmZhcm1kZXYuY29tL3B" +
"vc3RiYWNrIiwgInByb2R1Y3REYXRhIjogInRyYW5z" +
"YWN0aW9uX2lkPTU4IiwgInByaWNlUG9pbnQiOiAxL" +
"CAiY2hhcmdlYmFja1VSTCI6ICJodHRwOi8vaW5hcH" +
"AtcGF5LXRlc3QuZmFybWRldi5jb20vY2hhcmdlYmF" +
"jayIsICJuYW1lIjogIlRoZSBQcm9kdWN0In0sICJh" +
"dWQiOiAibWFya2V0cGxhY2UtZGV2LmFsbGl6b20ub" +
"3JnIiwgImV4cCI6IDEzNjEyMDczNDV9.KAHsJX1Hy" +
"fmwNvAckdVUqlpPvdHggpx9yX276TWacRg";
testGetPaymentRequest(null, {
jwt: missingTypJwt,
ret: true,
error: "PAY_REQUEST_ERROR_NO_TYP_PARAMETER"
});
run_next_test();
});
add_test(function test_missing_request_parameter() {
// Payload
// {
// "iss": "Enter you app key here!",
// "iat": 1352225299,
// "typ": "mock/payments/inapp/v1",
// "aud": "mockpayprovider.phpfogapp.com",
// "exp": 1352228899
// }
let missingRequestJwt = "eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9." +
"eyJpc3MiOiAiRW50ZXIgeW91IGFwcCBrZXkgaGVyZ" +
"SEiLCAiaWF0IjogMTM1MjIyNTI5OSwgInR5cCI6IC" +
"Jtb2NrL3BheW1lbnRzL2luYXBwL3YxIiwgImF1ZCI" +
"6ICJtb2NrcGF5cHJvdmlkZXIucGhwZm9nYXBwLmNv" +
"bSIsICJleHAiOiAxMzUyMjI4ODk5fQ.yXGinvZiUs" +
"v9JWvdfM6zPD0iOX9DgCPcIwIbCrL4tcs";
testGetPaymentRequest(null, {
jwt: missingRequestJwt,
ret: true,
error: "PAY_REQUEST_ERROR_NO_REQUEST_PARAMETER"
});
run_next_test();
});
add_test(function test_jwt_decoding_error() {
let wrongJwt = "eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9.^eyJhdWQiOiAibW9" +
"a3BheXByb3ZpZGVyLnBocGZvZ2FwcC5jb20iLCAiaXNzIjogIkVudGVyI" +
"HlvdSBhcHAga2V5IGhlcmUhIiwgInJlcXVlc3QiOiB7Im5hbWUiOiAiUG" +
"llY2Ugb2YgQ2FrZSIsICJwcmljZSI6ICIxMC41MCIsICJwcmljZVRpZXI" +
"iOiAxLCAicHJvZHVjdGRhdGEiOiAidHJhbnNhY3Rpb25faWQ9ODYiLCAi" +
"Y3VycmVuY3lDb2RlIjogIlVTRCIsICJkZXNjcmlwdGlvbiI6ICJWaXJ0d" +
"WFsIGNob2NvbGF0ZSBjYWtlIHRvIGZpbGwgeW91ciB2aXJ0dWFsIHR1bW" +
"15In0sICJleHAiOiAxMzUyMjMyNzkyLCAiaWF0IjogMTM1MjIyOTE5Miw" +
"gInR5cCI6ICJtb2NrL3BheW1lbnRzL2luYXBwL3YxIn0.QZxc62USCy4U" +
"IyKIC1TKelVhNklvk-Ou1l_daKntaFI";
testGetPaymentRequest(null, {
jwt: wrongJwt,
ret: true,
error: "PAY_REQUEST_ERROR_ERROR_DECODING_JWT"
});
run_next_test();
});
add_test(function test_non_https_provider() {
let providers = {};
let type = "mock/payments/inapp/v1";
providers[type] = {
name: "mockprovider",
description: "Mock Payment Provider",
uri: "http://mockpayprovider.phpfogapp.com/?req=",
requestMethod: "GET"
};
// Payload
// {
// "aud": "mockpayprovider.phpfogapp.com",
// "iss": "Enter you app key here!",
// "request": {
// "name": "Piece of Cake",
// "price": "10.50",
// "priceTier": 1,
// "productdata": "transaction_id=86",
// "currencyCode": "USD",
// "description": "Virtual chocolate cake to fill your virtual tummy"
// },
// "exp": 1352232792,
// "iat": 1352229192,
// "typ": "mock/payments/inapp/v1"
// }
let jwt = "eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9.eyJhdWQiOiAibW9j" +
"a3BheXByb3ZpZGVyLnBocGZvZ2FwcC5jb20iLCAiaXNzIjogIkVudGVyI" +
"HlvdSBhcHAga2V5IGhlcmUhIiwgInJlcXVlc3QiOiB7Im5hbWUiOiAiUG" +
"llY2Ugb2YgQ2FrZSIsICJwcmljZSI6ICIxMC41MCIsICJwcmljZVRpZXI" +
"iOiAxLCAicHJvZHVjdGRhdGEiOiAidHJhbnNhY3Rpb25faWQ9ODYiLCAi" +
"Y3VycmVuY3lDb2RlIjogIlVTRCIsICJkZXNjcmlwdGlvbiI6ICJWaXJ0d" +
"WFsIGNob2NvbGF0ZSBjYWtlIHRvIGZpbGwgeW91ciB2aXJ0dWFsIHR1bW" +
"15In0sICJleHAiOiAxMzUyMjMyNzkyLCAiaWF0IjogMTM1MjIyOTE5Miw" +
"gInR5cCI6ICJtb2NrL3BheW1lbnRzL2luYXBwL3YxIn0.QZxc62USCy4U" +
"IyKIC1TKelVhNklvk-Ou1l_daKntaFI";
testGetPaymentRequest(providers, {
jwt: jwt,
ret: true,
error: "INTERNAL_ERROR_NON_HTTPS_PROVIDER_URI"
});
run_next_test();
});

Просмотреть файл

@ -0,0 +1,5 @@
[DEFAULT]
head = header_helper.js
tail =
[test_paymanager_get_payment_request.js]

Просмотреть файл

@ -1621,7 +1621,7 @@ NPObjWrapper_NewResolve(JSContext *cx, JSHandleObject obj, JSHandleId id, unsign
NS_ASSERTION(JSID_IS_STRING(id) || JSID_IS_INT(id),
"id must be either string or int!\n");
if (!::JS_DefinePropertyById(cx, obj, id, JSVAL_VOID, nullptr,
nullptr, JSPROP_ENUMERATE)) {
nullptr, JSPROP_ENUMERATE | JSPROP_SHARED)) {
return JS_FALSE;
}

Просмотреть файл

@ -78,7 +78,10 @@ const RIL_IPC_MSG_NAMES = [
"RIL:SetCallForwardingOption",
"RIL:GetCallForwardingOption",
"RIL:CellBroadcastReceived",
"RIL:CfStateChanged"
"RIL:CfStateChanged",
"RIL:IccOpenChannel",
"RIL:IccCloseChannel",
"RIL:IccExchangeAPDU"
];
const kVoiceChangedTopic = "mobile-connection-voice-changed";
@ -611,6 +614,54 @@ RILContentHelper.prototype = {
cpmm.sendAsyncMessage("RIL:SendStkEventDownload", {event: event});
},
iccOpenChannel: function iccOpenChannel(window,
aid) {
if (window == null) {
throw Components.Exception("Can't get window object",
Cr.NS_ERROR_UNEXPECTED);
}
let request = Services.DOMRequest.createRequest(window);
let requestId = this.getRequestId(request);
cpmm.sendAsyncMessage("RIL:IccOpenChannel", {requestId: requestId,
aid: aid});
return request;
},
iccExchangeAPDU: function iccExchangeAPDU(window,
channel,
apdu) {
if (window == null) {
throw Components.Exception("Can't get window object",
Cr.NS_ERROR_UNEXPECTED);
}
let request = Services.DOMRequest.createRequest(window);
let requestId = this.getRequestId(request);
//Potentially you need serialization here and can't pass the jsval through
cpmm.sendAsyncMessage("RIL:IccExchangeAPDU", {requestId: requestId,
channel: channel,
apdu: apdu});
return request;
},
iccCloseChannel: function iccCloseChannel(window,
channel) {
if (window == null) {
throw Components.Exception("Can't get window object",
Cr.NS_ERROR_UNEXPECTED);
}
let request = Services.DOMRequest.createRequest(window);
let requestId = this.getRequestId(request);
cpmm.sendAsyncMessage("RIL:IccCloseChannel", {requestId: requestId,
channel: channel});
return request;
},
getCallForwardingOption: function getCallForwardingOption(window, reason) {
if (window == null) {
throw Components.Exception("Can't get window object",
@ -988,6 +1039,15 @@ RILContentHelper.prototype = {
case "RIL:StkSessionEnd":
Services.obs.notifyObservers(null, kStkSessionEndTopic, null);
break;
case "RIL:IccOpenChannel":
this.handleIccOpenChannel(msg.json);
break;
case "RIL:IccCloseChannel":
this.handleIccCloseChannel(msg.json);
break;
case "RIL:IccExchangeAPDU":
this.handleIccExchangeAPDU(msg.json);
break;
case "RIL:DataError":
this.updateConnectionInfo(msg.json, this.rilContext.dataConnectionInfo);
Services.obs.notifyObservers(null, kDataErrorTopic, msg.json.error);
@ -1075,6 +1135,31 @@ RILContentHelper.prototype = {
}
},
handleIccOpenChannel: function handleIccOpenChannel(message) {
if (message.error) {
this.fireRequestError(message.requestId, message.error);
} else {
this.fireRequestSuccess(message.requestId, message.channel);
}
},
handleIccCloseChannel: function handleIccCloseChannel(message) {
if (message.error) {
this.fireRequestError(message.requestId, message.error);
} else {
this.fireRequestSuccess(message.requestId, null);
}
},
handleIccExchangeAPDU: function handleIccExchangeAPDU(message) {
if (message.error) {
this.fireRequestError(message.requestId, message.error);
} else {
var result = [message.sw1, message.sw2, message.simResponse];
this.fireRequestSuccess(message.requestId, result);
}
},
handleVoicemailNotification: function handleVoicemailNotification(message) {
let changed = false;
if (!this.voicemailStatus) {

Просмотреть файл

@ -96,6 +96,9 @@ const RIL_IPC_MOBILECONNECTION_MSG_NAMES = [
"RIL:SendStkMenuSelection",
"RIL:SendStkTimerExpiration",
"RIL:SendStkEventDownload",
"RIL:IccOpenChannel",
"RIL:IccExchangeAPDU",
"RIL:IccCloseChannel",
"RIL:RegisterMobileConnectionMsg",
"RIL:SetCallForwardingOption",
"RIL:GetCallForwardingOption"
@ -493,6 +496,18 @@ RadioInterfaceLayer.prototype = {
case "RIL:SendStkEventDownload":
this.sendStkEventDownload(msg.json);
break;
case "RIL:IccOpenChannel":
this.saveRequestTarget(msg);
this.iccOpenChannel(msg.json);
break;
case "RIL:IccCloseChannel":
this.saveRequestTarget(msg);
this.iccCloseChannel(msg.json);
break;
case "RIL:IccExchangeAPDU":
this.saveRequestTarget(msg);
this.iccExchangeAPDU(msg.json);
break;
case "RIL:RegisterMobileConnectionMsg":
this.registerMessageTarget("mobileconnection", msg.target);
break;
@ -551,6 +566,15 @@ RadioInterfaceLayer.prototype = {
case "callError":
this.handleCallError(message);
break;
case "iccOpenChannel":
this.handleIccOpenChannel(message);
break;
case "iccCloseChannel":
this.handleIccCloseChannel(message);
break;
case "iccExchangeAPDU":
this.handleIccExchangeAPDU(message);
break;
case "getAvailableNetworks":
this.handleGetAvailableNetworks(message);
break;
@ -1364,6 +1388,30 @@ RadioInterfaceLayer.prototype = {
this._sendRequestResults("RIL:EnumerateCalls", options);
},
/**
* Open Logical UICC channel (aid) for Secure Element access
*/
handleIccOpenChannel: function handleIccOpenChannel(message) {
debug("handleIccOpenChannel: " + JSON.stringify(message));
this._sendRequestResults("RIL:IccOpenChannel", message);
},
/**
* Close Logical UICC channel
*/
handleIccCloseChannel: function handleIccCloseChannel(message) {
debug("handleIccCloseChannel: " + JSON.stringify(message));
this._sendRequestResults("RIL:IccCloseChannel", message);
},
/**
* Exchange APDU data on an open Logical UICC channel
*/
handleIccExchangeAPDU: function handleIccExchangeAPDU(message) {
debug("handleIccExchangeAPDU: " + JSON.stringify(message));
this._sendRequestResults("RIL:IccExchangeAPDU", message);
},
/**
* Handle available networks returned by the 'getAvailableNetworks' request.
*/
@ -2098,6 +2146,24 @@ RadioInterfaceLayer.prototype = {
this.worker.postMessage(message);
},
iccOpenChannel: function iccOpenChannel(message) {
debug("ICC Open Channel");
message.rilMessageType = "iccOpenChannel";
this.worker.postMessage(message);
},
iccCloseChannel: function iccCloseChannel(message) {
debug("ICC Close Channel");
message.rilMessageType = "iccCloseChannel";
this.worker.postMessage(message);
},
iccExchangeAPDU: function iccExchangeAPDU(message) {
debug("ICC Exchange APDU");
message.rilMessageType = "iccExchangeAPDU";
this.worker.postMessage(message);
},
setCallForwardingOption: function setCallForwardingOption(message) {
debug("setCallForwardingOption: " + JSON.stringify(message));
message.rilMessageType = "setCallForward";

Просмотреть файл

@ -149,6 +149,11 @@ this.REQUEST_MODIFY_QOS = 118;
this.REQUEST_SUSPEND_QOS = 119;
this.REQUEST_RESUME_QOS = 120;
// UICC Secure Access
this.REQUEST_SIM_OPEN_CHANNEL = 121;
this.REQUEST_SIM_CLOSE_CHANNEL = 122;
this.REQUEST_SIM_ACCESS_CHANNEL = 123;
this.RESPONSE_TYPE_SOLICITED = 0;
this.RESPONSE_TYPE_UNSOLICITED = 1;

Просмотреть файл

@ -1470,6 +1470,70 @@ let RIL = {
Buf.simpleRequest(REQUEST_SET_NETWORK_SELECTION_AUTOMATIC, options);
},
/**
* Open Logical UICC channel (aid) for Secure Element access
*/
iccOpenChannel: function iccOpenChannel(options) {
if (DEBUG) {
debug("iccOpenChannel: " + JSON.stringify(options));
}
let token = Buf.newParcel(REQUEST_SIM_OPEN_CHANNEL, options);
Buf.writeString(options.aid);
Buf.sendParcel();
},
/**
* Exchange APDU data on an open Logical UICC channel
*/
iccExchangeAPDU: function iccExchangeAPDU(options) {
if (DEBUG) debug("iccExchangeAPDU: " + JSON.stringify(options));
var cla = options.apdu.cla;
var command = options.apdu.command;
var channel = options.channel;
var path = options.apdu.path;
var data = options.apdu.data;
var data2 = options.apdu.data2;
if (path == null || path === undefined) {
var path = "";
}
if (data == null || data === undefined) {
var data = "";
}
if (data2 == null || data2 === undefined) {
var data2 = "";
}
var p1 = options.apdu.p1;
var p2 = options.apdu.p2;
var p3 = options.apdu.p3; // Extra
Buf.newParcel(REQUEST_SIM_ACCESS_CHANNEL, options);
Buf.writeUint32(cla);
Buf.writeUint32(command);
Buf.writeUint32(channel);
Buf.writeString(path); // path
Buf.writeUint32(p1);
Buf.writeUint32(p2);
Buf.writeUint32(p3);
Buf.writeString(data); // generic data field.
Buf.writeString(data2);
Buf.sendParcel();
},
/**
* Close Logical UICC channel
*/
iccCloseChannel: function iccCloseChannel(options) {
if (DEBUG) debug("iccCloseChannel: " + JSON.stringify(options));
Buf.newParcel(REQUEST_SIM_CLOSE_CHANNEL, options);
Buf.writeUint32(1);
Buf.writeUint32(options.channel);
Buf.sendParcel();
},
/**
* Tell the radio to choose a specific voice/data network
*/
@ -4690,6 +4754,42 @@ RIL[REQUEST_SET_FACILITY_LOCK] = function REQUEST_SET_FACILITY_LOCK(length, opti
this.sendDOMMessage(options);
};
RIL[REQUEST_CHANGE_BARRING_PASSWORD] = null;
RIL[REQUEST_SIM_OPEN_CHANNEL] = function REQUEST_SIM_OPEN_CHANNEL(length, options) {
if (options.rilRequestError) {
options.error = RIL_ERROR_TO_GECKO_ERROR[options.rilRequestError];
this.sendDOMMessage(options);
return;
}
options.channel = Buf.readUint32();
if (DEBUG) debug("Setting channel number in options: " + options.channel);
this.sendDOMMessage(options);
};
RIL[REQUEST_SIM_CLOSE_CHANNEL] = function REQUEST_SIM_CLOSE_CHANNEL(length, options) {
if (options.rilRequestError) {
options.error = RIL_ERROR_TO_GECKO_ERROR[options.rilRequestError];
this.sendDOMMessage(options);
return;
}
// No return value
this.sendDOMMessage(options);
};
RIL[REQUEST_SIM_ACCESS_CHANNEL] = function REQUEST_SIM_ACCESS_CHANNEL(length, options) {
if (options.rilRequestError) {
options.error = RIL_ERROR_TO_GECKO_ERROR[options.rilRequestError];
this.sendDOMMessage(options);
}
options.sw1 = Buf.readUint32();
options.sw2 = Buf.readUint32();
options.simResponse = Buf.readString();
if (DEBUG) {
debug("Setting return values for RIL[REQUEST_SIM_ACCESS_CHANNEL]: ["
+ options.sw1 + "," + options.sw2 + ", " + options.simResponse + "]");
}
this.sendDOMMessage(options);
};
RIL[REQUEST_QUERY_NETWORK_SELECTION_MODE] = function REQUEST_QUERY_NETWORK_SELECTION_MODE(length, options) {
this._receivedNetworkInfo(NETWORK_INFO_NETWORK_SELECTION_MODE);

Просмотреть файл

@ -27,6 +27,7 @@
#include "nsString.h"
#include "nsCRT.h"
#include "nspr.h"
#include "nsXULAppAPI.h"
extern PRLogModuleInfo *MCD;
@ -242,12 +243,12 @@ nsresult nsReadConfig::openAndEvaluateJSFile(const char *aFileName, int32_t obsc
nsCOMPtr<nsIInputStream> inStr;
if (isBinDir) {
nsCOMPtr<nsIFile> jsFile;
rv = NS_GetSpecialDirectory(NS_XPCOM_CURRENT_PROCESS_DIR,
rv = NS_GetSpecialDirectory(XRE_EXECUTABLE_FILE,
getter_AddRefs(jsFile));
if (NS_FAILED(rv))
return rv;
rv = jsFile->AppendNative(nsDependentCString(aFileName));
rv = jsFile->SetNativeLeafName(nsDependentCString(aFileName));
if (NS_FAILED(rv))
return rv;

Просмотреть файл

@ -14,7 +14,7 @@ interface imgIRequest;
[ptr] native nsIntRect(nsIntRect);
[scriptable, builtinclass, uuid(90b3d21c-317d-4d96-93c0-12add64a26bf)]
[scriptable, builtinclass, uuid(ac65c702-7771-4f6d-b18b-1c7d806ce3c1)]
interface imgINotificationObserver : nsISupports
{
const long SIZE_AVAILABLE = 1;
@ -23,7 +23,8 @@ interface imgINotificationObserver : nsISupports
const long LOAD_COMPLETE = 4;
const long DECODE_COMPLETE = 5;
const long DISCARD = 6;
const long IS_ANIMATED = 7;
const long UNLOCKED_DRAW = 7;
const long IS_ANIMATED = 8;
[noscript] void notify(in imgIRequest aProxy, in long aType, [const] in nsIntRect aRect);
};

Просмотреть файл

@ -3107,6 +3107,15 @@ RasterImage::Draw(gfxContext *aContext,
DiscardTracker::Reset(&mDiscardTrackerNode);
}
// We would like to just check if we have a zero lock count, but we can't do
// that for animated images because in EnsureAnimExists we lock the image and
// never unlock so that animated images always have their lock count >= 1. In
// that case we use our animation consumers count as a proxy for lock count.
if (mLockCount == 0 || (mAnim && mAnimationConsumers == 0)) {
if (mStatusTracker)
mStatusTracker->GetDecoderObserver()->OnUnlockedDraw();
}
// We use !mDecoded && mHasSourceData to mean discarded.
if (!mDecoded && mHasSourceData) {
mDrawStartTime = TimeStamp::Now();

Просмотреть файл

@ -109,6 +109,11 @@ public:
* image will initiate a new series of progressive decode notifications.
*/
virtual void OnDiscard() = 0;
/**
* Called when we are asked to Draw an image that is not locked.
*/
virtual void OnUnlockedDraw() = 0;
};
// We must define a destructor because derived classes call our destructor from

Просмотреть файл

@ -767,6 +767,17 @@ void imgRequestProxy::OnDiscard()
}
}
void imgRequestProxy::OnUnlockedDraw()
{
LOG_FUNC(GetImgLog(), "imgRequestProxy::OnUnlockedDraw");
if (mListener && !mCanceled) {
// Hold a ref to the listener while we call it, just in case.
nsCOMPtr<imgINotificationObserver> kungFuDeathGrip(mListener);
mListener->Notify(this, imgINotificationObserver::UNLOCKED_DRAW, nullptr);
}
}
void imgRequestProxy::OnImageIsAnimated()
{
LOG_FUNC(GetImgLog(), "imgRequestProxy::OnImageIsAnimated");

Просмотреть файл

@ -143,6 +143,7 @@ protected:
void OnStopFrame ();
void OnStopDecode ();
void OnDiscard ();
void OnUnlockedDraw ();
void OnImageIsAnimated ();
/* non-virtual sort-of-nsIRequestObserver methods */

Просмотреть файл

@ -165,6 +165,18 @@ public:
}
}
virtual void OnUnlockedDraw()
{
NS_ABORT_IF_FALSE(mTracker->GetImage(),
"OnUnlockedDraw callback before we've created our image");
mTracker->RecordUnlockedDraw();
nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(mTracker->mConsumers);
while (iter.HasMore()) {
mTracker->SendUnlockedDraw(iter.GetNext());
}
}
virtual void OnImageIsAnimated()
{
NS_ABORT_IF_FALSE(mTracker->GetImage(),
@ -568,6 +580,13 @@ imgStatusTracker::RecordDiscard()
mImageStatus &= ~statusBitsToClear;
}
void
imgStatusTracker::RecordUnlockedDraw()
{
NS_ABORT_IF_FALSE(mImage,
"RecordUnlockedDraw called before we have an Image");
}
void
imgStatusTracker::SendImageIsAnimated(imgRequestProxy* aProxy)
{
@ -593,6 +612,13 @@ imgStatusTracker::SendDiscard(imgRequestProxy* aProxy)
aProxy->OnDiscard();
}
void
imgStatusTracker::SendUnlockedDraw(imgRequestProxy* aProxy)
{
if (!aProxy->NotificationsDeferred())
aProxy->OnUnlockedDraw();
}
void
imgStatusTracker::RecordFrameChanged(const nsIntRect* aDirtyRect)
{

Просмотреть файл

@ -145,6 +145,8 @@ public:
void SendStopDecode(imgRequestProxy* aProxy, nsresult aStatus);
void RecordDiscard();
void SendDiscard(imgRequestProxy* aProxy);
void RecordUnlockedDraw();
void SendUnlockedDraw(imgRequestProxy* aProxy);
void RecordImageIsAnimated();
void SendImageIsAnimated(imgRequestProxy *aProxy);

Просмотреть файл

@ -479,10 +479,19 @@ class Vector : private AllocPolicy
void replaceRawBuffer(T *p, size_t length);
/*
* Places |val| at position |p|, shifting existing elements
* from |p| onward one position higher.
* Places |val| at position |p|, shifting existing elements from |p|
* onward one position higher. On success, |p| should not be reused
* because it will be a dangling pointer if reallocation of the vector
* storage occurred; the return value should be used instead. On failure,
* NULL is returned.
*
* Example usage:
*
* if (!(p = vec.insert(p, val)))
* <handle failure>
* <keep working with p>
*/
bool insert(T *p, const T &val);
T *insert(T *p, const T &val);
/*
* Removes the element |t|, which must fall in the bounds [begin, end),
@ -863,24 +872,25 @@ Vector<T,N,AP>::internalAppendN(const T &t, size_t needed)
}
template <class T, size_t N, class AP>
inline bool
inline T *
Vector<T,N,AP>::insert(T *p, const T &val)
{
JS_ASSERT(begin() <= p && p <= end());
size_t pos = p - begin();
JS_ASSERT(pos <= mLength);
size_t oldLength = mLength;
if (pos == oldLength)
return append(val);
{
if (pos == oldLength) {
if (!append(val))
return NULL;
} else {
T oldBack = back();
if (!append(oldBack)) /* Dup the last element. */
return false;
return NULL;
for (size_t i = oldLength; i > pos; --i)
(*this)[i] = (*this)[i - 1];
(*this)[pos] = val;
}
for (size_t i = oldLength; i > pos; --i)
(*this)[i] = (*this)[i - 1];
(*this)[pos] = val;
return true;
return begin() + pos;
}
template<typename T, size_t N, class AP>

Просмотреть файл

@ -46,14 +46,6 @@
#include "frontend/SharedContext-inl.h"
#include "vm/Shape-inl.h"
/* Allocation chunk counts, must be powers of two in general. */
#define BYTECODE_CHUNK_LENGTH 1024 /* initial bytecode chunk length */
#define SRCNOTE_CHUNK_LENGTH 1024 /* initial srcnote chunk length */
/* Macros to compute byte sizes from typed element counts. */
#define BYTECODE_SIZE(n) ((n) * sizeof(jsbytecode))
#define SRCNOTE_SIZE(n) ((n) * sizeof(jssrcnote))
using namespace js;
using namespace js::gc;
using namespace js::frontend;
@ -100,12 +92,16 @@ BytecodeEmitter::BytecodeEmitter(BytecodeEmitter *parent, Parser *parser, Shared
: sc(sc),
parent(parent),
script(sc->context, script),
prolog(sc->context, lineno),
main(sc->context, lineno),
current(&main),
parser(parser),
evalCaller(evalCaller),
topStmt(NULL),
topScopeStmt(NULL),
blockChain(sc->context),
atomIndices(sc->context),
firstLine(lineno),
stackDepth(0), maxStackDepth(0),
tryNoteList(sc->context),
arrayCompDepth(0),
@ -118,10 +114,6 @@ BytecodeEmitter::BytecodeEmitter(BytecodeEmitter *parent, Parser *parser, Shared
hasGlobalScope(hasGlobalScope),
selfHostingMode(selfHostingMode)
{
memset(&prolog, 0, sizeof prolog);
memset(&main, 0, sizeof main);
current = &main;
firstLine = prolog.currentLine = main.currentLine = lineno;
}
bool
@ -132,45 +124,17 @@ BytecodeEmitter::init()
BytecodeEmitter::~BytecodeEmitter()
{
js_free(prolog.base);
js_free(prolog.notes);
js_free(main.base);
js_free(main.notes);
}
static ptrdiff_t
EmitCheck(JSContext *cx, BytecodeEmitter *bce, ptrdiff_t delta)
{
jsbytecode *base = bce->base();
jsbytecode *newbase;
jsbytecode *next = bce->next();
jsbytecode *limit = bce->limit();
ptrdiff_t offset = next - base;
size_t minlength = offset + delta;
ptrdiff_t offset = bce->code().length();
if (next + delta > limit) {
size_t newlength;
if (!base) {
JS_ASSERT(!next && !limit);
newlength = BYTECODE_CHUNK_LENGTH;
if (newlength < minlength) /* make it bigger if necessary */
newlength = RoundUpPow2(minlength);
newbase = (jsbytecode *) cx->malloc_(BYTECODE_SIZE(newlength));
} else {
JS_ASSERT(base <= next && next <= limit);
newlength = (limit - base) * 2;
if (newlength < minlength) /* make it bigger if necessary */
newlength = RoundUpPow2(minlength);
newbase = (jsbytecode *) cx->realloc_(base, BYTECODE_SIZE(newlength));
}
if (!newbase) {
js_ReportOutOfMemory(cx);
return -1;
}
JS_ASSERT(newlength >= size_t(offset + delta));
bce->current->base = newbase;
bce->current->limit = newbase + newlength;
bce->current->next = newbase + offset;
jsbytecode dummy = 0;
if (!bce->code().appendN(dummy, delta)) {
js_ReportOutOfMemory(cx);
return -1;
}
return offset;
}
@ -190,7 +154,6 @@ UpdateDepth(JSContext *cx, BytecodeEmitter *bce, ptrdiff_t target)
JSOp op = (JSOp) *pc;
const JSCodeSpec *cs = &js_CodeSpec[op];
if (cs->format & JOF_TMPSLOT_MASK) {
/*
* An opcode may temporarily consume stack space during execution.
@ -239,11 +202,12 @@ ptrdiff_t
frontend::Emit1(JSContext *cx, BytecodeEmitter *bce, JSOp op)
{
ptrdiff_t offset = EmitCheck(cx, bce, 1);
if (offset < 0)
return -1;
if (offset >= 0) {
*bce->current->next++ = (jsbytecode)op;
UpdateDepth(cx, bce, offset);
}
jsbytecode *code = bce->code(offset);
code[0] = jsbytecode(op);
UpdateDepth(cx, bce, offset);
return offset;
}
@ -251,14 +215,13 @@ ptrdiff_t
frontend::Emit2(JSContext *cx, BytecodeEmitter *bce, JSOp op, jsbytecode op1)
{
ptrdiff_t offset = EmitCheck(cx, bce, 2);
if (offset < 0)
return -1;
if (offset >= 0) {
jsbytecode *next = bce->next();
next[0] = (jsbytecode)op;
next[1] = op1;
bce->current->next = next + 2;
UpdateDepth(cx, bce, offset);
}
jsbytecode *code = bce->code(offset);
code[0] = jsbytecode(op);
code[1] = op1;
UpdateDepth(cx, bce, offset);
return offset;
}
@ -271,15 +234,14 @@ frontend::Emit3(JSContext *cx, BytecodeEmitter *bce, JSOp op, jsbytecode op1,
JS_ASSERT(!IsLocalOp(op));
ptrdiff_t offset = EmitCheck(cx, bce, 3);
if (offset < 0)
return -1;
if (offset >= 0) {
jsbytecode *next = bce->next();
next[0] = (jsbytecode)op;
next[1] = op1;
next[2] = op2;
bce->current->next = next + 3;
UpdateDepth(cx, bce, offset);
}
jsbytecode *code = bce->code(offset);
code[0] = jsbytecode(op);
code[1] = op1;
code[2] = op2;
UpdateDepth(cx, bce, offset);
return offset;
}
@ -288,20 +250,20 @@ frontend::EmitN(JSContext *cx, BytecodeEmitter *bce, JSOp op, size_t extra)
{
ptrdiff_t length = 1 + (ptrdiff_t)extra;
ptrdiff_t offset = EmitCheck(cx, bce, length);
if (offset < 0)
return -1;
if (offset >= 0) {
jsbytecode *next = bce->next();
*next = (jsbytecode)op;
memset(next + 1, 0, BYTECODE_SIZE(extra));
bce->current->next = next + length;
jsbytecode *code = bce->code(offset);
code[0] = jsbytecode(op);
/* The remaining |extra| bytes are set by the caller */
/*
* Don't UpdateDepth if op's use-count comes from the immediate
* operand yet to be stored in the extra bytes after op.
*/
if (js_CodeSpec[op].nuses >= 0)
UpdateDepth(cx, bce, offset);
/*
* Don't UpdateDepth if op's use-count comes from the immediate
* operand yet to be stored in the extra bytes after op.
*/
if (js_CodeSpec[op].nuses >= 0)
UpdateDepth(cx, bce, offset);
}
return offset;
}
@ -309,14 +271,13 @@ static ptrdiff_t
EmitJump(JSContext *cx, BytecodeEmitter *bce, JSOp op, ptrdiff_t off)
{
ptrdiff_t offset = EmitCheck(cx, bce, 5);
if (offset < 0)
return -1;
if (offset >= 0) {
jsbytecode *next = bce->next();
next[0] = (jsbytecode)op;
SET_JUMP_OFFSET(next, off);
bce->current->next = next + 5;
UpdateDepth(cx, bce, offset);
}
jsbytecode *code = bce->code(offset);
code[0] = jsbytecode(op);
SET_JUMP_OFFSET(code, off);
UpdateDepth(cx, bce, offset);
return offset;
}
@ -714,7 +675,7 @@ PopStatementBCE(JSContext *cx, BytecodeEmitter *bce)
{
StmtInfoBCE *stmt = bce->topStmt;
if (!stmt->isTrying() &&
(!BackPatch(cx, bce, stmt->breaks, bce->next(), JSOP_GOTO) ||
(!BackPatch(cx, bce, stmt->breaks, bce->code().end(), JSOP_GOTO) ||
!BackPatch(cx, bce, stmt->continues, bce->code(stmt->update), JSOP_GOTO)))
{
return false;
@ -732,10 +693,9 @@ EmitIndex32(JSContext *cx, JSOp op, uint32_t index, BytecodeEmitter *bce)
if (offset < 0)
return false;
jsbytecode *next = bce->next();
next[0] = jsbytecode(op);
SET_UINT32_INDEX(next, index);
bce->current->next = next + len;
jsbytecode *code = bce->code(offset);
code[0] = jsbytecode(op);
SET_UINT32_INDEX(code, index);
UpdateDepth(cx, bce, offset);
CheckTypeSet(cx, bce, op);
return true;
@ -750,10 +710,9 @@ EmitIndexOp(JSContext *cx, JSOp op, uint32_t index, BytecodeEmitter *bce)
if (offset < 0)
return false;
jsbytecode *next = bce->next();
next[0] = jsbytecode(op);
SET_UINT32_INDEX(next, index);
bce->current->next = next + len;
jsbytecode *code = bce->code(offset);
code[0] = jsbytecode(op);
SET_UINT32_INDEX(code, index);
UpdateDepth(cx, bce, offset);
CheckTypeSet(cx, bce, op);
return true;
@ -799,10 +758,9 @@ EmitAtomIncDec(JSContext *cx, JSAtom *atom, JSOp op, BytecodeEmitter *bce)
if (offset < 0)
return false;
jsbytecode *next = bce->next();
next[0] = jsbytecode(op);
SET_UINT32_INDEX(next, index);
bce->current->next = next + len;
jsbytecode *code = bce->code(offset);
code[0] = jsbytecode(op);
SET_UINT32_INDEX(code, index);
UpdateDepth(cx, bce, offset);
CheckTypeSet(cx, bce, op);
return true;
@ -2370,10 +2328,10 @@ EmitSwitch(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
unsigned noteCount, noteCountDelta;
/* Switch note's second offset is to first JSOP_CASE. */
noteCount = bce->noteCount();
noteCount = bce->notes().length();
if (!SetSrcNoteOffset(cx, bce, (unsigned)noteIndex, 1, off - top))
return false;
noteCountDelta = bce->noteCount() - noteCount;
noteCountDelta = bce->notes().length() - noteCount;
if (noteCountDelta != 0)
caseNoteIndex += noteCountDelta;
beforeCases = false;
@ -2506,7 +2464,7 @@ frontend::EmitFunctionScript(JSContext *cx, BytecodeEmitter *bce, ParseNode *bod
FunctionBox *funbox = bce->sc->asFunctionBox();
if (funbox->argumentsHasLocalBinding()) {
JS_ASSERT(bce->next() == bce->base()); /* See JSScript::argumentsBytecode. */
JS_ASSERT(bce->offset() == 0); /* See JSScript::argumentsBytecode. */
bce->switchToProlog();
if (Emit1(cx, bce, JSOP_ARGUMENTS) < 0)
return false;
@ -3422,13 +3380,12 @@ EmitNewInit(JSContext *cx, BytecodeEmitter *bce, JSProtoKey key, ParseNode *pn)
if (offset < 0)
return false;
jsbytecode *next = bce->next();
next[0] = JSOP_NEWINIT;
next[1] = jsbytecode(key);
next[2] = 0;
next[3] = 0;
next[4] = 0;
bce->current->next = next + len;
jsbytecode *code = bce->code(offset);
code[0] = JSOP_NEWINIT;
code[1] = jsbytecode(key);
code[2] = 0;
code[3] = 0;
code[4] = 0;
UpdateDepth(cx, bce, offset);
CheckTypeSet(cx, bce, JSOP_NEWINIT);
return true;
@ -3808,7 +3765,7 @@ EmitTry(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
* Fix up the gosubs that might have been emitted before non-local
* jumps to the finally code.
*/
if (!BackPatch(cx, bce, stmtInfo.gosubs(), bce->next(), JSOP_GOSUB))
if (!BackPatch(cx, bce, stmtInfo.gosubs(), bce->code().end(), JSOP_GOSUB))
return false;
finallyStart = bce->offset();
@ -3833,7 +3790,7 @@ EmitTry(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
return false;
/* Fix up the end-of-try/catch jumps to come here. */
if (!BackPatch(cx, bce, catchJump, bce->next(), JSOP_GOTO))
if (!BackPatch(cx, bce, catchJump, bce->code().end(), JSOP_GOTO))
return false;
/*
@ -4653,7 +4610,7 @@ EmitReturn(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
if (!EmitNonLocalJumpFixup(cx, bce, NULL))
return false;
if (top + JSOP_RETURN_LENGTH != bce->offset()) {
bce->base()[top] = JSOP_SETRVAL;
bce->code()[top] = JSOP_SETRVAL;
if (Emit1(cx, bce, JSOP_RETRVAL) < 0)
return false;
}
@ -5231,7 +5188,7 @@ EmitObject(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
* ignore setters and to avoid dup'ing and popping the object as each
* property is added, as JSOP_SETELEM/JSOP_SETPROP would do.
*/
ptrdiff_t offset = bce->next() - bce->base();
ptrdiff_t offset = bce->offset();
if (!EmitNewInit(cx, bce, JSProto_Object, pn))
return false;
@ -5905,78 +5862,51 @@ frontend::EmitTree(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
}
static int
AllocSrcNote(JSContext *cx, BytecodeEmitter *bce)
AllocSrcNote(JSContext *cx, SrcNotesVector &notes)
{
jssrcnote *notes = bce->notes();
jssrcnote *newnotes;
unsigned index = bce->noteCount();
unsigned max = bce->noteLimit();
if (index == max) {
size_t newlength;
if (!notes) {
JS_ASSERT(!index && !max);
newlength = SRCNOTE_CHUNK_LENGTH;
newnotes = (jssrcnote *) cx->malloc_(SRCNOTE_SIZE(newlength));
} else {
JS_ASSERT(index <= max);
newlength = max * 2;
newnotes = (jssrcnote *) cx->realloc_(notes, SRCNOTE_SIZE(newlength));
}
if (!newnotes) {
js_ReportOutOfMemory(cx);
return -1;
}
bce->current->notes = newnotes;
bce->current->noteLimit = newlength;
jssrcnote dummy = 0;
if (!notes.append(dummy)) {
js_ReportOutOfMemory(cx);
return -1;
}
bce->current->noteCount = index + 1;
return (int)index;
return notes.length() - 1;
}
int
frontend::NewSrcNote(JSContext *cx, BytecodeEmitter *bce, SrcNoteType type)
{
int index, n;
jssrcnote *sn;
ptrdiff_t offset, delta, xdelta;
SrcNotesVector &notes = bce->notes();
int index;
/*
* Claim a note slot in bce->notes() by growing it if necessary and then
* incrementing bce->noteCount().
*/
index = AllocSrcNote(cx, bce);
index = AllocSrcNote(cx, notes);
if (index < 0)
return -1;
sn = &bce->notes()[index];
/*
* Compute delta from the last annotated bytecode's offset. If it's too
* big to fit in sn, allocate one or more xdelta notes and reset sn.
*/
offset = bce->offset();
delta = offset - bce->lastNoteOffset();
ptrdiff_t offset = bce->offset();
ptrdiff_t delta = offset - bce->lastNoteOffset();
bce->current->lastNoteOffset = offset;
if (delta >= SN_DELTA_LIMIT) {
do {
xdelta = Min(delta, SN_XDELTA_MASK);
SN_MAKE_XDELTA(sn, xdelta);
ptrdiff_t xdelta = Min(delta, SN_XDELTA_MASK);
SN_MAKE_XDELTA(&notes[index], xdelta);
delta -= xdelta;
index = AllocSrcNote(cx, bce);
index = AllocSrcNote(cx, notes);
if (index < 0)
return -1;
sn = &bce->notes()[index];
} while (delta >= SN_DELTA_LIMIT);
}
/*
* Initialize type and delta, then allocate the minimum number of notes
* needed for type's arity. Usually, we won't need more, but if an offset
* does take two bytes, SetSrcNoteOffset will grow bce->notes().
* does take two bytes, SetSrcNoteOffset will grow notes.
*/
SN_MAKE_NOTE(sn, type, delta);
for (n = (int)js_SrcNoteSpec[type].arity; n > 0; n--) {
SN_MAKE_NOTE(&notes[index], type, delta);
for (int n = (int)js_SrcNoteSpec[type].arity; n > 0; n--) {
if (NewSrcNote(cx, bce, SRC_NULL) < 0)
return -1;
}
@ -6012,26 +5942,9 @@ frontend::NewSrcNote3(JSContext *cx, BytecodeEmitter *bce, SrcNoteType type, ptr
return index;
}
static bool
GrowSrcNotes(JSContext *cx, BytecodeEmitter *bce)
{
size_t newlength = bce->noteLimit() * 2;
jssrcnote *newnotes = (jssrcnote *) cx->realloc_(bce->notes(), newlength);
if (!newnotes) {
js_ReportOutOfMemory(cx);
return false;
}
bce->current->notes = newnotes;
bce->current->noteLimit = newlength;
return true;
}
jssrcnote *
bool
frontend::AddToSrcNoteDelta(JSContext *cx, BytecodeEmitter *bce, jssrcnote *sn, ptrdiff_t delta)
{
ptrdiff_t base, limit, newdelta, diff;
int index;
/*
* Called only from FinishTakingSrcNotes to add to main script note
* deltas, and only by a small positive amount.
@ -6039,40 +5952,33 @@ frontend::AddToSrcNoteDelta(JSContext *cx, BytecodeEmitter *bce, jssrcnote *sn,
JS_ASSERT(bce->current == &bce->main);
JS_ASSERT((unsigned) delta < (unsigned) SN_XDELTA_LIMIT);
base = SN_DELTA(sn);
limit = SN_IS_XDELTA(sn) ? SN_XDELTA_LIMIT : SN_DELTA_LIMIT;
newdelta = base + delta;
ptrdiff_t base = SN_DELTA(sn);
ptrdiff_t limit = SN_IS_XDELTA(sn) ? SN_XDELTA_LIMIT : SN_DELTA_LIMIT;
ptrdiff_t newdelta = base + delta;
if (newdelta < limit) {
SN_SET_DELTA(sn, newdelta);
} else {
index = sn - bce->main.notes;
if (bce->main.noteCount == bce->main.noteLimit) {
if (!GrowSrcNotes(cx, bce))
return NULL;
sn = bce->main.notes + index;
}
diff = bce->main.noteCount - index;
bce->main.noteCount++;
memmove(sn + 1, sn, SRCNOTE_SIZE(diff));
SN_MAKE_XDELTA(sn, delta);
sn++;
jssrcnote xdelta;
SN_MAKE_XDELTA(&xdelta, delta);
if (!(sn = bce->main.notes.insert(sn, xdelta)))
return false;
}
return sn;
return true;
}
static bool
SetSrcNoteOffset(JSContext *cx, BytecodeEmitter *bce, unsigned index, unsigned which, ptrdiff_t offset)
SetSrcNoteOffset(JSContext *cx, BytecodeEmitter *bce, unsigned index, unsigned which,
ptrdiff_t offset)
{
jssrcnote *sn;
ptrdiff_t diff;
if (size_t(offset) > SN_MAX_OFFSET) {
ReportStatementTooLarge(cx, bce->topStmt);
return false;
}
SrcNotesVector &notes = bce->notes();
/* Find the offset numbered which (i.e., skip exactly which offsets). */
sn = &bce->notes()[index];
jssrcnote *sn = notes.begin() + index;
JS_ASSERT(SN_TYPE(sn) != SRC_XDELTA);
JS_ASSERT((int) which < js_SrcNoteSpec[SN_TYPE(sn)].arity);
for (sn++; which; sn++, which--) {
@ -6088,25 +5994,14 @@ SetSrcNoteOffset(JSContext *cx, BytecodeEmitter *bce, unsigned index, unsigned w
if (offset > (ptrdiff_t)SN_3BYTE_OFFSET_MASK || (*sn & SN_3BYTE_OFFSET_FLAG)) {
/* Maybe this offset was already set to a three-byte value. */
if (!(*sn & SN_3BYTE_OFFSET_FLAG)) {
/* Losing, need to insert another two bytes for this offset. */
index = sn - bce->notes();
/*
* Test to see if the source note array must grow to accommodate
* either the first or second byte of additional storage required
* by this 3-byte offset.
*/
if (bce->noteCount() + 1 >= bce->noteLimit()) {
if (!GrowSrcNotes(cx, bce))
return false;
sn = bce->notes() + index;
/* Insert two dummy bytes that will be overwritten shortly. */
jssrcnote dummy = 0;
if (!(sn = notes.insert(sn, dummy)) ||
!(sn = notes.insert(sn, dummy)))
{
js_ReportOutOfMemory(cx);
return false;
}
bce->current->noteCount += 2;
diff = bce->noteCount() - (index + 3);
JS_ASSERT(diff >= 0);
if (diff > 0)
memmove(sn + 3, sn + 1, SRCNOTE_SIZE(diff));
}
*sn++ = (jssrcnote)(SN_3BYTE_OFFSET_FLAG | (offset >> 16));
*sn++ = (jssrcnote)(offset >> 8);
@ -6156,18 +6051,14 @@ DumpSrcNoteSizeHist()
bool
frontend::FinishTakingSrcNotes(JSContext *cx, BytecodeEmitter *bce, jssrcnote *notes)
{
unsigned prologCount, mainCount, totalCount;
ptrdiff_t offset, delta;
jssrcnote *sn;
JS_ASSERT(bce->current == &bce->main);
prologCount = bce->prolog.noteCount;
unsigned prologCount = bce->prolog.notes.length();
if (prologCount && bce->prolog.currentLine != bce->firstLine) {
bce->switchToProlog();
if (NewSrcNote2(cx, bce, SRC_SETLINE, (ptrdiff_t)bce->firstLine) < 0)
return false;
prologCount = bce->prolog.noteCount;
prologCount = bce->prolog.notes.length();
bce->switchToMain();
} else {
/*
@ -6177,14 +6068,14 @@ frontend::FinishTakingSrcNotes(JSContext *cx, BytecodeEmitter *bce, jssrcnote *n
* prepending SRC_XDELTA notes to it to account for prolog bytecodes
* that came at and after the last annotated bytecode.
*/
offset = bce->prologOffset() - bce->prolog.lastNoteOffset;
ptrdiff_t offset = bce->prologOffset() - bce->prolog.lastNoteOffset;
JS_ASSERT(offset >= 0);
if (offset > 0 && bce->main.noteCount != 0) {
if (offset > 0 && bce->main.notes.length() != 0) {
/* NB: Use as much of the first main note's delta as we can. */
sn = bce->main.notes;
delta = SN_IS_XDELTA(sn)
? SN_XDELTA_MASK - (*sn & SN_XDELTA_MASK)
: SN_DELTA_MASK - (*sn & SN_DELTA_MASK);
jssrcnote *sn = bce->main.notes.begin();
ptrdiff_t delta = SN_IS_XDELTA(sn)
? SN_XDELTA_MASK - (*sn & SN_XDELTA_MASK)
: SN_DELTA_MASK - (*sn & SN_DELTA_MASK);
if (offset < delta)
delta = offset;
for (;;) {
@ -6194,16 +6085,16 @@ frontend::FinishTakingSrcNotes(JSContext *cx, BytecodeEmitter *bce, jssrcnote *n
if (offset == 0)
break;
delta = Min(offset, SN_XDELTA_MASK);
sn = bce->main.notes;
sn = bce->main.notes.begin();
}
}
}
mainCount = bce->main.noteCount;
totalCount = prologCount + mainCount;
unsigned mainCount = bce->main.notes.length();
unsigned totalCount = prologCount + mainCount;
if (prologCount)
PodCopy(notes, bce->prolog.notes, prologCount);
PodCopy(notes + prologCount, bce->main.notes, mainCount);
PodCopy(notes, bce->prolog.notes.begin(), prologCount);
PodCopy(notes + prologCount, bce->main.notes.begin(), mainCount);
SN_MAKE_TERMINATOR(&notes[totalCount]);
return true;

Просмотреть файл

@ -59,6 +59,11 @@ class CGConstList {
struct StmtInfoBCE;
// Use zero inline elements because these go on the stack and affect how many
// nested functions are possible.
typedef Vector<jsbytecode, 0> BytecodeVector;
typedef Vector<jssrcnote, 0> SrcNotesVector;
struct BytecodeEmitter
{
typedef StmtInfoBCE StmtInfo;
@ -69,18 +74,24 @@ struct BytecodeEmitter
Rooted<JSScript*> script; /* the JSScript we're ultimately producing */
struct {
jsbytecode *base; /* base of JS bytecode vector */
jsbytecode *limit; /* one byte beyond end of bytecode */
jsbytecode *next; /* pointer to next free bytecode */
jssrcnote *notes; /* source notes, see below */
unsigned noteCount; /* number of source notes so far */
unsigned noteLimit; /* limit number for source notes in notePool */
struct EmitSection {
BytecodeVector code; /* bytecode */
SrcNotesVector notes; /* source notes, see below */
ptrdiff_t lastNoteOffset; /* code offset for last source note */
unsigned currentLine; /* line number for tree-based srcnote gen */
unsigned lastColumn; /* zero-based column index on currentLine of
last SRC_COLSPAN-annotated opcode */
} prolog, main, *current;
EmitSection(JSContext *cx, unsigned lineno)
: code(cx), notes(cx), lastNoteOffset(0), currentLine(lineno), lastColumn(0)
{
// Start them off moderately large, to avoid repeated resizings
// early on.
code.reserve(1024);
notes.reserve(1024);
}
};
EmitSection prolog, main, *current;
Parser *const parser; /* the parser */
@ -126,17 +137,17 @@ struct BytecodeEmitter
don't ever get emitted. See the comment for
the field |selfHostingMode| in Parser.h for details. */
/*
* Note that BytecodeEmitters are magic: they own the arena "top-of-stack"
* space above their tempMark points. This means that you cannot alloc from
* tempLifoAlloc and save the pointer beyond the next BytecodeEmitter
* destruction.
*/
BytecodeEmitter(BytecodeEmitter *parent, Parser *parser, SharedContext *sc,
HandleScript script, HandleScript evalCaller, bool hasGlobalScope,
unsigned lineno, bool selfHostingMode = false);
bool init();
/*
* Note that BytecodeEmitters are magic: they own the arena "top-of-stack"
* space above their tempMark points. This means that you cannot alloc from
* tempLifoAlloc and save the pointer beyond the next BytecodeEmitter
* destructor call.
*/
~BytecodeEmitter();
bool isAliasedName(ParseNode *pn);
@ -166,19 +177,14 @@ struct BytecodeEmitter
TokenStream *tokenStream() { return &parser->tokenStream; }
jsbytecode *base() const { return current->base; }
jsbytecode *limit() const { return current->limit; }
jsbytecode *next() const { return current->next; }
jsbytecode *code(ptrdiff_t offset) const { return base() + offset; }
ptrdiff_t offset() const { return next() - base(); }
jsbytecode *prologBase() const { return prolog.base; }
ptrdiff_t prologOffset() const { return prolog.next - prolog.base; }
BytecodeVector &code() const { return current->code; }
jsbytecode *code(ptrdiff_t offset) const { return current->code.begin() + offset; }
ptrdiff_t offset() const { return current->code.end() - current->code.begin(); }
ptrdiff_t prologOffset() const { return prolog.code.end() - prolog.code.begin(); }
void switchToMain() { current = &main; }
void switchToProlog() { current = &prolog; }
jssrcnote *notes() const { return current->notes; }
unsigned noteCount() const { return current->noteCount; }
unsigned noteLimit() const { return current->noteLimit; }
SrcNotesVector &notes() const { return current->notes; }
ptrdiff_t lastNoteOffset() const { return current->lastNoteOffset; }
unsigned currentLine() const { return current->currentLine; }
unsigned lastColumn() const { return current->lastColumn; }
@ -379,10 +385,8 @@ int
NewSrcNote3(JSContext *cx, BytecodeEmitter *bce, SrcNoteType type, ptrdiff_t offset1,
ptrdiff_t offset2);
/*
* NB: this function can add at most one extra extended delta note.
*/
jssrcnote *
/* NB: this function can add at most one extra extended delta note. */
bool
AddToSrcNoteDelta(JSContext *cx, BytecodeEmitter *bce, jssrcnote *sn, ptrdiff_t delta);
bool
@ -402,14 +406,14 @@ inline ptrdiff_t
BytecodeEmitter::countFinalSourceNotes()
{
ptrdiff_t diff = prologOffset() - prolog.lastNoteOffset;
ptrdiff_t cnt = prolog.noteCount + main.noteCount + 1;
if (prolog.noteCount && prolog.currentLine != firstLine) {
ptrdiff_t cnt = prolog.notes.length() + main.notes.length() + 1;
if (prolog.notes.length() && prolog.currentLine != firstLine) {
if (diff > SN_DELTA_MASK)
cnt += JS_HOWMANY(diff - SN_DELTA_MASK, SN_XDELTA_MASK);
cnt += 2 + ((firstLine > SN_3BYTE_OFFSET_MASK) << 1);
} else if (diff > 0) {
if (main.noteCount) {
jssrcnote *sn = main.notes;
if (main.notes.length()) {
jssrcnote *sn = main.notes.begin();
diff -= SN_IS_XDELTA(sn)
? SN_XDELTA_MASK - (*sn & SN_XDELTA_MASK)
: SN_DELTA_MASK - (*sn & SN_DELTA_MASK);

Просмотреть файл

@ -1874,8 +1874,8 @@ JSScript::fullyInitFromEmitter(JSContext *cx, Handle<JSScript*> script, Bytecode
return false;
jsbytecode *code = ssd->data;
PodCopy<jsbytecode>(code, bce->prologBase(), prologLength);
PodCopy<jsbytecode>(code + prologLength, bce->base(), mainLength);
PodCopy<jsbytecode>(code, bce->prolog.code.begin(), prologLength);
PodCopy<jsbytecode>(code + prologLength, bce->code().begin(), mainLength);
if (!FinishTakingSrcNotes(cx, bce, (jssrcnote *)(code + script->length)))
return false;
InitAtomMap(cx, bce->atomIndices.getMap(), ssd->atoms(script->length, nsrcnotes));

Просмотреть файл

@ -125,6 +125,7 @@ public:
PAINTING,
EVENT_DELIVERY,
PLUGIN_GEOMETRY,
IMAGE_VISIBILITY,
OTHER
};
nsDisplayListBuilder(nsIFrame* aReferenceFrame, Mode aMode, bool aBuildCaret);
@ -158,6 +159,11 @@ public:
* @return true if the display list is being built for painting.
*/
bool IsForPainting() { return mMode == PAINTING; }
/**
* @return true if the display list is being built for determining image
* visibility.
*/
bool IsForImageVisibility() { return mMode == IMAGE_VISIBILITY; }
bool WillComputePluginGeometry() { return mWillComputePluginGeometry; }
/**
* @return true if "painting is suppressed" during page load and we

Просмотреть файл

@ -38,6 +38,7 @@
#include "nsInterfaceHashtable.h"
#include "nsEventStates.h"
#include "nsPresArena.h"
#include "nsIImageLoadingContent.h"
class nsIContent;
class nsIDocument;
@ -120,10 +121,10 @@ typedef struct CapturingContentInfo {
nsIContent* mContent;
} CapturingContentInfo;
// da75e297-2c23-43c4-8d7f-96a668e96ba9
// 835b3946-1a4f-4132-b3ce-2e2e8be377c8
#define NS_IPRESSHELL_IID \
{ 0xda75e297, 0x2c23, 0x43c4, \
{ 0x8d, 0x7f, 0x96, 0xa6, 0x68, 0xe9, 0x6b, 0xa9 } }
{ 0x835b3946, 0x1a4f, 0x4132, \
{ 0xb3, 0xce, 0x2e, 0x2e, 0x8b, 0xe3, 0x77, 0xc8 } }
// debug VerifyReflow flags
#define VERIFY_REFLOW_ON 0x01
@ -1320,6 +1321,16 @@ public:
void InvalidatePresShellIfHidden();
// Schedule an update of the list of visible images.
virtual void ScheduleImageVisibilityUpdate() = 0;
// Clears the current list of visible images on this presshell and replaces it
// with images that are in the display list aList.
virtual void RebuildImageVisibility(const nsDisplayList& aList) = 0;
// Ensures the image is in the list of visible images.
virtual void EnsureImageInVisibleList(nsIImageLoadingContent* aImage) = 0;
/**
* Refresh observer management.
*/

Просмотреть файл

@ -182,6 +182,7 @@
#include "nsTransitionManager.h"
#include "LayerTreeInvalidation.h"
#include "nsAsyncDOMEvent.h"
#include "nsIImageLoadingContent.h"
#define ANCHOR_SCROLL_FLAGS \
(nsIPresShell::SCROLL_OVERFLOW_HIDDEN | nsIPresShell::SCROLL_NO_PARENT_FRAMES)
@ -1001,6 +1002,10 @@ PresShell::Destroy()
mSynthMouseMoveEvent.Revoke();
mUpdateImageVisibilityEvent.Revoke();
ClearVisibleImagesList();
if (mCaret) {
mCaret->Terminate();
mCaret = nullptr;
@ -3613,8 +3618,10 @@ PresShell::UnsuppressAndInvalidate()
if (win)
win->SetReadyForFocus();
if (!mHaveShutDown)
if (!mHaveShutDown) {
SynthesizeMouseMove(false);
ScheduleImageVisibilityUpdate();
}
}
void
@ -5278,6 +5285,190 @@ PresShell::ProcessSynthMouseMoveEvent(bool aFromScroll)
}
}
/* static */ void
PresShell::MarkImagesInListVisible(const nsDisplayList& aList)
{
for (nsDisplayItem* item = aList.GetBottom(); item; item = item->GetAbove()) {
nsDisplayList* sublist = item->GetChildren();
if (sublist) {
MarkImagesInListVisible(*sublist);
continue;
}
nsIFrame* f = item->GetUnderlyingFrame();
// We could check the type of the display item, only a handful can hold an
// image loading content.
if (f) {
// dont bother nscomptr here, it is wasteful
nsCOMPtr<nsIImageLoadingContent> content(do_QueryInterface(f->GetContent()));
if (content) {
// use the presshell containing the image
PresShell* presShell = static_cast<PresShell*>(f->PresContext()->PresShell());
if (presShell) {
content->IncrementVisibleCount();
presShell->mVisibleImages.AppendElement(content);
}
}
}
}
}
void
PresShell::RebuildImageVisibility(const nsDisplayList& aList)
{
MOZ_ASSERT(!mImageVisibilityVisited, "already visited?");
mImageVisibilityVisited = true;
nsTArray< nsCOMPtr<nsIImageLoadingContent > > beforeimagelist;
beforeimagelist.SwapElements(mVisibleImages);
MarkImagesInListVisible(aList);
for (uint32_t i = 0; i < beforeimagelist.Length(); ++i) {
beforeimagelist[i]->DecrementVisibleCount();
}
}
/* static */ void
PresShell::ClearImageVisibilityVisited(nsView* aView, bool aClear)
{
nsViewManager* vm = aView->GetViewManager();
if (aClear) {
PresShell* presShell = static_cast<PresShell*>(vm->GetPresShell());
if (!presShell->mImageVisibilityVisited) {
presShell->ClearVisibleImagesList();
}
presShell->mImageVisibilityVisited = false;
}
for (nsView* v = aView->GetFirstChild(); v; v = v->GetNextSibling()) {
ClearImageVisibilityVisited(v, v->GetViewManager() != vm);
}
}
void
PresShell::ClearVisibleImagesList()
{
for (uint32_t i = 0; i < mVisibleImages.Length(); ++i) {
mVisibleImages[i]->DecrementVisibleCount();
}
mVisibleImages.Clear();
}
void
PresShell::UpdateImageVisibility()
{
MOZ_ASSERT(!mPresContext || mPresContext->IsRootContentDocument(),
"updating image visibility on a non-root content document?");
mUpdateImageVisibilityEvent.Revoke();
if (mHaveShutDown || mIsDestroying) {
return;
}
// call update on that frame
nsIFrame* rootFrame = GetRootFrame();
if (!rootFrame) {
ClearVisibleImagesList();
return;
}
// We could walk the frame tree directly and skip creating a display list for
// better perf.
nsRect updateRect(nsPoint(0, 0), rootFrame->GetSize());
nsDisplayListBuilder builder(rootFrame, nsDisplayListBuilder::IMAGE_VISIBILITY, true);
builder.IgnorePaintSuppression();
builder.EnterPresShell(rootFrame, updateRect);
nsDisplayList list;
rootFrame->BuildDisplayListForStackingContext(&builder, updateRect, &list);
builder.LeavePresShell(rootFrame, updateRect);
RebuildImageVisibility(list);
ClearImageVisibilityVisited(rootFrame->GetView(), true);
list.DeleteAll();
}
static bool
AssumeAllImagesVisible(nsPresContext* aPresContext, nsIDocument* aDocument)
{
static bool sImageVisibilityEnabled = true;
static bool sImageVisibilityPrefCached = false;
if (!sImageVisibilityPrefCached) {
Preferences::AddBoolVarCache(&sImageVisibilityEnabled,
"layout.imagevisibility.enabled", true);
sImageVisibilityPrefCached = true;
}
if (!sImageVisibilityEnabled || !aPresContext || !aDocument)
return true;
// We assume all images are visible in print, print preview, chrome, xul, and
// resource docs and don't keep track of them.
if (aPresContext->Type() == nsPresContext::eContext_PrintPreview ||
aPresContext->Type() == nsPresContext::eContext_Print ||
aPresContext->IsChrome() ||
aDocument->IsResourceDoc() ||
aDocument->IsXUL()) {
return true;
}
return false;
}
void
PresShell::ScheduleImageVisibilityUpdate()
{
if (AssumeAllImagesVisible(mPresContext, mDocument))
return;
if (!mPresContext->IsRootContentDocument()) {
nsPresContext* presContext = mPresContext->GetToplevelContentDocumentPresContext();
if (!presContext)
return;
MOZ_ASSERT(presContext->IsRootContentDocument(),
"Didn't get a root prescontext from GetToplevelContentDocumentPresContext?");
presContext->PresShell()->ScheduleImageVisibilityUpdate();
return;
}
if (mHaveShutDown || mIsDestroying)
return;
if (mUpdateImageVisibilityEvent.IsPending())
return;
nsRefPtr<nsRunnableMethod<PresShell> > ev =
NS_NewRunnableMethod(this, &PresShell::UpdateImageVisibility);
if (NS_SUCCEEDED(NS_DispatchToCurrentThread(ev))) {
mUpdateImageVisibilityEvent = ev;
}
}
void
PresShell::EnsureImageInVisibleList(nsIImageLoadingContent* aImage)
{
if (AssumeAllImagesVisible(mPresContext, mDocument)) {
aImage->IncrementVisibleCount();
return;
}
#ifdef DEBUG
// if it has a frame make sure its in this presshell
nsCOMPtr<nsIContent> content = do_QueryInterface(aImage);
if (content) {
PresShell* shell = static_cast<PresShell*>(content->OwnerDoc()->GetShell());
MOZ_ASSERT(!shell || shell == this, "wrong shell");
}
#endif
// nsImageLoadingContent doesn't call this function if it has a positive
// visible count so the image shouldn't be in mVisibleImages. Either way it
// doesn't hurt to put it in multiple times.
MOZ_ASSERT(!mVisibleImages.Contains(aImage), "image already in the array");
mVisibleImages.AppendElement(aImage);
aImage->IncrementVisibleCount();
}
class nsAutoNotifyDidPaint
{
public:
@ -5304,6 +5495,8 @@ PresShell::Paint(nsView* aViewToPaint,
NS_ASSERTION(!mIsDestroying, "painting a destroyed PresShell");
NS_ASSERTION(aViewToPaint, "null view");
MOZ_ASSERT(!mImageVisibilityVisited, "should have been cleared");
if (!mIsActive || mIsZombie) {
return;
}
@ -7281,6 +7474,8 @@ FreezeSubDocument(nsIDocument *aDocument, void *aData)
void
PresShell::Freeze()
{
mUpdateImageVisibilityEvent.Revoke();
MaybeReleaseCapturingContent();
mDocument->EnumerateFreezableElements(FreezeElement, nullptr);

Просмотреть файл

@ -335,6 +335,12 @@ public:
uint32_t mContentToScrollToFlags;
};
virtual void ScheduleImageVisibilityUpdate();
virtual void RebuildImageVisibility(const nsDisplayList& aList);
virtual void EnsureImageInVisibleList(nsIImageLoadingContent* aImage);
protected:
virtual ~PresShell();
@ -703,6 +709,17 @@ protected:
virtual void ThemeChanged() { mPresContext->ThemeChanged(); }
virtual void BackingScaleFactorChanged() { mPresContext->UIResolutionChanged(); }
void UpdateImageVisibility();
nsRevocableEventPtr<nsRunnableMethod<PresShell> > mUpdateImageVisibilityEvent;
void ClearVisibleImagesList();
static void ClearImageVisibilityVisited(nsView* aView, bool aClear);
static void MarkImagesInListVisible(const nsDisplayList& aList);
// A list of images that are visible or almost visible.
nsTArray< nsCOMPtr<nsIImageLoadingContent > > mVisibleImages;
#ifdef DEBUG
// The reflow root under which we're currently reflowing. Null when
// not in reflow.
@ -792,6 +809,8 @@ protected:
bool mAsyncResizeTimerIsActive : 1;
bool mInResize : 1;
bool mImageVisibilityVisited : 1;
static bool sDisableNonTestMouseEvents;
};

Просмотреть файл

@ -24,7 +24,7 @@ load 321224.xul
load 322780-1.xul
load 323381-1.html
load 323381-2.html
asserts-if(gtk2Widget,13-14) load 323386-1.html # Bug 575011
asserts-if(gtk2Widget,13-15) load 323386-1.html # Bug 575011
load 323389-1.html
load 323389-2.html
load 323493-1.html
@ -296,8 +296,8 @@ load 465651-1.html
load 467137-1.html
load 467213-1.html
load 467487-1.html
asserts(6-9) load 467493-1.html
asserts(4-8) load 467493-2.html
asserts(6-10) load 467493-1.html
asserts(4-9) load 467493-2.html
load 467875-1.xhtml
load 467914-1.html
load 468207-1.html

Просмотреть файл

@ -54,6 +54,8 @@
#include "nsRefreshDriver.h"
#include "nsContentList.h"
#include <algorithm>
#include <cstdlib> // for std::abs(int/long)
#include <cmath> // for std::abs(float/double)
using namespace mozilla;
using namespace mozilla::dom;
@ -1427,6 +1429,7 @@ nsGfxScrollFrameInner::nsGfxScrollFrameInner(nsContainerFrame* aOuter,
, mRestorePos(-1, -1)
, mLastPos(-1, -1)
, mScrollPosForLayerPixelAlignment(-1, -1)
, mLastUpdateImagesPos(-1, -1)
, mNeverHasVerticalScrollbar(false)
, mNeverHasHorizontalScrollbar(false)
, mHasVerticalScrollbar(false)
@ -1880,6 +1883,35 @@ nsGfxScrollFrameInner::ScrollToImpl(nsPoint aPt, const nsRect& aRange)
return;
}
bool needImageVisibilityUpdate = (mLastUpdateImagesPos == nsPoint(-1,-1));
static bool sImageVisPrefsCached = false;
// The fraction of the scrollport we allow to scroll by before we schedule
// an update of image visibility.
static int32_t sHorzScrollFraction = 2;
static int32_t sVertScrollFraction = 2;
if (!sImageVisPrefsCached) {
Preferences::AddIntVarCache(&sHorzScrollFraction,
"layout.imagevisibility.amountscrollbeforeupdatehorizontal", 2);
Preferences::AddIntVarCache(&sVertScrollFraction,
"layout.imagevisibility.amountscrollbeforeupdatevertical", 2);
sImageVisPrefsCached = true;
}
nsPoint dist(std::abs(pt.x - mLastUpdateImagesPos.x),
std::abs(pt.y - mLastUpdateImagesPos.y));
nscoord horzAllowance = std::max(mScrollPort.width / std::max(sHorzScrollFraction, 1),
nsPresContext::AppUnitsPerCSSPixel());
nscoord vertAllowance = std::max(mScrollPort.height / std::max(sVertScrollFraction, 1),
nsPresContext::AppUnitsPerCSSPixel());
if (dist.x >= horzAllowance || dist.y >= vertAllowance) {
needImageVisibilityUpdate = true;
}
if (needImageVisibilityUpdate) {
presContext->PresShell()->ScheduleImageVisibilityUpdate();
}
// notify the listeners.
for (uint32_t i = 0; i < mListeners.Length(); i++) {
mListeners[i]->ScrollPositionWillChange(pt.x, pt.y);
@ -1995,6 +2027,10 @@ nsGfxScrollFrameInner::BuildDisplayList(nsDisplayListBuilder* aBuilder,
const nsRect& aDirtyRect,
const nsDisplayListSet& aLists)
{
if (aBuilder->IsForImageVisibility()) {
mLastUpdateImagesPos = GetScrollPosition();
}
mOuter->DisplayBorderBackgroundOutline(aBuilder, aLists);
if (aBuilder->IsPaintingToWindow()) {
@ -2061,6 +2097,33 @@ nsGfxScrollFrameInner::BuildDisplayList(nsDisplayListBuilder* aBuilder,
dirtyRect = displayPort;
}
if (aBuilder->IsForImageVisibility()) {
static bool sImageVisPrefsCached = false;
// The number of scrollports wide/high to expand when looking for images.
static uint32_t sHorzExpandScrollPort = 0;
static uint32_t sVertExpandScrollPort = 1;
if (!sImageVisPrefsCached) {
Preferences::AddUintVarCache(&sHorzExpandScrollPort,
"layout.imagevisibility.numscrollportwidths", (uint32_t)0);
Preferences::AddUintVarCache(&sVertExpandScrollPort,
"layout.imagevisibility.numscrollportheights", 1);
sImageVisPrefsCached = true;
}
// We expand the dirty rect to catch images just outside of the scroll port.
// We could be smarter and not expand the dirty rect in a direction in which
// we are not able to scroll.
nsRect dirtyRectBefore = dirtyRect;
nsPoint vertShift = nsPoint(0, sVertExpandScrollPort * dirtyRectBefore.height);
dirtyRect = dirtyRect.Union(dirtyRectBefore - vertShift);
dirtyRect = dirtyRect.Union(dirtyRectBefore + vertShift);
nsPoint horzShift = nsPoint(sHorzExpandScrollPort * dirtyRectBefore.width, 0);
dirtyRect = dirtyRect.Union(dirtyRectBefore - horzShift);
dirtyRect = dirtyRect.Union(dirtyRectBefore + horzShift);
}
nsDisplayListCollection set;
mOuter->BuildDisplayListForChild(aBuilder, mScrolledFrame, dirtyRect, set);

Просмотреть файл

@ -299,6 +299,9 @@ public:
nsCOMPtr<nsITimer> mScrollActivityTimer;
nsPoint mScrollPosForLayerPixelAlignment;
// The scroll position where we last updated image visibility.
nsPoint mLastUpdateImagesPos;
bool mNeverHasVerticalScrollbar:1;
bool mNeverHasHorizontalScrollbar:1;
bool mHasVerticalScrollbar:1;

Просмотреть файл

@ -465,10 +465,15 @@ nsSubDocumentFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
childItems.AppendToTop(item);
}
if (mIsInline) {
WrapReplacedContentForBorderRadius(aBuilder, &childItems, aLists);
if (aBuilder->IsForImageVisibility()) {
// We don't add the childItems to the return list as we're dealing with them here.
presShell->RebuildImageVisibility(childItems);
} else {
aLists.Content()->AppendToTop(&childItems);
if (mIsInline) {
WrapReplacedContentForBorderRadius(aBuilder, &childItems, aLists);
} else {
aLists.Content()->AppendToTop(&childItems);
}
}
// delete childItems in case of OOM

Просмотреть файл

@ -1568,7 +1568,7 @@ skip-if(B2G) fails-if(Android) random-if(layersGPUAccelerated) fails-if(/^Window
== 582037-1b.html 582037-1-ref.html
skip-if(B2G) == 582037-2a.html 582037-2-ref.html
skip-if(B2G) == 582037-2b.html 582037-2-ref.html
asserts(0-12) == 582146-1.html about:blank
asserts(0-13) == 582146-1.html about:blank
skip-if(B2G) == 582476-1.svg 582476-1-ref.svg
== 584400-dash-length.svg 584400-dash-length-ref.svg
== 584699-1.html 584699-1-ref.html

Просмотреть файл

@ -88,6 +88,7 @@ SVGFEImageFrame::DestroyFrom(nsIFrame* aDestructRoot)
if (imageLoader) {
imageLoader->FrameDestroyed(this);
imageLoader->DecrementVisibleCount();
}
SVGFEImageFrameBase::DestroyFrom(aDestructRoot);
@ -108,6 +109,8 @@ SVGFEImageFrame::Init(nsIContent* aContent,
if (imageLoader) {
imageLoader->FrameCreated(this);
// We assume that feImage's are always visible.
imageLoader->IncrementVisibleCount();
}
return NS_OK;

Просмотреть файл

@ -153,7 +153,11 @@ static int nr_stun_server_get_password(void *arg, nr_stun_message *msg, Data **p
ABORT(R_NOT_FOUND);
}
r_log(NR_LOG_STUN,LOG_NOTICE,"STUN-SERVER(%s): Unable to find password for unknown user: %s",ctx->label,username_attribute->u.username);
/* Although this is an exceptional condition, we'll already have seen a
* NOTICE-level log message about the unknown user, so additional log
* messages at any level higher than DEBUG are unnecessary. */
r_log(NR_LOG_STUN,LOG_DEBUG,"STUN-SERVER(%s): Unable to find password for unknown user: %s",ctx->label,username_attribute->u.username);
ABORT(R_NOT_FOUND);
}

Просмотреть файл

@ -22,6 +22,12 @@
#include "android/log.h"
#if !defined(MOZ_ANDROID_FROYO)
#define DEFAULT_STAGEFRIGHT_FLAGS OMXCodec::kClientNeedsFramebuffer
#else
#define DEFAULT_STAGEFRIGHT_FLAGS 0
#endif
#undef LOG
#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "OmxPlugin" , ## args)
@ -285,6 +291,9 @@ static uint32_t GetVideoCreationFlags(PluginHost* aPluginHost)
}
#endif
}
flags |= DEFAULT_STAGEFRIGHT_FLAGS;
return static_cast<uint32_t>(flags);
#endif
}
@ -294,10 +303,10 @@ static sp<MediaSource> CreateVideoSource(PluginHost* aPluginHost,
const sp<MediaSource>& aVideoTrack)
{
uint32_t flags = GetVideoCreationFlags(aPluginHost);
if (flags == 0) {
if (flags == DEFAULT_STAGEFRIGHT_FLAGS) {
// Let Stagefright choose hardware or software decoder.
sp<MediaSource> videoSource = OMXCodec::Create(aOmx, aVideoTrack->getFormat(),
false, aVideoTrack, NULL, 0);
false, aVideoTrack, NULL, flags);
if (videoSource == NULL)
return NULL;
@ -337,13 +346,13 @@ static sp<MediaSource> CreateVideoSource(PluginHost* aPluginHost,
LOG("Falling back to software decoder");
videoSource.clear();
#if defined(MOZ_ANDROID_V2_X_X)
flags = OMXCodec::kPreferSoftwareCodecs;
flags = DEFAULT_STAGEFRIGHT_FLAGS | OMXCodec::kPreferSoftwareCodecs;
#else
flags = OMXCodec::kSoftwareCodecsOnly;
flags = DEFAULT_STAGEFRIGHT_FLAGS | OMXCodec::kSoftwareCodecsOnly;
#endif
}
MOZ_ASSERT(flags != 0);
MOZ_ASSERT(flags != DEFAULT_STAGEFRIGHT_FLAGS);
return OMXCodec::Create(aOmx, aVideoTrack->getFormat(), false, aVideoTrack,
NULL, flags);
}

Просмотреть файл

@ -30,7 +30,7 @@ cc_string_t lineLabels[MAX_CONFIG_LINES+1] = {0};
void ccsnap_set_line_label(int btn, cc_string_t label) {
CCAPP_ERROR(DEB_F_PREFIX"btn=%d label=%s\n", DEB_F_PREFIX_ARGS(SIP_CC_PROV, "ccsnap_set_line_label"), btn, label);
CCAPP_DEBUG(DEB_F_PREFIX"btn=%d label=%s\n", DEB_F_PREFIX_ARGS(SIP_CC_PROV, "ccsnap_set_line_label"), btn, label);
if ( btn > 0 && btn <= MAX_CONFIG_LINES+1 ) {
if ( label == NULL ) {
label = strlib_empty();

Просмотреть файл

@ -92,7 +92,7 @@ config_set_string (int id, char *buffer)
}
}
#define MAX_CONFIG_VAL_PRINT_LEN 256
#define MAX_CONFIG_VAL_PRINT_LEN 258
/*
* Function: print_config_value()
*

Просмотреть файл

@ -675,6 +675,8 @@ pref("app.orientation.default", "");
// back to the system.
pref("memory.free_dirty_pages", true);
pref("layout.imagevisibility.enabled", false);
#ifdef MOZ_PKG_SPECIAL
// Disable webgl on ARMv6 because running the reftests takes
// too long for some reason (bug 843738)

Просмотреть файл

@ -123,17 +123,23 @@ abstract public class BrowserApp extends GeckoApp
invalidateOptionsMenu();
}
break;
case PAGE_SHOW:
handlePageShow(tab);
break;
case LINK_ADDED:
handleLinkAdded(tab);
break;
case SECURITY_CHANGE:
handleSecurityChange(tab);
break;
case READER_ENABLED:
handleReaderEnabled(tab);
break;
}
super.onTabChanged(tab, msg, data);
}
@Override
void handlePageShow(final int tabId) {
super.handlePageShow(tabId);
final Tab tab = Tabs.getInstance().getTab(tabId);
if (tab == null)
return;
void handlePageShow(final Tab tab) {
mMainHandler.post(new Runnable() {
public void run() {
loadFavicon(tab);
@ -141,16 +147,7 @@ abstract public class BrowserApp extends GeckoApp
});
}
@Override
void handleLinkAdded(final int tabId, String rel, final String href, int size) {
super.handleLinkAdded(tabId, rel, href, size);
if (rel.indexOf("[icon]") == -1)
return;
final Tab tab = Tabs.getInstance().getTab(tabId);
if (tab == null)
return;
void handleLinkAdded(final Tab tab) {
// If tab is not loading and the favicon is updated, we
// want to load the image straight away. If tab is still
// loading, we only load the favicon once the page's content
@ -170,13 +167,7 @@ abstract public class BrowserApp extends GeckoApp
updateAboutHomeTopSites();
}
@Override
void handleSecurityChange(final int tabId, final JSONObject identityData) {
super.handleSecurityChange(tabId, identityData);
final Tab tab = Tabs.getInstance().getTab(tabId);
if (tab == null)
return;
void handleSecurityChange(final Tab tab) {
mMainHandler.post(new Runnable() {
public void run() {
if (Tabs.getInstance().isSelectedTab(tab))
@ -185,12 +176,30 @@ abstract public class BrowserApp extends GeckoApp
});
}
void handleReaderEnabled(final int tabId) {
super.handleReaderEnabled(tabId);
final Tab tab = Tabs.getInstance().getTab(tabId);
if (tab == null)
void handleReaderAdded(boolean success, final String title, final String url) {
if (!success) {
showToast(R.string.reading_list_failed, Toast.LENGTH_SHORT);
return;
}
GeckoAppShell.getHandler().post(new Runnable() {
public void run() {
BrowserDB.addReadingListItem(getContentResolver(), title, url);
showToast(R.string.reading_list_added, Toast.LENGTH_SHORT);
}
});
}
void handleReaderRemoved(final String url) {
GeckoAppShell.getHandler().post(new Runnable() {
public void run() {
BrowserDB.removeReadingListItemWithURL(getContentResolver(), url);
showToast(R.string.reading_list_removed, Toast.LENGTH_SHORT);
}
});
}
void handleReaderEnabled(final Tab tab) {
mMainHandler.post(new Runnable() {
public void run() {
if (Tabs.getInstance().isSelectedTab(tab))
@ -536,6 +545,19 @@ abstract public class BrowserApp extends GeckoApp
Telemetry.HistogramAdd("PLACES_BOOKMARKS_COUNT", BrowserDB.getCount(getContentResolver(), "bookmarks"));
Telemetry.HistogramAdd("FENNEC_FAVICONS_COUNT", BrowserDB.getCount(getContentResolver(), "favicons"));
Telemetry.HistogramAdd("FENNEC_THUMBNAILS_COUNT", BrowserDB.getCount(getContentResolver(), "thumbnails"));
} else if (event.equals("Reader:Added")) {
final boolean success = message.getBoolean("success");
final String title = message.getString("title");
final String url = message.getString("url");
handleReaderAdded(success, title, url);
} else if (event.equals("Reader:Removed")) {
final String url = message.getString("url");
handleReaderRemoved(url);
} else if (event.equals("Reader:Share")) {
final String title = message.getString("title");
final String url = message.getString("url");
GeckoAppShell.openUriExternal(url, "text/plain", "", "",
Intent.ACTION_SEND, title);
} else {
super.handleMessage(event, message);
}

Просмотреть файл

@ -56,21 +56,41 @@ public final class Distribution {
return;
}
// This pref stores the path to the distribution directory. If it is null, Gecko
// looks for distribution files in /data/data/org.mozilla.xxx/distribution.
String pathKeyName = context.getPackageName() + ".distribution_path";
String distPath = null;
// Send a message to Gecko if we've set a distribution.
if (state == STATE_SET) {
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Distribution:Set", null));
distPath = settings.getString(pathKeyName, null);
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Distribution:Set", distPath));
return;
}
boolean distributionSet = false;
try {
// First, try copying distribution files out of the APK.
distributionSet = copyFiles(context, packagePath);
} catch (IOException e) {
Log.e(LOGTAG, "Error copying distribution files", e);
}
if (!distributionSet) {
// If there aren't any distribution files in the APK, look in the /system directory.
File distDir = new File("/system/" + context.getPackageName() + "/distribution");
if (distDir.exists()) {
distributionSet = true;
distPath = distDir.getPath();
settings.edit().putString(pathKeyName, distPath).commit();
}
}
Log.i("BOOM", "distributionSet: " + distributionSet);
Log.i("BOOM", "distPath: " + distPath);
if (distributionSet) {
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Distribution:Set", null));
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Distribution:Set", distPath));
settings.edit().putInt(keyName, STATE_SET).commit();
} else {
settings.edit().putInt(keyName, STATE_NONE).commit();

Просмотреть файл

@ -609,22 +609,6 @@ abstract public class GeckoApp
outState.putString(SAVED_STATE_PRIVATE_SESSION, mPrivateBrowsingSession);
}
void handleSecurityChange(final int tabId, final JSONObject identityData) {
final Tab tab = Tabs.getInstance().getTab(tabId);
if (tab == null)
return;
tab.updateIdentityData(identityData);
}
void handleReaderEnabled(final int tabId) {
final Tab tab = Tabs.getInstance().getTab(tabId);
if (tab == null)
return;
tab.setReaderEnabled(true);
}
void handleFaviconRequest(final String url) {
(new UiAsyncTask<Void, Void, String>(mMainHandler, GeckoAppShell.getHandler()) {
@Override
@ -650,17 +634,6 @@ abstract public class GeckoApp
}).execute();
}
void handleLoadError(final int tabId, final String uri, final String title) {
final Tab tab = Tabs.getInstance().getTab(tabId);
if (tab == null)
return;
// When a load error occurs, the URLBar can get corrupt so we reset it
Tabs.getInstance().notifyListeners(tab, Tabs.TabEvents.LOAD_ERROR);
}
void handlePageShow(final int tabId) { }
void handleClearHistory() {
BrowserDB.clearHistory(getContentResolver());
}
@ -776,60 +749,15 @@ abstract public class GeckoApp
if (layerView != null && Tabs.getInstance().isSelectedTab(tab)) {
layerView.setBackgroundColor(tab.getBackgroundColor());
}
} else if (event.equals("DOMTitleChanged")) {
final int tabId = message.getInt("tabID");
final String title = message.getString("title");
handleTitleChanged(tabId, title);
} else if (event.equals("DOMLinkAdded")) {
final int tabId = message.getInt("tabID");
final String rel = message.getString("rel");
final String href = message.getString("href");
final int size = message.getInt("size");
handleLinkAdded(tabId, rel, href, size);
} else if (event.equals("DOMWindowClose")) {
final int tabId = message.getInt("tabID");
handleWindowClose(tabId);
} else if (event.equals("log")) {
// generic log listener
final String msg = message.getString("msg");
Log.d(LOGTAG, "Log: " + msg);
} else if (event.equals("Content:SecurityChange")) {
final int tabId = message.getInt("tabID");
final JSONObject identity = message.getJSONObject("identity");
Log.i(LOGTAG, "Security Mode - " + identity.getString("mode"));
handleSecurityChange(tabId, identity);
} else if (event.equals("Content:ReaderEnabled")) {
final int tabId = message.getInt("tabID");
handleReaderEnabled(tabId);
} else if (event.equals("Reader:FaviconRequest")) {
final String url = message.getString("url");
handleFaviconRequest(url);
} else if (event.equals("Reader:GoToReadingList")) {
showReadingList();
} else if (event.equals("Content:StateChange")) {
final int tabId = message.getInt("tabID");
final String uri = message.getString("uri");
final boolean success = message.getBoolean("success");
int state = message.getInt("state");
Log.d(LOGTAG, "State - " + state);
if ((state & GeckoAppShell.WPL_STATE_IS_NETWORK) != 0) {
if ((state & GeckoAppShell.WPL_STATE_START) != 0) {
Log.d(LOGTAG, "Got a document start event.");
final boolean showProgress = message.getBoolean("showProgress");
handleDocumentStart(tabId, showProgress, uri);
} else if ((state & GeckoAppShell.WPL_STATE_STOP) != 0) {
Log.d(LOGTAG, "Got a document stop event.");
handleDocumentStop(tabId, success);
}
}
} else if (event.equals("Content:LoadError")) {
final int tabId = message.getInt("tabID");
final String uri = message.getString("uri");
final String title = message.getString("title");
handleLoadError(tabId, uri, title);
} else if (event.equals("Content:PageShow")) {
final int tabId = message.getInt("tabID");
handlePageShow(tabId);
} else if (event.equals("Gecko:Ready")) {
mGeckoReadyStartupTimer.stop();
connectGeckoLayerClient();
@ -1041,38 +969,6 @@ abstract public class GeckoApp
});
}
void handleDocumentStart(int tabId, final boolean showProgress, String uri) {
final Tab tab = Tabs.getInstance().getTab(tabId);
if (tab == null)
return;
tab.setState(shouldShowProgress(uri) ? Tab.STATE_SUCCESS : Tab.STATE_LOADING);
tab.updateIdentityData(null);
tab.setReaderEnabled(false);
Tabs.getInstance().notifyListeners(tab, Tabs.TabEvents.START, showProgress);
}
void handleDocumentStop(int tabId, boolean success) {
final Tab tab = Tabs.getInstance().getTab(tabId);
if (tab == null)
return;
tab.setState(success ? Tab.STATE_SUCCESS : Tab.STATE_ERROR);
Tabs.getInstance().notifyListeners(tab, Tabs.TabEvents.STOP);
final String oldURL = tab.getURL();
GeckoAppShell.getHandler().postDelayed(new Runnable() {
public void run() {
// tab.getURL() may return null
if (!TextUtils.equals(oldURL, tab.getURL()))
return;
ThumbnailHelper.getInstance().getAndProcessThumbnailFor(tab);
}
}, 500);
}
public void showToast(final int resId, final int duration) {
mMainHandler.post(new Runnable() {
public void run() {
@ -1102,31 +998,6 @@ abstract public class GeckoApp
Tabs.getInstance().notifyListeners(tab, Tabs.TabEvents.LOADED);
}
void handleTitleChanged(int tabId, String title) {
final Tab tab = Tabs.getInstance().getTab(tabId);
if (tab == null)
return;
tab.updateTitle(title);
}
void handleLinkAdded(final int tabId, String rel, final String href, int size) {
if (rel.indexOf("[icon]") == -1)
return;
final Tab tab = Tabs.getInstance().getTab(tabId);
if (tab == null)
return;
tab.updateFaviconURL(href, size);
}
void handleWindowClose(final int tabId) {
Tabs tabs = Tabs.getInstance();
Tab tab = tabs.getTab(tabId);
tabs.closeTab(tab);
}
private void addFullScreenPluginView(View view) {
if (mFullScreenPluginView != null) {
Log.w(LOGTAG, "Already have a fullscreen plugin view");
@ -1766,15 +1637,10 @@ abstract public class GeckoApp
//register for events
registerEventListener("DOMContentLoaded");
registerEventListener("DOMTitleChanged");
registerEventListener("DOMLinkAdded");
registerEventListener("DOMWindowClose");
registerEventListener("log");
registerEventListener("Content:SecurityChange");
registerEventListener("Content:ReaderEnabled");
registerEventListener("Content:StateChange");
registerEventListener("Content:LoadError");
registerEventListener("Content:PageShow");
registerEventListener("Reader:Added");
registerEventListener("Reader:Removed");
registerEventListener("Reader:Share");
registerEventListener("Reader:FaviconRequest");
registerEventListener("Reader:GoToReadingList");
registerEventListener("onCameraCapture");
@ -2167,15 +2033,10 @@ abstract public class GeckoApp
GeckoAppShell.sendEventToGecko(GeckoEvent.createShutdownEvent());
unregisterEventListener("DOMContentLoaded");
unregisterEventListener("DOMTitleChanged");
unregisterEventListener("DOMLinkAdded");
unregisterEventListener("DOMWindowClose");
unregisterEventListener("log");
unregisterEventListener("Content:SecurityChange");
unregisterEventListener("Content:ReaderEnabled");
unregisterEventListener("Content:StateChange");
unregisterEventListener("Content:LoadError");
unregisterEventListener("Content:PageShow");
unregisterEventListener("Reader:Added");
unregisterEventListener("Reader:Removed");
unregisterEventListener("Reader:Share");
unregisterEventListener("Reader:FaviconRequest");
unregisterEventListener("Reader:GoToReadingList");
unregisterEventListener("onCameraCapture");
@ -2753,10 +2614,6 @@ abstract public class GeckoApp
return false;
}
public static boolean shouldShowProgress(String url) {
return "about:home".equals(url) || ReaderModeUtils.isAboutReader(url);
}
public static void assertOnUiThread() {
Thread uiThread = mAppContext.getMainLooper().getThread();
assertOnThread(uiThread);

Просмотреть файл

@ -1502,12 +1502,11 @@ public class GeckoAppShell
boolean callback(int pid);
}
static int sPidColumn = -1;
static int sUserColumn = -1;
private static void EnumerateGeckoProcesses(GeckoProcessesVisitor visiter) {
int pidColumn = -1;
int userColumn = -1;
try {
// run ps and parse its output
java.lang.Process ps = Runtime.getRuntime().exec("ps");
BufferedReader in = new BufferedReader(new InputStreamReader(ps.getInputStream()),
@ -1516,30 +1515,28 @@ public class GeckoAppShell
String headerOutput = in.readLine();
// figure out the column offsets. We only care about the pid and user fields
if (sPidColumn == -1 || sUserColumn == -1) {
StringTokenizer st = new StringTokenizer(headerOutput);
int tokenSoFar = 0;
while(st.hasMoreTokens()) {
String next = st.nextToken();
if (next.equalsIgnoreCase("PID"))
sPidColumn = tokenSoFar;
else if (next.equalsIgnoreCase("USER"))
sUserColumn = tokenSoFar;
tokenSoFar++;
}
StringTokenizer st = new StringTokenizer(headerOutput);
int tokenSoFar = 0;
while (st.hasMoreTokens()) {
String next = st.nextToken();
if (next.equalsIgnoreCase("PID"))
pidColumn = tokenSoFar;
else if (next.equalsIgnoreCase("USER"))
userColumn = tokenSoFar;
tokenSoFar++;
}
// alright, the rest are process entries.
String psOutput = null;
while ((psOutput = in.readLine()) != null) {
String[] split = psOutput.split("\\s+");
if (split.length <= sPidColumn || split.length <= sUserColumn)
if (split.length <= pidColumn || split.length <= userColumn)
continue;
int uid = android.os.Process.getUidForName(split[sUserColumn]);
int uid = android.os.Process.getUidForName(split[userColumn]);
if (uid == android.os.Process.myUid() &&
!split[split.length - 1].equalsIgnoreCase("ps")) {
int pid = Integer.parseInt(split[sPidColumn]);
int pid = Integer.parseInt(split[pidColumn]);
boolean keepGoing = visiter.callback(pid);
if (keepGoing == false)
break;

Просмотреть файл

@ -22,6 +22,7 @@ import android.graphics.Color;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
@ -88,7 +89,7 @@ public class Tab {
mZoomConstraints = new ZoomConstraints(false);
mPluginViews = new ArrayList<View>();
mPluginLayers = new HashMap<Object, Layer>();
mState = GeckoApp.shouldShowProgress(url) ? STATE_SUCCESS : STATE_LOADING;
mState = shouldShowProgress(url) ? STATE_SUCCESS : STATE_LOADING;
}
private ContentResolver getContentResolver() {
@ -529,6 +530,32 @@ public class Tab {
Tabs.getInstance().notifyListeners(this, Tabs.TabEvents.LOCATION_CHANGE, uri);
}
private boolean shouldShowProgress(String url) {
return "about:home".equals(url) || ReaderModeUtils.isAboutReader(url);
}
void handleDocumentStart(boolean showProgress, String url) {
setState(shouldShowProgress(url) ? STATE_SUCCESS : STATE_LOADING);
updateIdentityData(null);
setReaderEnabled(false);
}
void handleDocumentStop(boolean success) {
setState(success ? STATE_SUCCESS : STATE_ERROR);
final String oldURL = getURL();
final Tab tab = this;
GeckoAppShell.getHandler().postDelayed(new Runnable() {
public void run() {
// tab.getURL() may return null
if (!TextUtils.equals(oldURL, getURL()))
return;
ThumbnailHelper.getInstance().getAndProcessThumbnailFor(tab);
}
}, 500);
}
protected void saveThumbnailToDB() {
try {
String url = getURL();

Просмотреть файл

@ -59,6 +59,7 @@ public class Tabs implements GeckoEventListener {
private ContentObserver mContentObserver;
private Tabs() {
registerEventListener("Session:RestoreEnd");
registerEventListener("SessionHistory:New");
registerEventListener("SessionHistory:Back");
registerEventListener("SessionHistory:Forward");
@ -68,10 +69,13 @@ public class Tabs implements GeckoEventListener {
registerEventListener("Tab:Close");
registerEventListener("Tab:Select");
registerEventListener("Content:LocationChange");
registerEventListener("Session:RestoreEnd");
registerEventListener("Reader:Added");
registerEventListener("Reader:Removed");
registerEventListener("Reader:Share");
registerEventListener("Content:SecurityChange");
registerEventListener("Content:ReaderEnabled");
registerEventListener("Content:StateChange");
registerEventListener("Content:LoadError");
registerEventListener("Content:PageShow");
registerEventListener("DOMTitleChanged");
registerEventListener("DOMLinkAdded");
}
public void attachToActivity(GeckoApp activity) {
@ -275,25 +279,25 @@ public class Tabs implements GeckoEventListener {
public void handleMessage(String event, JSONObject message) {
try {
if (event.startsWith("SessionHistory:")) {
Tab tab = getTab(message.getInt("tabID"));
if (tab != null) {
event = event.substring("SessionHistory:".length());
tab.handleSessionHistoryMessage(event, message);
}
} else if (event.equals("Tab:Added")) {
if (event.equals("Session:RestoreEnd")) {
notifyListeners(null, TabEvents.RESTORED);
return;
}
// All other events handled below should contain a tabID property
int id = message.getInt("tabID");
Tab tab = getTab(id);
// "Tab:Added" is a special case because tab will be null if the tab was just added
if (event.equals("Tab:Added")) {
String url = message.isNull("uri") ? null : message.getString("uri");
int id = message.getInt("tabID");
Tab tab = null;
if (message.getBoolean("stub")) {
if (mTabs.containsKey(id)) {
tab = mTabs.get(id);
tab.updateURL(url);
} else {
if (tab == null) {
// Tab was already closed; abort
return;
}
tab.updateURL(url);
} else {
tab = addTab(id, url, message.getBoolean("external"),
message.getInt("parentId"),
@ -302,66 +306,60 @@ public class Tabs implements GeckoEventListener {
}
if (message.getBoolean("selected"))
selectTab(tab.getId());
selectTab(id);
if (message.getBoolean("delayLoad"))
tab.setState(Tab.STATE_DELAYED);
if (message.getBoolean("desktopMode"))
tab.setDesktopMode(true);
return;
}
// Tab was already closed; abort
if (tab == null)
return;
if (event.startsWith("SessionHistory:")) {
event = event.substring("SessionHistory:".length());
tab.handleSessionHistoryMessage(event, message);
} else if (event.equals("Tab:Close")) {
Tab tab = getTab(message.getInt("tabID"));
closeTab(tab);
} else if (event.equals("Tab:Select")) {
selectTab(message.getInt("tabID"));
selectTab(tab.getId());
} else if (event.equals("Content:LocationChange")) {
Tab tab = getTab(message.getInt("tabID"));
if (tab != null) {
tab.handleLocationChange(message);
tab.handleLocationChange(message);
} else if (event.equals("Content:SecurityChange")) {
tab.updateIdentityData(message.getJSONObject("identity"));
notifyListeners(tab, TabEvents.SECURITY_CHANGE);
} else if (event.equals("Content:ReaderEnabled")) {
tab.setReaderEnabled(true);
notifyListeners(tab, TabEvents.READER_ENABLED);
} else if (event.equals("Content:StateChange")) {
int state = message.getInt("state");
if ((state & GeckoAppShell.WPL_STATE_IS_NETWORK) != 0) {
if ((state & GeckoAppShell.WPL_STATE_START) != 0) {
boolean showProgress = message.getBoolean("showProgress");
tab.handleDocumentStart(showProgress, message.getString("uri"));
notifyListeners(tab, Tabs.TabEvents.START, showProgress);
} else if ((state & GeckoAppShell.WPL_STATE_STOP) != 0) {
tab.handleDocumentStop(message.getBoolean("success"));
notifyListeners(tab, Tabs.TabEvents.STOP);
}
}
} else if (event.equals("Session:RestoreEnd")) {
notifyListeners(null, TabEvents.RESTORED);
} else if (event.equals("Reader:Added")) {
final boolean success = message.getBoolean("success");
final String title = message.getString("title");
final String url = message.getString("url");
handleReaderAdded(success, title, url);
} else if (event.equals("Reader:Removed")) {
final String url = message.getString("url");
handleReaderRemoved(url);
} else if (event.equals("Reader:Share")) {
final String title = message.getString("title");
final String url = message.getString("url");
GeckoAppShell.openUriExternal(url, "text/plain", "", "",
Intent.ACTION_SEND, title);
} else if (event.equals("Content:LoadError")) {
notifyListeners(tab, Tabs.TabEvents.LOAD_ERROR);
} else if (event.equals("Content:PageShow")) {
notifyListeners(tab, TabEvents.PAGE_SHOW);
} else if (event.equals("DOMTitleChanged")) {
tab.updateTitle(message.getString("title"));
} else if (event.equals("DOMLinkAdded")) {
tab.updateFaviconURL(message.getString("href"), message.getInt("size"));
notifyListeners(tab, TabEvents.LINK_ADDED);
}
} catch (Exception e) {
Log.w(LOGTAG, "handleMessage threw for " + event, e);
}
}
void handleReaderAdded(boolean success, final String title, final String url) {
if (!success) {
mActivity.showToast(R.string.reading_list_failed, Toast.LENGTH_SHORT);
return;
}
GeckoAppShell.getHandler().post(new Runnable() {
public void run() {
BrowserDB.addReadingListItem(getContentResolver(), title, url);
mActivity.showToast(R.string.reading_list_added, Toast.LENGTH_SHORT);
}
});
}
void handleReaderRemoved(final String url) {
GeckoAppShell.getHandler().post(new Runnable() {
public void run() {
BrowserDB.removeReadingListItemWithURL(getContentResolver(), url);
mActivity.showToast(R.string.reading_list_removed, Toast.LENGTH_SHORT);
}
});
}
public void refreshThumbnails() {
final ThumbnailHelper helper = ThumbnailHelper.getInstance();
Iterator<Tab> iterator = mTabs.values().iterator();
@ -409,7 +407,11 @@ public class Tabs implements GeckoEventListener {
ADDED,
RESTORED,
LOCATION_CHANGE,
MENU_UPDATED
MENU_UPDATED,
PAGE_SHOW,
LINK_ADDED,
SECURITY_CHANGE,
READER_ENABLED
}
public void notifyListeners(Tab tab, TabEvents msg) {

Просмотреть файл

@ -679,9 +679,7 @@ var BrowserApp = {
if (tab) {
let message = {
type: "Content:LoadError",
tabID: tab.id,
uri: aBrowser.currentURI.spec,
title: aBrowser.contentTitle
tabID: tab.id
};
sendMessageToJava(message);
dump("Handled load error: " + e)
@ -2923,9 +2921,7 @@ Tab.prototype = {
} catch(e) {
let message = {
type: "Content:LoadError",
tabID: this.id,
uri: this.browser.currentURI.spec,
title: this.browser.contentTitle
tabID: this.id
};
sendMessageToJava(message);
dump("Handled load error: " + e);
@ -3450,6 +3446,10 @@ Tab.prototype = {
list.push("[" + rel + "]");
}
// We only care about icon links
if (list.indexOf("[icon]") == -1)
return;
// We want to get the largest icon size possible for our UI.
let maxSize = 0;
@ -3510,7 +3510,7 @@ Tab.prototype = {
aEvent.preventDefault();
sendMessageToJava({
type: "DOMWindowClose",
type: "Tab:Close",
tabID: this.id
});
}
@ -8152,15 +8152,19 @@ var MemoryObserver = {
};
var Distribution = {
// File used to store campaign data
_file: null,
// Path to distribution directory for distribution customizations
_path: null,
init: function dc_init() {
Services.obs.addObserver(this, "Distribution:Set", false);
Services.obs.addObserver(this, "prefservice:after-app-defaults", false);
Services.obs.addObserver(this, "Campaign:Set", false);
// Look for file outside the APK:
// /data/data/org.mozilla.fennec/distribution.json
// /data/data/org.mozilla.xxx/distribution.json
this._file = Services.dirsvc.get("XCurProcD", Ci.nsIFile);
this._file.append("distribution.json");
this.readJSON(this._file, this.update);
@ -8175,6 +8179,8 @@ var Distribution = {
observe: function dc_observe(aSubject, aTopic, aData) {
switch (aTopic) {
case "Distribution:Set":
this._path = aData;
// Reload the default prefs so we can observe "prefservice:after-app-defaults"
Services.prefs.QueryInterface(Ci.nsIObserver).observe(null, "reload-default-prefs", null);
break;
@ -8215,10 +8221,16 @@ var Distribution = {
},
getPrefs: function dc_getPrefs() {
// Look for preferences file outside the APK:
// /data/data/org.mozilla.fennec/distribution/preferences.json
let file = Services.dirsvc.get("XCurProcD", Ci.nsIFile);
file.append("distribution");
let file;
if (this._path) {
file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
file.initWithPath(this._path);
} else {
// If a path isn't specified, look in the data directory:
// /data/data/org.mozilla.xxx/distribution
file = Services.dirsvc.get("XCurProcD", Ci.nsIFile);
file.append("distribution");
}
file.append("preferences.json");
this.readJSON(file, this.applyPrefs);

Просмотреть файл

@ -657,3 +657,5 @@ pref("media.realtime_decoder.enabled", true);
// Mobile manages state by autodetection
pref("network.manage-offline-status", true);
pref("layout.imagevisibility.enabled", false);

Просмотреть файл

@ -232,7 +232,7 @@ pref("gfx.filter.nearest.force-enabled", false);
// whether to always search all font cmaps during system font fallback
pref("gfx.font_rendering.fallback.always_use_cmaps", false);
pref("gfx.font_rendering.graphite.enabled", false);
pref("gfx.font_rendering.graphite.enabled", true);
// Check intl/unicharutil/util/nsUnicodeProperties.h for definitions of script bits
// in the ShapingType enumeration
@ -4110,6 +4110,12 @@ pref("dom.placeholder.show_on_focus", true);
pref("wap.UAProf.url", "");
pref("wap.UAProf.tagname", "x-wap-profile");
//Retrieval mode for MMS
//manual: Manual retrieval mode.
//automatic: Automatic retrieval mode.
//never: Never retrieval mode.
pref("dom.mms.retrieval_mode", "manual");
// If the user puts a finger down on an element and we think the user
// might be executing a pan gesture, how long do we wait before
// tentatively deciding the gesture is actually a tap and activating

Просмотреть файл

@ -11,42 +11,31 @@ VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
CC_WRAPPER =
CXX_WRAPPER =
default::
include $(topsrcdir)/config/config.mk
ifndef MOZ_NATIVE_NSS
LOADABLE_ROOT_MODULE = $(DLL_PREFIX)nssckbi$(DLL_SUFFIX)
endif
NSS_DLLS = \
nss3 \
nssutil3 \
smime3 \
ssl3 \
$(NULL)
NSS3_LIB = $(DLL_PREFIX)nss3$(DLL_SUFFIX)
NSSUTIL3_LIB = $(DLL_PREFIX)nssutil3$(DLL_SUFFIX)
SMIME3_LIB = $(DLL_PREFIX)smime3$(DLL_SUFFIX)
SSL3_LIB = $(DLL_PREFIX)ssl3$(DLL_SUFFIX)
SOFTOKEN3_LIB = $(DLL_PREFIX)softokn3$(DLL_SUFFIX)
NSS_EXTRA_DLLS = \
nssckbi \
softokn3 \
$(NULL)
ifndef NSS_DISABLE_DBM
NSSDBM3_LIB = $(DLL_PREFIX)nssdbm3$(DLL_SUFFIX)
else
NSSDBM3_LIB =
NSS_EXTRA_DLLS += nssdbm3
endif
ifndef MOZ_NATIVE_NSS
SDK_LIBS = crmf
ifneq (,$(filter OS2 WINNT,$(OS_ARCH)))
SDK_LIBS = \
$(DIST)/lib/$(LIB_PREFIX)crmf.$(LIB_SUFFIX) \
$(DIST)/lib/$(LIB_PREFIX)smime3.$(LIB_SUFFIX) \
$(DIST)/lib/$(LIB_PREFIX)ssl3.$(LIB_SUFFIX) \
$(DIST)/lib/$(LIB_PREFIX)nss3.$(LIB_SUFFIX) \
$(DIST)/lib/$(LIB_PREFIX)nssutil3.$(LIB_SUFFIX) \
$(NULL)
else
SDK_LIBS = \
$(DIST)/lib/$(LIB_PREFIX)crmf.$(LIB_SUFFIX) \
$(DIST)/lib/$(LIB_PREFIX)smime.$(LIB_SUFFIX) \
$(DIST)/lib/$(LIB_PREFIX)ssl.$(LIB_SUFFIX) \
$(DIST)/lib/$(LIB_PREFIX)nss.$(LIB_SUFFIX) \
$(DIST)/lib/$(LIB_PREFIX)nssutil.$(LIB_SUFFIX) \
$(NULL)
endif
SDK_LIBS += $(NSS_DLLS)
endif
# Default
@ -77,18 +66,18 @@ endif
endif
ifdef HAVE_FREEBL_LIBS
FREEBL_LIB = $(DLL_PREFIX)freebl3$(DLL_SUFFIX)
NSS_EXTRA_DLLS += freebl3
endif
ifdef HAVE_FREEBL_LIBS_32
FREEBL_32INT_LIB = libfreebl_32int_3$(DLL_SUFFIX)
FREEBL_32FPU_LIB = libfreebl_32fpu_3$(DLL_SUFFIX)
NSS_EXTRA_DLLS += freebl_32int_3
NSS_EXTRA_DLLS += freebl_32fpu_3
endif
ifdef HAVE_FREEBL_LIBS_32INT64
FREEBL_32INT64_LIB = libfreebl_32int64_3$(DLL_SUFFIX)
NSS_EXTRA_DLLS += freebl_32int64_3
endif
ifdef HAVE_FREEBL_LIBS_64
FREEBL_64INT_LIB = libfreebl_64int_3$(DLL_SUFFIX)
FREEBL_64FPU_LIB = libfreebl_64fpu_3$(DLL_SUFFIX)
NSS_EXTRA_DLLS += freebl_64int_3
NSS_EXTRA_DLLS += freebl_64fpu_3
endif
ABS_DIST := $(call core_abspath,$(DIST))
@ -123,8 +112,7 @@ endif
# To get debug symbols from NSS
export MOZ_DEBUG_SYMBOLS
# NSS makefiles are not safe for parallel execution.
DEFAULT_GMAKE_FLAGS = -j1
DEFAULT_GMAKE_FLAGS =
DEFAULT_GMAKE_FLAGS += CC="$(CC)"
DEFAULT_GMAKE_FLAGS += SOURCE_MD_DIR=$(ABS_DIST)
DEFAULT_GMAKE_FLAGS += SOURCE_MDHEADERS_DIR=$(NSPR_INCLUDE_DIR)
@ -135,6 +123,9 @@ DEFAULT_GMAKE_FLAGS += MOZILLA_CLIENT=1
DEFAULT_GMAKE_FLAGS += NO_MDUPDATE=1
DEFAULT_GMAKE_FLAGS += NSS_ENABLE_ECC=1
DEFAULT_GMAKE_FLAGS += NSINSTALL="$(NSINSTALL)"
ifeq ($(OS_ARCH),WINNT)
DEFAULT_GMAKE_FLAGS += INSTALL="$(NSINSTALL) -t"
endif
ifndef MOZ_NATIVE_SQLITE
DEFAULT_GMAKE_FLAGS += SQLITE_LIB_NAME=mozsqlite3
DEFAULT_GMAKE_FLAGS += SQLITE_INCLUDE_DIR=$(ABS_DIST)/include
@ -251,6 +242,18 @@ DEFAULT_GMAKE_FLAGS += XCFLAGS="$(CFLAGS)"
DEFAULT_GMAKE_FLAGS += DARWIN_DYLIB_VERSIONS="-compatibility_version 1 -current_version 1 $(LDFLAGS)"
endif
# Put NSS headers directly under $(DIST)/include
DEFAULT_GMAKE_FLAGS += PUBLIC_EXPORT_DIR='$(ABS_DIST)/include/$$(MODULE)'
DEFAULT_GMAKE_FLAGS += SOURCE_XPHEADERS_DIR='$$(SOURCE_XP_DIR)/include/$$(MODULE)'
DEFAULT_GMAKE_FLAGS += MODULE_INCLUDES='$$(addprefix -I$$(SOURCE_XP_DIR)/include/,$$(REQUIRES))'
# Work around NSS's MAKE_OBJDIR being racy. See bug #836220
DEFAULT_GMAKE_FLAGS += MAKE_OBJDIR='$$(INSTALL) -D $$(OBJDIR)'
# Work around NSS adding IMPORT_LIBRARY to TARGETS with no rule for
# it, creating race conditions. See bug #836220
DEFAULT_GMAKE_FLAGS += TARGETS='$$(LIBRARY) $$(SHARED_LIBRARY) $$(PROGRAM)'
ifdef MOZ_B2G_CERTDATA
include $(srcdir)/b2g-certdata.mk
endif
@ -298,53 +301,59 @@ ifneq (,$(filter %--build-id,$(LDFLAGS)))
DEFAULT_GMAKE_ENV = LDFLAGS=-Wl,--build-id
endif
ifndef MOZ_NATIVE_NSS
define build_rules
libs::
$$(DEFAULT_GMAKE_ENV) $$(MAKE) -C $$(NSS_SRCDIR)/security/$(1) $$(DEFAULT_GMAKE_FLAGS)
NSS_DIST_DLL_FILES := $(addprefix $(DIST)/lib/$(DLL_PREFIX),$(addsuffix $(DLL_SUFFIX),$(NSS_DLLS) $(NSS_EXTRA_DLLS)))
NSS_DIST_DLL_DEST := $(DIST)/bin
INSTALL_TARGETS += NSS_DIST_DLL
clean clobber clobber_all realclean distclean depend::
$$(MAKE) -C $$(NSS_SRCDIR)/security/$(1) $$(DEFAULT_GMAKE_FLAGS) clean
endef
$(foreach dir,$(NSS_DIRS),$(eval $(call build_rules,$(dir))))
NSS_LIBS = \
$(LOADABLE_ROOT_MODULE) \
$(SOFTOKEN3_LIB) \
$(NSSDBM3_LIB) \
$(NSS3_LIB) \
$(NSSUTIL3_LIB) \
$(SSL3_LIB) \
$(SMIME3_LIB) \
$(FREEBL_LIB) \
$(FREEBL_32INT_LIB) \
$(FREEBL_32FPU_LIB) \
$(FREEBL_32INT64_LIB) \
$(FREEBL_64INT_LIB) \
$(FREEBL_64FPU_LIB) \
$(NULL)
define install_rules
libs::
ifeq ($(OS_ARCH)_$(1), SunOS_$(SOFTOKEN3_LIB))
ifeq ($(OS_ARCH)_$(1), SunOS_softokn3)
# has to use copy mode on Solaris, see #665509
$$(NSINSTALL) -t -m 755 $$(DIST)/lib/$(1) $$(DIST)/bin
else
$$(INSTALL) -m 755 $$(DIST)/lib/$(1) $$(DIST)/bin
$(DIST)/bin/$(DLL_PREFIX)softokn3$(DLL_SUFFIX): INSTALL := $(INSTALL) -t
endif
install::
$$(SYSINSTALL) -m 755 $$(DIST)/lib/$(1) $$(DESTDIR)$$(mozappdir)
endef
$(foreach lib,$(NSS_LIBS),$(eval $(call install_rules,$(lib))))
NSS_SDK_LIB_FILES := \
$(addprefix $(DIST)/lib/$(LIB_PREFIX),$(addsuffix .$(LIB_SUFFIX),$(SDK_LIBS))) \
$(addprefix $(DIST)/bin/$(DLL_PREFIX),$(addsuffix $(DLL_SUFFIX),$(NSS_DLLS))) \
$(NULL)
NSS_SDK_LIB_DEST := $(DIST)/sdk/lib
INSTALL_TARGETS += NSS_SDK_LIB
libs::
$(INSTALL) -m 755 $(SDK_LIBS) $(DIST)/sdk/lib
# NSS installs headers to dist/public and we want them in dist/include
$(NSINSTALL) -D $(DIST)/include/nss
(cd $(DIST)/public/nss && tar $(TAR_CREATE_FLAGS) - .) | \
(cd $(DIST)/include/nss && tar -xf -)
endif # MOZ_NATIVE_NSS
$(NSS_DIST_DLL_FILES) $(NSS_SDK_LIB_FILES): libs-nss/lib
include $(topsrcdir)/config/rules.mk
DEFAULT_GMAKE_FLAGS += $(EXTRA_GMAKE_FLAGS)
$(addprefix libs-,$(NSS_DIRS)): libs-%:
# Work around NSS's export rule being racy when recursing for private_export
# See bug #836220.
$(addprefix export-,$(NSS_DIRS)): EXTRA_GMAKE_FLAGS = PRIVATE_EXPORTS=
$(addprefix export-,$(NSS_DIRS)): export-%: private_export-%
$(addprefix private_export-,$(NSS_DIRS)): EXTRA_GMAKE_FLAGS =
$(addprefix private_export-,$(NSS_DIRS)): private_export-%:
# Work around bug #836228 in pymake
ifdef .PYMAKE
$(foreach p,libs export private_export,$(addprefix $(p)-,$(NSS_DIRS))): *=$(subst $(NULL) $(NULL),-,$(wordlist 2,$(words $(subst -, ,$@)),$(subst -, ,$@)))
endif
$(foreach p,libs export private_export,$(addprefix $(p)-,$(NSS_DIRS))):
$(DEFAULT_GMAKE_ENV) $(MAKE) -C $(NSS_SRCDIR)/security/$* $(@:-$*=) $(DEFAULT_GMAKE_FLAGS)
export:: $(addprefix export-,$(NSS_DIRS))
$(addprefix clean-,$(NSS_DIRS)): clean-%:
$(MAKE) -C $(NSS_SRCDIR)/security/$* $(DEFAULT_GMAKE_FLAGS) clean
clean clobber clobber_all realclean distclean depend:: $(addprefix clean-,$(NSS_DIRS))
NSS_CMD_TARGETS := $(addprefix libs-,$(filter-out nss/cmd/lib,$(filter nss/cmd/%,$(NSS_DIRS))))
libs:: $(NSS_CMD_TARGETS)
$(NSS_CMD_TARGETS): libs-nss/lib libs-nss/cmd/lib
ifndef NSS_DISABLE_DBM
libs-nss/lib: libs-dbm
endif
# Work around NSS build system race condition creating certdata.c in
# security/nss/lib/ckfw/builtins. See bug #836220.
libs-nss/lib: $(call mkdir_deps,../nss/lib/ckfw/builtins)

Просмотреть файл

@ -30,6 +30,6 @@ hacked-certdata.txt : $(srcdir)/../nss/lib/ckfw/builtins/certdata.txt
combined-certdata.txt : hacked-certdata.txt $(srcdir)/b2g-certdata.txt
cat $^ > $@
libs:: combined-certdata.txt
libs-nss/lib: combined-certdata.txt
DEFAULT_GMAKE_FLAGS += NSS_CERTDATA_TXT='$(CURDIR)/combined-certdata.txt'

Просмотреть файл

@ -22,6 +22,7 @@ mochikit.jar:
content/tests/SimpleTest/SimpleTest.js (tests/SimpleTest/SimpleTest.js)
content/tests/SimpleTest/test.css (tests/SimpleTest/test.css)
content/tests/SimpleTest/TestRunner.js (tests/SimpleTest/TestRunner.js)
content/tests/SimpleTest/iframe-between-tests.html (tests/SimpleTest/iframe-between-tests.html)
content/tests/SimpleTest/WindowSnapshot.js (tests/SimpleTest/WindowSnapshot.js)
content/tests/SimpleTest/MockObjects.js (tests/SimpleTest/MockObjects.js)
content/tests/SimpleTest/NativeKeyCodes.js (tests/SimpleTest/NativeKeyCodes.js)

Просмотреть файл

@ -21,6 +21,7 @@ _SIMPLETEST_FILES = LogController.js \
MockObjects.js \
NativeKeyCodes.js \
paint_listener.js \
iframe-between-tests.html \
$(DEPTH)/testing/specialpowers/content/MozillaLogger.js \
$(DEPTH)/docshell/test/chrome/docshell_helpers.js \
$(NULL)

Просмотреть файл

@ -468,6 +468,44 @@ SimpleTest.requestLongerTimeout = function (factor) {
}
}
/**
* Note that the given range of assertions is to be expected. When
* this function is not called, 0 assertions are expected. When only
* one argument is given, that number of assertions are expected.
*
* A test where we expect to have assertions (which should largely be a
* transitional mechanism to get assertion counts down from our current
* situation) can call the SimpleTest.expectAssertions() function, with
* either one or two arguments: one argument gives an exact number
* expected, and two arguments give a range. For example, a test might do
* one of the following:
*
* // Currently triggers two assertions (bug NNNNNN).
* SimpleTest.expectAssertions(2);
*
* // Currently triggers one assertion on Mac (bug NNNNNN).
* if (navigator.platform.indexOf("Mac") == 0) {
* SimpleTest.expectAssertions(1);
* }
*
* // Currently triggers two assertions on all platforms (bug NNNNNN),
* // but intermittently triggers two additional assertions (bug NNNNNN)
* // on Windows.
* if (navigator.platform.indexOf("Win") == 0) {
* SimpleTest.expectAssertions(2, 4);
* } else {
* SimpleTest.expectAssertions(2);
* }
*
* // Intermittently triggers up to three assertions (bug NNNNNN).
* SimpleTest.expectAssertions(0, 3);
*/
SimpleTest.expectAssertions = function(min, max) {
if (parentRunner) {
parentRunner.expectAssertions(min, max);
}
}
SimpleTest.waitForFocus_started = false;
SimpleTest.waitForFocus_loaded = false;
SimpleTest.waitForFocus_focused = false;

Просмотреть файл

@ -72,9 +72,13 @@ function flattenArguments(lst/* ...*/) {
var TestRunner = {};
TestRunner.logEnabled = false;
TestRunner._currentTest = 0;
TestRunner._lastTestFinished = -1;
TestRunner.currentTestURL = "";
TestRunner.originalTestURL = "";
TestRunner._urls = [];
TestRunner._lastAssertionCount = 0;
TestRunner._expectedMinAsserts = 0;
TestRunner._expectedMaxAsserts = 0;
TestRunner.timeout = 5 * 60 * 1000; // 5 minutes.
TestRunner.maxTimeouts = 4; // halt testing after too many timeouts
@ -146,6 +150,18 @@ TestRunner.requestLongerTimeout = function(factor) {
TestRunner.repeat = 0;
TestRunner._currentLoop = 0;
TestRunner.expectAssertions = function(min, max) {
if (typeof(max) == "undefined") {
max = min;
}
if (typeof(min) != "number" || typeof(max) != "number" ||
min < 0 || max < min) {
throw "bad parameter to expectAssertions";
}
TestRunner._expectedMinAsserts = min;
TestRunner._expectedMaxAsserts = max;
}
/**
* This function is called after generating the summary.
**/
@ -338,6 +354,8 @@ TestRunner.runNextTest = function() {
TestRunner._currentTestStartTime = new Date().valueOf();
TestRunner._timeoutFactor = 1;
TestRunner._expectedMinAsserts = 0;
TestRunner._expectedMaxAsserts = 0;
TestRunner.log("TEST-START | " + url); // used by automation.py
@ -401,6 +419,16 @@ TestRunner.expectChildProcessCrash = function() {
* This stub is called by SimpleTest when a test is finished.
**/
TestRunner.testFinished = function(tests) {
// Prevent a test from calling finish() multiple times before we
// have a chance to unload it.
if (TestRunner._currentTest == TestRunner._lastTestFinished) {
TestRunner.error("TEST-UNEXPECTED-FAIL | " +
TestRunner.currentTestURL +
" | called finish() multiple times");
return;
}
TestRunner._lastTestFinished = TestRunner._currentTest;
function cleanUpCrashDumpFiles() {
if (!SpecialPowers.removeExpectedCrashDumpFiles(TestRunner._expectingProcessCrash)) {
TestRunner.error("TEST-UNEXPECTED-FAIL | " +
@ -440,12 +468,14 @@ TestRunner.testFinished = function(tests) {
" | finished in " + runtime + "ms");
TestRunner.updateUI(tests);
TestRunner._currentTest++;
if (TestRunner.runSlower) {
setTimeout(TestRunner.runNextTest, 1000);
var interstitialURL;
if ($('testframe').contentWindow.location.protocol == "chrome:") {
interstitialURL = "tests/SimpleTest/iframe-between-tests.html";
} else {
TestRunner.runNextTest();
interstitialURL = "/tests/SimpleTest/iframe-between-tests.html";
}
TestRunner._makeIframe(interstitialURL, 0);
}
SpecialPowers.executeAfterFlushingMessageQueue(function() {
@ -454,6 +484,35 @@ TestRunner.testFinished = function(tests) {
});
};
TestRunner.testUnloaded = function() {
if (SpecialPowers.isDebugBuild) {
var newAssertionCount = SpecialPowers.assertionCount();
var numAsserts = newAssertionCount - TestRunner._lastAssertionCount;
TestRunner._lastAssertionCount = newAssertionCount;
var url = TestRunner._urls[TestRunner._currentTest];
var max = TestRunner._expectedMaxAsserts;
var min = TestRunner._expectedMinAsserts;
if (numAsserts > max) {
// WHEN ENABLING, change "log" to "error" and "DETCEPXENU"
// to "UNEXPECTED".
TestRunner.log("TEST-DETCEPXENU-FAIL | " + url + " | Assertion count " + numAsserts + " is greater than expected range " + min + "-" + max + " assertions.");
} else if (numAsserts < min) {
// WHEN ENABLING, change "log" to "error" and "DETCEPXENU"
// to "UNEXPECTED".
TestRunner.log("TEST-DETCEPXENU-PASS | " + url + " | Assertion count " + numAsserts + " is less than expected range " + min + "-" + max + " assertions.");
} else if (numAsserts > 0) {
TestRunner.log("TEST-KNOWN-FAIL | " + url + " | Assertion count " + numAsserts + " within expected range " + min + "-" + max + " assertions.");
}
}
TestRunner._currentTest++;
if (TestRunner.runSlower) {
setTimeout(TestRunner.runNextTest, 1000);
} else {
TestRunner.runNextTest();
}
};
/**
* Get the results.
*/

Просмотреть файл

@ -0,0 +1,12 @@
<title>iframe for between tests</title>
<!--
This page exists so that our accounting for assertions correctly
counts assertions that happen while leaving a page. We load this page
after a test finishes, check the assertion counts, and then go on to
load the next.
-->
<script>
window.addEventListener("load", function() {
(parent.TestRunner || parent.wrappedJSObject.TestRunner).testUnloaded();
});
</script>

Просмотреть файл

@ -1206,6 +1206,10 @@ SpecialPowersAPI.prototype = {
var debug = Cc["@mozilla.org/xpcom/debug;1"].getService(Ci.nsIDebug2);
return this.isDebugBuild = debug.isDebugBuild;
},
assertionCount: function() {
var debugsvc = Cc['@mozilla.org/xpcom/debug;1'].getService(Ci.nsIDebug2);
return debugsvc.assertionCount;
},
/**
* Get the message manager associated with an <iframe mozbrowser>.

Просмотреть файл

@ -17,6 +17,7 @@
[include:dom/network/tests/unit/xpcshell.ini]
[include:dom/network/tests/unit_ipc/xpcshell.ini]
[include:dom/network/tests/unit_stats/xpcshell.ini]
[include:dom/payment/tests/unit/xpcshell.ini]
[include:dom/permission/tests/unit/xpcshell.ini]
[include:dom/src/json/test/unit/xpcshell.ini]
[include:dom/system/gonk/tests/xpcshell.ini]

Просмотреть файл

@ -9,6 +9,8 @@ srcdir = @srcdir@
VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
USE_RCS_MK := 1
include $(topsrcdir)/config/makefiles/rcs.mk
MODULE = telemetry
XPIDL_MODULE = telemetry
@ -63,7 +65,7 @@ ifdef MOZILLA_OFFICIAL
DEFINES += -DMOZILLA_OFFICIAL
endif
MOZ_HISTOGRAMS_VERSION ?= $(shell hg path default)rev/$(shell hg -R $(topsrcdir) parent --template="{node|short}\n" 2>/dev/null)
MOZ_HISTOGRAMS_VERSION ?= $(call getSourceRepo)/rev/$(firstword $(shell hg -R $(topsrcdir) parent --template="{node|short}\n" 2>/dev/null))
ifdef MOZ_HISTOGRAMS_VERSION
DEFINES += -DHISTOGRAMS_FILE_VERSION="$(MOZ_HISTOGRAMS_VERSION)"
endif

Просмотреть файл

@ -610,7 +610,7 @@ ifdef ACCESSIBILITY
OS_LIBS += $(call EXPAND_LIBNAME,oleacc)
endif
ifdef MOZ_METRO
OS_LIBS += $(call EXPAND_LIBNAME,uiautomationcore)
OS_LIBS += $(call EXPAND_LIBNAME,uiautomationcore runtimeobject)
endif
ifdef _MSC_VER
OS_LIBS += $(call EXPAND_LIBNAME,delayimp)

Просмотреть файл

@ -13,6 +13,18 @@ tier_nspr_staticdirs += nsprpub
tier_nspr_dirs += config/nspr
endif
TIERS += nss
ifndef MOZ_NATIVE_SQLITE
tier_nss_dirs += db/sqlite3/src
endif
ifdef MOZ_PSM
ifndef MOZ_NATIVE_NSS
tier_nss_dirs += security/build
endif
endif
include $(topsrcdir)/config/js/build.mk
TIERS += platform
@ -31,16 +43,6 @@ endif
tier_platform_dirs += xpcom
ifndef MOZ_NATIVE_SQLITE
tier_platform_dirs += db/sqlite3/src
endif
ifdef MOZ_PSM
tier_platform_dirs += \
security/build \
$(NULL)
endif
tier_platform_dirs += \
modules/libpref \
intl \

Просмотреть файл

@ -102,7 +102,15 @@ typedef uint16_t Modifiers;
// NotificationToIME is shared by nsIMEStateManager and TextComposition.
enum NotificationToIME {
// XXX We should replace NOTIFY_IME_OF_CURSOR_POS_CHANGED with
// NOTIFY_IME_OF_SELECTION_CHANGE later.
NOTIFY_IME_OF_CURSOR_POS_CHANGED,
// An editable content is getting focus
NOTIFY_IME_OF_FOCUS,
// An editable content is losing focus
NOTIFY_IME_OF_BLUR,
// Selection in the focused editable content is changed
NOTIFY_IME_OF_SELECTION_CHANGE,
REQUEST_TO_COMMIT_COMPOSITION,
REQUEST_TO_CANCEL_COMPOSITION
};

Просмотреть файл

@ -52,6 +52,7 @@ CPPSRCS = \
nsWidgetFactory.cpp \
WinUtils.cpp \
WinMouseScrollHandler.cpp \
WinIMEHandler.cpp \
$(NULL)
ifdef MOZ_CRASHREPORTER

Просмотреть файл

@ -0,0 +1,389 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
#include "WinIMEHandler.h"
#include "nsIMM32Handler.h"
#ifdef NS_ENABLE_TSF
#include "nsTextStore.h"
#endif // #ifdef NS_ENABLE_TSF
#include "nsWindow.h"
namespace mozilla {
namespace widget {
/******************************************************************************
* IMEHandler
******************************************************************************/
#ifdef NS_ENABLE_TSF
bool IMEHandler::sIsInTSFMode = false;
bool IMEHandler::sPluginHasFocus = false;
#endif // #ifdef NS_ENABLE_TSF
// static
void
IMEHandler::Initialize()
{
#ifdef NS_ENABLE_TSF
nsTextStore::Initialize();
sIsInTSFMode = nsTextStore::IsInTSFMode();
#endif // #ifdef NS_ENABLE_TSF
nsIMM32Handler::Initialize();
}
// static
void
IMEHandler::Terminate()
{
#ifdef NS_ENABLE_TSF
if (sIsInTSFMode) {
nsTextStore::Terminate();
sIsInTSFMode = false;
}
#endif // #ifdef NS_ENABLE_TSF
nsIMM32Handler::Terminate();
}
// static
void*
IMEHandler::GetNativeData(uint32_t aDataType)
{
#ifdef NS_ENABLE_TSF
void* result = nsTextStore::GetNativeData(aDataType);
if (!result || !(*(static_cast<void**>(result)))) {
return nullptr;
}
// XXX During the TSF module test, sIsInTSFMode must be true. After that,
// the value should be restored but currently, there is no way for that.
// When the TSF test is enabled again, we need to fix this. Perhaps,
// sending a message can fix this.
sIsInTSFMode = true;
return result;
#else // #ifdef NS_ENABLE_TSF
return nullptr;
#endif // #ifdef NS_ENABLE_TSF #else
}
// static
bool
IMEHandler::CanOptimizeKeyAndIMEMessages()
{
#ifdef NS_ENABLE_TSF
if (IsTSFAvailable()) {
return nsTextStore::CanOptimizeKeyAndIMEMessages();
}
#endif // #ifdef NS_ENABLE_TSF
return nsIMM32Handler::CanOptimizeKeyAndIMEMessages();
}
// static
bool
IMEHandler::IsIMEEnabled(const InputContext& aInputContext)
{
return IsIMEEnabled(aInputContext.mIMEState.mEnabled);
}
// static
bool
IMEHandler::IsIMEEnabled(IMEState::Enabled aIMEState)
{
return (aIMEState == mozilla::widget::IMEState::ENABLED ||
aIMEState == mozilla::widget::IMEState::PLUGIN);
}
// static
bool
IMEHandler::ProcessMessage(nsWindow* aWindow, UINT aMessage,
WPARAM& aWParam, LPARAM& aLParam,
LRESULT* aRetValue, bool& aEatMessage)
{
#ifdef NS_ENABLE_TSF
if (IsTSFAvailable()) {
if (aMessage == WM_USER_TSF_TEXTCHANGE) {
nsTextStore::OnTextChangeMsg();
aEatMessage = true;
return true;
}
return false;
}
#endif // #ifdef NS_ENABLE_TSF
return nsIMM32Handler::ProcessMessage(aWindow, aMessage, aWParam, aLParam,
aRetValue, aEatMessage);
}
// static
bool
IMEHandler::IsComposing()
{
#ifdef NS_ENABLE_TSF
if (IsTSFAvailable()) {
return nsTextStore::IsComposing();
}
#endif // #ifdef NS_ENABLE_TSF
return nsIMM32Handler::IsComposing();
}
// static
bool
IMEHandler::IsComposingOn(nsWindow* aWindow)
{
#ifdef NS_ENABLE_TSF
if (IsTSFAvailable()) {
return nsTextStore::IsComposingOn(aWindow);
}
#endif // #ifdef NS_ENABLE_TSF
return nsIMM32Handler::IsComposingOn(aWindow);
}
// static
nsresult
IMEHandler::NotifyIME(nsWindow* aWindow,
NotificationToIME aNotification)
{
#ifdef NS_ENABLE_TSF
if (IsTSFAvailable()) {
switch (aNotification) {
case NOTIFY_IME_OF_SELECTION_CHANGE:
return nsTextStore::OnSelectionChange();
case NOTIFY_IME_OF_FOCUS:
return nsTextStore::OnFocusChange(true, aWindow,
aWindow->GetInputContext().mIMEState.mEnabled);
case NOTIFY_IME_OF_BLUR:
return nsTextStore::OnFocusChange(false, aWindow,
aWindow->GetInputContext().mIMEState.mEnabled);
case REQUEST_TO_COMMIT_COMPOSITION:
if (nsTextStore::IsComposingOn(aWindow)) {
nsTextStore::CommitComposition(false);
}
return NS_OK;
case REQUEST_TO_CANCEL_COMPOSITION:
if (nsTextStore::IsComposingOn(aWindow)) {
nsTextStore::CommitComposition(true);
}
return NS_OK;
default:
return NS_ERROR_NOT_IMPLEMENTED;
}
}
#endif //NS_ENABLE_TSF
switch (aNotification) {
case REQUEST_TO_COMMIT_COMPOSITION:
nsIMM32Handler::CommitComposition(aWindow);
return NS_OK;
case REQUEST_TO_CANCEL_COMPOSITION:
nsIMM32Handler::CancelComposition(aWindow);
return NS_OK;
#ifdef NS_ENABLE_TSF
case NOTIFY_IME_OF_BLUR:
// If a plugin gets focus while TSF has focus, we need to notify TSF of
// the blur.
if (nsTextStore::ThinksHavingFocus()) {
return nsTextStore::OnFocusChange(false, aWindow,
aWindow->GetInputContext().mIMEState.mEnabled);
}
return NS_ERROR_NOT_IMPLEMENTED;
#endif //NS_ENABLE_TSF
default:
return NS_ERROR_NOT_IMPLEMENTED;
}
}
// static
nsresult
IMEHandler::NotifyIMEOfTextChange(uint32_t aStart,
uint32_t aOldEnd,
uint32_t aNewEnd)
{
#ifdef NS_ENABLE_TSF
if (IsTSFAvailable()) {
return nsTextStore::OnTextChange(aStart, aOldEnd, aNewEnd);
}
#endif //NS_ENABLE_TSF
return NS_ERROR_NOT_IMPLEMENTED;
}
// static
nsIMEUpdatePreference
IMEHandler::GetUpdatePreference()
{
#ifdef NS_ENABLE_TSF
if (IsTSFAvailable()) {
return nsTextStore::GetIMEUpdatePreference();
}
#endif //NS_ENABLE_TSF
return nsIMEUpdatePreference(false, false);
}
// static
bool
IMEHandler::GetOpenState(nsWindow* aWindow)
{
#ifdef NS_ENABLE_TSF
if (IsTSFAvailable()) {
return nsTextStore::GetIMEOpenState();
}
#endif //NS_ENABLE_TSF
nsIMEContext IMEContext(aWindow->GetWindowHandle());
return IMEContext.GetOpenState();
}
// static
void
IMEHandler::OnDestroyWindow(nsWindow* aWindow)
{
// We need to do nothing here for TSF. Just restore the default context
// if it's been disassociated.
nsIMEContext IMEContext(aWindow->GetWindowHandle());
IMEContext.AssociateDefaultContext();
}
// static
void
IMEHandler::SetInputContext(nsWindow* aWindow, InputContext& aInputContext)
{
// FYI: If there is no composition, this call will do nothing.
NotifyIME(aWindow, REQUEST_TO_COMMIT_COMPOSITION);
// Assume that SetInputContext() is called only when aWindow has focus.
sPluginHasFocus = (aInputContext.mIMEState.mEnabled == IMEState::PLUGIN);
bool enable = IsIMEEnabled(aInputContext);
bool adjustOpenState = (enable &&
aInputContext.mIMEState.mOpen != IMEState::DONT_CHANGE_OPEN_STATE);
bool open = (adjustOpenState &&
aInputContext.mIMEState.mOpen == IMEState::OPEN);
aInputContext.mNativeIMEContext = nullptr;
#ifdef NS_ENABLE_TSF
// Note that even while a plugin has focus, we need to notify TSF of that.
if (sIsInTSFMode) {
nsTextStore::SetInputContext(aInputContext);
if (IsTSFAvailable()) {
aInputContext.mNativeIMEContext = nsTextStore::GetTextStore();
}
// Currently, nsTextStore doesn't set focus to keyboard disabled document.
// Therefore, we still need to perform the following legacy code.
}
#endif // #ifdef NS_ENABLE_TSF
nsIMEContext IMEContext(aWindow->GetWindowHandle());
if (enable) {
IMEContext.AssociateDefaultContext();
if (!aInputContext.mNativeIMEContext) {
aInputContext.mNativeIMEContext = static_cast<void*>(IMEContext.get());
}
} else if (!aWindow->Destroyed()) {
// Don't disassociate the context after the window is destroyed.
IMEContext.Disassociate();
if (!aInputContext.mNativeIMEContext) {
// The old InputContext must store the default IMC.
aInputContext.mNativeIMEContext =
aWindow->GetInputContext().mNativeIMEContext;
}
}
if (adjustOpenState) {
#ifdef NS_ENABLE_TSF
if (IsTSFAvailable()) {
nsTextStore::SetIMEOpenState(open);
return;
}
#endif // #ifdef NS_ENABLE_TSF
IMEContext.SetOpenState(open);
}
}
// static
void
IMEHandler::InitInputContext(nsWindow* aWindow, InputContext& aInputContext)
{
// For a11y, the default enabled state should be 'enabled'.
aInputContext.mIMEState.mEnabled = IMEState::ENABLED;
#ifdef NS_ENABLE_TSF
if (sIsInTSFMode) {
nsTextStore::SetInputContext(aInputContext);
aInputContext.mNativeIMEContext = nsTextStore::GetTextStore();
MOZ_ASSERT(aInputContext.mNativeIMEContext);
return;
}
#endif // #ifdef NS_ENABLE_TSF
// NOTE: mNativeIMEContext may be null if IMM module isn't installed.
nsIMEContext IMEContext(aWindow->GetWindowHandle());
aInputContext.mNativeIMEContext = static_cast<void*>(IMEContext.get());
MOZ_ASSERT(aInputContext.mNativeIMEContext || !CurrentKeyboardLayoutHasIME());
// If no IME context is available, we should set the widget's pointer since
// nullptr indicates there is only one context per process on the platform.
if (!aInputContext.mNativeIMEContext) {
aInputContext.mNativeIMEContext = static_cast<void*>(aWindow);
}
}
#ifdef DEBUG
// static
bool
IMEHandler::CurrentKeyboardLayoutHasIME()
{
#ifdef NS_ENABLE_TSF
if (sIsInTSFMode) {
return nsTextStore::CurrentKeyboardLayoutHasIME();
}
#endif // #ifdef NS_ENABLE_TSF
return nsIMM32Handler::IsIMEAvailable();
}
#endif // #ifdef DEBUG
// static
bool
IMEHandler::IsDoingKakuteiUndo(HWND aWnd)
{
// Following message pattern is caused by "Kakutei-Undo" of ATOK or WXG:
// ---------------------------------------------------------------------------
// WM_KEYDOWN * n (wParam = VK_BACK, lParam = 0x1)
// WM_KEYUP * 1 (wParam = VK_BACK, lParam = 0xC0000001) # ATOK
// WM_IME_STARTCOMPOSITION * 1 (wParam = 0x0, lParam = 0x0)
// WM_IME_COMPOSITION * 1 (wParam = 0x0, lParam = 0x1BF)
// WM_CHAR * n (wParam = VK_BACK, lParam = 0x1)
// WM_KEYUP * 1 (wParam = VK_BACK, lParam = 0xC00E0001)
// ---------------------------------------------------------------------------
// This doesn't match usual key message pattern such as:
// WM_KEYDOWN -> WM_CHAR -> WM_KEYDOWN -> WM_CHAR -> ... -> WM_KEYUP
// See following bugs for the detail.
// https://bugzilla.mozilla.gr.jp/show_bug.cgi?id=2885 (written in Japanese)
// https://bugzilla.mozilla.org/show_bug.cgi?id=194559 (written in English)
MSG startCompositionMsg, compositionMsg, charMsg;
return ::PeekMessageW(&startCompositionMsg, aWnd,
WM_IME_STARTCOMPOSITION, WM_IME_STARTCOMPOSITION,
PM_NOREMOVE | PM_NOYIELD) &&
::PeekMessageW(&compositionMsg, aWnd, WM_IME_COMPOSITION,
WM_IME_COMPOSITION, PM_NOREMOVE | PM_NOYIELD) &&
::PeekMessageW(&charMsg, aWnd, WM_CHAR, WM_CHAR,
PM_NOREMOVE | PM_NOYIELD) &&
startCompositionMsg.wParam == 0x0 &&
startCompositionMsg.lParam == 0x0 &&
compositionMsg.wParam == 0x0 &&
compositionMsg.lParam == 0x1BF &&
charMsg.wParam == VK_BACK && charMsg.lParam == 0x1 &&
startCompositionMsg.time <= compositionMsg.time &&
compositionMsg.time <= charMsg.time;
}
} // namespace widget
} // namespace mozilla

Просмотреть файл

@ -0,0 +1,137 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
#ifndef WinIMEHandler_h_
#define WinIMEHandler_h_
#include "nscore.h"
#include "nsEvent.h"
#include "nsIWidget.h"
#include <windows.h>
#define NS_WM_IMEFIRST WM_IME_SETCONTEXT
#define NS_WM_IMELAST WM_IME_KEYUP
class nsWindow;
namespace mozilla {
namespace widget {
/**
* IMEHandler class is a mediator class. On Windows, there are two IME API
* sets: One is IMM which is legacy API set. The other is TSF which is modern
* API set. By using this class, non-IME handler classes don't need to worry
* that we're in which mode.
*/
class IMEHandler MOZ_FINAL
{
public:
static void Initialize();
static void Terminate();
/**
* Returns TSF related native data.
*/
static void* GetNativeData(uint32_t aDataType);
/**
* Returns true if our message loop can optimize the message order for
* a key message or an IME message. Otherwise, false.
*/
static bool CanOptimizeKeyAndIMEMessages();
/**
* Returns true if the context or IME state is enabled. Otherwise, false.
*/
static bool IsIMEEnabled(const InputContext& aInputContext);
static bool IsIMEEnabled(IMEState::Enabled aIMEState);
/**
* When the message is not needed to handle anymore by the caller, this
* returns true. Otherwise, false.
* Additionally, if aEatMessage is true, the caller shouldn't call next
* wndproc anymore.
*/
static bool ProcessMessage(nsWindow* aWindow, UINT aMessage,
WPARAM& aWParam, LPARAM& aLParam,
LRESULT* aRetValue, bool& aEatMessage);
/**
* When there is a composition, returns true. Otherwise, false.
*/
static bool IsComposing();
/**
* When there is a composition and it's in the window, returns true.
* Otherwise, false.
*/
static bool IsComposingOn(nsWindow* aWindow);
/**
* Notifies IME of the notification (a request or an event).
*/
static nsresult NotifyIME(nsWindow* aWindow,
NotificationToIME aNotification);
/**
* Notifies IME of text change in the focused editable content.
*/
static nsresult NotifyIMEOfTextChange(uint32_t aStart,
uint32_t aOldEnd,
uint32_t aNewEnd);
/**
* Returns update preferences.
*/
static nsIMEUpdatePreference GetUpdatePreference();
/**
* Returns IME open state on the window.
*/
static bool GetOpenState(nsWindow* aWindow);
/**
* Called when the window is destroying.
*/
static void OnDestroyWindow(nsWindow* aWindow);
/**
* Called when nsIWidget::SetInputContext() is called before the window's
* InputContext is modified actually.
*/
static void SetInputContext(nsWindow* aWindow, InputContext& aInputContext);
/**
* Called when the window is created.
*/
static void InitInputContext(nsWindow* aWindow, InputContext& aInputContext);
/**
* "Kakutei-Undo" of ATOK or WXG (both of them are Japanese IME) causes
* strange WM_KEYDOWN/WM_KEYUP/WM_CHAR message pattern. So, when this
* returns true, the caller needs to be careful for processing the messages.
*/
static bool IsDoingKakuteiUndo(HWND aWnd);
#ifdef DEBUG
/**
* Returns true when current keyboard layout has IME. Otherwise, false.
*/
static bool CurrentKeyboardLayoutHasIME();
#endif // #ifdef DEBUG
private:
#ifdef NS_ENABLE_TSF
static bool sIsInTSFMode;
static bool sPluginHasFocus;
static bool IsTSFAvailable() { return (sIsInTSFMode && !sPluginHasFocus); }
#endif // #ifdef NS_ENABLE_TSF
};
} // namespace widget
} // namespace mozilla
#endif // #ifndef WinIMEHandler_h_

Просмотреть файл

@ -11,7 +11,7 @@
#include "WinMouseScrollHandler.h"
#include "nsWindowDefs.h"
#include "nsString.h"
#include "nsIMM32Handler.h"
#include "WinIMEHandler.h"
#include "mozilla/widget/AudioSession.h"
#include "mozilla/HangMonitor.h"
@ -66,7 +66,7 @@ static bool PeekUIMessage(MSG* aMsg)
pMsg = &imeMsg;
}
if (pMsg && !nsIMM32Handler::CanOptimizeKeyAndIMEMessages(pMsg)) {
if (pMsg && !mozilla::widget::IMEHandler::CanOptimizeKeyAndIMEMessages()) {
return false;
}

Просмотреть файл

@ -106,41 +106,6 @@ nsIMM32Handler::IsTopLevelWindowOfComposition(nsWindow* aWindow)
return WinUtils::GetTopLevelHWND(wnd, true) == aWindow->GetWindowHandle();
}
/* static */ bool
nsIMM32Handler::IsDoingKakuteiUndo(HWND aWnd)
{
// This message pattern is "Kakutei-Undo" on ATOK and WXG.
// In this case, the message queue has following messages:
// ---------------------------------------------------------------------------
// WM_KEYDOWN * n (wParam = VK_BACK, lParam = 0x1)
// WM_KEYUP * 1 (wParam = VK_BACK, lParam = 0xC0000001) # ATOK
// WM_IME_STARTCOMPOSITION * 1 (wParam = 0x0, lParam = 0x0)
// WM_IME_COMPOSITION * 1 (wParam = 0x0, lParam = 0x1BF)
// WM_CHAR * n (wParam = VK_BACK, lParam = 0x1)
// WM_KEYUP * 1 (wParam = VK_BACK, lParam = 0xC00E0001)
// ---------------------------------------------------------------------------
// This message pattern does not match to the above case;
// i.e.,WM_KEYDOWN -> WM_CHAR -> WM_KEYDOWN -> WM_CHAR.
// For more information of this problem:
// https://bugzilla.mozilla.gr.jp/show_bug.cgi?id=2885 (written in Japanese)
// https://bugzilla.mozilla.org/show_bug.cgi?id=194559 (written in English)
MSG imeStartCompositionMsg, imeCompositionMsg, charMsg;
return ::PeekMessageW(&imeStartCompositionMsg, aWnd,
WM_IME_STARTCOMPOSITION, WM_IME_STARTCOMPOSITION,
PM_NOREMOVE | PM_NOYIELD) &&
::PeekMessageW(&imeCompositionMsg, aWnd, WM_IME_COMPOSITION,
WM_IME_COMPOSITION, PM_NOREMOVE | PM_NOYIELD) &&
::PeekMessageW(&charMsg, aWnd, WM_CHAR, WM_CHAR,
PM_NOREMOVE | PM_NOYIELD) &&
imeStartCompositionMsg.wParam == 0x0 &&
imeStartCompositionMsg.lParam == 0x0 &&
imeCompositionMsg.wParam == 0x0 &&
imeCompositionMsg.lParam == 0x1BF &&
charMsg.wParam == VK_BACK && charMsg.lParam == 0x1 &&
imeStartCompositionMsg.time <= imeCompositionMsg.time &&
imeCompositionMsg.time <= charMsg.time;
}
/* static */ bool
nsIMM32Handler::ShouldDrawCompositionStringOurselves()
{
@ -172,7 +137,7 @@ nsIMM32Handler::GetKeyboardCodePage()
}
/* static */ bool
nsIMM32Handler::CanOptimizeKeyAndIMEMessages(MSG *aNextKeyOrIMEMessage)
nsIMM32Handler::CanOptimizeKeyAndIMEMessages()
{
// If IME is opening right now, we shouldn't optimize the key and IME message
// order because ATOK (Japanese IME of third party) has some problem with the
@ -249,19 +214,19 @@ nsIMM32Handler::CommitComposition(nsWindow* aWindow, bool aForce)
return;
}
bool associated = aWindow->AssociateDefaultIMC(true);
nsIMEContext IMEContext(aWindow->GetWindowHandle());
bool associated = IMEContext.AssociateDefaultContext();
PR_LOG(gIMM32Log, PR_LOG_ALWAYS,
("IMM32: CommitComposition, associated=%s\n",
associated ? "YES" : "NO"));
nsIMEContext IMEContext(aWindow->GetWindowHandle());
if (IMEContext.IsValid()) {
::ImmNotifyIME(IMEContext.get(), NI_COMPOSITIONSTR, CPS_COMPLETE, 0);
::ImmNotifyIME(IMEContext.get(), NI_COMPOSITIONSTR, CPS_CANCEL, 0);
}
if (associated) {
aWindow->AssociateDefaultIMC(false);
IMEContext.Disassociate();
}
}
@ -280,18 +245,18 @@ nsIMM32Handler::CancelComposition(nsWindow* aWindow, bool aForce)
return;
}
bool associated = aWindow->AssociateDefaultIMC(true);
nsIMEContext IMEContext(aWindow->GetWindowHandle());
bool associated = IMEContext.AssociateDefaultContext();
PR_LOG(gIMM32Log, PR_LOG_ALWAYS,
("IMM32: CancelComposition, associated=%s\n",
associated ? "YES" : "NO"));
nsIMEContext IMEContext(aWindow->GetWindowHandle());
if (IMEContext.IsValid()) {
::ImmNotifyIME(IMEContext.get(), NI_COMPOSITIONSTR, CPS_CANCEL, 0);
}
if (associated) {
aWindow->AssociateDefaultIMC(false);
IMEContext.Disassociate();
}
}

Просмотреть файл

@ -16,9 +16,6 @@ class nsIWidget;
class nsWindow;
struct nsIntRect;
#define NS_WM_IMEFIRST WM_IME_SETCONTEXT
#define NS_WM_IMELAST WM_IME_KEYUP
class nsIMEContext
{
public:
@ -45,6 +42,48 @@ public:
return !!mIMC;
}
void SetOpenState(bool aOpen) const
{
if (!mIMC) {
return;
}
::ImmSetOpenStatus(mIMC, aOpen);
}
bool GetOpenState() const
{
if (!mIMC) {
return false;
}
return (::ImmGetOpenStatus(mIMC) != FALSE);
}
bool AssociateDefaultContext()
{
// We assume that there is only default IMC, no new IMC has been created.
if (mIMC) {
return false;
}
if (!::ImmAssociateContextEx(mWnd, NULL, IACE_DEFAULT)) {
return false;
}
mIMC = ::ImmGetContext(mWnd);
return (mIMC != NULL);
}
bool Disassociate()
{
if (!mIMC) {
return false;
}
if (!::ImmAssociateContextEx(mWnd, NULL, 0)) {
return false;
}
::ImmReleaseContext(mWnd, mIMC);
mIMC = NULL;
return true;
}
protected:
nsIMEContext()
{
@ -83,9 +122,7 @@ public:
return IsComposing() && IsComposingWindow(aWindow);
}
static bool IsDoingKakuteiUndo(HWND aWnd);
static bool CanOptimizeKeyAndIMEMessages(MSG *aNextKeyOrIMEMessage);
static bool CanOptimizeKeyAndIMEMessages();
#ifdef DEBUG
/**

Просмотреть файл

@ -2817,9 +2817,7 @@ nsTextStore::OnFocusChange(bool aGotFocus,
GetIMEEnabledName(aIMEEnabled), sTsfThreadMgr, sTsfTextStore));
// no change notifications if TSF is disabled
if (!sTsfThreadMgr || !sTsfTextStore) {
return NS_ERROR_NOT_AVAILABLE;
}
NS_ENSURE_TRUE(sTsfThreadMgr && sTsfTextStore, NS_ERROR_NOT_AVAILABLE);
if (aGotFocus) {
bool bRet = sTsfTextStore->Create(aFocusedWidget, aIMEEnabled);
@ -3179,3 +3177,57 @@ nsTextStore::Terminate(void)
NS_RELEASE(sTsfThreadMgr);
}
}
#ifdef DEBUG
// static
bool
nsTextStore::CurrentKeyboardLayoutHasIME()
{
// XXX MSDN documents that ITfInputProcessorProfiles is available only on
// desktop apps. However, there is no known way to obtain
// ITfInputProcessorProfileMgr instance without ITfInputProcessorProfiles
// instance.
nsRefPtr<ITfInputProcessorProfiles> profiles;
HRESULT hr = ::CoCreateInstance(CLSID_TF_InputProcessorProfiles, NULL,
CLSCTX_INPROC_SERVER,
IID_ITfInputProcessorProfiles,
getter_AddRefs(profiles));
if (FAILED(hr) || !profiles) {
PR_LOG(sTextStoreLog, PR_LOG_ERROR,
("TSF: nsTextStore::CurrentKeyboardLayoutHasIME() FAILED to create "
"an input processor profiles instance"));
return false;
}
nsRefPtr<ITfInputProcessorProfileMgr> profileMgr;
hr = profiles->QueryInterface(IID_ITfInputProcessorProfileMgr,
getter_AddRefs(profileMgr));
if (FAILED(hr) || !profileMgr) {
// On Windows Vista or later, ImmIsIME() API always returns true.
// If we failed to obtain the profile manager, we cannot know if current
// keyboard layout has IME.
if (WinUtils::GetWindowsVersion() >= WinUtils::VISTA_VERSION) {
PR_LOG(sTextStoreLog, PR_LOG_ERROR,
("TSF: nsTextStore::CurrentKeyboardLayoutHasIME() FAILED to query "
"ITfInputProcessorProfileMgr"));
return false;
}
// If the profiles instance doesn't have ITfInputProcessorProfileMgr
// interface, that means probably we're running on WinXP or WinServer2003
// (except WinServer2003 R2). Then, we should use ImmIsIME().
return ::ImmIsIME(::GetKeyboardLayout(0));
}
TF_INPUTPROCESSORPROFILE profile;
hr = profileMgr->GetActiveProfile(GUID_TFCAT_TIP_KEYBOARD, &profile);
if (hr == S_FALSE) {
return false; // not found or not active
}
if (FAILED(hr)) {
PR_LOG(sTextStoreLog, PR_LOG_ERROR,
("TSF: nsTextStore::CurrentKeyboardLayoutHasIME() FAILED to retreive "
"active profile"));
return false;
}
return (profile.dwProfileType == TF_PROFILETYPE_INPUTPROCESSOR);
}
#endif // #ifdef DEBUG

Просмотреть файл

@ -101,13 +101,13 @@ public:
static void CommitComposition(bool aDiscard)
{
if (!sTsfTextStore) return;
NS_ENSURE_TRUE_VOID(sTsfTextStore);
sTsfTextStore->CommitCompositionInternal(aDiscard);
}
static void SetInputContext(const InputContext& aContext)
{
if (!sTsfTextStore) return;
NS_ENSURE_TRUE_VOID(sTsfTextStore);
sTsfTextStore->SetInputScope(aContext.mHTMLInputType);
sTsfTextStore->SetInputContextInternal(aContext.mIMEState.mEnabled);
}
@ -119,13 +119,13 @@ public:
uint32_t aOldEnd,
uint32_t aNewEnd)
{
if (!sTsfTextStore) return NS_OK;
NS_ENSURE_TRUE(sTsfTextStore, NS_ERROR_NOT_AVAILABLE);
return sTsfTextStore->OnTextChangeInternal(aStart, aOldEnd, aNewEnd);
}
static void OnTextChangeMsg(void)
{
if (!sTsfTextStore) return;
NS_ENSURE_TRUE_VOID(sTsfTextStore);
// Notify TSF text change
// (see comments on WM_USER_TSF_TEXTCHANGE in nsTextStore.h)
sTsfTextStore->OnTextChangeMsgInternal();
@ -133,7 +133,7 @@ public:
static nsresult OnSelectionChange(void)
{
if (!sTsfTextStore) return NS_OK;
NS_ENSURE_TRUE(sTsfTextStore, NS_ERROR_NOT_AVAILABLE);
return sTsfTextStore->OnSelectionChangeInternal();
}
@ -145,24 +145,59 @@ public:
ts->OnCompositionTimer();
}
static bool CanOptimizeKeyAndIMEMessages()
{
// TODO: We need to implement this for ATOK.
return true;
}
// Returns the address of the pointer so that the TSF automatic test can
// replace the system object with a custom implementation for testing.
static void* GetThreadMgr(void)
static void* GetNativeData(uint32_t aDataType)
{
Initialize(); // Apply any previous changes
return (void*) & sTsfThreadMgr;
switch (aDataType) {
case NS_NATIVE_TSF_THREAD_MGR:
Initialize(); // Apply any previous changes
return static_cast<void*>(&sTsfThreadMgr);
case NS_NATIVE_TSF_CATEGORY_MGR:
return static_cast<void*>(&sCategoryMgr);
case NS_NATIVE_TSF_DISPLAY_ATTR_MGR:
return static_cast<void*>(&sDisplayAttrMgr);
default:
return nullptr;
}
}
static void* GetCategoryMgr(void)
static void* GetTextStore()
{
return (void*) & sCategoryMgr;
return static_cast<void*>(sTsfTextStore);
}
static void* GetDisplayAttrMgr(void)
static bool ThinksHavingFocus()
{
return (void*) & sDisplayAttrMgr;
return (sTsfTextStore && sTsfTextStore->mContext);
}
static bool IsInTSFMode()
{
return sTsfThreadMgr != nullptr;
}
static bool IsComposing()
{
return (sTsfTextStore && sTsfTextStore->mCompositionView != nullptr);
}
static bool IsComposingOn(nsWindowBase* aWidget)
{
return (IsComposing() && sTsfTextStore->mWidget == aWidget);
}
#ifdef DEBUG
// Returns true when keyboard layout has IME (TIP).
static bool CurrentKeyboardLayoutHasIME();
#endif // #ifdef DEBUG
protected:
nsTextStore();
~nsTextStore();

Просмотреть файл

@ -153,10 +153,6 @@
#include "nsIWinTaskbar.h"
#define NS_TASKBAR_CONTRACTID "@mozilla.org/windows-taskbar;1"
#if defined(NS_ENABLE_TSF)
#include "nsTextStore.h"
#endif // defined(NS_ENABLE_TSF)
// Windowless plugin support
#include "npapi.h"
@ -168,7 +164,7 @@
#include "nsIContent.h"
#include "mozilla/HangMonitor.h"
#include "nsIMM32Handler.h"
#include "WinIMEHandler.h"
using namespace mozilla::widget;
using namespace mozilla::layers;
@ -362,11 +358,7 @@ nsWindow::nsWindow() : nsWindowBase()
// WinTaskbar.cpp for details.
mozilla::widget::WinTaskbar::RegisterAppUserModelID();
gKbdLayout.LoadLayout(::GetKeyboardLayout(0));
// Init IME handler
nsIMM32Handler::Initialize();
#ifdef NS_ENABLE_TSF
nsTextStore::Initialize();
#endif
IMEHandler::Initialize();
if (SUCCEEDED(::OleInitialize(NULL))) {
sIsOleInitialized = TRUE;
}
@ -406,17 +398,13 @@ nsWindow::~nsWindow()
// Global shutdown
if (sInstanceCount == 0) {
#ifdef NS_ENABLE_TSF
nsTextStore::Terminate();
#endif
IMEHandler::Terminate();
NS_IF_RELEASE(sCursorImgContainer);
if (sIsOleInitialized) {
::OleFlushClipboard();
::OleUninitialize();
sIsOleInitialized = FALSE;
}
// delete any of the IME structures that we allocated
nsIMM32Handler::Terminate();
}
NS_IF_RELEASE(mNativeDragTarget);
@ -596,16 +584,7 @@ nsWindow::Create(nsIWidget *aParent,
SubclassWindow(TRUE);
// NOTE: mNativeIMEContext may be null if IMM module isn't installed.
nsIMEContext IMEContext(mWnd);
mInputContext.mNativeIMEContext = static_cast<void*>(IMEContext.get());
MOZ_ASSERT(mInputContext.mNativeIMEContext ||
!nsIMM32Handler::IsIMEAvailable());
// If no IME context is available, we should set this widget's pointer since
// nullptr indicates there is only one context per process on the platform.
if (!mInputContext.mNativeIMEContext) {
mInputContext.mNativeIMEContext = this;
}
IMEHandler::InitInputContext(this, mInputContext);
// If the internal variable set by the config.trim_on_minimize pref has not
// been initialized, and if this is the hidden window (conveniently created
@ -2867,14 +2846,10 @@ void* nsWindow::GetNativeData(uint32_t aDataType)
return (void*)::GetDC(mWnd);
#endif
#ifdef NS_ENABLE_TSF
case NS_NATIVE_TSF_THREAD_MGR:
return nsTextStore::GetThreadMgr();
case NS_NATIVE_TSF_CATEGORY_MGR:
return nsTextStore::GetCategoryMgr();
case NS_NATIVE_TSF_DISPLAY_ATTR_MGR:
return nsTextStore::GetDisplayAttrMgr();
#endif //NS_ENABLE_TSF
return IMEHandler::GetNativeData(aDataType);
default:
break;
@ -4509,8 +4484,8 @@ bool nsWindow::ProcessMessage(UINT msg, WPARAM &wParam, LPARAM &lParam,
#endif
bool eatMessage;
if (nsIMM32Handler::ProcessMessage(this, msg, wParam, lParam, aRetValue,
eatMessage)) {
if (IMEHandler::ProcessMessage(this, msg, wParam, lParam, aRetValue,
eatMessage)) {
return mWnd ? eatMessage : true;
}
@ -5432,11 +5407,6 @@ bool nsWindow::ProcessMessage(UINT msg, WPARAM &wParam, LPARAM &lParam,
default:
{
#ifdef NS_ENABLE_TSF
if (msg == WM_USER_TSF_TEXTCHANGE) {
nsTextStore::OnTextChangeMsg();
}
#endif //NS_ENABLE_TSF
if (msg == nsAppShell::GetTaskbarButtonCreatedMessage())
SetHasTaskbarIconBeenCreated();
if (msg == sOOPPPluginFocusEvent) {
@ -5707,7 +5677,7 @@ LRESULT nsWindow::ProcessKeyUpMessage(const MSG &aMsg, bool *aEventDispatched)
return FALSE;
}
if (!nsIMM32Handler::IsComposingOn(this)) {
if (!IMEHandler::IsComposingOn(this)) {
return OnKeyUp(aMsg, modKeyState, aEventDispatched);
}
@ -5746,7 +5716,7 @@ LRESULT nsWindow::ProcessKeyDownMessage(const MSG &aMsg,
return FALSE;
LRESULT result = 0;
if (!nsIMM32Handler::IsComposingOn(this)) {
if (!IMEHandler::IsComposingOn(this)) {
result = OnKeyDown(aMsg, modKeyState, aEventDispatched, nullptr);
// OnKeyDown cleaned up the redirected message information itself, so,
// we should do nothing.
@ -6501,7 +6471,7 @@ LRESULT nsWindow::OnKeyDown(const MSG &aMsg,
static bool sRedirectedKeyDownEventPreventedDefault = false;
bool noDefault;
if (aFakeCharMessage || !IsRedirectedKeyDownMessage(aMsg)) {
nsIMEContext IMEContext(mWnd);
bool isIMEEnabled = IMEHandler::IsIMEEnabled(mInputContext);
nsKeyEvent keydownEvent(true, NS_KEY_DOWN, this);
keydownEvent.keyCode = DOMKeyCode;
InitKeyEvent(keydownEvent, nativeKey, aModKeyState);
@ -6519,9 +6489,8 @@ LRESULT nsWindow::OnKeyDown(const MSG &aMsg,
// application, we shouldn't redirect the message to it because the keydown
// message is processed by us, so, nobody shouldn't process it.
HWND focusedWnd = ::GetFocus();
nsIMEContext newIMEContext(mWnd);
if (!noDefault && !aFakeCharMessage && focusedWnd && !PluginHasFocus() &&
!IMEContext.get() && newIMEContext.get()) {
!isIMEEnabled && IMEHandler::IsIMEEnabled(mInputContext)) {
RemoveNextCharMessage(focusedWnd);
INPUT keyinput;
@ -6617,7 +6586,7 @@ LRESULT nsWindow::OnKeyDown(const MSG &aMsg,
}
if (!anyCharMessagesRemoved && DOMKeyCode == NS_VK_BACK &&
nsIMM32Handler::IsDoingKakuteiUndo(mWnd)) {
IMEHandler::IsDoingKakuteiUndo(mWnd)) {
NS_ASSERTION(!aFakeCharMessage,
"We shouldn't be touching the real msg queue");
RemoveMessageAndDispatchPluginEvent(WM_CHAR, WM_CHAR);
@ -6891,7 +6860,7 @@ LRESULT nsWindow::OnChar(const MSG &aMsg,
modKeyState.Unset(MODIFIER_ALT | MODIFIER_CONTROL);
}
if (nsIMM32Handler::IsComposingOn(this)) {
if (IMEHandler::IsComposingOn(this)) {
ResetInputState();
}
@ -7212,8 +7181,7 @@ void nsWindow::OnDestroy()
CaptureRollupEvents(nullptr, false);
}
// Restore the IM context.
AssociateDefaultIMC(true);
IMEHandler::OnDestroyWindow(this);
// Turn off mouse trails if enabled.
MouseTrailer* mtrailer = nsToolkit::gMouseTrailer;
@ -7396,94 +7364,33 @@ nsWindow::OnSysColorChanged()
NS_IMETHODIMP nsWindow::ResetInputState()
{
#ifdef DEBUG_KBSTATE
PR_LOG(gWindowsLog, PR_LOG_ALWAYS, ("ResetInputState\n"));
#endif
#ifdef NS_ENABLE_TSF
nsTextStore::CommitComposition(false);
#endif //NS_ENABLE_TSF
nsIMM32Handler::CommitComposition(this);
return NS_OK;
return IMEHandler::NotifyIME(this, REQUEST_TO_COMMIT_COMPOSITION);
}
NS_IMETHODIMP_(void)
nsWindow::SetInputContext(const InputContext& aContext,
const InputContextAction& aAction)
{
#ifdef NS_ENABLE_TSF
nsTextStore::SetInputContext(aContext);
#endif //NS_ENABLE_TSF
if (nsIMM32Handler::IsComposing()) {
ResetInputState();
}
void* nativeIMEContext = mInputContext.mNativeIMEContext;
mInputContext = aContext;
mInputContext.mNativeIMEContext = nullptr;
bool enable = (mInputContext.mIMEState.mEnabled == IMEState::ENABLED ||
mInputContext.mIMEState.mEnabled == IMEState::PLUGIN);
AssociateDefaultIMC(enable);
if (enable) {
nsIMEContext IMEContext(mWnd);
mInputContext.mNativeIMEContext = static_cast<void*>(IMEContext.get());
}
// Restore the latest associated context when we cannot get actual context.
if (!mInputContext.mNativeIMEContext) {
mInputContext.mNativeIMEContext = nativeIMEContext;
}
if (enable &&
mInputContext.mIMEState.mOpen != IMEState::DONT_CHANGE_OPEN_STATE) {
bool open = (mInputContext.mIMEState.mOpen == IMEState::OPEN);
#ifdef NS_ENABLE_TSF
nsTextStore::SetIMEOpenState(open);
#endif //NS_ENABLE_TSF
nsIMEContext IMEContext(mWnd);
if (IMEContext.IsValid()) {
::ImmSetOpenStatus(IMEContext.get(), open);
}
}
InputContext newInputContext = aContext;
IMEHandler::SetInputContext(this, newInputContext);
mInputContext = newInputContext;
}
NS_IMETHODIMP_(InputContext)
nsWindow::GetInputContext()
{
mInputContext.mIMEState.mOpen = IMEState::CLOSED;
switch (mInputContext.mIMEState.mEnabled) {
case IMEState::ENABLED:
case IMEState::PLUGIN: {
nsIMEContext IMEContext(mWnd);
if (IMEContext.IsValid()) {
mInputContext.mIMEState.mOpen =
::ImmGetOpenStatus(IMEContext.get()) ? IMEState::OPEN :
IMEState::CLOSED;
}
#ifdef NS_ENABLE_TSF
if (mInputContext.mIMEState.mOpen == IMEState::CLOSED &&
nsTextStore::GetIMEOpenState()) {
mInputContext.mIMEState.mOpen = IMEState::OPEN;
}
#endif //NS_ENABLE_TSF
}
if (IMEHandler::IsIMEEnabled(mInputContext) && IMEHandler::GetOpenState(this)) {
mInputContext.mIMEState.mOpen = IMEState::OPEN;
} else {
mInputContext.mIMEState.mOpen = IMEState::CLOSED;
}
return mInputContext;
}
NS_IMETHODIMP nsWindow::CancelIMEComposition()
{
#ifdef DEBUG_KBSTATE
PR_LOG(gWindowsLog, PR_LOG_ALWAYS, ("CancelIMEComposition\n"));
#endif
#ifdef NS_ENABLE_TSF
nsTextStore::CommitComposition(true);
#endif //NS_ENABLE_TSF
nsIMM32Handler::CancelComposition(this);
return NS_OK;
return IMEHandler::NotifyIME(this, REQUEST_TO_CANCEL_COMPOSITION);
}
NS_IMETHODIMP
@ -7497,15 +7404,11 @@ nsWindow::GetToggledKeyState(uint32_t aKeyCode, bool* aLEDState)
return NS_OK;
}
#ifdef NS_ENABLE_TSF
NS_IMETHODIMP
nsWindow::OnIMEFocusChange(bool aFocus)
{
nsresult rv = nsTextStore::OnFocusChange(aFocus, this,
mInputContext.mIMEState.mEnabled);
if (rv == NS_ERROR_NOT_AVAILABLE)
rv = NS_OK; // TSF is not enabled, maybe.
return rv;
return IMEHandler::NotifyIME(this, aFocus ? NOTIFY_IME_OF_FOCUS :
NOTIFY_IME_OF_BLUR);
}
NS_IMETHODIMP
@ -7513,57 +7416,19 @@ nsWindow::OnIMETextChange(uint32_t aStart,
uint32_t aOldEnd,
uint32_t aNewEnd)
{
return nsTextStore::OnTextChange(aStart, aOldEnd, aNewEnd);
return IMEHandler::NotifyIMEOfTextChange(aStart, aOldEnd, aNewEnd);
}
NS_IMETHODIMP
nsWindow::OnIMESelectionChange(void)
{
return nsTextStore::OnSelectionChange();
return IMEHandler::NotifyIME(this, NOTIFY_IME_OF_SELECTION_CHANGE);
}
nsIMEUpdatePreference
nsWindow::GetIMEUpdatePreference()
{
return nsTextStore::GetIMEUpdatePreference();
}
#endif //NS_ENABLE_TSF
bool nsWindow::AssociateDefaultIMC(bool aAssociate)
{
nsIMEContext IMEContext(mWnd);
if (aAssociate) {
BOOL ret = ::ImmAssociateContextEx(mWnd, NULL, IACE_DEFAULT);
#ifdef DEBUG
// Note that if IME isn't available with current keyboard layout,
// IMM might not be installed on the system such as English Windows.
// On such system, IMM APIs always fail.
NS_ASSERTION(ret || !nsIMM32Handler::IsIMEAvailable(),
"ImmAssociateContextEx failed to restore default IMC");
if (ret) {
nsIMEContext newIMEContext(mWnd);
NS_ASSERTION(!IMEContext.get() || newIMEContext.get() == IMEContext.get(),
"Unknown IMC had been associated");
}
#endif
return ret && !IMEContext.get();
}
if (mOnDestroyCalled) {
// If OnDestroy() has been called, we shouldn't disassociate the default
// IMC at destroying the window.
return false;
}
if (!IMEContext.get()) {
return false; // already disassociated
}
BOOL ret = ::ImmAssociateContextEx(mWnd, NULL, 0);
NS_ASSERTION(ret, "ImmAssociateContextEx failed to disassociate the IMC");
return ret != FALSE;
return IMEHandler::GetUpdatePreference();
}
#ifdef ACCESSIBILITY

Просмотреть файл

@ -176,12 +176,10 @@ public:
virtual nsTransparencyMode GetTransparencyMode();
virtual void UpdateOpaqueRegion(const nsIntRegion& aOpaqueRegion);
#endif // MOZ_XUL
#ifdef NS_ENABLE_TSF
NS_IMETHOD OnIMEFocusChange(bool aFocus);
NS_IMETHOD OnIMETextChange(uint32_t aStart, uint32_t aOldEnd, uint32_t aNewEnd);
NS_IMETHOD OnIMESelectionChange(void);
virtual nsIMEUpdatePreference GetIMEUpdatePreference();
#endif // NS_ENABLE_TSF
NS_IMETHOD GetNonClientMargins(nsIntMargin &margins);
NS_IMETHOD SetNonClientMargins(nsIntMargin &margins);
void SetDrawsInTitlebar(bool aState);

Просмотреть файл

@ -20,12 +20,6 @@ using namespace ABI::Windows::Foundation;
using namespace Microsoft::WRL;
using namespace Microsoft::WRL::Wrappers;
// XXX move
#pragma comment(lib, "dwrite.lib")
#pragma comment(lib, "d2d1.lib")
#pragma comment(lib, "d3d11.lib")
#pragma comment(lib, "runtimeobject.lib")
// Metro specific XRE methods we call from here on an
// appropriate thread.
extern nsresult XRE_metroStartup();

Просмотреть файл

@ -1025,11 +1025,9 @@ MetroWidget::GetNativeData(uint32_t aDataType)
}
break;
case NS_NATIVE_TSF_THREAD_MGR:
return nsTextStore::GetThreadMgr();
case NS_NATIVE_TSF_CATEGORY_MGR:
return nsTextStore::GetCategoryMgr();
case NS_NATIVE_TSF_DISPLAY_ATTR_MGR:
return nsTextStore::GetDisplayAttrMgr();
return nsTextStore::GetNativeData(aDataType);
}
return nullptr;
}