зеркало из https://github.com/mozilla/gecko-dev.git
Merge m-c to b-i
This commit is contained in:
Коммит
e0a2166785
|
@ -409,6 +409,14 @@ XULTreeGridRowAccessible::RowInvalidated(int32_t aStartColIdx,
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsAutoString name;
|
||||
Name(name);
|
||||
|
||||
if (name != mCachedName) {
|
||||
nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_NAME_CHANGE, this);
|
||||
mCachedName = name;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -106,6 +106,7 @@ protected:
|
|||
|
||||
// XULTreeItemAccessibleBase
|
||||
mutable AccessibleHashtable mAccessibleCache;
|
||||
nsString mCachedName;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -92,6 +92,7 @@
|
|||
|
||||
case kShowElm:
|
||||
aNode.style.display = "block";
|
||||
break;
|
||||
|
||||
default:
|
||||
return INVOKER_ACTION_FAILED;
|
||||
|
|
|
@ -97,6 +97,26 @@
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check name changed a11y event for a row.
|
||||
*/
|
||||
function rowNameChangeChecker(aMsg, aRow)
|
||||
{
|
||||
this.type = EVENT_NAME_CHANGE;
|
||||
|
||||
function targetGetter()
|
||||
{
|
||||
var acc = getAccessible(gTree);
|
||||
return acc.getChildAt(aRow + 1);
|
||||
}
|
||||
Object.defineProperty(this, "target", { get: targetGetter });
|
||||
|
||||
this.getID = function getID()
|
||||
{
|
||||
return aMsg + "name changed";
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Invokers
|
||||
|
||||
|
@ -221,9 +241,10 @@
|
|||
|
||||
this.eventSeq =
|
||||
[
|
||||
new nameChangeChecker("invalidateColumn: ", 1, 0),
|
||||
new nameChangeChecker("invalidateColumn: ", 1, 1),
|
||||
new treeInvalidatedChecker("invalidateColumn", 1, 1, null, null)
|
||||
new nameChangeChecker("invalidateRow: ", 1, 0),
|
||||
new nameChangeChecker("invalidateRow: ", 1, 1),
|
||||
new rowNameChangeChecker("invalidateRow: ", 1),
|
||||
new treeInvalidatedChecker("invalidateRow", 1, 1, null, null)
|
||||
];
|
||||
|
||||
this.getID = function invalidateRow_getID()
|
||||
|
@ -277,11 +298,16 @@
|
|||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=308564"
|
||||
title="No accessibility events when data in a tree row changes.">
|
||||
Mozilla Bug 308564
|
||||
</a>
|
||||
</a><br/>
|
||||
<a target="_blank"
|
||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=739524"
|
||||
title="replace TreeViewChanged DOM event on direct call from XUL tree.">
|
||||
Mozilla Bug 739524
|
||||
</a><br/>
|
||||
<a target="_blank"
|
||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=743568"
|
||||
title="Thunderbird message list tree emitting incorrect focus signals after message deleted.">
|
||||
Mozilla Bug 743568
|
||||
</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
|
|
@ -15,4 +15,5 @@ support-files =
|
|||
[test_output.html]
|
||||
[test_tables.html]
|
||||
[test_touch_adapter.html]
|
||||
skip-if = true # disabled for a number of intermitten failures: Bug 982326
|
||||
[test_traversal.html]
|
||||
|
|
|
@ -293,7 +293,7 @@
|
|||
accesskey="&keywordfield.accesskey;"
|
||||
oncommand="AddKeywordForSearchField();"/>
|
||||
<menuitem id="context-searchselect"
|
||||
oncommand="BrowserSearch.loadSearchFromContext(getBrowserSelection());"/>
|
||||
oncommand="BrowserSearch.loadSearchFromContext(this.searchTerms);"/>
|
||||
<menuitem id="context-shareselect"
|
||||
label="&shareSelectCmd.label;"
|
||||
accesskey="&shareSelectCmd.accesskey;"
|
||||
|
|
|
@ -32,7 +32,7 @@ nsContextMenu.prototype = {
|
|||
this.ellipsis = gPrefService.getComplexValue("intl.ellipsis",
|
||||
Ci.nsIPrefLocalizedString).data;
|
||||
} catch (e) { }
|
||||
this.isTextSelected = this.isTextSelection();
|
||||
|
||||
this.isContentSelected = this.isContentSelection();
|
||||
this.onPlainTextLink = false;
|
||||
|
||||
|
@ -268,19 +268,22 @@ nsContextMenu.prototype = {
|
|||
},
|
||||
|
||||
initMiscItems: function CM_initMiscItems() {
|
||||
var isTextSelected = this.isTextSelected;
|
||||
|
||||
// Use "Bookmark This Link" if on a link.
|
||||
this.showItem("context-bookmarkpage",
|
||||
!(this.isContentSelected || this.onTextInput || this.onLink ||
|
||||
this.onImage || this.onVideo || this.onAudio || this.onSocial));
|
||||
this.showItem("context-bookmarklink", (this.onLink && !this.onMailtoLink &&
|
||||
!this.onSocial) || this.onPlainTextLink);
|
||||
this.showItem("context-searchselect", isTextSelected);
|
||||
this.showItem("context-keywordfield",
|
||||
this.onTextInput && this.onKeywordField);
|
||||
this.showItem("frame", this.inFrame);
|
||||
|
||||
let showSearchSelect = (this.isTextSelected || this.onLink) && !this.onImage;
|
||||
this.showItem("context-searchselect", showSearchSelect);
|
||||
if (showSearchSelect) {
|
||||
this.formatSearchContextItem();
|
||||
}
|
||||
|
||||
// srcdoc cannot be opened separately due to concerns about web
|
||||
// content with about:srcdoc in location bar masquerading as trusted
|
||||
// chrome/addon content.
|
||||
|
@ -292,7 +295,7 @@ nsContextMenu.prototype = {
|
|||
this.showItem("context-bookmarkframe", !this.inSrcdocFrame);
|
||||
this.showItem("open-frame-sep", !this.inSrcdocFrame);
|
||||
|
||||
this.showItem("frame-sep", this.inFrame && isTextSelected);
|
||||
this.showItem("frame-sep", this.inFrame && this.isTextSelected);
|
||||
|
||||
// Hide menu entries for images, show otherwise
|
||||
if (this.inFrame) {
|
||||
|
@ -540,6 +543,8 @@ nsContextMenu.prototype = {
|
|||
this.isDesignMode = false;
|
||||
this.onCTPPlugin = false;
|
||||
this.canSpellCheck = false;
|
||||
this.textSelected = getBrowserSelection();
|
||||
this.isTextSelected = this.textSelected.length != 0;
|
||||
|
||||
// Remember the node that was clicked.
|
||||
this.target = aNode;
|
||||
|
@ -1442,39 +1447,6 @@ nsContextMenu.prototype = {
|
|||
return text;
|
||||
},
|
||||
|
||||
// Get selected text. Only display the first 15 chars.
|
||||
isTextSelection: function() {
|
||||
// Get 16 characters, so that we can trim the selection if it's greater
|
||||
// than 15 chars
|
||||
var selectedText = getBrowserSelection(16);
|
||||
|
||||
if (!selectedText)
|
||||
return false;
|
||||
|
||||
if (selectedText.length > 15)
|
||||
selectedText = selectedText.substr(0,15) + this.ellipsis;
|
||||
|
||||
// Use the current engine if the search bar is visible, the default
|
||||
// engine otherwise.
|
||||
var engineName = "";
|
||||
var ss = Cc["@mozilla.org/browser/search-service;1"].
|
||||
getService(Ci.nsIBrowserSearchService);
|
||||
if (isElementVisible(BrowserSearch.searchBar))
|
||||
engineName = ss.currentEngine.name;
|
||||
else
|
||||
engineName = ss.defaultEngine.name;
|
||||
|
||||
// format "Search <engine> for <selection>" string to show in menu
|
||||
var menuLabel = gNavigatorBundle.getFormattedString("contextMenuSearch",
|
||||
[engineName,
|
||||
selectedText]);
|
||||
document.getElementById("context-searchselect").label = menuLabel;
|
||||
document.getElementById("context-searchselect").accessKey =
|
||||
gNavigatorBundle.getString("contextMenuSearch.accesskey");
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
// Returns true if anything is selected.
|
||||
isContentSelection: function() {
|
||||
return !document.commandDispatcher.focusedWindow.getSelection().isCollapsed;
|
||||
|
@ -1688,5 +1660,34 @@ nsContextMenu.prototype = {
|
|||
if (this.onImage)
|
||||
return this.mediaURL;
|
||||
return "";
|
||||
},
|
||||
|
||||
// Formats the 'Search <engine> for "<selection or link text>"' context menu.
|
||||
formatSearchContextItem: function() {
|
||||
var menuItem = document.getElementById("context-searchselect");
|
||||
var selectedText = this.onLink ? this.linkText() : this.textSelected;
|
||||
|
||||
// Store searchTerms in context menu item so we know what to search onclick
|
||||
menuItem.searchTerms = selectedText;
|
||||
|
||||
if (selectedText.length > 15)
|
||||
selectedText = selectedText.substr(0,15) + this.ellipsis;
|
||||
|
||||
// Use the current engine if the search bar is visible, the default
|
||||
// engine otherwise.
|
||||
var engineName = "";
|
||||
var ss = Cc["@mozilla.org/browser/search-service;1"].
|
||||
getService(Ci.nsIBrowserSearchService);
|
||||
if (isElementVisible(BrowserSearch.searchBar))
|
||||
engineName = ss.currentEngine.name;
|
||||
else
|
||||
engineName = ss.defaultEngine.name;
|
||||
|
||||
// format "Search <engine> for <selection>" string to show in menu
|
||||
var menuLabel = gNavigatorBundle.getFormattedString("contextMenuSearch",
|
||||
[engineName,
|
||||
selectedText]);
|
||||
menuItem.label = menuLabel;
|
||||
menuItem.accessKey = gNavigatorBundle.getString("contextMenuSearch.accesskey");
|
||||
}
|
||||
};
|
||||
|
|
|
@ -9,6 +9,7 @@ support-files =
|
|||
browser_bug479408_sample.html
|
||||
browser_bug678392-1.html
|
||||
browser_bug678392-2.html
|
||||
browser_bug970746.xhtml
|
||||
browser_registerProtocolHandler_notification.html
|
||||
browser_star_hsts.sjs
|
||||
browser_tab_dragdrop2_frame1.xul
|
||||
|
@ -202,6 +203,7 @@ skip-if = os == "mac" # Intermittent failures, bug 925225
|
|||
[browser_bug882977.js]
|
||||
[browser_bug902156.js]
|
||||
[browser_bug906190.js]
|
||||
[browser_bug970746.js]
|
||||
[browser_canonizeURL.js]
|
||||
[browser_contentAreaClick.js]
|
||||
[browser_contextSearchTabPosition.js]
|
||||
|
|
|
@ -0,0 +1,104 @@
|
|||
/* Make sure context menu includes option to search hyperlink text on search engine */
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
gBrowser.selectedTab = gBrowser.addTab();
|
||||
|
||||
gBrowser.selectedBrowser.addEventListener("load", function() {
|
||||
gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
|
||||
|
||||
let doc = gBrowser.contentDocument;
|
||||
let contentAreaContextMenu = document.getElementById("contentAreaContextMenu");
|
||||
let ellipsis = "\u2026";
|
||||
|
||||
// Tests if the "Search <engine> for '<some terms>'" context menu item is shown for the
|
||||
// given query string of an element. Tests to make sure label includes the proper search terms.
|
||||
//
|
||||
// Options:
|
||||
//
|
||||
// id: The id of the element to test.
|
||||
// isSelected: Flag to enable selection (text hilight) the contents of the element
|
||||
// shouldBeShown: The display state of the menu item
|
||||
// expectedLabelContents: The menu item label should contain a portion of this string.
|
||||
// Will only be tested if shouldBeShown is true.
|
||||
|
||||
let testElement = function(opts) {
|
||||
let element = doc.getElementById(opts.id);
|
||||
document.popupNode = element;
|
||||
|
||||
let selection = content.getSelection();
|
||||
selection.removeAllRanges();
|
||||
|
||||
if(opts.isSelected) {
|
||||
selection.selectAllChildren(element);
|
||||
}
|
||||
|
||||
let contextMenu = new nsContextMenu(contentAreaContextMenu);
|
||||
let menuItem = document.getElementById("context-searchselect");
|
||||
|
||||
is(document.getElementById("context-searchselect").hidden, !opts.shouldBeShown, "search context menu item is shown for '#" + opts.id + "' and selected is '" + opts.isSelected + "'");
|
||||
|
||||
if(opts.shouldBeShown) {
|
||||
ok(menuItem.label.contains(opts.expectedLabelContents), "Menu item text '" + menuItem.label + "' contains the correct search terms '" + opts.expectedLabelContents + "'");
|
||||
}
|
||||
}
|
||||
|
||||
testElement({
|
||||
id: "link",
|
||||
isSelected: true,
|
||||
shouldBeShown: true,
|
||||
expectedLabelContents: "I'm a link!",
|
||||
});
|
||||
testElement({
|
||||
id: "link",
|
||||
isSelected: false,
|
||||
shouldBeShown: true,
|
||||
expectedLabelContents: "I'm a link!",
|
||||
});
|
||||
|
||||
testElement({
|
||||
id: "longLink",
|
||||
isSelected: true,
|
||||
shouldBeShown: true,
|
||||
expectedLabelContents: "I'm a really lo" + ellipsis,
|
||||
});
|
||||
testElement({
|
||||
id: "longLink",
|
||||
isSelected: false,
|
||||
shouldBeShown: true,
|
||||
expectedLabelContents: "I'm a really lo" + ellipsis,
|
||||
});
|
||||
|
||||
testElement({
|
||||
id: "plainText",
|
||||
isSelected: true,
|
||||
shouldBeShown: true,
|
||||
expectedLabelContents: "Right clicking " + ellipsis,
|
||||
});
|
||||
testElement({
|
||||
id: "plainText",
|
||||
isSelected: false,
|
||||
shouldBeShown: false,
|
||||
});
|
||||
|
||||
testElement({
|
||||
id: "mixedContent",
|
||||
isSelected: true,
|
||||
shouldBeShown: true,
|
||||
expectedLabelContents: "I'm some text, " + ellipsis,
|
||||
});
|
||||
testElement({
|
||||
id: "mixedContent",
|
||||
isSelected: false,
|
||||
shouldBeShown: false,
|
||||
});
|
||||
|
||||
// cleanup
|
||||
document.popupNode = null;
|
||||
gBrowser.removeCurrentTab();
|
||||
finish();
|
||||
}, true);
|
||||
|
||||
content.location = "http://mochi.test:8888/browser/browser/base/content/test/general/browser_bug970746.xhtml";
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<body>
|
||||
<a href="http://mozilla.org" id="link">I'm a link!</a>
|
||||
<a href="http://mozilla.org" id="longLink">I'm a really long link and I should be truncated.</a>
|
||||
|
||||
<span id="plainText">
|
||||
Right clicking me when I'm selected should show the menu item.
|
||||
</span>
|
||||
<span id="mixedContent">
|
||||
I'm some text, and <a href="http://mozilla.org">I'm a link!</a>
|
||||
</span>
|
||||
</body>
|
||||
</html>
|
|
@ -118,7 +118,8 @@ function runTest(testNum) {
|
|||
"---", null,
|
||||
"context-bookmarklink", true,
|
||||
"context-savelink", true,
|
||||
"context-copylink", true
|
||||
"context-copylink", true,
|
||||
"context-searchselect", true
|
||||
].concat(inspectItems));
|
||||
} else {
|
||||
checkContextMenu(["context-openlinkintab", true,
|
||||
|
@ -126,7 +127,8 @@ function runTest(testNum) {
|
|||
"---", null,
|
||||
"context-bookmarklink", true,
|
||||
"context-savelink", true,
|
||||
"context-copylink", true
|
||||
"context-copylink", true,
|
||||
"context-searchselect", true
|
||||
].concat(inspectItems));
|
||||
}
|
||||
closeContextMenu();
|
||||
|
@ -135,7 +137,9 @@ function runTest(testNum) {
|
|||
|
||||
case 4:
|
||||
// Context menu for text mailto-link
|
||||
checkContextMenu(["context-copyemail", true].concat(inspectItems));
|
||||
checkContextMenu(["context-copyemail", true,
|
||||
"context-searchselect", true
|
||||
].concat(inspectItems));
|
||||
closeContextMenu();
|
||||
openContextMenuFor(img); // Invoke context menu for next test.
|
||||
break;
|
||||
|
|
|
@ -28,7 +28,9 @@ pref("app.update.checkInstallTime.days", 2);
|
|||
|
||||
// Search codes belong only in builds with official branding
|
||||
pref("browser.search.param.yahoo-fr", "");
|
||||
pref("browser.search.param.yahoo-fr-metro", "");
|
||||
pref("browser.search.param.yahoo-fr-cjkt", ""); // now unused
|
||||
pref("browser.search.param.yahoo-fr-ja", "");
|
||||
pref("browser.search.param.yahoo-f-CN", "");
|
||||
#ifdef MOZ_METRO
|
||||
pref("browser.search.param.yahoo-fr-metro", "");
|
||||
#endif
|
||||
|
|
|
@ -25,7 +25,9 @@ pref("app.update.checkInstallTime.days", 2);
|
|||
|
||||
// Search codes belong only in builds with official branding
|
||||
pref("browser.search.param.yahoo-fr", "");
|
||||
pref("browser.search.param.yahoo-fr-metro", "");
|
||||
pref("browser.search.param.yahoo-fr-cjkt", ""); // now unused
|
||||
pref("browser.search.param.yahoo-fr-ja", "");
|
||||
pref("browser.search.param.yahoo-f-CN", "");
|
||||
#ifdef MOZ_METRO
|
||||
pref("browser.search.param.yahoo-fr-metro", "");
|
||||
#endif
|
||||
|
|
|
@ -24,8 +24,10 @@ pref("app.update.url.details", "https://www.mozilla.org/%LOCALE%/firefox/notes")
|
|||
pref("app.update.checkInstallTime.days", 63);
|
||||
|
||||
pref("browser.search.param.ms-pc", "MOZI");
|
||||
pref("browser.search.param.ms-pc-metro", "MOZW");
|
||||
pref("browser.search.param.yahoo-fr", "moz35");
|
||||
pref("browser.search.param.yahoo-fr-metro", "mozilla_metro_search");
|
||||
pref("browser.search.param.yahoo-fr-cjkt", "moz35"); // now unused
|
||||
pref("browser.search.param.yahoo-fr-ja", "mozff");
|
||||
#ifdef MOZ_METRO
|
||||
pref("browser.search.param.ms-pc-metro", "MOZW");
|
||||
pref("browser.search.param.yahoo-fr-metro", "mozilla_metro_search");
|
||||
#endif
|
||||
|
|
|
@ -25,7 +25,9 @@ pref("app.update.checkInstallTime.days", 2);
|
|||
|
||||
// Search codes belong only in builds with official branding
|
||||
pref("browser.search.param.yahoo-fr", "");
|
||||
pref("browser.search.param.yahoo-fr-metro", "");
|
||||
pref("browser.search.param.yahoo-fr-cjkt", ""); // now unused
|
||||
pref("browser.search.param.yahoo-fr-ja", "");
|
||||
pref("browser.search.param.yahoo-f-CN", "");
|
||||
#ifdef MOZ_METRO
|
||||
pref("browser.search.param.yahoo-fr-metro", "");
|
||||
#endif
|
||||
|
|
|
@ -167,7 +167,7 @@ DistributionCustomizer.prototype = {
|
|||
, index: index
|
||||
, feedURI: this._makeURI(items[iid]["feedLink"])
|
||||
, siteURI: this._makeURI(items[iid]["siteLink"])
|
||||
});
|
||||
}).then(null, Cu.reportError);
|
||||
break;
|
||||
|
||||
case "bookmark":
|
||||
|
|
|
@ -251,24 +251,20 @@ var BookmarkPropertiesPanel = {
|
|||
|
||||
case "folder":
|
||||
this._itemType = BOOKMARK_FOLDER;
|
||||
PlacesUtils.livemarks.getLivemark(
|
||||
{ id: this._itemId },
|
||||
(function (aStatus, aLivemark) {
|
||||
if (Components.isSuccessCode(aStatus)) {
|
||||
this._itemType = LIVEMARK_CONTAINER;
|
||||
this._feedURI = aLivemark.feedURI;
|
||||
this._siteURI = aLivemark.siteURI;
|
||||
this._fillEditProperties();
|
||||
PlacesUtils.livemarks.getLivemark({ id: this._itemId })
|
||||
.then(aLivemark => {
|
||||
this._itemType = LIVEMARK_CONTAINER;
|
||||
this._feedURI = aLivemark.feedURI;
|
||||
this._siteURI = aLivemark.siteURI;
|
||||
this._fillEditProperties();
|
||||
|
||||
let acceptButton = document.documentElement.getButton("accept");
|
||||
acceptButton.disabled = !this._inputIsValid();
|
||||
let acceptButton = document.documentElement.getButton("accept");
|
||||
acceptButton.disabled = !this._inputIsValid();
|
||||
|
||||
let newHeight = window.outerHeight +
|
||||
this._element("descriptionField").boxObject.height;
|
||||
window.resizeTo(window.outerWidth, newHeight);
|
||||
}
|
||||
}).bind(this)
|
||||
);
|
||||
let newHeight = window.outerHeight +
|
||||
this._element("descriptionField").boxObject.height;
|
||||
window.resizeTo(window.outerWidth, newHeight);
|
||||
}, () => undefined);
|
||||
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -317,21 +317,17 @@ PlacesViewBase.prototype = {
|
|||
element.setAttribute("hostContainer", "true");
|
||||
}
|
||||
else if (itemId != -1) {
|
||||
PlacesUtils.livemarks.getLivemark(
|
||||
{ id: itemId },
|
||||
function (aStatus, aLivemark) {
|
||||
if (Components.isSuccessCode(aStatus)) {
|
||||
element.setAttribute("livemark", "true");
|
||||
PlacesUtils.livemarks.getLivemark({ id: itemId })
|
||||
.then(aLivemark => {
|
||||
element.setAttribute("livemark", "true");
|
||||
#ifdef XP_MACOSX
|
||||
// OS X native menubar doesn't track list-style-images since
|
||||
// it doesn't have a frame (bug 733415). Thus enforce updating.
|
||||
element.setAttribute("image", "");
|
||||
element.removeAttribute("image");
|
||||
// OS X native menubar doesn't track list-style-images since
|
||||
// it doesn't have a frame (bug 733415). Thus enforce updating.
|
||||
element.setAttribute("image", "");
|
||||
element.removeAttribute("image");
|
||||
#endif
|
||||
this.controller.cacheLivemarkInfo(aPlacesNode, aLivemark);
|
||||
}
|
||||
}.bind(this)
|
||||
);
|
||||
this.controller.cacheLivemarkInfo(aPlacesNode, aLivemark);
|
||||
}, () => undefined);
|
||||
}
|
||||
|
||||
let popup = document.createElement("menupopup");
|
||||
|
@ -509,16 +505,12 @@ PlacesViewBase.prototype = {
|
|||
#endif
|
||||
}
|
||||
|
||||
PlacesUtils.livemarks.getLivemark(
|
||||
{ id: aPlacesNode.itemId },
|
||||
function (aStatus, aLivemark) {
|
||||
if (Components.isSuccessCode(aStatus)) {
|
||||
// Controller will use this to build the meta data for the node.
|
||||
this.controller.cacheLivemarkInfo(aPlacesNode, aLivemark);
|
||||
this.invalidateContainer(aPlacesNode);
|
||||
}
|
||||
}.bind(this)
|
||||
);
|
||||
PlacesUtils.livemarks.getLivemark({ id: aPlacesNode.itemId })
|
||||
.then(aLivemark => {
|
||||
// Controller will use this to build the meta data for the node.
|
||||
this.controller.cacheLivemarkInfo(aPlacesNode, aLivemark);
|
||||
this.invalidateContainer(aPlacesNode);
|
||||
}, () => undefined);
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -647,26 +639,23 @@ PlacesViewBase.prototype = {
|
|||
return;
|
||||
}
|
||||
|
||||
PlacesUtils.livemarks.getLivemark({ id: aPlacesNode.itemId },
|
||||
function (aStatus, aLivemark) {
|
||||
if (Components.isSuccessCode(aStatus)) {
|
||||
let shouldInvalidate =
|
||||
!this.controller.hasCachedLivemarkInfo(aPlacesNode);
|
||||
this.controller.cacheLivemarkInfo(aPlacesNode, aLivemark);
|
||||
if (aNewState == Ci.nsINavHistoryContainerResultNode.STATE_OPENED) {
|
||||
aLivemark.registerForUpdates(aPlacesNode, this);
|
||||
// Prioritize the current livemark.
|
||||
aLivemark.reload();
|
||||
PlacesUtils.livemarks.reloadLivemarks();
|
||||
if (shouldInvalidate)
|
||||
this.invalidateContainer(aPlacesNode);
|
||||
}
|
||||
else {
|
||||
aLivemark.unregisterForUpdates(aPlacesNode);
|
||||
}
|
||||
PlacesUtils.livemarks.getLivemark({ id: aPlacesNode.itemId })
|
||||
.then(aLivemark => {
|
||||
let shouldInvalidate =
|
||||
!this.controller.hasCachedLivemarkInfo(aPlacesNode);
|
||||
this.controller.cacheLivemarkInfo(aPlacesNode, aLivemark);
|
||||
if (aNewState == Ci.nsINavHistoryContainerResultNode.STATE_OPENED) {
|
||||
aLivemark.registerForUpdates(aPlacesNode, this);
|
||||
// Prioritize the current livemark.
|
||||
aLivemark.reload();
|
||||
PlacesUtils.livemarks.reloadLivemarks();
|
||||
if (shouldInvalidate)
|
||||
this.invalidateContainer(aPlacesNode);
|
||||
}
|
||||
}.bind(this)
|
||||
);
|
||||
else {
|
||||
aLivemark.unregisterForUpdates(aPlacesNode);
|
||||
}
|
||||
}, () => undefined);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -678,10 +667,10 @@ PlacesViewBase.prototype = {
|
|||
if (aPopup._startMarker.nextSibling == aPopup._endMarker)
|
||||
this._setLivemarkStatusMenuItem(aPopup, Ci.mozILivemark.STATUS_LOADING);
|
||||
|
||||
PlacesUtils.livemarks.getLivemark({ id: aPopup._placesNode.itemId },
|
||||
function (aStatus, aLivemark) {
|
||||
PlacesUtils.livemarks.getLivemark({ id: aPopup._placesNode.itemId })
|
||||
.then(aLivemark => {
|
||||
let placesNode = aPopup._placesNode;
|
||||
if (!Components.isSuccessCode(aStatus) || !placesNode.containerOpen)
|
||||
if (!placesNode.containerOpen)
|
||||
return;
|
||||
|
||||
if (aLivemark.status != Ci.mozILivemark.STATUS_LOADING)
|
||||
|
@ -698,8 +687,7 @@ PlacesViewBase.prototype = {
|
|||
else
|
||||
this._getDOMNodeForPlacesNode(child).removeAttribute("visited");
|
||||
}
|
||||
}.bind(this)
|
||||
);
|
||||
}, Components.utils.reportError);
|
||||
},
|
||||
|
||||
invalidateContainer: function PVB_invalidateContainer(aPlacesNode) {
|
||||
|
@ -1008,15 +996,11 @@ PlacesToolbar.prototype = {
|
|||
button.setAttribute("tagContainer", "true");
|
||||
}
|
||||
else if (PlacesUtils.nodeIsFolder(aChild)) {
|
||||
PlacesUtils.livemarks.getLivemark(
|
||||
{ id: aChild.itemId },
|
||||
function (aStatus, aLivemark) {
|
||||
if (Components.isSuccessCode(aStatus)) {
|
||||
button.setAttribute("livemark", "true");
|
||||
this.controller.cacheLivemarkInfo(aChild, aLivemark);
|
||||
}
|
||||
}.bind(this)
|
||||
);
|
||||
PlacesUtils.livemarks.getLivemark({ id: aChild.itemId })
|
||||
.then(aLivemark => {
|
||||
button.setAttribute("livemark", "true");
|
||||
this.controller.cacheLivemarkInfo(aChild, aLivemark);
|
||||
}, () => undefined);
|
||||
}
|
||||
|
||||
let popup = document.createElement("menupopup");
|
||||
|
@ -1268,15 +1252,11 @@ PlacesToolbar.prototype = {
|
|||
if (aAnno == PlacesUtils.LMANNO_FEEDURI) {
|
||||
elt.setAttribute("livemark", true);
|
||||
|
||||
PlacesUtils.livemarks.getLivemark(
|
||||
{ id: aPlacesNode.itemId },
|
||||
function (aStatus, aLivemark) {
|
||||
if (Components.isSuccessCode(aStatus)) {
|
||||
this.controller.cacheLivemarkInfo(aPlacesNode, aLivemark);
|
||||
this.invalidateContainer(aPlacesNode);
|
||||
}
|
||||
}.bind(this)
|
||||
);
|
||||
PlacesUtils.livemarks.getLivemark({ id: aPlacesNode.itemId })
|
||||
.then(aLivemark => {
|
||||
this.controller.cacheLivemarkInfo(aPlacesNode, aLivemark);
|
||||
this.invalidateContainer(aPlacesNode);
|
||||
}, Components.utils.reportError);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -1840,15 +1820,11 @@ PlacesPanelMenuView.prototype = {
|
|||
button.setAttribute("tagContainer", "true");
|
||||
}
|
||||
else if (PlacesUtils.nodeIsFolder(aChild)) {
|
||||
PlacesUtils.livemarks.getLivemark(
|
||||
{ id: aChild.itemId },
|
||||
function (aStatus, aLivemark) {
|
||||
if (Components.isSuccessCode(aStatus)) {
|
||||
button.setAttribute("livemark", "true");
|
||||
this.controller.cacheLivemarkInfo(aChild, aLivemark);
|
||||
}
|
||||
}.bind(this)
|
||||
);
|
||||
PlacesUtils.livemarks.getLivemark({ id: aChild.itemId })
|
||||
.then(aLivemark => {
|
||||
button.setAttribute("livemark", "true");
|
||||
this.controller.cacheLivemarkInfo(aChild, aLivemark);
|
||||
}, () => undefined);
|
||||
}
|
||||
}
|
||||
else if (PlacesUtils.nodeIsURI(aChild)) {
|
||||
|
@ -1912,15 +1888,11 @@ PlacesPanelMenuView.prototype = {
|
|||
if (aAnno == PlacesUtils.LMANNO_FEEDURI) {
|
||||
elt.setAttribute("livemark", true);
|
||||
|
||||
PlacesUtils.livemarks.getLivemark(
|
||||
{ id: aPlacesNode.itemId },
|
||||
function (aStatus, aLivemark) {
|
||||
if (Components.isSuccessCode(aStatus)) {
|
||||
this.controller.cacheLivemarkInfo(aPlacesNode, aLivemark);
|
||||
this.invalidateContainer(aPlacesNode);
|
||||
}
|
||||
}.bind(this)
|
||||
);
|
||||
PlacesUtils.livemarks.getLivemark({ id: aPlacesNode.itemId })
|
||||
.then(aLivemark => {
|
||||
this.controller.cacheLivemarkInfo(aPlacesNode, aLivemark);
|
||||
this.invalidateContainer(aPlacesNode);
|
||||
}, Components.utils.reportError);
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
@ -694,14 +694,10 @@ PlacesController.prototype = {
|
|||
var selectedNode = this._view.selectedNode;
|
||||
if (selectedNode) {
|
||||
let itemId = selectedNode.itemId;
|
||||
PlacesUtils.livemarks.getLivemark(
|
||||
{ id: itemId },
|
||||
(function(aStatus, aLivemark) {
|
||||
if (Components.isSuccessCode(aStatus)) {
|
||||
aLivemark.reload(true);
|
||||
}
|
||||
}).bind(this)
|
||||
);
|
||||
PlacesUtils.livemarks.getLivemark({ id: itemId })
|
||||
.then(aLivemark => {
|
||||
aLivemark.reload(true);
|
||||
}, Components.utils.reportError);
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
@ -147,17 +147,13 @@ var gEditItemOverlay = {
|
|||
else {
|
||||
this._uri = null;
|
||||
this._isLivemark = false;
|
||||
PlacesUtils.livemarks.getLivemark(
|
||||
{id: this._itemId },
|
||||
(function (aStatus, aLivemark) {
|
||||
if (Components.isSuccessCode(aStatus)) {
|
||||
this._isLivemark = true;
|
||||
this._initTextField("feedLocationField", aLivemark.feedURI.spec, true);
|
||||
this._initTextField("siteLocationField", aLivemark.siteURI ? aLivemark.siteURI.spec : "", true);
|
||||
this._showHideRows();
|
||||
}
|
||||
}).bind(this)
|
||||
);
|
||||
PlacesUtils.livemarks.getLivemark({id: this._itemId })
|
||||
.then(aLivemark => {
|
||||
this._isLivemark = true;
|
||||
this._initTextField("feedLocationField", aLivemark.feedURI.spec, true);
|
||||
this._initTextField("siteLocationField", aLivemark.siteURI ? aLivemark.siteURI.spec : "", true);
|
||||
this._showHideRows();
|
||||
}, () => undefined);
|
||||
}
|
||||
|
||||
// folder picker
|
||||
|
|
|
@ -326,10 +326,13 @@ var PlacesOrganizer = {
|
|||
},
|
||||
|
||||
openFlatContainer: function PO_openFlatContainerFlatContainer(aContainer) {
|
||||
if (aContainer.itemId != -1)
|
||||
if (aContainer.itemId != -1) {
|
||||
PlacesUtils.asContainer(this._places.selectedNode).containerOpen = true;
|
||||
this._places.selectItems([aContainer.itemId], false);
|
||||
else if (PlacesUtils.nodeIsQuery(aContainer))
|
||||
}
|
||||
else if (PlacesUtils.nodeIsQuery(aContainer)) {
|
||||
this._places.selectPlaceURI(aContainer.uri);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -786,11 +786,11 @@ PlacesTreeView.prototype = {
|
|||
},
|
||||
|
||||
_populateLivemarkContainer: function PTV__populateLivemarkContainer(aNode) {
|
||||
PlacesUtils.livemarks.getLivemark({ id: aNode.itemId },
|
||||
function (aStatus, aLivemark) {
|
||||
PlacesUtils.livemarks.getLivemark({ id: aNode.itemId })
|
||||
.then(aLivemark => {
|
||||
let placesNode = aNode;
|
||||
// Need to check containerOpen since getLivemark is async.
|
||||
if (!Components.isSuccessCode(aStatus) || !placesNode.containerOpen)
|
||||
if (!placesNode.containerOpen)
|
||||
return;
|
||||
|
||||
let children = aLivemark.getNodesForContainer(placesNode);
|
||||
|
@ -798,7 +798,7 @@ PlacesTreeView.prototype = {
|
|||
let child = children[i];
|
||||
this.nodeInserted(placesNode, child, i);
|
||||
}
|
||||
}.bind(this));
|
||||
}, Components.utils.reportError);
|
||||
},
|
||||
|
||||
nodeTitleChanged: function PTV_nodeTitleChanged(aNode, aNewTitle) {
|
||||
|
@ -847,19 +847,15 @@ PlacesTreeView.prototype = {
|
|||
this._invalidateCellValue(aNode, this.COLUMN_TYPE_DESCRIPTION);
|
||||
}
|
||||
else if (aAnno == PlacesUtils.LMANNO_FEEDURI) {
|
||||
PlacesUtils.livemarks.getLivemark(
|
||||
{ id: aNode.itemId },
|
||||
function (aStatus, aLivemark) {
|
||||
if (Components.isSuccessCode(aStatus)) {
|
||||
this._controller.cacheLivemarkInfo(aNode, aLivemark);
|
||||
let properties = this._cellProperties.get(aNode);
|
||||
this._cellProperties.set(aNode, properties += " livemark ");
|
||||
PlacesUtils.livemarks.getLivemark({ id: aNode.itemId })
|
||||
.then(aLivemark => {
|
||||
this._controller.cacheLivemarkInfo(aNode, aLivemark);
|
||||
let properties = this._cellProperties.get(aNode);
|
||||
this._cellProperties.set(aNode, properties += " livemark ");
|
||||
|
||||
// The livemark attribute is set as a cell property on the title cell.
|
||||
this._invalidateCellValue(aNode, this.COLUMN_TYPE_TITLE);
|
||||
}
|
||||
}.bind(this)
|
||||
);
|
||||
// The livemark attribute is set as a cell property on the title cell.
|
||||
this._invalidateCellValue(aNode, this.COLUMN_TYPE_TITLE);
|
||||
}, Components.utils.reportError);
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -883,26 +879,23 @@ PlacesTreeView.prototype = {
|
|||
return;
|
||||
}
|
||||
|
||||
PlacesUtils.livemarks.getLivemark({ id: aNode.itemId },
|
||||
function (aStatus, aLivemark) {
|
||||
if (Components.isSuccessCode(aStatus)) {
|
||||
let shouldInvalidate =
|
||||
!this._controller.hasCachedLivemarkInfo(aNode);
|
||||
this._controller.cacheLivemarkInfo(aNode, aLivemark);
|
||||
if (aNewState == Components.interfaces.nsINavHistoryContainerResultNode.STATE_OPENED) {
|
||||
aLivemark.registerForUpdates(aNode, this);
|
||||
// Prioritize the current livemark.
|
||||
aLivemark.reload();
|
||||
PlacesUtils.livemarks.reloadLivemarks();
|
||||
if (shouldInvalidate)
|
||||
this.invalidateContainer(aNode);
|
||||
}
|
||||
else {
|
||||
aLivemark.unregisterForUpdates(aNode);
|
||||
}
|
||||
PlacesUtils.livemarks.getLivemark({ id: aNode.itemId })
|
||||
.then(aLivemark => {
|
||||
let shouldInvalidate =
|
||||
!this._controller.hasCachedLivemarkInfo(aNode);
|
||||
this._controller.cacheLivemarkInfo(aNode, aLivemark);
|
||||
if (aNewState == Components.interfaces.nsINavHistoryContainerResultNode.STATE_OPENED) {
|
||||
aLivemark.registerForUpdates(aNode, this);
|
||||
// Prioritize the current livemark.
|
||||
aLivemark.reload();
|
||||
PlacesUtils.livemarks.reloadLivemarks();
|
||||
if (shouldInvalidate)
|
||||
this.invalidateContainer(aNode);
|
||||
}
|
||||
}.bind(this)
|
||||
);
|
||||
else {
|
||||
aLivemark.unregisterForUpdates(aNode);
|
||||
}
|
||||
}, () => undefined);
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -1174,17 +1167,13 @@ PlacesTreeView.prototype = {
|
|||
properties += " livemark";
|
||||
}
|
||||
else {
|
||||
PlacesUtils.livemarks.getLivemark(
|
||||
{ id: node.itemId },
|
||||
function (aStatus, aLivemark) {
|
||||
if (Components.isSuccessCode(aStatus)) {
|
||||
this._controller.cacheLivemarkInfo(node, aLivemark);
|
||||
properties += " livemark";
|
||||
// The livemark attribute is set as a cell property on the title cell.
|
||||
this._invalidateCellValue(node, this.COLUMN_TYPE_TITLE);
|
||||
}
|
||||
}.bind(this)
|
||||
);
|
||||
PlacesUtils.livemarks.getLivemark({ id: node.itemId })
|
||||
.then(aLivemark => {
|
||||
this._controller.cacheLivemarkInfo(node, aLivemark);
|
||||
properties += " livemark";
|
||||
// The livemark attribute is set as a cell property on the title cell.
|
||||
this._invalidateCellValue(node, this.COLUMN_TYPE_TITLE);
|
||||
}, () => undefined);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -47,3 +47,4 @@ skip-if = true
|
|||
[browser_library_left_pane_select_hierarchy.js]
|
||||
[browser_435851_copy_query.js]
|
||||
[browser_toolbarbutton_menu_context.js]
|
||||
[browser_library_openFlatContainer.js]
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
/**
|
||||
* Test opening a flat container in the right pane even if its parent in the
|
||||
* left pane is closed.
|
||||
*/
|
||||
|
||||
add_task(function* () {
|
||||
let folder = PlacesUtils.bookmarks
|
||||
.createFolder(PlacesUtils.unfiledBookmarksFolderId,
|
||||
"Folder",
|
||||
PlacesUtils.bookmarks.DEFAULT_INDEX);
|
||||
let bookmark = PlacesUtils.bookmarks
|
||||
.insertBookmark(folder, NetUtil.newURI("http://example.com/"),
|
||||
PlacesUtils.bookmarks.DEFAULT_INDEX,
|
||||
"Bookmark");
|
||||
|
||||
let library = yield promiseLibrary("AllBookmarks");
|
||||
registerCleanupFunction(function () {
|
||||
library.close();
|
||||
PlacesUtils.bookmarks.removeFolderChildren(PlacesUtils.unfiledBookmarksFolderId);
|
||||
});
|
||||
|
||||
// Select unfiled later, to ensure it's closed.
|
||||
library.PlacesOrganizer.selectLeftPaneQuery("UnfiledBookmarks");
|
||||
ok(!library.PlacesOrganizer._places.selectedNode.containerOpen,
|
||||
"Unfiled container is closed");
|
||||
|
||||
let folderNode = library.ContentTree.view.view.nodeForTreeIndex(0);
|
||||
is(folderNode.itemId, folder,
|
||||
"Found the expected folder in the right pane");
|
||||
// Select the folder node in the right pane.
|
||||
library.ContentTree.view.selectNode(folderNode);
|
||||
|
||||
synthesizeClickOnSelectedTreeCell(library.ContentTree.view,
|
||||
{ clickCount: 2 });
|
||||
|
||||
is(library.ContentTree.view.view.nodeForTreeIndex(0).itemId, bookmark,
|
||||
"Found the expected bookmark in the right pane");
|
||||
});
|
|
@ -119,27 +119,6 @@ function test() {
|
|||
}, true);
|
||||
}
|
||||
|
||||
function synthesizeClickOnSelectedTreeCell(aTree) {
|
||||
let tbo = aTree.treeBoxObject;
|
||||
is(tbo.view.selection.count, 1,
|
||||
"The test node should be successfully selected");
|
||||
// Get selection rowID.
|
||||
let min = {}, max = {};
|
||||
tbo.view.selection.getRangeAt(0, min, max);
|
||||
let rowID = min.value;
|
||||
tbo.ensureRowIsVisible(rowID);
|
||||
|
||||
// Calculate the click coordinates.
|
||||
let x = {}, y = {}, width = {}, height = {};
|
||||
tbo.getCoordsForCellItem(rowID, aTree.columns[0], "text",
|
||||
x, y, width, height);
|
||||
x = x.value + width.value / 2;
|
||||
y = y.value + height.value / 2;
|
||||
// Simulate the click.
|
||||
EventUtils.synthesizeMouse(aTree.body, x, y, {},
|
||||
aTree.ownerDocument.defaultView);
|
||||
}
|
||||
|
||||
function changeSidebarDirection(aDirection) {
|
||||
sidebar.contentDocument.documentElement.style.direction = aDirection;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
Components.utils.import("resource://gre/modules/NetUtil.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
|
||||
"resource://gre/modules/NetUtil.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Promise",
|
||||
"resource://gre/modules/commonjs/sdk/core/promise.js");
|
||||
|
||||
// We need to cache this before test runs...
|
||||
let cachedLeftPaneFolderIdGetter;
|
||||
|
@ -182,6 +186,22 @@ function addVisits(aPlaceInfo, aWindow, aCallback, aStack) {
|
|||
);
|
||||
}
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Promise",
|
||||
"resource://gre/modules/commonjs/sdk/core/promise.js");
|
||||
|
||||
function synthesizeClickOnSelectedTreeCell(aTree, aOptions) {
|
||||
let tbo = aTree.treeBoxObject;
|
||||
if (tbo.view.selection.count != 1)
|
||||
throw new Error("The test node should be successfully selected");
|
||||
// Get selection rowID.
|
||||
let min = {}, max = {};
|
||||
tbo.view.selection.getRangeAt(0, min, max);
|
||||
let rowID = min.value;
|
||||
tbo.ensureRowIsVisible(rowID);
|
||||
// Calculate the click coordinates.
|
||||
let x = {}, y = {}, width = {}, height = {};
|
||||
tbo.getCoordsForCellItem(rowID, aTree.columns[0], "text",
|
||||
x, y, width, height);
|
||||
x = x.value + width.value / 2;
|
||||
y = y.value + height.value / 2;
|
||||
// Simulate the click.
|
||||
EventUtils.synthesizeMouse(aTree.body, x, y, aOptions || {},
|
||||
aTree.ownerDocument.defaultView);
|
||||
}
|
||||
|
|
|
@ -11,8 +11,8 @@ Services.prefs.setBoolPref("devtools.debugger.log", true);
|
|||
let gProcess;
|
||||
|
||||
function test() {
|
||||
// Windows XP test slaves are terribly slow at this test.
|
||||
requestLongerTimeout(4);
|
||||
// Windows XP and 8.1 test slaves are terribly slow at this test.
|
||||
requestLongerTimeout(5);
|
||||
|
||||
initChromeDebugger(aOnClose).then(aProcess => {
|
||||
gProcess = aProcess;
|
||||
|
|
|
@ -217,10 +217,14 @@ toolbarbutton[sdk-button="true"][cui-areatype="menu-panel"] > .toolbarbutton-ico
|
|||
-moz-box-orient: vertical;
|
||||
width: calc(@menuPanelButtonWidth@ - 2px);
|
||||
height: calc(49px + 2.2em);
|
||||
margin-top: 3px; /* Hack needed to get type=menu-button to properly align vertically. */
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.panelUI-grid .toolbarbutton-1 > .toolbarbutton-menubutton-button > .toolbarbutton-text,
|
||||
.panelUI-grid .toolbarbutton-1 > .toolbarbutton-menubutton-button > .toolbarbutton-multiline-text {
|
||||
margin-top: 2px; /* Hack needed to get the label of type=menu-button aligned with other buttons */
|
||||
}
|
||||
|
||||
.panel-customization-placeholder-child {
|
||||
margin: 6px 0 0;
|
||||
padding: 2px 6px;
|
||||
|
|
|
@ -57,7 +57,7 @@ robocop_FILES := \
|
|||
$(NULL)
|
||||
robocop-deps := $(notdir $(robocop_FILES))
|
||||
|
||||
MOCHITEST_ROBOCOP_FILES := \
|
||||
ROBOCOP_FILES := \
|
||||
$(wildcard $(TESTPATH)/*.html) \
|
||||
$(wildcard $(TESTPATH)/*.jpg) \
|
||||
$(wildcard $(TESTPATH)/*.sjs) \
|
||||
|
@ -67,6 +67,9 @@ MOCHITEST_ROBOCOP_FILES := \
|
|||
$(wildcard $(TESTPATH)/*.swf) \
|
||||
$(NULL)
|
||||
|
||||
ROBOCOP_DEST = $(DEPTH)/_tests/testing/mochitest/tests/robocop/
|
||||
INSTALL_TARGETS += ROBOCOP
|
||||
|
||||
GARBAGE += \
|
||||
AndroidManifest.xml \
|
||||
$(robocop-deps) \
|
||||
|
|
|
@ -73,8 +73,14 @@ _MOZBUILD_EXTERNAL_VARIABLES := \
|
|||
|
||||
_DEPRECATED_VARIABLES := \
|
||||
ANDROID_RESFILES \
|
||||
MOCHITEST_FILES_PARTS \
|
||||
MOCHITEST_A11Y_FILES \
|
||||
MOCHITEST_BROWSER_FILES \
|
||||
MOCHITEST_BROWSER_FILES_PARTS \
|
||||
MOCHITEST_CHROME_FILES \
|
||||
MOCHITEST_FILES \
|
||||
MOCHITEST_FILES_PARTS \
|
||||
MOCHITEST_METRO_FILES \
|
||||
MOCHITEST_ROBOCOP_FILES \
|
||||
SHORT_LIBNAME \
|
||||
$(NULL)
|
||||
|
||||
|
|
|
@ -1,52 +0,0 @@
|
|||
# -*- makefile -*-
|
||||
# vim:set ts=8 sw=8 sts=8 noet:
|
||||
#
|
||||
# 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 INCLUDED_TESTS_MOCHITEST_MK #{
|
||||
|
||||
# $1- test directory name
|
||||
# $2- optional: if passed dot used to flatten directory hierarchy copy
|
||||
# else- relativesrcdir
|
||||
mochitestdir = \
|
||||
$(strip \
|
||||
$(if $(2),$(DEPTH)/_tests/testing/mochitest/$1/. \
|
||||
,$(DEPTH)/_tests/testing/mochitest/$1/$(relativesrcdir) \
|
||||
))
|
||||
|
||||
|
||||
ifdef MOCHITEST_FILES
|
||||
MOCHITEST_DEST := $(call mochitestdir,tests)
|
||||
INSTALL_TARGETS += MOCHITEST
|
||||
endif
|
||||
|
||||
ifdef MOCHITEST_CHROME_FILES
|
||||
MOCHITEST_CHROME_DEST := $(call mochitestdir,chrome)
|
||||
INSTALL_TARGETS += MOCHITEST_CHROME
|
||||
endif
|
||||
|
||||
ifdef MOCHITEST_BROWSER_FILES
|
||||
MOCHITEST_BROWSER_DEST := $(call mochitestdir,browser)
|
||||
INSTALL_TARGETS += MOCHITEST_BROWSER
|
||||
endif
|
||||
|
||||
ifdef MOCHITEST_A11Y_FILES
|
||||
MOCHITEST_A11Y_DEST := $(call mochitestdir,a11y)
|
||||
INSTALL_TARGETS += MOCHITEST_A11Y
|
||||
endif
|
||||
|
||||
ifdef MOCHITEST_METRO_FILES
|
||||
MOCHITEST_METRO_DEST := $(call mochitestdir,metro)
|
||||
INSTALL_TARGETS += MOCHITEST_METRO
|
||||
endif
|
||||
|
||||
ifdef MOCHITEST_ROBOCOP_FILES
|
||||
MOCHITEST_ROBOCOP_DEST := $(call mochitestdir,tests/robocop,flat_hierarchy)
|
||||
INSTALL_TARGETS += MOCHITEST_ROBOCOP
|
||||
endif
|
||||
|
||||
INCLUDED_TESTS_MOCHITEST_MK := 1
|
||||
|
||||
endif #} INCLUDED_TESTS_MOCHITEST_MK
|
|
@ -99,10 +99,6 @@ ifdef ENABLE_TESTS
|
|||
# locally against non-current test code.
|
||||
DIRS += $(TEST_DIRS)
|
||||
|
||||
ifndef INCLUDED_TESTS_MOCHITEST_MK #{
|
||||
include $(topsrcdir)/config/makefiles/mochitest.mk
|
||||
endif #}
|
||||
|
||||
ifdef CPP_UNIT_TESTS
|
||||
ifdef COMPILE_ENVIRONMENT
|
||||
|
||||
|
@ -1635,12 +1631,6 @@ FREEZE_VARIABLES = \
|
|||
TIERS \
|
||||
EXTRA_COMPONENTS \
|
||||
EXTRA_PP_COMPONENTS \
|
||||
MOCHITEST_FILES \
|
||||
MOCHITEST_CHROME_FILES \
|
||||
MOCHITEST_BROWSER_FILES \
|
||||
MOCHITEST_A11Y_FILES \
|
||||
MOCHITEST_METRO_FILES \
|
||||
MOCHITEST_ROBOCOP_FILES \
|
||||
$(NULL)
|
||||
|
||||
$(foreach var,$(FREEZE_VARIABLES),$(eval $(var)_FROZEN := '$($(var))'))
|
||||
|
|
|
@ -1964,6 +1964,7 @@ GK_ATOM(genConInitializerProperty, "QuoteNodeProperty")
|
|||
GK_ATOM(labelMouseDownPtProperty, "LabelMouseDownPtProperty")
|
||||
GK_ATOM(baseURIProperty, "baseURIProperty")
|
||||
GK_ATOM(lockedStyleStates, "lockedStyleStates")
|
||||
GK_ATOM(apzCallbackTransform, "apzCallbackTransform")
|
||||
|
||||
// Languages for lang-specific transforms
|
||||
GK_ATOM(Japanese, "ja")
|
||||
|
|
|
@ -241,6 +241,16 @@ public:
|
|||
MOZ_ASSERT(aTarget);
|
||||
}
|
||||
|
||||
nsSimplePluginEvent(nsIContent* aTarget,
|
||||
nsIDocument* aDocument,
|
||||
const nsAString& aEvent)
|
||||
: mTarget(aTarget)
|
||||
, mDocument(aDocument)
|
||||
, mEvent(aEvent)
|
||||
{
|
||||
MOZ_ASSERT(aTarget && aDocument);
|
||||
}
|
||||
|
||||
~nsSimplePluginEvent() {}
|
||||
|
||||
NS_IMETHOD Run();
|
||||
|
@ -703,7 +713,7 @@ nsObjectLoadingContent::UnbindFromTree(bool aDeep, bool aNullParent)
|
|||
nsIDocument* ownerDoc = thisContent->OwnerDoc();
|
||||
ownerDoc->RemovePlugin(this);
|
||||
|
||||
if (mType == eType_Plugin && mInstanceOwner) {
|
||||
if (mType == eType_Plugin && (mInstanceOwner || mInstantiating)) {
|
||||
// we'll let the plugin continue to run at least until we get back to
|
||||
// the event loop. If we get back to the event loop and the node
|
||||
// has still not been added back to the document then we tear down the
|
||||
|
@ -744,7 +754,7 @@ nsObjectLoadingContent::~nsObjectLoadingContent()
|
|||
NS_NOTREACHED("Should not be tearing down frame loaders at this point");
|
||||
mFrameLoader->Destroy();
|
||||
}
|
||||
if (mInstanceOwner) {
|
||||
if (mInstanceOwner || mInstantiating) {
|
||||
// This is especially bad as delayed stop will try to hold on to this
|
||||
// object...
|
||||
NS_NOTREACHED("Should not be tearing down a plugin at this point!");
|
||||
|
@ -772,7 +782,7 @@ nsObjectLoadingContent::InstantiatePluginInstance(bool aIsLoading)
|
|||
nsCOMPtr<nsIContent> thisContent =
|
||||
do_QueryInterface(static_cast<nsIImageLoadingContent *>(this));
|
||||
|
||||
nsIDocument* doc = thisContent->GetCurrentDoc();
|
||||
nsCOMPtr<nsIDocument> doc = thisContent->GetCurrentDoc();
|
||||
if (!doc || !InActiveDocument(thisContent)) {
|
||||
NS_ERROR("Shouldn't be calling "
|
||||
"InstantiatePluginInstance without an active document");
|
||||
|
@ -894,8 +904,10 @@ nsObjectLoadingContent::InstantiatePluginInstance(bool aIsLoading)
|
|||
}
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIRunnable> ev = new nsSimplePluginEvent(thisContent,
|
||||
NS_LITERAL_STRING("PluginInstantiated"));
|
||||
nsCOMPtr<nsIRunnable> ev = \
|
||||
new nsSimplePluginEvent(thisContent,
|
||||
doc,
|
||||
NS_LITERAL_STRING("PluginInstantiated"));
|
||||
NS_DispatchToCurrentThread(ev);
|
||||
|
||||
return NS_OK;
|
||||
|
@ -909,7 +921,7 @@ nsObjectLoadingContent::NotifyOwnerDocumentActivityChanged()
|
|||
|
||||
// If we have a plugin we want to queue an event to stop it unless we are
|
||||
// moved into an active document before returning to the event loop.
|
||||
if (mInstanceOwner)
|
||||
if (mInstanceOwner || mInstantiating)
|
||||
QueueCheckPluginStopEvent();
|
||||
}
|
||||
|
||||
|
@ -1073,8 +1085,10 @@ nsObjectLoadingContent::HasNewFrame(nsIObjectFrame* aFrame)
|
|||
// Lost our frame. If we aren't going to be getting a new frame, e.g. we've
|
||||
// become display:none, we'll want to stop the plugin. Queue a
|
||||
// CheckPluginStopEvent
|
||||
if (mInstanceOwner) {
|
||||
mInstanceOwner->SetFrame(nullptr);
|
||||
if (mInstanceOwner || mInstantiating) {
|
||||
if (mInstanceOwner) {
|
||||
mInstanceOwner->SetFrame(nullptr);
|
||||
}
|
||||
QueueCheckPluginStopEvent();
|
||||
}
|
||||
return NS_OK;
|
||||
|
@ -2826,6 +2840,10 @@ nsObjectLoadingContent::StopPluginInstance()
|
|||
mPendingInstantiateEvent = nullptr;
|
||||
mPendingCheckPluginStopEvent = nullptr;
|
||||
|
||||
// If we're currently instantiating, clearing this will cause
|
||||
// InstantiatePluginInstance's re-entrance check to destroy the created plugin
|
||||
mInstantiating = false;
|
||||
|
||||
if (!mInstanceOwner) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -1006,6 +1006,7 @@ nsScriptLoader::FillCompileOptionsForRequest(nsScriptLoadRequest *aRequest,
|
|||
// aRequest ended up getting script data from, as the script filename.
|
||||
nsContentUtils::GetWrapperSafeScriptFilename(mDocument, aRequest->mURI, aRequest->mURL);
|
||||
|
||||
aOptions->setIntroductionType("scriptElement");
|
||||
aOptions->setFileAndLine(aRequest->mURL.get(), aRequest->mLineNo);
|
||||
aOptions->setVersion(JSVersion(aRequest->mJSVersion));
|
||||
aOptions->setCompileAndGo(JS_IsGlobalObject(aScopeChain));
|
||||
|
|
|
@ -1,2 +1,4 @@
|
|||
[test_messagemanager_assertpermission.html]
|
||||
skip-if = buildapp == 'b2g' #b2g(specialpowers.wrap issue, NS_ERROR_XPC_GS_RETURNED_FAILURE) b2g-debug(specialpowers.wrap issue, NS_ERROR_XPC_GS_RETURNED_FAILURE) b2g-desktop(specialpowers.wrap issue, NS_ERROR_XPC_GS_RETURNED_FAILURE)
|
||||
[test_child_process_shutdown_message.html]
|
||||
skip-if = buildapp == 'b2g' #b2g(specialpowers.wrap issue, NS_ERROR_XPC_GS_RETURNED_FAILURE) b2g-debug(specialpowers.wrap issue, NS_ERROR_XPC_GS_RETURNED_FAILURE) b2g-desktop(specialpowers.wrap issue, NS_ERROR_XPC_GS_RETURNED_FAILURE)
|
||||
|
|
|
@ -544,7 +544,7 @@ skip-if = buildapp == 'b2g' || toolkit == 'android' #needs plugin support # b2g(
|
|||
[test_classList.html]
|
||||
# This test fails on the Mac for some reason
|
||||
[test_copyimage.html]
|
||||
skip-if = toolkit != 'gtk2' && toolkit != 'gtk3' && toolkit != 'windows'
|
||||
skip-if = (buildapp == 'b2g' && toolkit != 'gonk') || toolkit != 'gtk2' && toolkit != 'gtk3' && toolkit != 'windows' #b2g-desktop(Bug 931116, b2g desktop specific, initial triage)
|
||||
[test_copypaste.html]
|
||||
skip-if = buildapp == 'b2g' || toolkit == 'android' #bug 904183 # b2g(clipboard undefined) b2g-debug(clipboard undefined) b2g-desktop(clipboard undefined)
|
||||
[test_copypaste.xhtml]
|
||||
|
|
|
@ -475,15 +475,15 @@ skip-if = buildapp == 'b2g'
|
|||
skip-if = appname == "seamonkey" # See bug 598252
|
||||
|
||||
[test_buffered.html]
|
||||
skip-if = toolkit == 'android' || os == "win" # See bug 832768 and 864682
|
||||
skip-if = toolkit == 'android' || os == "win" || (toolkit == 'gonk' && !debug) # See bug 832768 and 864682, b2g(assertion failures)
|
||||
[test_bug465498.html]
|
||||
skip-if = os == "win" # See bug 832768 and 864682
|
||||
skip-if = os == "win" || (toolkit == 'gonk' && !debug) # See bug 832768 and 864682
|
||||
[test_bug493187.html]
|
||||
skip-if = os == "win" || (buildapp=='b2g'&&debug) # See bug 707777, #b2g-emulator-debug - process crash
|
||||
skip-if = os == "win" || (buildapp=='b2g'&&debug) || (toolkit == 'gonk' && !debug) # See bug 707777, #b2g-emulator-debug - process crash
|
||||
[test_media_selection.html]
|
||||
skip-if = os == "win" # See bug 897843
|
||||
skip-if = os == "win" || (toolkit == 'gonk' && !debug) # See bug 897843, b2g(timed out)
|
||||
[test_seek.html]
|
||||
skip-if = toolkit == 'android' || os == "win" # See bug 832678, 795271, and 857424 # android(bug 845162) androidx86(bug 845162)
|
||||
skip-if = toolkit == 'android' || os == "win" || (toolkit == 'gonk' && !debug) # See bug 832678, 795271, and 857424 # android(bug 845162) androidx86(bug 845162)
|
||||
|
||||
# The tests below contain backend-specific tests. Write backend independent
|
||||
# tests rather than adding to this list.
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
[DEFAULT]
|
||||
skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) #b2g-debug(bug 916135) b2g-desktop(bug 916135)
|
||||
support-files =
|
||||
audio-expected.wav
|
||||
audio-mono-expected-2.wav
|
||||
|
|
|
@ -2643,7 +2643,8 @@ nsXULPrototypeScript::Compile(const char16_t* aText,
|
|||
// Ok, compile it to create a prototype script object!
|
||||
NS_ENSURE_TRUE(JSVersion(mLangVersion) != JSVERSION_UNKNOWN, NS_OK);
|
||||
JS::CompileOptions options(cx);
|
||||
options.setFileAndLine(urlspec.get(), aLineNo)
|
||||
options.setIntroductionType("scriptElement")
|
||||
.setFileAndLine(urlspec.get(), aLineNo)
|
||||
.setVersion(JSVersion(mLangVersion));
|
||||
// If the script was inline, tell the JS parser to save source for
|
||||
// Function.prototype.toSource(). If it's out of line, we retrieve the
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
[DEFAULT]
|
||||
skip-if = buildapp == 'b2g' #tests that use xul
|
||||
|
||||
[test_bug486990.xul]
|
||||
skip-if = toolkit == 'android' #TIMED_OUT
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
[DEFAULT]
|
||||
skip-if = toolkit=='gonk' #b2g(bug 972927, nearly perma-fail) b2g-debug(bug 972927, nearly perma-fail)
|
||||
support-files =
|
||||
file_app.sjs
|
||||
file_app.template.html
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
# so we don't run that test on platforms which don't support OOP tests.
|
||||
# OOP tests don't work on native-fennec (bug 774939).
|
||||
# Bug 960345 - Disabled on OSX debug for frequent crashes.
|
||||
skip-if = os == "android" || (toolkit == "cocoa" && debug)
|
||||
skip-if = os == "android" || (toolkit == "cocoa" && debug) || (buildapp == 'b2g' && (toolkit != 'gonk' || debug))
|
||||
support-files =
|
||||
browserElement_OpenMixedProcess.js
|
||||
file_browserElement_OpenMixedProcess.html
|
||||
|
@ -11,15 +11,19 @@ support-files =
|
|||
[test_browserElement_inproc_ErrorSecurity.html]
|
||||
skip-if = toolkit=='gonk'
|
||||
[test_browserElement_inproc_OpenMixedProcess.html]
|
||||
skip-if = toolkit=='gonk'
|
||||
skip-if = toolkit=='gonk' || (toolkit == 'gonk' && !debug)
|
||||
[test_browserElement_oop_Alert.html]
|
||||
[test_browserElement_oop_AlertInFrame.html]
|
||||
[test_browserElement_oop_AppFramePermission.html]
|
||||
skip-if = (toolkit == 'gonk' && !debug)
|
||||
[test_browserElement_oop_AppWindowNamespace.html]
|
||||
skip-if = (toolkit == 'gonk' && !debug)
|
||||
[test_browserElement_oop_Auth.html]
|
||||
skip-if = (toolkit == 'gonk' && !debug)
|
||||
[test_browserElement_oop_BackForward.html]
|
||||
[test_browserElement_oop_BadScreenshot.html]
|
||||
[test_browserElement_oop_BrowserWindowNamespace.html]
|
||||
skip-if = (toolkit == 'gonk' && !debug)
|
||||
[test_browserElement_oop_BrowserWindowResize.html]
|
||||
[test_browserElement_oop_Close.html]
|
||||
[test_browserElement_oop_CookiesNotThirdParty.html]
|
||||
|
@ -27,20 +31,28 @@ skip-if = toolkit=='gonk'
|
|||
[test_browserElement_oop_DataURI.html]
|
||||
[test_browserElement_oop_DocumentFirstPaint.html]
|
||||
[test_browserElement_oop_ErrorSecurity.html]
|
||||
skip-if = (toolkit == 'gonk' && !debug)
|
||||
[test_browserElement_oop_FirstPaint.html]
|
||||
[test_browserElement_oop_ForwardName.html]
|
||||
[test_browserElement_oop_FrameWrongURI.html]
|
||||
skip-if = (toolkit == 'gonk' && !debug)
|
||||
[test_browserElement_oop_GetScreenshot.html]
|
||||
[test_browserElement_oop_GetScreenshotDppx.html]
|
||||
[test_browserElement_oop_Iconchange.html]
|
||||
[test_browserElement_oop_LoadEvents.html]
|
||||
[test_browserElement_oop_Metachange.html]
|
||||
[test_browserElement_oop_OpenMixedProcess.html]
|
||||
skip-if = (toolkit == 'gonk' && !debug)
|
||||
[test_browserElement_oop_OpenNamed.html]
|
||||
skip-if = (toolkit == 'gonk' && !debug)
|
||||
[test_browserElement_oop_OpenWindow.html]
|
||||
skip-if = (toolkit == 'gonk' && !debug)
|
||||
[test_browserElement_oop_OpenWindowDifferentOrigin.html]
|
||||
skip-if = (toolkit == 'gonk' && !debug)
|
||||
[test_browserElement_oop_OpenWindowInFrame.html]
|
||||
skip-if = (toolkit == 'gonk' && !debug)
|
||||
[test_browserElement_oop_OpenWindowRejected.html]
|
||||
skip-if = (toolkit == 'gonk' && !debug)
|
||||
[test_browserElement_oop_Opensearch.html]
|
||||
[test_browserElement_oop_PromptCheck.html]
|
||||
[test_browserElement_oop_PromptConfirm.html]
|
||||
|
@ -50,7 +62,7 @@ skip-if = toolkit=='gonk'
|
|||
[test_browserElement_oop_RemoveBrowserElement.html]
|
||||
[test_browserElement_oop_ScrollEvent.html]
|
||||
[test_browserElement_oop_SecurityChange.html]
|
||||
skip-if = toolkit == 'android' #TIMED_OUT, bug 766586
|
||||
skip-if = toolkit == 'android' || (toolkit == 'gonk' && !debug) #TIMED_OUT, bug 766586
|
||||
[test_browserElement_oop_SendEvent.html]
|
||||
[test_browserElement_oop_SetInputMethodActive.html]
|
||||
[test_browserElement_oop_SetVisible.html]
|
||||
|
@ -58,6 +70,7 @@ skip-if = toolkit == 'android' #TIMED_OUT, bug 766586
|
|||
[test_browserElement_oop_SetVisibleFrames2.html]
|
||||
[test_browserElement_oop_Stop.html]
|
||||
[test_browserElement_oop_TargetBlank.html]
|
||||
skip-if = (toolkit == 'gonk' && !debug)
|
||||
[test_browserElement_oop_TargetTop.html]
|
||||
[test_browserElement_oop_Titlechange.html]
|
||||
[test_browserElement_oop_TopBarrier.html]
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
[DEFAULT]
|
||||
skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug))
|
||||
support-files =
|
||||
../../../browser/base/content/test/general/audio.ogg
|
||||
../../../content/media/test/short-video.ogv
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[DEFAULT]
|
||||
# Good luck running these tests on anything but desktop Linux.
|
||||
skip-if = toolkit != "gtk2"
|
||||
skip-if = toolkit != "gtk2" || (buildapp == 'b2g' && (toolkit != 'gonk' || debug))
|
||||
|
||||
# Note: ../browserElementTestHelpers.js makes all tests in this directory OOP,
|
||||
# because testing the process-priority manager without OOP frames does not make
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
[DEFAULT]
|
||||
skip-if = toolkit=='gonk' #b2g(bug 974270, frequent failures) b2g-debug(bug 974270, frequent failures)
|
||||
support-files =
|
||||
file_app_install.html
|
||||
file_readonly.html
|
||||
|
|
|
@ -10,17 +10,19 @@ support-files =
|
|||
|
||||
[conformancetest/test_event.html]
|
||||
[conformancetest/test_runtest.html]
|
||||
skip-if = toolkit == 'android'
|
||||
skip-if = (toolkit == 'android') || (buildapp == 'b2g') #b2g(takes too long) b2g-debug(takes too long) b2g-desktop(takes too long)
|
||||
[selecttest/test_Document-open.html]
|
||||
[selecttest/test_addRange.html]
|
||||
skip-if = toolkit == 'android' #bug 775227
|
||||
skip-if = (toolkit == 'android') || (buildapp == 'b2g') #android(bug 775227) b2g(oom?, bug 775227) b2g-debug(oom?, bug 775227) b2g-desktop(oom?, bug 775227)
|
||||
[selecttest/test_collapse.html]
|
||||
[selecttest/test_collapseToStartEnd.html]
|
||||
[selecttest/test_deleteFromDocument.html]
|
||||
[selecttest/test_extend.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure; time out)
|
||||
[selecttest/test_getRangeAt.html]
|
||||
[selecttest/test_getSelection.html]
|
||||
[selecttest/test_interfaces.html]
|
||||
[selecttest/test_isCollapsed.html]
|
||||
[selecttest/test_removeAllRanges.html]
|
||||
[selecttest/test_selectAllChildren.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
|
|
|
@ -57,211 +57,414 @@ support-files =
|
|||
webgl/common.js
|
||||
|
||||
[dom/collections/test_HTMLCollection-empty-name.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/errors/test_DOMException-constants.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/errors/test_exceptions.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/events/test_Event-constants.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/events/test_Event-constructors.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/events/test_Event-defaultPrevented.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/events/test_Event-initEvent.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/events/test_Event-propagation.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/events/test_Event-type.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/events/test_EventTarget-addEventListener.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/events/test_EventTarget-dispatchEvent.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/events/test_EventTarget-removeEventListener.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/events/test_ProgressEvent.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/lists/test_DOMTokenList-stringifier.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/nodes/test_CharacterData-appendData.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/nodes/test_CharacterData-deleteData.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/nodes/test_CharacterData-insertData.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/nodes/test_CharacterData-remove.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/nodes/test_CharacterData-replaceData.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/nodes/test_Comment-constructor.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/nodes/test_DOMImplementation-createDocument.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/nodes/test_DOMImplementation-createDocumentType.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/nodes/test_DOMImplementation-createHTMLDocument.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/nodes/test_DOMImplementation-hasFeature.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/nodes/test_Document-adoptNode.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/nodes/test_Document-createComment.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/nodes/test_Document-createElement-namespace.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/nodes/test_Document-createElement.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/nodes/test_Document-createElementNS.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/nodes/test_Document-createEvent.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/nodes/test_Document-createProcessingInstruction-literal-1.xhtml]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/nodes/test_Document-createProcessingInstruction-literal-2.xhtml]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/nodes/test_Document-createProcessingInstruction.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/nodes/test_Document-createProcessingInstruction.xhtml]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/nodes/test_Document-createTreeWalker.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/nodes/test_Document-getElementById.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/nodes/test_Document-getElementsByTagName.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/nodes/test_Document-getElementsByTagNameNS.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/nodes/test_Document-importNode.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/nodes/test_DocumentType-remove.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/nodes/test_Element-children.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/nodes/test_Element-getElementsByClassName.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/nodes/test_Element-remove.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/nodes/test_Element-removeAttributeNS.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/nodes/test_Element-tagName.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/nodes/test_Node-appendChild.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/nodes/test_Node-cloneNode.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/nodes/test_Node-compareDocumentPosition.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/nodes/test_Node-constants.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/nodes/test_Node-contains.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/nodes/test_Node-contains.xml]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/nodes/test_Node-insertBefore.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/nodes/test_Node-isEqualNode.xhtml]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/nodes/test_Node-lookupPrefix.xhtml]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/nodes/test_Node-nodeName.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/nodes/test_Node-nodeName.xhtml]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/nodes/test_Node-normalize.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/nodes/test_Node-parentElement.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/nodes/test_Node-parentNode.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/nodes/test_Node-properties.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/nodes/test_Node-removeChild.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/nodes/test_Node-replaceChild.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/nodes/test_attributes.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/nodes/test_case.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/nodes/test_getElementsByClassName-01.htm]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/nodes/test_getElementsByClassName-02.htm]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/nodes/test_getElementsByClassName-03.htm]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/nodes/test_getElementsByClassName-04.htm]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/nodes/test_getElementsByClassName-05.htm]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/nodes/test_getElementsByClassName-06.htm]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/nodes/test_getElementsByClassName-07.htm]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/nodes/test_getElementsByClassName-08.htm]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/nodes/test_getElementsByClassName-09.htm]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/nodes/test_getElementsByClassName-10.xml]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/nodes/test_getElementsByClassName-11.xml]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/nodes/test_getElementsByClassName-12.htm]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/nodes/test_getElementsByClassName-13.htm]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/nodes/test_getElementsByClassName-14.htm]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/nodes/test_getElementsByClassName-15.htm]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/nodes/test_getElementsByClassName-16.htm]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/nodes/test_getElementsByClassName-17.htm]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/nodes/test_getElementsByClassName-18.htm]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/ranges/test_Range-attributes.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/ranges/test_Range-cloneContents.html]
|
||||
skip-if = buildapp == 'b2g'
|
||||
[dom/ranges/test_Range-cloneRange.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/ranges/test_Range-collapse.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/ranges/test_Range-commonAncestorContainer-2.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/ranges/test_Range-commonAncestorContainer.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/ranges/test_Range-compareBoundaryPoints.html]
|
||||
skip-if = buildapp == 'b2g' #b2g(times out, bug 862196) b2g-debug(times out, bug 862196) b2g-desktop(times out, bug 862196)
|
||||
[dom/ranges/test_Range-comparePoint-2.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/ranges/test_Range-comparePoint.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/ranges/test_Range-deleteContents.html]
|
||||
skip-if = buildapp == 'b2g'
|
||||
[dom/ranges/test_Range-detach.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/ranges/test_Range-extractContents.html]
|
||||
skip-if = buildapp == 'b2g'
|
||||
[dom/ranges/test_Range-insertNode.html]
|
||||
skip-if = buildapp == 'b2g' #b2g(oom?, bug 775227) b2g-debug(oom?, bug 775227) b2g-desktop(oom?, bug 775227)
|
||||
[dom/ranges/test_Range-intersectsNode-binding.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/ranges/test_Range-intersectsNode.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/ranges/test_Range-isPointInRange.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/ranges/test_Range-mutations.html]
|
||||
skip-if = buildapp == 'b2g' #Test timed out.
|
||||
[dom/ranges/test_Range-selectNode.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/ranges/test_Range-set.html]
|
||||
skip-if = buildapp == 'b2g'
|
||||
[dom/ranges/test_Range-surroundContents.html]
|
||||
skip-if = buildapp == 'b2g'
|
||||
[dom/test_historical.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/test_interface-objects.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/test_interfaces.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[dom/traversal/test_NodeFilter-constants.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[domxpath/test_evaluator-constructor.html]
|
||||
[html/browsers/browsing-the-web/read-media/test_pageload-image.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/browsers/browsing-the-web/read-media/test_pageload-video.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/browsers/the-window-object/named-access-on-the-window-object/test_window-null-names.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/browsers/the-window-object/test_window-indexed-properties-strict.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/browsers/the-window-object/test_window-indexed-properties.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/browsers/the-window-object/test_window-named-properties.html]
|
||||
skip-if = true # bug 859075
|
||||
skip-if = true || (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure) bug 859075
|
||||
[html/browsers/the-window-object/test_window-properties.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/browsers/the-window-object/test_window-prototype-chain.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/dom/documents/dta/doc.gEBN/test_document.getElementsByName-case.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/dom/documents/dta/doc.gEBN/test_document.getElementsByName-case.xhtml]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/dom/documents/dta/doc.gEBN/test_document.getElementsByName-id.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/dom/documents/dta/doc.gEBN/test_document.getElementsByName-id.xhtml]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/dom/documents/dta/doc.gEBN/test_document.getElementsByName-namespace.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/dom/documents/dta/doc.gEBN/test_document.getElementsByName-namespace.xhtml]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/dom/documents/dta/doc.gEBN/test_document.getElementsByName-newelements.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/dom/documents/dta/doc.gEBN/test_document.getElementsByName-newelements.xhtml]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/dom/documents/dta/doc.gEBN/test_document.getElementsByName-null-undef.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/dom/documents/dta/doc.gEBN/test_document.getElementsByName-null-undef.xhtml]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/dom/documents/dta/doc.gEBN/test_document.getElementsByName-param.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/dom/documents/dta/doc.gEBN/test_document.getElementsByName-param.xhtml]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/dom/documents/dta/doc.gEBN/test_document.getElementsByName-same.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/dom/documents/dta/test_Document.getElementsByClassName-null-undef.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/dom/documents/dta/test_Element.getElementsByClassName-null-undef.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/dom/documents/dta/test_document.body-getter.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/dom/documents/dta/test_document.body-setter-01.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/dom/documents/dta/test_document.embeds-document.plugins-01.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/dom/documents/dta/test_document.getElementsByClassName-same.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/dom/documents/dta/test_document.head-01.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/dom/documents/dta/test_document.head-02.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/dom/documents/dta/test_document.images.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/dom/documents/dta/test_document.title-01.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/dom/documents/dta/test_document.title-02.xhtml]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/dom/documents/dta/test_document.title-03.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/dom/documents/dta/test_document.title-04.xhtml]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/dom/documents/dta/test_document.title-05.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/dom/documents/dta/test_document.title-06.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/dom/documents/dta/test_document.title-07.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/dom/documents/dta/test_nameditem-01.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/dom/documents/dta/test_nameditem-02.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/dom/documents/dta/test_nameditem-03.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/dom/documents/dta/test_nameditem-04.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/dom/documents/dta/test_nameditem-05.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/dom/documents/dta/test_nameditem-06.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/dom/elements/global-attributes/test_classlist-nonstring.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/dom/elements/global-attributes/test_dataset-delete.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/dom/elements/global-attributes/test_dataset-enumeration.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/dom/elements/global-attributes/test_dataset-get.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/dom/elements/global-attributes/test_dataset-prototype.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/dom/elements/global-attributes/test_dataset-set.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/dom/elements/global-attributes/test_dataset.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/dom/elements/global-attributes/test_document-dir.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/dom/elements/global-attributes/test_id-attribute.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/dom/elements/global-attributes/test_id-name.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/obsolete/implreq/oeaaa/test_document-color-01.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/obsolete/implreq/oeaaa/test_document-color-02.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/obsolete/implreq/oeaaa/test_document-color-03.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/obsolete/implreq/oeaaa/test_document-color-04.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/obsolete/implreq/oeaaa/test_heading-obsolete-attributes-01.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/obsolete/implreq/oeaaa/test_script-IDL-event-htmlfor.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/semantics/document-metadata/the-title-element/test_title.text-01.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/semantics/document-metadata/the-title-element/test_title.text-02.xhtml]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/semantics/document-metadata/the-title-element/test_title.text-03.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/semantics/document-metadata/the-title-element/test_title.text-04.xhtml]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/semantics/forms/the-form-element/test_form-elements-interfaces-01.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/semantics/forms/the-form-element/test_form-elements-matches.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/semantics/forms/the-form-element/test_form-elements-nameditem-01.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/semantics/forms/the-form-element/test_form-elements-nameditem-02.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/semantics/forms/the-form-element/test_form-nameditem.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/semantics/forms/the-option-element/test_option-text-backslash.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/semantics/forms/the-option-element/test_option-text-recurse.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/semantics/forms/the-option-element/test_option-text-spaces.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/semantics/forms/the-select-element/test_select-named-getter.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/semantics/forms/the-select-element/test_select-remove.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/semantics/scripting-1/the-script-element/test_script-for-event.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/semantics/scripting-1/the-script-element/test_script-for-event.xhtml]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/semantics/scripting-1/the-script-element/test_script-for-onload.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/semantics/scripting-1/the-script-element/test_script-language-type.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/semantics/scripting-1/the-script-element/test_script-languages-01.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/semantics/scripting-1/the-script-element/test_script-languages-02.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/semantics/scripting-1/the-script-element/test_script-noembed-noframes-iframe.xhtml]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/semantics/scripting-1/the-script-element/test_script-onload-string.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/semantics/scripting-1/the-script-element/test_script-text.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/semantics/scripting-1/the-script-element/test_script-text.xhtml]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/semantics/tabular-data/the-table-element/test_createTBody.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/semantics/tabular-data/the-table-element/test_insertRow-method-01.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/semantics/tabular-data/the-table-element/test_insertRow-method-02.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/semantics/tabular-data/the-table-element/test_tBodies.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/semantics/tabular-data/the-table-element/test_table-insertRow.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/semantics/tabular-data/the-table-element/test_table-rows.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/semantics/text-level-semantics/the-time-element/test_001.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/webappapis/atob/test_base64.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/webappapis/scripting/events/test_body-onload.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/webappapis/scripting/events/test_event-handler-javascript.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/webappapis/scripting/events/test_event-handler-spec-example.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/webappapis/scripting/processing-model-2/test_window-onerror-parse-error.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/webappapis/scripting/processing-model-2/test_window-onerror-runtime-error-throw.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/webappapis/scripting/processing-model-2/test_window-onerror-runtime-error.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[html/webappapis/timers/test_evil-spec-example.html]
|
||||
skip-if = (toolkit == 'gonk' && debug) #b2g-debug(debug-only failure)
|
||||
[js/builtins/test_Array.DefineOwnProperty.html]
|
||||
[js/builtins/test_Array.prototype.join-order.html]
|
||||
[js/builtins/test_Math.max.html]
|
||||
|
@ -271,14 +474,14 @@ skip-if = true # bug 859075
|
|||
[microdata/microdata-dom-api/test_001.html]
|
||||
[typedarrays/test_constructors.html]
|
||||
[webgl/test_bufferSubData.html]
|
||||
skip-if = toolkit == 'android' #WebGL
|
||||
skip-if = (toolkit == 'android') || (buildapp == 'b2g') #android(WebGL)
|
||||
[webgl/test_compressedTexImage2D.html]
|
||||
skip-if = toolkit == 'android' #WebGL
|
||||
skip-if = (toolkit == 'android') || (buildapp == 'b2g') #android(WebGL)
|
||||
[webgl/test_compressedTexSubImage2D.html]
|
||||
skip-if = toolkit == 'android' #WebGL
|
||||
skip-if = (toolkit == 'android') || (buildapp == 'b2g') #android(WebGL)
|
||||
[webgl/test_texImage2D.html]
|
||||
skip-if = toolkit == 'android' #WebGL
|
||||
skip-if = (toolkit == 'android') || (buildapp == 'b2g') #android(WebGL)
|
||||
[webgl/test_texSubImage2D.html]
|
||||
skip-if = toolkit == 'android' #WebGL
|
||||
skip-if = (toolkit == 'android') || (buildapp == 'b2g') #android(WebGL)
|
||||
[webgl/test_uniformMatrixNfv.html]
|
||||
skip-if = toolkit == 'android' #WebGL
|
||||
skip-if = (toolkit == 'android') || (buildapp == 'b2g') #android(WebGL)
|
||||
|
|
|
@ -47,7 +47,7 @@ using class mozilla::WidgetTouchEvent from "ipc/nsGUIEventIPC.h";
|
|||
using struct mozilla::dom::RemoteDOMEvent from "mozilla/dom/TabMessageUtils.h";
|
||||
using mozilla::dom::ScreenOrientation from "mozilla/dom/ScreenOrientation.h";
|
||||
using struct mozilla::layers::TextureFactoryIdentifier from "mozilla/layers/CompositorTypes.h";
|
||||
using mozilla::CSSIntPoint from "Units.h";
|
||||
using mozilla::CSSPoint from "Units.h";
|
||||
using mozilla::CSSToScreenScale from "Units.h";
|
||||
|
||||
namespace mozilla {
|
||||
|
@ -366,21 +366,21 @@ child:
|
|||
* the scroll offset. This message is expected to round-trip back to
|
||||
* ZoomToRect() with a rect indicating where we should zoom to.
|
||||
*/
|
||||
HandleDoubleTap(CSSIntPoint point, ScrollableLayerGuid aGuid);
|
||||
HandleDoubleTap(CSSPoint point, ScrollableLayerGuid aGuid);
|
||||
|
||||
/**
|
||||
* Requests handling of a single tap. |point| is in CSS pixels, relative to
|
||||
* the scroll offset. This message is expected to send a "mousedown" and
|
||||
* "mouseup" series of events at this point.
|
||||
*/
|
||||
HandleSingleTap(CSSIntPoint point, ScrollableLayerGuid aGuid);
|
||||
HandleSingleTap(CSSPoint point, ScrollableLayerGuid aGuid);
|
||||
|
||||
/**
|
||||
* Requests handling of a long tap. |point| is in CSS pixels, relative to
|
||||
* the scroll offset. This message is expected to send a "contextmenu"
|
||||
* events at this point.
|
||||
*/
|
||||
HandleLongTap(CSSIntPoint point, ScrollableLayerGuid aGuid);
|
||||
HandleLongTap(CSSPoint point, ScrollableLayerGuid aGuid);
|
||||
|
||||
/**
|
||||
* Requests handling of releasing a long tap. |aPoint| is in CSS pixels,
|
||||
|
@ -389,7 +389,7 @@ child:
|
|||
* this message is expected to generate a "mousedown" and "mouseup"
|
||||
* series of events
|
||||
*/
|
||||
HandleLongTapUp(CSSIntPoint point, ScrollableLayerGuid aGuid);
|
||||
HandleLongTapUp(CSSPoint point, ScrollableLayerGuid aGuid);
|
||||
|
||||
/**
|
||||
* Notifies the child that the parent has begun or finished transforming
|
||||
|
|
|
@ -661,7 +661,7 @@ TabChild::HandlePossibleViewportChange()
|
|||
|
||||
// Force a repaint with these metrics. This, among other things, sets the
|
||||
// displayport, so we start with async painting.
|
||||
ProcessUpdateFrame(metrics);
|
||||
mLastRootMetrics = ProcessUpdateFrame(metrics);
|
||||
|
||||
if (viewportInfo.IsZoomAllowed() && scrollIdentifiersValid) {
|
||||
// If the CSS viewport is narrower than the screen (i.e. width <= device-width)
|
||||
|
@ -832,7 +832,7 @@ TabChild::SetChromeFlags(uint32_t aChromeFlags)
|
|||
NS_IMETHODIMP
|
||||
TabChild::DestroyBrowserWindow()
|
||||
{
|
||||
NS_NOTREACHED("TabChild::SetWebBrowser not supported in TabChild");
|
||||
NS_NOTREACHED("TabChild::DestroyBrowserWindow not supported in TabChild");
|
||||
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
@ -1477,7 +1477,9 @@ TabChild::RecvUpdateFrame(const FrameMetrics& aFrameMetrics)
|
|||
if (aFrameMetrics.mIsRoot) {
|
||||
nsCOMPtr<nsIDOMWindowUtils> utils(GetDOMWindowUtils());
|
||||
if (APZCCallbackHelper::HasValidPresShellId(utils, aFrameMetrics)) {
|
||||
return ProcessUpdateFrame(aFrameMetrics);
|
||||
mLastRootMetrics = ProcessUpdateFrame(aFrameMetrics);
|
||||
APZCCallbackHelper::UpdateCallbackTransform(aFrameMetrics, mLastRootMetrics);
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
// aFrameMetrics.mIsRoot is false, so we are trying to update a subframe.
|
||||
|
@ -1487,6 +1489,7 @@ TabChild::RecvUpdateFrame(const FrameMetrics& aFrameMetrics)
|
|||
if (content) {
|
||||
FrameMetrics newSubFrameMetrics(aFrameMetrics);
|
||||
APZCCallbackHelper::UpdateSubFrame(content, newSubFrameMetrics);
|
||||
APZCCallbackHelper::UpdateCallbackTransform(aFrameMetrics, newSubFrameMetrics);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -1494,7 +1497,8 @@ TabChild::RecvUpdateFrame(const FrameMetrics& aFrameMetrics)
|
|||
// We've recieved a message that is out of date and we want to ignore.
|
||||
// However we can't reply without painting so we reply by painting the
|
||||
// exact same thing as we did before.
|
||||
return ProcessUpdateFrame(mLastRootMetrics);
|
||||
mLastRootMetrics = ProcessUpdateFrame(mLastRootMetrics);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -1505,11 +1509,11 @@ TabChild::RecvAcknowledgeScrollUpdate(const ViewID& aScrollId,
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
FrameMetrics
|
||||
TabChild::ProcessUpdateFrame(const FrameMetrics& aFrameMetrics)
|
||||
{
|
||||
if (!mGlobal || !mTabChildGlobal) {
|
||||
return true;
|
||||
return aFrameMetrics;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMWindowUtils> utils(GetDOMWindowUtils());
|
||||
|
@ -1549,22 +1553,20 @@ TabChild::ProcessUpdateFrame(const FrameMetrics& aFrameMetrics)
|
|||
data.AppendLiteral(" }");
|
||||
|
||||
DispatchMessageManagerMessage(NS_LITERAL_STRING("Viewport:Change"), data);
|
||||
|
||||
mLastRootMetrics = newMetrics;
|
||||
|
||||
return true;
|
||||
return newMetrics;
|
||||
}
|
||||
|
||||
bool
|
||||
TabChild::RecvHandleDoubleTap(const CSSIntPoint& aPoint, const ScrollableLayerGuid& aGuid)
|
||||
TabChild::RecvHandleDoubleTap(const CSSPoint& aPoint, const ScrollableLayerGuid& aGuid)
|
||||
{
|
||||
if (!mGlobal || !mTabChildGlobal) {
|
||||
return true;
|
||||
}
|
||||
|
||||
CSSPoint point = APZCCallbackHelper::ApplyCallbackTransform(aPoint, aGuid);
|
||||
nsCString data;
|
||||
data += nsPrintfCString("{ \"x\" : %d", aPoint.x);
|
||||
data += nsPrintfCString(", \"y\" : %d", aPoint.y);
|
||||
data += nsPrintfCString("{ \"x\" : %f", point.x);
|
||||
data += nsPrintfCString(", \"y\" : %f", point.y);
|
||||
data += nsPrintfCString(" }");
|
||||
|
||||
DispatchMessageManagerMessage(NS_LITERAL_STRING("Gesture:DoubleTap"), data);
|
||||
|
@ -1573,13 +1575,13 @@ TabChild::RecvHandleDoubleTap(const CSSIntPoint& aPoint, const ScrollableLayerGu
|
|||
}
|
||||
|
||||
bool
|
||||
TabChild::RecvHandleSingleTap(const CSSIntPoint& aPoint, const ScrollableLayerGuid& aGuid)
|
||||
TabChild::RecvHandleSingleTap(const CSSPoint& aPoint, const ScrollableLayerGuid& aGuid)
|
||||
{
|
||||
if (!mGlobal || !mTabChildGlobal) {
|
||||
return true;
|
||||
}
|
||||
|
||||
LayoutDevicePoint currentPoint = CSSPoint(aPoint) * mWidget->GetDefaultScale();;
|
||||
LayoutDevicePoint currentPoint = APZCCallbackHelper::ApplyCallbackTransform(aPoint, aGuid) * mWidget->GetDefaultScale();;
|
||||
|
||||
MessageLoop::current()->PostDelayedTask(
|
||||
FROM_HERE,
|
||||
|
@ -1598,14 +1600,16 @@ TabChild::FireSingleTapEvent(LayoutDevicePoint aPoint)
|
|||
}
|
||||
|
||||
bool
|
||||
TabChild::RecvHandleLongTap(const CSSIntPoint& aPoint, const ScrollableLayerGuid& aGuid)
|
||||
TabChild::RecvHandleLongTap(const CSSPoint& aPoint, const ScrollableLayerGuid& aGuid)
|
||||
{
|
||||
if (!mGlobal || !mTabChildGlobal) {
|
||||
return true;
|
||||
}
|
||||
|
||||
mContextMenuHandled =
|
||||
DispatchMouseEvent(NS_LITERAL_STRING("contextmenu"), aPoint, 2, 1, 0, false,
|
||||
DispatchMouseEvent(NS_LITERAL_STRING("contextmenu"),
|
||||
APZCCallbackHelper::ApplyCallbackTransform(aPoint, aGuid),
|
||||
2, 1, 0, false,
|
||||
nsIDOMMouseEvent::MOZ_SOURCE_TOUCH);
|
||||
|
||||
SendContentReceivedTouch(aGuid, mContextMenuHandled);
|
||||
|
@ -1614,7 +1618,7 @@ TabChild::RecvHandleLongTap(const CSSIntPoint& aPoint, const ScrollableLayerGuid
|
|||
}
|
||||
|
||||
bool
|
||||
TabChild::RecvHandleLongTapUp(const CSSIntPoint& aPoint, const ScrollableLayerGuid& aGuid)
|
||||
TabChild::RecvHandleLongTapUp(const CSSPoint& aPoint, const ScrollableLayerGuid& aGuid)
|
||||
{
|
||||
if (mContextMenuHandled) {
|
||||
mContextMenuHandled = false;
|
||||
|
@ -1857,6 +1861,10 @@ TabChild::RecvRealTouchEvent(const WidgetTouchEvent& aEvent,
|
|||
const ScrollableLayerGuid& aGuid)
|
||||
{
|
||||
WidgetTouchEvent localEvent(aEvent);
|
||||
for (size_t i = 0; i < localEvent.touches.Length(); i++) {
|
||||
aEvent.touches[i]->mRefPoint = APZCCallbackHelper::ApplyCallbackTransform(aEvent.touches[i]->mRefPoint, aGuid, mWidget->GetDefaultScale());
|
||||
}
|
||||
|
||||
nsEventStatus status = DispatchWidgetEvent(localEvent);
|
||||
|
||||
if (!IsAsyncPanZoomEnabled()) {
|
||||
|
|
|
@ -218,13 +218,13 @@ public:
|
|||
virtual bool RecvUpdateFrame(const mozilla::layers::FrameMetrics& aFrameMetrics) MOZ_OVERRIDE;
|
||||
virtual bool RecvAcknowledgeScrollUpdate(const ViewID& aScrollId,
|
||||
const uint32_t& aScrollGeneration) MOZ_OVERRIDE;
|
||||
virtual bool RecvHandleDoubleTap(const CSSIntPoint& aPoint,
|
||||
virtual bool RecvHandleDoubleTap(const CSSPoint& aPoint,
|
||||
const mozilla::layers::ScrollableLayerGuid& aGuid) MOZ_OVERRIDE;
|
||||
virtual bool RecvHandleSingleTap(const CSSIntPoint& aPoint,
|
||||
virtual bool RecvHandleSingleTap(const CSSPoint& aPoint,
|
||||
const mozilla::layers::ScrollableLayerGuid& aGuid) MOZ_OVERRIDE;
|
||||
virtual bool RecvHandleLongTap(const CSSIntPoint& aPoint,
|
||||
virtual bool RecvHandleLongTap(const CSSPoint& aPoint,
|
||||
const mozilla::layers::ScrollableLayerGuid& aGuid) MOZ_OVERRIDE;
|
||||
virtual bool RecvHandleLongTapUp(const CSSIntPoint& aPoint,
|
||||
virtual bool RecvHandleLongTapUp(const CSSPoint& aPoint,
|
||||
const mozilla::layers::ScrollableLayerGuid& aGuid) MOZ_OVERRIDE;
|
||||
virtual bool RecvNotifyTransformBegin(const ViewID& aViewId) MOZ_OVERRIDE;
|
||||
virtual bool RecvNotifyTransformEnd(const ViewID& aViewId) MOZ_OVERRIDE;
|
||||
|
@ -417,7 +417,7 @@ private:
|
|||
bool InitRenderingState();
|
||||
void DestroyWindow();
|
||||
void SetProcessNameToAppName();
|
||||
bool ProcessUpdateFrame(const mozilla::layers::FrameMetrics& aFrameMetrics);
|
||||
FrameMetrics ProcessUpdateFrame(const FrameMetrics& aFrameMetrics);
|
||||
|
||||
// Call RecvShow(nsIntSize(0, 0)) and block future calls to RecvShow().
|
||||
void DoFakeShow();
|
||||
|
|
|
@ -516,7 +516,7 @@ TabParent::AcknowledgeScrollUpdate(const ViewID& aScrollId, const uint32_t& aScr
|
|||
}
|
||||
}
|
||||
|
||||
void TabParent::HandleDoubleTap(const CSSIntPoint& aPoint,
|
||||
void TabParent::HandleDoubleTap(const CSSPoint& aPoint,
|
||||
int32_t aModifiers,
|
||||
const ScrollableLayerGuid &aGuid)
|
||||
{
|
||||
|
@ -525,7 +525,7 @@ void TabParent::HandleDoubleTap(const CSSIntPoint& aPoint,
|
|||
}
|
||||
}
|
||||
|
||||
void TabParent::HandleSingleTap(const CSSIntPoint& aPoint,
|
||||
void TabParent::HandleSingleTap(const CSSPoint& aPoint,
|
||||
int32_t aModifiers,
|
||||
const ScrollableLayerGuid &aGuid)
|
||||
{
|
||||
|
@ -535,7 +535,7 @@ void TabParent::HandleSingleTap(const CSSIntPoint& aPoint,
|
|||
}
|
||||
}
|
||||
|
||||
void TabParent::HandleLongTap(const CSSIntPoint& aPoint,
|
||||
void TabParent::HandleLongTap(const CSSPoint& aPoint,
|
||||
int32_t aModifiers,
|
||||
const ScrollableLayerGuid &aGuid)
|
||||
{
|
||||
|
@ -544,7 +544,7 @@ void TabParent::HandleLongTap(const CSSIntPoint& aPoint,
|
|||
}
|
||||
}
|
||||
|
||||
void TabParent::HandleLongTapUp(const CSSIntPoint& aPoint,
|
||||
void TabParent::HandleLongTapUp(const CSSPoint& aPoint,
|
||||
int32_t aModifiers,
|
||||
const ScrollableLayerGuid &aGuid)
|
||||
{
|
||||
|
@ -721,7 +721,7 @@ bool TabParent::SendRealMouseEvent(WidgetMouseEvent& event)
|
|||
return PBrowserParent::SendRealMouseEvent(event);
|
||||
}
|
||||
|
||||
CSSIntPoint TabParent::AdjustTapToChildWidget(const CSSIntPoint& aPoint)
|
||||
CSSPoint TabParent::AdjustTapToChildWidget(const CSSPoint& aPoint)
|
||||
{
|
||||
nsCOMPtr<nsIContent> content = do_QueryInterface(mFrameElement);
|
||||
|
||||
|
@ -735,12 +735,12 @@ CSSIntPoint TabParent::AdjustTapToChildWidget(const CSSIntPoint& aPoint)
|
|||
}
|
||||
nsPresContext* presContext = doc->GetShell()->GetPresContext();
|
||||
|
||||
return CSSIntPoint(
|
||||
aPoint.x + presContext->DevPixelsToIntCSSPixels(mChildProcessOffsetAtTouchStart.x),
|
||||
aPoint.y + presContext->DevPixelsToIntCSSPixels(mChildProcessOffsetAtTouchStart.y));
|
||||
return aPoint + CSSPoint(
|
||||
presContext->DevPixelsToFloatCSSPixels(mChildProcessOffsetAtTouchStart.x),
|
||||
presContext->DevPixelsToFloatCSSPixels(mChildProcessOffsetAtTouchStart.y));
|
||||
}
|
||||
|
||||
bool TabParent::SendHandleSingleTap(const CSSIntPoint& aPoint, const ScrollableLayerGuid& aGuid)
|
||||
bool TabParent::SendHandleSingleTap(const CSSPoint& aPoint, const ScrollableLayerGuid& aGuid)
|
||||
{
|
||||
if (mIsDestroyed) {
|
||||
return false;
|
||||
|
@ -749,7 +749,7 @@ bool TabParent::SendHandleSingleTap(const CSSIntPoint& aPoint, const ScrollableL
|
|||
return PBrowserParent::SendHandleSingleTap(AdjustTapToChildWidget(aPoint), aGuid);
|
||||
}
|
||||
|
||||
bool TabParent::SendHandleLongTap(const CSSIntPoint& aPoint, const ScrollableLayerGuid& aGuid)
|
||||
bool TabParent::SendHandleLongTap(const CSSPoint& aPoint, const ScrollableLayerGuid& aGuid)
|
||||
{
|
||||
if (mIsDestroyed) {
|
||||
return false;
|
||||
|
@ -758,7 +758,7 @@ bool TabParent::SendHandleLongTap(const CSSIntPoint& aPoint, const ScrollableLay
|
|||
return PBrowserParent::SendHandleLongTap(AdjustTapToChildWidget(aPoint), aGuid);
|
||||
}
|
||||
|
||||
bool TabParent::SendHandleLongTapUp(const CSSIntPoint& aPoint, const ScrollableLayerGuid& aGuid)
|
||||
bool TabParent::SendHandleLongTapUp(const CSSPoint& aPoint, const ScrollableLayerGuid& aGuid)
|
||||
{
|
||||
if (mIsDestroyed) {
|
||||
return false;
|
||||
|
@ -767,7 +767,7 @@ bool TabParent::SendHandleLongTapUp(const CSSIntPoint& aPoint, const ScrollableL
|
|||
return PBrowserParent::SendHandleLongTapUp(AdjustTapToChildWidget(aPoint), aGuid);
|
||||
}
|
||||
|
||||
bool TabParent::SendHandleDoubleTap(const CSSIntPoint& aPoint, const ScrollableLayerGuid& aGuid)
|
||||
bool TabParent::SendHandleDoubleTap(const CSSPoint& aPoint, const ScrollableLayerGuid& aGuid)
|
||||
{
|
||||
if (mIsDestroyed) {
|
||||
return false;
|
||||
|
|
|
@ -198,16 +198,16 @@ public:
|
|||
void UpdateDimensions(const nsRect& rect, const nsIntSize& size);
|
||||
void UpdateFrame(const layers::FrameMetrics& aFrameMetrics);
|
||||
void AcknowledgeScrollUpdate(const ViewID& aScrollId, const uint32_t& aScrollGeneration);
|
||||
void HandleDoubleTap(const CSSIntPoint& aPoint,
|
||||
void HandleDoubleTap(const CSSPoint& aPoint,
|
||||
int32_t aModifiers,
|
||||
const ScrollableLayerGuid& aGuid);
|
||||
void HandleSingleTap(const CSSIntPoint& aPoint,
|
||||
void HandleSingleTap(const CSSPoint& aPoint,
|
||||
int32_t aModifiers,
|
||||
const ScrollableLayerGuid& aGuid);
|
||||
void HandleLongTap(const CSSIntPoint& aPoint,
|
||||
void HandleLongTap(const CSSPoint& aPoint,
|
||||
int32_t aModifiers,
|
||||
const ScrollableLayerGuid& aGuid);
|
||||
void HandleLongTapUp(const CSSIntPoint& aPoint,
|
||||
void HandleLongTapUp(const CSSPoint& aPoint,
|
||||
int32_t aModifiers,
|
||||
const ScrollableLayerGuid& aGuid);
|
||||
void NotifyTransformBegin(ViewID aViewId);
|
||||
|
@ -229,10 +229,10 @@ public:
|
|||
bool SendMouseWheelEvent(mozilla::WidgetWheelEvent& event);
|
||||
bool SendRealKeyEvent(mozilla::WidgetKeyboardEvent& event);
|
||||
bool SendRealTouchEvent(WidgetTouchEvent& event);
|
||||
bool SendHandleSingleTap(const CSSIntPoint& aPoint, const ScrollableLayerGuid& aGuid);
|
||||
bool SendHandleLongTap(const CSSIntPoint& aPoint, const ScrollableLayerGuid& aGuid);
|
||||
bool SendHandleLongTapUp(const CSSIntPoint& aPoint, const ScrollableLayerGuid& aGuid);
|
||||
bool SendHandleDoubleTap(const CSSIntPoint& aPoint, const ScrollableLayerGuid& aGuid);
|
||||
bool SendHandleSingleTap(const CSSPoint& aPoint, const ScrollableLayerGuid& aGuid);
|
||||
bool SendHandleLongTap(const CSSPoint& aPoint, const ScrollableLayerGuid& aGuid);
|
||||
bool SendHandleLongTapUp(const CSSPoint& aPoint, const ScrollableLayerGuid& aGuid);
|
||||
bool SendHandleDoubleTap(const CSSPoint& aPoint, const ScrollableLayerGuid& aGuid);
|
||||
|
||||
virtual PDocumentRendererParent*
|
||||
AllocPDocumentRendererParent(const nsRect& documentRect,
|
||||
|
@ -360,7 +360,7 @@ private:
|
|||
nsRefPtr<ContentParent> mManager;
|
||||
void TryCacheDPIAndScale();
|
||||
|
||||
CSSIntPoint AdjustTapToChildWidget(const CSSIntPoint& aPoint);
|
||||
CSSPoint AdjustTapToChildWidget(const CSSPoint& aPoint);
|
||||
|
||||
// When true, we create a pan/zoom controller for our frame and
|
||||
// notify it of input events targeting us.
|
||||
|
|
|
@ -21,4 +21,4 @@ disabled = disabled until bug 859593 is fixed
|
|||
[test_keyboard.html]
|
||||
skip-if = buildapp != 'b2g'
|
||||
[test_wifi-manage.html]
|
||||
skip-if = buildapp != 'b2g'
|
||||
skip-if = (buildapp != 'b2g') || (buildapp == 'b2g' && toolkit != 'gonk') #b2g-desktop(Bug 931116, b2g desktop specific, initial triage)
|
||||
|
|
|
@ -1566,13 +1566,7 @@ bool nsPluginHost::IsJavaMIMEType(const char* aType)
|
|||
(0 == PL_strncasecmp(aType, "application/x-java-applet",
|
||||
sizeof("application/x-java-applet") - 1)) ||
|
||||
(0 == PL_strncasecmp(aType, "application/x-java-bean",
|
||||
sizeof("application/x-java-bean") - 1))
|
||||
#ifdef DEBUG
|
||||
// Emulate java handling for the npjavatest plugin
|
||||
|| (0 == PL_strncasecmp(aType, "application/x-java-test",
|
||||
sizeof("application/x-java-test") - 1))
|
||||
#endif
|
||||
);
|
||||
sizeof("application/x-java-bean") - 1)));
|
||||
}
|
||||
|
||||
// Check whether or not a tag is a live, valid tag, and that it's loaded.
|
||||
|
|
|
@ -1682,7 +1682,8 @@ nsPluginInstanceOwner::ProcessMouseDown(nsIDOMEvent* aMouseEvent)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult nsPluginInstanceOwner::DispatchMouseToPlugin(nsIDOMEvent* aMouseEvent)
|
||||
nsresult nsPluginInstanceOwner::DispatchMouseToPlugin(nsIDOMEvent* aMouseEvent,
|
||||
bool aAllowPropagate)
|
||||
{
|
||||
#if !defined(XP_MACOSX)
|
||||
if (!mPluginWindow || (mPluginWindow->type == NPWindowTypeWindow))
|
||||
|
@ -1699,7 +1700,9 @@ nsresult nsPluginInstanceOwner::DispatchMouseToPlugin(nsIDOMEvent* aMouseEvent)
|
|||
nsEventStatus rv = ProcessEvent(*mouseEvent);
|
||||
if (nsEventStatus_eConsumeNoDefault == rv) {
|
||||
aMouseEvent->PreventDefault();
|
||||
aMouseEvent->StopPropagation();
|
||||
if (!aAllowPropagate) {
|
||||
aMouseEvent->StopPropagation();
|
||||
}
|
||||
}
|
||||
if (mouseEvent->message == NS_MOUSE_BUTTON_UP) {
|
||||
mLastMouseDownButtonType = -1;
|
||||
|
@ -1741,8 +1744,10 @@ nsPluginInstanceOwner::HandleEvent(nsIDOMEvent* aEvent)
|
|||
}
|
||||
return DispatchMouseToPlugin(aEvent);
|
||||
}
|
||||
if (eventType.EqualsLiteral("mousemove") ||
|
||||
eventType.EqualsLiteral("click") ||
|
||||
if (eventType.EqualsLiteral("mousemove")) {
|
||||
return DispatchMouseToPlugin(aEvent, true);
|
||||
}
|
||||
if (eventType.EqualsLiteral("click") ||
|
||||
eventType.EqualsLiteral("dblclick") ||
|
||||
eventType.EqualsLiteral("mouseover") ||
|
||||
eventType.EqualsLiteral("mouseout")) {
|
||||
|
|
|
@ -365,7 +365,8 @@ private:
|
|||
nsRefPtr<nsPluginDOMContextMenuListener> mCXMenuListener;
|
||||
|
||||
nsresult DispatchKeyToPlugin(nsIDOMEvent* aKeyEvent);
|
||||
nsresult DispatchMouseToPlugin(nsIDOMEvent* aMouseEvent);
|
||||
nsresult DispatchMouseToPlugin(nsIDOMEvent* aMouseEvent,
|
||||
bool aAllowPropagate = false);
|
||||
nsresult DispatchFocusToPlugin(nsIDOMEvent* aFocusEvent);
|
||||
|
||||
int mLastMouseDownButtonType;
|
||||
|
|
|
@ -169,8 +169,9 @@ PluginModuleChild::Init(const std::string& aPluginFilename,
|
|||
|
||||
#if defined(MOZ_X11) || defined(OS_MACOSX)
|
||||
nsPluginInfo info = nsPluginInfo();
|
||||
if (NS_FAILED(pluginFile.GetPluginInfo(info, &mLibrary)))
|
||||
if (NS_FAILED(pluginFile.GetPluginInfo(info, &mLibrary))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
#if defined(MOZ_X11)
|
||||
NS_NAMED_LITERAL_CSTRING(flash10Head, "Shockwave Flash 10.");
|
||||
|
@ -181,6 +182,8 @@ PluginModuleChild::Init(const std::string& aPluginFilename,
|
|||
mozilla::plugins::PluginUtilsOSX::SetProcessName(info.fName);
|
||||
#endif
|
||||
|
||||
pluginFile.FreePluginInfo(info);
|
||||
|
||||
if (!mLibrary)
|
||||
#endif
|
||||
{
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
[DEFAULT]
|
||||
skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #b2g-desktop(tests that use plugins)
|
||||
support-files =
|
||||
307-xo-redirect.sjs
|
||||
crashing_subpage.html
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
*
|
||||
*
|
||||
* Copyright (c) 2008, Mozilla Corporation
|
||||
* All rights reserved.
|
||||
*
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
|
@ -14,7 +14,7 @@
|
|||
* * Neither the name of the Mozilla Corporation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
|
@ -25,11 +25,11 @@
|
|||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*
|
||||
* Contributor(s):
|
||||
* Dave Townsend <dtownsend@oxymoronical.com>
|
||||
* Josh Aas <josh@mozilla.com>
|
||||
*
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "nptest.h"
|
||||
|
@ -389,7 +389,7 @@ static void initializeIdentifiers()
|
|||
NPN_GetStringIdentifiers(sPluginPropertyIdentifierNames,
|
||||
ARRAY_LENGTH(sPluginPropertyIdentifierNames), sPluginPropertyIdentifiers);
|
||||
|
||||
sIdentifiersInitialized = true;
|
||||
sIdentifiersInitialized = true;
|
||||
|
||||
// Check whether nullptr is handled in NPN_GetStringIdentifiers
|
||||
NPIdentifier IDList[2];
|
||||
|
@ -431,7 +431,7 @@ static void sendBufferToFrame(NPP instance)
|
|||
if (!instanceData->npnNewStream) outbuf = "data:text/html,";
|
||||
const char* buf = reinterpret_cast<char *>(instanceData->streamBuf);
|
||||
int32_t bufsize = instanceData->streamBufSize;
|
||||
if (instanceData->streamMode == NP_ASFILE ||
|
||||
if (instanceData->streamMode == NP_ASFILE ||
|
||||
instanceData->streamMode == NP_ASFILEONLY) {
|
||||
buf = reinterpret_cast<char *>(instanceData->fileBuf);
|
||||
bufsize = instanceData->fileBufSize;
|
||||
|
@ -445,24 +445,24 @@ static void sendBufferToFrame(NPP instance)
|
|||
else {
|
||||
outbuf.append("Error: no data in buffer");
|
||||
}
|
||||
|
||||
|
||||
if (instanceData->npnNewStream &&
|
||||
instanceData->err.str().length() == 0) {
|
||||
char typeHTML[] = "text/html";
|
||||
NPStream* stream;
|
||||
printf("calling NPN_NewStream...");
|
||||
NPError err = NPN_NewStream(instance, typeHTML,
|
||||
NPError err = NPN_NewStream(instance, typeHTML,
|
||||
instanceData->frame.c_str(), &stream);
|
||||
printf("return value %d\n", err);
|
||||
if (err != NPERR_NO_ERROR) {
|
||||
instanceData->err << "NPN_NewStream returned " << err;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
int32_t bytesToWrite = outbuf.length();
|
||||
int32_t bytesWritten = 0;
|
||||
while ((bytesToWrite - bytesWritten) > 0) {
|
||||
int32_t numBytes = (bytesToWrite - bytesWritten) <
|
||||
int32_t numBytes = (bytesToWrite - bytesWritten) <
|
||||
instanceData->streamChunkSize ?
|
||||
bytesToWrite - bytesWritten : instanceData->streamChunkSize;
|
||||
int32_t written = NPN_Write(instance, stream,
|
||||
|
@ -503,7 +503,7 @@ static void sendBufferToFrame(NPP instance)
|
|||
}
|
||||
}
|
||||
|
||||
NPError err = NPN_GetURL(instance, outbuf.c_str(),
|
||||
NPError err = NPN_GetURL(instance, outbuf.c_str(),
|
||||
instanceData->frame.c_str());
|
||||
if (err != NPERR_NO_ERROR) {
|
||||
instanceData->err << "NPN_GetURL returned " << err;
|
||||
|
@ -523,7 +523,7 @@ static void XPSleep(unsigned int seconds)
|
|||
TestFunction
|
||||
getFuncFromString(const char* funcname)
|
||||
{
|
||||
FunctionTable funcTable[] =
|
||||
FunctionTable funcTable[] =
|
||||
{
|
||||
{ FUNCTION_NPP_NEWSTREAM, "npp_newstream" },
|
||||
{ FUNCTION_NPP_WRITEREADY, "npp_writeready" },
|
||||
|
@ -856,7 +856,7 @@ NPP_New(NPMIMEType pluginType, NPP instance, uint16_t mode, int16_t argc, char*
|
|||
for (int i = 0; i < argc; i++) {
|
||||
if (strcmp(argn[i], "drawmode") == 0) {
|
||||
if (strcmp(argv[i], "solid") == 0)
|
||||
scriptableObject->drawMode = DM_SOLID_COLOR;
|
||||
scriptableObject->drawMode = DM_SOLID_COLOR;
|
||||
}
|
||||
else if (strcmp(argn[i], "color") == 0) {
|
||||
scriptableObject->drawColor = parseHexColor(argv[i], strlen(argv[i]));
|
||||
|
@ -1034,7 +1034,7 @@ NPP_New(NPMIMEType pluginType, NPP instance, uint16_t mode, int16_t argc, char*
|
|||
NPN_ReleaseObject(o);
|
||||
o = nullptr;
|
||||
}
|
||||
|
||||
|
||||
// Set a property on NPNVWindowNPObject
|
||||
err = NPN_GetValue(instance, NPNVWindowNPObject, &o);
|
||||
if (err == NPERR_NO_ERROR) {
|
||||
|
@ -1053,7 +1053,7 @@ NPP_New(NPMIMEType pluginType, NPP instance, uint16_t mode, int16_t argc, char*
|
|||
}
|
||||
}
|
||||
else if (instanceData->testFunction == FUNCTION_NPP_GETURLNOTIFY) {
|
||||
NPError err = NPN_GetURLNotify(instance, instanceData->testUrl.c_str(),
|
||||
NPError err = NPN_GetURLNotify(instance, instanceData->testUrl.c_str(),
|
||||
nullptr, static_cast<void*>(&kNotifyData));
|
||||
if (err != NPERR_NO_ERROR) {
|
||||
instanceData->err << "NPN_GetURLNotify returned " << err;
|
||||
|
@ -1178,7 +1178,7 @@ NPP_NewStream(NPP instance, NPMIMEType type, NPStream* stream, NPBool seekable,
|
|||
{
|
||||
printf("NPP_NewStream\n");
|
||||
InstanceData* instanceData = (InstanceData*)(instance->pdata);
|
||||
|
||||
|
||||
if (instanceData->functionToFail == FUNCTION_NPP_NEWSTREAM &&
|
||||
instanceData->failureCode) {
|
||||
instanceData->err << SUCCESS_STRING;
|
||||
|
@ -1257,20 +1257,20 @@ NPP_DestroyStream(NPP instance, NPStream* stream, NPReason reason)
|
|||
return NPERR_GENERIC_ERROR;
|
||||
}
|
||||
|
||||
if (strcmp(reinterpret_cast<char *>(instanceData->fileBuf),
|
||||
if (strcmp(reinterpret_cast<char *>(instanceData->fileBuf),
|
||||
reinterpret_cast<char *>(instanceData->streamBuf))) {
|
||||
instanceData->err <<
|
||||
"Error: data passed to NPP_Write and NPP_StreamAsFile differed";
|
||||
}
|
||||
}
|
||||
if (instanceData->frame.length() > 0 &&
|
||||
if (instanceData->frame.length() > 0 &&
|
||||
instanceData->testFunction != FUNCTION_NPP_GETURLNOTIFY &&
|
||||
instanceData->testFunction != FUNCTION_NPP_POSTURL) {
|
||||
sendBufferToFrame(instance);
|
||||
}
|
||||
if (instanceData->testFunction == FUNCTION_NPP_POSTURL) {
|
||||
NPError err = NPN_PostURL(instance, instanceData->testUrl.c_str(),
|
||||
instanceData->postMode == POSTMODE_FRAME ? instanceData->frame.c_str() : nullptr,
|
||||
NPError err = NPN_PostURL(instance, instanceData->testUrl.c_str(),
|
||||
instanceData->postMode == POSTMODE_FRAME ? instanceData->frame.c_str() : nullptr,
|
||||
instanceData->streamBufSize,
|
||||
reinterpret_cast<char *>(instanceData->streamBuf), false);
|
||||
if (err != NPERR_NO_ERROR)
|
||||
|
@ -1288,7 +1288,7 @@ NPP_WriteReady(NPP instance, NPStream* stream)
|
|||
if (instanceData->functionToFail == FUNCTION_NPP_NEWSTREAM) {
|
||||
instanceData->err << "NPP_WriteReady called";
|
||||
}
|
||||
|
||||
|
||||
// temporarily disabled per bug 519870
|
||||
//if (instanceData->writeReadyCount == 1) {
|
||||
// return 0;
|
||||
|
@ -1318,7 +1318,7 @@ NPP_Write(NPP instance, NPStream* stream, int32_t offset, int32_t len, void* buf
|
|||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
if (instanceData->functionToFail == FUNCTION_NPP_NEWSTREAM) {
|
||||
instanceData->err << "NPP_Write called";
|
||||
}
|
||||
|
@ -1354,7 +1354,7 @@ NPP_Write(NPP instance, NPStream* stream, int32_t offset, int32_t len, void* buf
|
|||
NPN_DestroyStream(instance, stream, NPRES_USER_BREAK);
|
||||
}
|
||||
else if (instanceData->streamMode == NP_SEEK &&
|
||||
stream->end != 0 &&
|
||||
stream->end != 0 &&
|
||||
stream->end == ((uint32_t)instanceData->streamBufSize + len)) {
|
||||
// If the complete stream has been written, and we're doing a seek test,
|
||||
// then call NPN_RequestRead.
|
||||
|
@ -1373,7 +1373,7 @@ NPP_Write(NPP instance, NPStream* stream, int32_t offset, int32_t len, void* buf
|
|||
char* streamBuf = reinterpret_cast<char *>(instanceData->streamBuf);
|
||||
if (offset + len <= instanceData->streamBufSize) {
|
||||
if (memcmp(buffer, streamBuf + offset, len)) {
|
||||
instanceData->err <<
|
||||
instanceData->err <<
|
||||
"Error: data written from NPN_RequestRead doesn't match";
|
||||
}
|
||||
else {
|
||||
|
@ -1402,8 +1402,8 @@ NPP_Write(NPP instance, NPStream* stream, int32_t offset, int32_t len, void* buf
|
|||
streamBuf = reinterpret_cast<char *>(instanceData->streamBuf);
|
||||
}
|
||||
else {
|
||||
instanceData->streamBuf =
|
||||
realloc(reinterpret_cast<char *>(instanceData->streamBuf),
|
||||
instanceData->streamBuf =
|
||||
realloc(reinterpret_cast<char *>(instanceData->streamBuf),
|
||||
instanceData->streamBufSize + len + 1);
|
||||
streamBuf = reinterpret_cast<char *>(instanceData->streamBuf);
|
||||
}
|
||||
|
@ -1813,14 +1813,14 @@ NPN_RequestRead(NPStream* stream, NPByteRange* rangeList)
|
|||
}
|
||||
|
||||
NPError
|
||||
NPN_PostURLNotify(NPP instance, const char* url,
|
||||
const char* target, uint32_t len,
|
||||
NPN_PostURLNotify(NPP instance, const char* url,
|
||||
const char* target, uint32_t len,
|
||||
const char* buf, NPBool file, void* notifyData)
|
||||
{
|
||||
return sBrowserFuncs->posturlnotify(instance, url, target, len, buf, file, notifyData);
|
||||
}
|
||||
|
||||
NPError
|
||||
NPError
|
||||
NPN_PostURL(NPP instance, const char *url,
|
||||
const char *target, uint32_t len,
|
||||
const char *buf, NPBool file)
|
||||
|
@ -1835,8 +1835,8 @@ NPN_DestroyStream(NPP instance, NPStream* stream, NPError reason)
|
|||
}
|
||||
|
||||
NPError
|
||||
NPN_NewStream(NPP instance,
|
||||
NPMIMEType type,
|
||||
NPN_NewStream(NPP instance,
|
||||
NPMIMEType type,
|
||||
const char* target,
|
||||
NPStream** stream)
|
||||
{
|
||||
|
@ -1858,7 +1858,7 @@ NPN_Enumerate(NPP instance,
|
|||
NPIdentifier **identifiers,
|
||||
uint32_t *identifierCount)
|
||||
{
|
||||
return sBrowserFuncs->enumerate(instance, npobj, identifiers,
|
||||
return sBrowserFuncs->enumerate(instance, npobj, identifiers,
|
||||
identifierCount);
|
||||
}
|
||||
|
||||
|
@ -1999,7 +1999,7 @@ scriptableInvoke(NPObject* npobj, NPIdentifier name, const NPVariant* args, uint
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
for (int i = 0; i < int(ARRAY_LENGTH(sPluginMethodIdentifiers)); i++) {
|
||||
if (name == sPluginMethodIdentifiers[i])
|
||||
return sPluginMethodFunctions[i](npobj, args, argCount, result);
|
||||
|
@ -2048,7 +2048,9 @@ scriptableInvokeDefault(NPObject* npobj, const NPVariant* args, uint32_t argCoun
|
|||
value << ";other";
|
||||
}
|
||||
}
|
||||
STRINGZ_TO_NPVARIANT(NPN_StrDup(value.str().c_str()), *result);
|
||||
|
||||
char *outval = NPN_StrDup(value.str().c_str());
|
||||
STRINGZ_TO_NPVARIANT(outval, *result);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -2056,16 +2058,21 @@ bool
|
|||
scriptableHasProperty(NPObject* npobj, NPIdentifier name)
|
||||
{
|
||||
if (NPN_IdentifierIsString(name)) {
|
||||
if (NPN_GetStringIdentifier(NPN_UTF8FromIdentifier(name)) != name)
|
||||
NPUTF8 *asUTF8 = NPN_UTF8FromIdentifier(name);
|
||||
if (NPN_GetStringIdentifier(asUTF8) != name) {
|
||||
Crash();
|
||||
}
|
||||
NPN_MemFree(asUTF8);
|
||||
}
|
||||
else {
|
||||
if (NPN_GetIntIdentifier(NPN_IntFromIdentifier(name)) != name)
|
||||
if (NPN_GetIntIdentifier(NPN_IntFromIdentifier(name)) != name) {
|
||||
Crash();
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < int(ARRAY_LENGTH(sPluginPropertyIdentifiers)); i++) {
|
||||
if (name == sPluginPropertyIdentifiers[i])
|
||||
if (name == sPluginPropertyIdentifiers[i]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -2141,7 +2148,7 @@ compareVariants(NPP instance, const NPVariant* var1, const NPVariant* var2)
|
|||
" expected " << var2->type;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
switch (var1->type) {
|
||||
case NPVariantType_Int32: {
|
||||
int32_t result = NPVARIANT_TO_INT32(*var1);
|
||||
|
@ -2184,8 +2191,8 @@ compareVariants(NPP instance, const NPVariant* var1, const NPVariant* var2)
|
|||
const NPString* expected = &NPVARIANT_TO_STRING(*var2);
|
||||
if (strcmp(result->UTF8Characters, expected->UTF8Characters) ||
|
||||
strlen(result->UTF8Characters) != strlen(expected->UTF8Characters)) {
|
||||
id->err << "Variant values don't match; got " <<
|
||||
result->UTF8Characters << " expected " <<
|
||||
id->err << "Variant values don't match; got " <<
|
||||
result->UTF8Characters << " expected " <<
|
||||
expected->UTF8Characters;
|
||||
success = false;
|
||||
}
|
||||
|
@ -2221,7 +2228,7 @@ compareVariants(NPP instance, const NPVariant* var1, const NPVariant* var2)
|
|||
success = false;
|
||||
}
|
||||
else {
|
||||
success = compareVariants(instance, &resultVariant,
|
||||
success = compareVariants(instance, &resultVariant,
|
||||
&expectedVariant);
|
||||
NPN_ReleaseVariantValue(&expectedVariant);
|
||||
}
|
||||
|
@ -2235,7 +2242,7 @@ compareVariants(NPP instance, const NPVariant* var1, const NPVariant* var2)
|
|||
id->err << "Unknown variant type";
|
||||
success = false;
|
||||
}
|
||||
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
|
@ -2246,7 +2253,7 @@ throwExceptionNextInvoke(NPObject* npobj, const NPVariant* args, uint32_t argCou
|
|||
InstanceData* id = static_cast<InstanceData*>(npp->pdata);
|
||||
id->throwOnNextInvoke = true;
|
||||
BOOLEAN_TO_NPVARIANT(true, *result);
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
|
@ -2254,7 +2261,7 @@ npnInvokeDefaultTest(NPObject* npobj, const NPVariant* args, uint32_t argCount,
|
|||
{
|
||||
bool success = false;
|
||||
NPP npp = static_cast<TestNPObject*>(npobj)->npp;
|
||||
|
||||
|
||||
NPObject* windowObject;
|
||||
NPN_GetValue(npp, NPNVWindowNPObject, &windowObject);
|
||||
if (!windowObject)
|
||||
|
@ -2271,7 +2278,7 @@ npnInvokeDefaultTest(NPObject* npobj, const NPVariant* args, uint32_t argCount,
|
|||
NPObject* selfObject = NPVARIANT_TO_OBJECT(objectVariant);
|
||||
if (selfObject != nullptr) {
|
||||
NPVariant resultVariant;
|
||||
if (NPN_InvokeDefault(npp, selfObject, argCount > 1 ? &args[1] : nullptr,
|
||||
if (NPN_InvokeDefault(npp, selfObject, argCount > 1 ? &args[1] : nullptr,
|
||||
argCount - 1, &resultVariant)) {
|
||||
*result = resultVariant;
|
||||
success = true;
|
||||
|
@ -2297,18 +2304,18 @@ npnInvokeTest(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVaria
|
|||
NPIdentifier function = variantToIdentifier(args[0]);
|
||||
if (!function)
|
||||
return false;
|
||||
|
||||
|
||||
NPObject* windowObject;
|
||||
NPN_GetValue(npp, NPNVWindowNPObject, &windowObject);
|
||||
if (!windowObject)
|
||||
return false;
|
||||
|
||||
|
||||
NPVariant invokeResult;
|
||||
bool invokeReturn = NPN_Invoke(npp, windowObject, function,
|
||||
argCount > 2 ? &args[2] : nullptr, argCount - 2, &invokeResult);
|
||||
|
||||
|
||||
bool compareResult = compareVariants(npp, &invokeResult, &args[1]);
|
||||
|
||||
|
||||
NPN_ReleaseObject(windowObject);
|
||||
NPN_ReleaseVariantValue(&invokeResult);
|
||||
BOOLEAN_TO_NPVARIANT(invokeReturn && compareResult, *result);
|
||||
|
@ -2320,10 +2327,10 @@ npnEvaluateTest(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVar
|
|||
{
|
||||
bool success = false;
|
||||
NPP npp = static_cast<TestNPObject*>(npobj)->npp;
|
||||
|
||||
|
||||
if (argCount != 1)
|
||||
return false;
|
||||
|
||||
|
||||
if (!NPVARIANT_IS_STRING(args[0]))
|
||||
return false;
|
||||
|
||||
|
@ -2331,9 +2338,9 @@ npnEvaluateTest(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVar
|
|||
NPN_GetValue(npp, NPNVWindowNPObject, &windowObject);
|
||||
if (!windowObject)
|
||||
return false;
|
||||
|
||||
|
||||
success = NPN_Evaluate(npp, windowObject, (NPString*)&NPVARIANT_TO_STRING(args[0]), result);
|
||||
|
||||
|
||||
NPN_ReleaseObject(windowObject);
|
||||
return success;
|
||||
}
|
||||
|
@ -2580,10 +2587,13 @@ getError(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* r
|
|||
|
||||
NPP npp = static_cast<TestNPObject*>(npobj)->npp;
|
||||
InstanceData* id = static_cast<InstanceData*>(npp->pdata);
|
||||
if (id->err.str().length() == 0)
|
||||
STRINGZ_TO_NPVARIANT(NPN_StrDup(SUCCESS_STRING), *result);
|
||||
else
|
||||
STRINGZ_TO_NPVARIANT(NPN_StrDup(id->err.str().c_str()), *result);
|
||||
if (id->err.str().length() == 0) {
|
||||
char *outval = NPN_StrDup(SUCCESS_STRING);
|
||||
STRINGZ_TO_NPVARIANT(outval, *result);
|
||||
} else {
|
||||
char *outval = NPN_StrDup(id->err.str().c_str());
|
||||
STRINGZ_TO_NPVARIANT(outval, *result);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -2663,7 +2673,7 @@ convertPointY(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVaria
|
|||
|
||||
double resultX, resultY;
|
||||
NPN_ConvertPoint(npp, sourceX, sourceY, (NPCoordinateSpace)sourceSpace, &resultX, &resultY, (NPCoordinateSpace)destSpace);
|
||||
|
||||
|
||||
DOUBLE_TO_NPVARIANT(resultY, *result);
|
||||
return true;
|
||||
}
|
||||
|
@ -2906,7 +2916,9 @@ static bool getJavaCodebase(NPObject* npobj, const NPVariant* args, uint32_t arg
|
|||
|
||||
NPP npp = static_cast<TestNPObject*>(npobj)->npp;
|
||||
InstanceData* id = static_cast<InstanceData*>(npp->pdata);
|
||||
STRINGZ_TO_NPVARIANT(NPN_StrDup(id->javaCodebase.c_str()), *result);
|
||||
|
||||
char *outval = NPN_StrDup(id->javaCodebase.c_str());
|
||||
STRINGZ_TO_NPVARIANT(outval, *result);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -2954,12 +2966,12 @@ static bool enableFPExceptions(NPObject* npobj, const NPVariant* args, uint32_t
|
|||
// caller is responsible for freeing return buffer
|
||||
static char* URLForInstanceWindow(NPP instance) {
|
||||
char *outString = nullptr;
|
||||
|
||||
|
||||
NPObject* windowObject = nullptr;
|
||||
NPError err = NPN_GetValue(instance, NPNVWindowNPObject, &windowObject);
|
||||
if (err != NPERR_NO_ERROR || !windowObject)
|
||||
return nullptr;
|
||||
|
||||
|
||||
NPIdentifier locationIdentifier = NPN_GetStringIdentifier("location");
|
||||
NPVariant locationVariant;
|
||||
if (NPN_GetProperty(instance, windowObject, locationIdentifier, &locationVariant)) {
|
||||
|
@ -2977,13 +2989,13 @@ static char* URLForInstanceWindow(NPP instance) {
|
|||
}
|
||||
}
|
||||
NPN_ReleaseVariantValue(&hrefVariant);
|
||||
}
|
||||
}
|
||||
}
|
||||
NPN_ReleaseVariantValue(&locationVariant);
|
||||
}
|
||||
|
||||
|
||||
NPN_ReleaseObject(windowObject);
|
||||
|
||||
|
||||
return outString;
|
||||
}
|
||||
|
||||
|
@ -2995,15 +3007,15 @@ setCookie(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant*
|
|||
if (!NPVARIANT_IS_STRING(args[0]))
|
||||
return false;
|
||||
const NPString* cookie = &NPVARIANT_TO_STRING(args[0]);
|
||||
|
||||
|
||||
NPP npp = static_cast<TestNPObject*>(npobj)->npp;
|
||||
|
||||
|
||||
char* url = URLForInstanceWindow(npp);
|
||||
if (!url)
|
||||
return false;
|
||||
NPError err = NPN_SetValueForURL(npp, NPNURLVCookie, url, cookie->UTF8Characters, cookie->UTF8Length);
|
||||
free(url);
|
||||
|
||||
|
||||
return (err == NPERR_NO_ERROR);
|
||||
}
|
||||
|
||||
|
@ -3012,9 +3024,9 @@ getCookie(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant*
|
|||
{
|
||||
if (argCount != 0)
|
||||
return false;
|
||||
|
||||
|
||||
NPP npp = static_cast<TestNPObject*>(npobj)->npp;
|
||||
|
||||
|
||||
char* url = URLForInstanceWindow(npp);
|
||||
if (!url)
|
||||
return false;
|
||||
|
@ -3024,7 +3036,7 @@ getCookie(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant*
|
|||
free(url);
|
||||
if (err != NPERR_NO_ERROR || !cookie)
|
||||
return false;
|
||||
|
||||
|
||||
STRINGZ_TO_NPVARIANT(cookie, *result);
|
||||
return true;
|
||||
}
|
||||
|
@ -3051,18 +3063,18 @@ getAuthInfo(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant
|
|||
char* username = nullptr;
|
||||
char* password = nullptr;
|
||||
uint32_t ulen = 0, plen = 0;
|
||||
|
||||
NPError err = NPN_GetAuthenticationInfo(npp,
|
||||
protocol->UTF8Characters,
|
||||
host->UTF8Characters,
|
||||
port,
|
||||
scheme->UTF8Characters,
|
||||
|
||||
NPError err = NPN_GetAuthenticationInfo(npp,
|
||||
protocol->UTF8Characters,
|
||||
host->UTF8Characters,
|
||||
port,
|
||||
scheme->UTF8Characters,
|
||||
realm->UTF8Characters,
|
||||
&username,
|
||||
&ulen,
|
||||
&password,
|
||||
&username,
|
||||
&ulen,
|
||||
&password,
|
||||
&plen);
|
||||
|
||||
|
||||
if (err != NPERR_NO_ERROR) {
|
||||
return false;
|
||||
}
|
||||
|
@ -3077,7 +3089,7 @@ getAuthInfo(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant
|
|||
|
||||
NPN_MemFree(username);
|
||||
NPN_MemFree(password);
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -3105,7 +3117,7 @@ static void timerCallback(NPP npp, uint32_t timerID)
|
|||
}
|
||||
|
||||
NPN_ReleaseObject(windowObject);
|
||||
|
||||
|
||||
if (event.timerIdSchedule > -1) {
|
||||
id->timerID[event.timerIdSchedule] = NPN_ScheduleTimer(npp, event.timerInterval, event.timerRepeat, timerCallback);
|
||||
}
|
||||
|
@ -3128,9 +3140,9 @@ timerTest(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant*
|
|||
|
||||
id->timerTestResult = true;
|
||||
timerEvent event = timerEvents[currentTimerEventCount];
|
||||
|
||||
|
||||
id->timerID[event.timerIdSchedule] = NPN_ScheduleTimer(npp, event.timerInterval, event.timerRepeat, timerCallback);
|
||||
|
||||
|
||||
return id->timerID[event.timerIdSchedule] != 0;
|
||||
}
|
||||
|
||||
|
@ -3171,7 +3183,7 @@ asyncCallback(void* cookie)
|
|||
id->asyncCallbackResult = false;
|
||||
#endif
|
||||
break;
|
||||
|
||||
|
||||
// async callback triggered from different thread
|
||||
default:
|
||||
NPObject* windowObject;
|
||||
|
@ -3197,11 +3209,11 @@ asyncCallbackTest(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPV
|
|||
return false;
|
||||
const NPString* argstr = &NPVARIANT_TO_STRING(args[0]);
|
||||
id->asyncTestScriptCallback = argstr->UTF8Characters;
|
||||
|
||||
|
||||
id->asyncTestPhase = 0;
|
||||
id->asyncCallbackResult = true;
|
||||
NPN_PluginThreadAsyncCall(npp, asyncCallback, (void*)npobj);
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -3287,7 +3299,7 @@ checkGCRace(NPObject* npobj, const NPVariant* args, uint32_t argCount,
|
|||
return false;
|
||||
|
||||
NPP npp = static_cast<TestNPObject*>(npobj)->npp;
|
||||
|
||||
|
||||
NPObject* localFunc =
|
||||
NPN_CreateObject(npp, const_cast<NPClass*>(&kGCRaceClass));
|
||||
|
||||
|
@ -3310,7 +3322,7 @@ hangPlugin(NPObject* npobj, const NPVariant* args, uint32_t argCount,
|
|||
busyHang = NPVARIANT_TO_BOOLEAN(args[0]);
|
||||
}
|
||||
|
||||
if (busyHang) {
|
||||
if (busyHang) {
|
||||
const time_t start = std::time(nullptr);
|
||||
while ((std::time(nullptr) - start) < 100000) {
|
||||
volatile int dummy = 0;
|
||||
|
@ -3660,7 +3672,7 @@ bool constructObject(NPObject* npobj, const NPVariant* args, uint32_t argCount,
|
|||
return false;
|
||||
|
||||
NPObject* ctor = NPVARIANT_TO_OBJECT(args[0]);
|
||||
|
||||
|
||||
NPP npp = static_cast<TestNPObject*>(npobj)->npp;
|
||||
|
||||
return NPN_Construct(npp, ctor, args + 1, argCount - 1, result);
|
||||
|
@ -3693,12 +3705,12 @@ bool setSitesWithData(NPObject* npobj, const NPVariant* args, uint32_t argCount,
|
|||
const char* flagsEnd = strchr(siteEnd + 1, ':');
|
||||
*((char*) flagsEnd) = '\0';
|
||||
*((char*) next) = '\0';
|
||||
|
||||
|
||||
siteData data;
|
||||
data.site = string(iterator);
|
||||
data.flags = atoi(siteEnd + 1);
|
||||
data.age = atoi(flagsEnd + 1);
|
||||
|
||||
|
||||
sSitesWithData->push_back(data);
|
||||
|
||||
if (next == end)
|
||||
|
@ -3728,7 +3740,9 @@ bool getLastKeyText(NPObject* npobj, const NPVariant* args, uint32_t argCount,
|
|||
|
||||
NPP npp = static_cast<TestNPObject*>(npobj)->npp;
|
||||
InstanceData* id = static_cast<InstanceData*>(npp->pdata);
|
||||
STRINGZ_TO_NPVARIANT(NPN_StrDup(id->lastKeyText.c_str()), *result);
|
||||
|
||||
char *outval = NPN_StrDup(id->lastKeyText.c_str());
|
||||
STRINGZ_TO_NPVARIANT(outval, *result);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -3756,7 +3770,7 @@ bool getMouseUpEventCount(NPObject* npobj, const NPVariant* args, uint32_t argCo
|
|||
if (argCount != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
NPP npp = static_cast<TestNPObject*>(npobj)->npp;
|
||||
InstanceData* id = static_cast<InstanceData*>(npp->pdata);
|
||||
INT32_TO_NPVARIANT(id->mouseUpEventCount, *result);
|
||||
|
|
|
@ -185,11 +185,10 @@ public:
|
|||
NS_IMPL_CYCLE_COLLECTION_CLASS(Promise)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Promise)
|
||||
tmp->MaybeReportRejected();
|
||||
tmp->MaybeReportRejectedOnce();
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mGlobal)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mResolveCallbacks);
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mRejectCallbacks);
|
||||
tmp->mResult = JS::UndefinedValue();
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
|
@ -229,8 +228,7 @@ Promise::Promise(nsIGlobalObject* aGlobal)
|
|||
|
||||
Promise::~Promise()
|
||||
{
|
||||
MaybeReportRejected();
|
||||
mResult = JS::UndefinedValue();
|
||||
MaybeReportRejectedOnce();
|
||||
mozilla::DropJSObjects(this);
|
||||
}
|
||||
|
||||
|
@ -822,6 +820,9 @@ Promise::AppendCallbacks(PromiseCallback* aResolveCallback,
|
|||
if (aRejectCallback) {
|
||||
mHadRejectCallback = true;
|
||||
mRejectCallbacks.AppendElement(aRejectCallback);
|
||||
|
||||
// Now that there is a callback, we don't need to report anymore.
|
||||
RemoveFeature();
|
||||
}
|
||||
|
||||
// If promise's state is resolved, queue a task to process our resolve
|
||||
|
@ -1058,9 +1059,47 @@ Promise::RunResolveTask(JS::Handle<JS::Value> aValue,
|
|||
|
||||
SetResult(aValue);
|
||||
SetState(aState);
|
||||
|
||||
// If the Promise was rejected, and there is no reject handler already setup,
|
||||
// watch for thread shutdown.
|
||||
if (aState == PromiseState::Rejected &&
|
||||
!mHadRejectCallback &&
|
||||
!NS_IsMainThread()) {
|
||||
WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
|
||||
MOZ_ASSERT(worker);
|
||||
worker->AssertIsOnWorkerThread();
|
||||
|
||||
mFeature = new PromiseReportRejectFeature(this);
|
||||
if (NS_WARN_IF(!worker->AddFeature(worker->GetJSContext(), mFeature))) {
|
||||
// Worker is shutting down, report rejection immediately since it is
|
||||
// unlikely that reject callbacks will be added after this point.
|
||||
MaybeReportRejected();
|
||||
}
|
||||
}
|
||||
|
||||
RunTask();
|
||||
}
|
||||
|
||||
void
|
||||
Promise::RemoveFeature()
|
||||
{
|
||||
if (mFeature) {
|
||||
WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
|
||||
MOZ_ASSERT(worker);
|
||||
worker->RemoveFeature(worker->GetJSContext(), mFeature);
|
||||
mFeature = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
PromiseReportRejectFeature::Notify(JSContext* aCx, workers::Status aStatus)
|
||||
{
|
||||
MOZ_ASSERT(aStatus > workers::Running);
|
||||
mPromise->MaybeReportRejectedOnce();
|
||||
// After this point, `this` has been deleted by RemoveFeature!
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
Promise::ArgumentToJSValue(const nsAString& aArgument,
|
||||
JSContext* aCx,
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
#include "nsAutoPtr.h"
|
||||
#include "js/TypeDecls.h"
|
||||
|
||||
#include "mozilla/dom/workers/bindings/WorkerFeature.h"
|
||||
|
||||
class nsIGlobalObject;
|
||||
|
||||
namespace mozilla {
|
||||
|
@ -28,6 +30,23 @@ class PromiseCallback;
|
|||
class PromiseInit;
|
||||
class PromiseNativeHandler;
|
||||
|
||||
class Promise;
|
||||
class PromiseReportRejectFeature : public workers::WorkerFeature
|
||||
{
|
||||
// The Promise that owns this feature.
|
||||
Promise* mPromise;
|
||||
|
||||
public:
|
||||
PromiseReportRejectFeature(Promise* aPromise)
|
||||
: mPromise(aPromise)
|
||||
{
|
||||
MOZ_ASSERT(mPromise);
|
||||
}
|
||||
|
||||
virtual bool
|
||||
Notify(JSContext* aCx, workers::Status aStatus) MOZ_OVERRIDE;
|
||||
};
|
||||
|
||||
class Promise MOZ_FINAL : public nsISupports,
|
||||
public nsWrapperCache
|
||||
{
|
||||
|
@ -35,6 +54,7 @@ class Promise MOZ_FINAL : public nsISupports,
|
|||
friend class PromiseResolverMixin;
|
||||
friend class PromiseResolverTask;
|
||||
friend class PromiseTask;
|
||||
friend class PromiseReportRejectFeature;
|
||||
friend class RejectPromiseCallback;
|
||||
friend class ResolvePromiseCallback;
|
||||
friend class WorkerPromiseResolverTask;
|
||||
|
@ -157,8 +177,15 @@ private:
|
|||
|
||||
// If we have been rejected and our mResult is a JS exception,
|
||||
// report it to the error console.
|
||||
// Use MaybeReportRejectedOnce() for actual calls.
|
||||
void MaybeReportRejected();
|
||||
|
||||
void MaybeReportRejectedOnce() {
|
||||
MaybeReportRejected();
|
||||
RemoveFeature();
|
||||
mResult = JS::UndefinedValue();
|
||||
}
|
||||
|
||||
void MaybeResolveInternal(JSContext* aCx,
|
||||
JS::Handle<JS::Value> aValue,
|
||||
PromiseTaskSync aSync = AsyncTask);
|
||||
|
@ -271,6 +298,8 @@ private:
|
|||
|
||||
void HandleException(JSContext* aCx);
|
||||
|
||||
void RemoveFeature();
|
||||
|
||||
nsRefPtr<nsIGlobalObject> mGlobal;
|
||||
|
||||
nsTArray<nsRefPtr<PromiseCallback> > mResolveCallbacks;
|
||||
|
@ -282,6 +311,12 @@ private:
|
|||
bool mHadRejectCallback;
|
||||
|
||||
bool mResolvePending;
|
||||
|
||||
// If a rejected promise on a worker has no reject callbacks attached, it
|
||||
// needs to know when the worker is shutting down, to report the error on the
|
||||
// console before the worker's context is deleted. This feature is used for
|
||||
// that purpose.
|
||||
nsAutoPtr<PromiseReportRejectFeature> mFeature;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
|
|
@ -310,15 +310,17 @@ gfxMemorySharedReadLock::GetReadCount()
|
|||
|
||||
gfxShmSharedReadLock::gfxShmSharedReadLock(ISurfaceAllocator* aAllocator)
|
||||
: mAllocator(aAllocator)
|
||||
, mAllocSuccess(false)
|
||||
{
|
||||
MOZ_COUNT_CTOR(gfxShmSharedReadLock);
|
||||
|
||||
MOZ_ASSERT(mAllocator);
|
||||
if (mAllocator) {
|
||||
#define MOZ_ALIGN_WORD(x) (((x) + 3) & ~3)
|
||||
if (mAllocator->AllocUnsafeShmem(MOZ_ALIGN_WORD(sizeof(ShmReadLockInfo)),
|
||||
mozilla::ipc::SharedMemory::TYPE_BASIC, &mShmem)) {
|
||||
ShmReadLockInfo* info = GetShmReadLockInfoPtr();
|
||||
info->readCount = 1;
|
||||
mAllocSuccess = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -331,13 +333,18 @@ gfxShmSharedReadLock::~gfxShmSharedReadLock()
|
|||
int32_t
|
||||
gfxShmSharedReadLock::ReadLock() {
|
||||
NS_ASSERT_OWNINGTHREAD(gfxShmSharedReadLock);
|
||||
|
||||
if (!mAllocSuccess) {
|
||||
return 0;
|
||||
}
|
||||
ShmReadLockInfo* info = GetShmReadLockInfoPtr();
|
||||
return PR_ATOMIC_INCREMENT(&info->readCount);
|
||||
}
|
||||
|
||||
int32_t
|
||||
gfxShmSharedReadLock::ReadUnlock() {
|
||||
if (!mAllocSuccess) {
|
||||
return 0;
|
||||
}
|
||||
ShmReadLockInfo* info = GetShmReadLockInfoPtr();
|
||||
int32_t readCount = PR_ATOMIC_DECREMENT(&info->readCount);
|
||||
NS_ASSERTION(readCount >= 0, "ReadUnlock called without a ReadLock.");
|
||||
|
@ -350,7 +357,9 @@ gfxShmSharedReadLock::ReadUnlock() {
|
|||
int32_t
|
||||
gfxShmSharedReadLock::GetReadCount() {
|
||||
NS_ASSERT_OWNINGTHREAD(gfxShmSharedReadLock);
|
||||
|
||||
if (!mAllocSuccess) {
|
||||
return 0;
|
||||
}
|
||||
ShmReadLockInfo* info = GetShmReadLockInfoPtr();
|
||||
return info->readCount;
|
||||
}
|
||||
|
@ -514,6 +523,9 @@ TileClient::GetBackBuffer(const nsIntRegion& aDirtyRegion, TextureClientPool *aP
|
|||
} else {
|
||||
mBackLock = new gfxShmSharedReadLock(mManager->AsShadowForwarder());
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mBackLock->IsValid());
|
||||
|
||||
*aCreatedTextureClient = true;
|
||||
mInvalidBack = nsIntRect(0, 0, TILEDLAYERBUFFER_TILE_SIZE, TILEDLAYERBUFFER_TILE_SIZE);
|
||||
}
|
||||
|
|
|
@ -55,6 +55,7 @@ public:
|
|||
virtual int32_t ReadLock() = 0;
|
||||
virtual int32_t ReadUnlock() = 0;
|
||||
virtual int32_t GetReadCount() = 0;
|
||||
virtual bool IsValid() const = 0;
|
||||
|
||||
enum gfxSharedReadLockType {
|
||||
TYPE_MEMORY,
|
||||
|
@ -80,6 +81,8 @@ public:
|
|||
|
||||
virtual gfxSharedReadLockType GetType() MOZ_OVERRIDE { return TYPE_MEMORY; }
|
||||
|
||||
virtual bool IsValid() const MOZ_OVERRIDE { return true; };
|
||||
|
||||
private:
|
||||
int32_t mReadCount;
|
||||
};
|
||||
|
@ -101,6 +104,8 @@ public:
|
|||
|
||||
virtual int32_t GetReadCount() MOZ_OVERRIDE;
|
||||
|
||||
virtual bool IsValid() const MOZ_OVERRIDE { return mAllocSuccess; };
|
||||
|
||||
virtual gfxSharedReadLockType GetType() MOZ_OVERRIDE { return TYPE_SHMEM; }
|
||||
|
||||
mozilla::ipc::Shmem& GetShmem() { return mShmem; }
|
||||
|
@ -116,6 +121,7 @@ private:
|
|||
gfxShmSharedReadLock(ISurfaceAllocator* aAllocator, const mozilla::ipc::Shmem& aShmem)
|
||||
: mAllocator(aAllocator)
|
||||
, mShmem(aShmem)
|
||||
, mAllocSuccess(true)
|
||||
{
|
||||
MOZ_COUNT_CTOR(gfxShmSharedReadLock);
|
||||
}
|
||||
|
@ -128,6 +134,7 @@ private:
|
|||
|
||||
RefPtr<ISurfaceAllocator> mAllocator;
|
||||
mozilla::ipc::Shmem mShmem;
|
||||
bool mAllocSuccess;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -170,14 +177,18 @@ struct TileClient
|
|||
|
||||
void ReadUnlock()
|
||||
{
|
||||
NS_ASSERTION(mFrontLock != nullptr, "ReadUnlock with no gfxSharedReadLock");
|
||||
mFrontLock->ReadUnlock();
|
||||
MOZ_ASSERT(mFrontLock, "ReadLock with no gfxSharedReadLock");
|
||||
if (mFrontLock) {
|
||||
mFrontLock->ReadUnlock();
|
||||
}
|
||||
}
|
||||
|
||||
void ReadLock()
|
||||
{
|
||||
NS_ASSERTION(mFrontLock != nullptr, "ReadLock with no gfxSharedReadLock");
|
||||
mFrontLock->ReadLock();
|
||||
MOZ_ASSERT(mFrontLock, "ReadLock with no gfxSharedReadLock");
|
||||
if (mFrontLock) {
|
||||
mFrontLock->ReadLock();
|
||||
}
|
||||
}
|
||||
|
||||
void Release()
|
||||
|
|
|
@ -904,7 +904,7 @@ nsEventStatus AsyncPanZoomController::OnScaleEnd(const PinchGestureInput& aEvent
|
|||
}
|
||||
|
||||
bool
|
||||
AsyncPanZoomController::ConvertToGecko(const ScreenPoint& aPoint, CSSIntPoint* aOut)
|
||||
AsyncPanZoomController::ConvertToGecko(const ScreenPoint& aPoint, CSSPoint* aOut)
|
||||
{
|
||||
APZCTreeManager* treeManagerLocal = mTreeManager;
|
||||
if (treeManagerLocal) {
|
||||
|
@ -917,8 +917,7 @@ AsyncPanZoomController::ConvertToGecko(const ScreenPoint& aPoint, CSSIntPoint* a
|
|||
LayoutDevicePoint layoutPoint = LayoutDevicePoint(result.x, result.y);
|
||||
{ // scoped lock to access mFrameMetrics
|
||||
ReentrantMonitorAutoEnter lock(mMonitor);
|
||||
CSSPoint cssPoint = layoutPoint / mFrameMetrics.mDevPixelsPerCSSPixel;
|
||||
*aOut = gfx::RoundedToInt(cssPoint);
|
||||
*aOut = layoutPoint / mFrameMetrics.mDevPixelsPerCSSPixel;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -930,7 +929,7 @@ nsEventStatus AsyncPanZoomController::OnLongPress(const TapGestureInput& aEvent)
|
|||
nsRefPtr<GeckoContentController> controller = GetGeckoContentController();
|
||||
if (controller) {
|
||||
int32_t modifiers = WidgetModifiersToDOMModifiers(aEvent.modifiers);
|
||||
CSSIntPoint geckoScreenPoint;
|
||||
CSSPoint geckoScreenPoint;
|
||||
if (ConvertToGecko(aEvent.mPoint, &geckoScreenPoint)) {
|
||||
SetState(WAITING_CONTENT_RESPONSE);
|
||||
SetContentResponseTimer();
|
||||
|
@ -946,7 +945,7 @@ nsEventStatus AsyncPanZoomController::OnLongPressUp(const TapGestureInput& aEven
|
|||
nsRefPtr<GeckoContentController> controller = GetGeckoContentController();
|
||||
if (controller) {
|
||||
int32_t modifiers = WidgetModifiersToDOMModifiers(aEvent.modifiers);
|
||||
CSSIntPoint geckoScreenPoint;
|
||||
CSSPoint geckoScreenPoint;
|
||||
if (ConvertToGecko(aEvent.mPoint, &geckoScreenPoint)) {
|
||||
controller->HandleLongTapUp(geckoScreenPoint, modifiers, GetGuid());
|
||||
return nsEventStatus_eConsumeNoDefault;
|
||||
|
@ -962,7 +961,7 @@ nsEventStatus AsyncPanZoomController::OnSingleTapUp(const TapGestureInput& aEven
|
|||
// sending event to content
|
||||
if (controller && !mZoomConstraints.mAllowDoubleTapZoom) {
|
||||
int32_t modifiers = WidgetModifiersToDOMModifiers(aEvent.modifiers);
|
||||
CSSIntPoint geckoScreenPoint;
|
||||
CSSPoint geckoScreenPoint;
|
||||
if (ConvertToGecko(aEvent.mPoint, &geckoScreenPoint)) {
|
||||
// Because this may be being running as part of APZCTreeManager::ReceiveInputEvent,
|
||||
// calling controller->HandleSingleTap directly might mean that content receives
|
||||
|
@ -984,7 +983,7 @@ nsEventStatus AsyncPanZoomController::OnSingleTapConfirmed(const TapGestureInput
|
|||
nsRefPtr<GeckoContentController> controller = GetGeckoContentController();
|
||||
if (controller) {
|
||||
int32_t modifiers = WidgetModifiersToDOMModifiers(aEvent.modifiers);
|
||||
CSSIntPoint geckoScreenPoint;
|
||||
CSSPoint geckoScreenPoint;
|
||||
if (ConvertToGecko(aEvent.mPoint, &geckoScreenPoint)) {
|
||||
// See comment in OnSingleTapUp as to why we do this in PostDelayedTask.
|
||||
controller->PostDelayedTask(
|
||||
|
@ -1003,7 +1002,7 @@ nsEventStatus AsyncPanZoomController::OnDoubleTap(const TapGestureInput& aEvent)
|
|||
if (controller) {
|
||||
if (mZoomConstraints.mAllowDoubleTapZoom) {
|
||||
int32_t modifiers = WidgetModifiersToDOMModifiers(aEvent.modifiers);
|
||||
CSSIntPoint geckoScreenPoint;
|
||||
CSSPoint geckoScreenPoint;
|
||||
if (ConvertToGecko(aEvent.mPoint, &geckoScreenPoint)) {
|
||||
controller->HandleDoubleTap(geckoScreenPoint, modifiers, GetGuid());
|
||||
}
|
||||
|
@ -1685,7 +1684,8 @@ gfx3DMatrix AsyncPanZoomController::GetNontransientAsyncTransform() {
|
|||
|
||||
gfx3DMatrix AsyncPanZoomController::GetTransformToLastDispatchedPaint() {
|
||||
ReentrantMonitorAutoEnter lock(mMonitor);
|
||||
CSSPoint scrollChange = mLastContentPaintMetrics.mScrollOffset - mLastDispatchedPaintMetrics.mScrollOffset;
|
||||
LayerPoint scrollChange = (mLastContentPaintMetrics.mScrollOffset - mLastDispatchedPaintMetrics.mScrollOffset)
|
||||
* mLastContentPaintMetrics.LayersPixelsPerCSSPixel();
|
||||
float zoomChange = mLastContentPaintMetrics.mZoom.scale / mLastDispatchedPaintMetrics.mZoom.scale;
|
||||
return gfx3DMatrix::Translation(scrollChange.x, scrollChange.y, 0) *
|
||||
gfx3DMatrix::ScalingMatrix(zoomChange, zoomChange, 1);
|
||||
|
|
|
@ -601,12 +601,12 @@ private:
|
|||
void SetState(PanZoomState aState);
|
||||
|
||||
/**
|
||||
* Convert ScreenPoint relative to this APZC to CSSIntPoint relative
|
||||
* Convert ScreenPoint relative to this APZC to CSSPoint relative
|
||||
* to the parent document. This excludes the transient compositor transform.
|
||||
* NOTE: This must be converted to CSSIntPoint relative to the child
|
||||
* NOTE: This must be converted to CSSPoint relative to the child
|
||||
* document before sending over IPC.
|
||||
*/
|
||||
bool ConvertToGecko(const ScreenPoint& aPoint, CSSIntPoint* aOut);
|
||||
bool ConvertToGecko(const ScreenPoint& aPoint, CSSPoint* aOut);
|
||||
|
||||
/**
|
||||
* Internal helpers for checking general state of this apzc.
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
#define mozilla_layers_GeckoContentController_h
|
||||
|
||||
#include "FrameMetrics.h" // for FrameMetrics, etc
|
||||
#include "Units.h" // for CSSIntPoint, CSSRect, etc
|
||||
#include "Units.h" // for CSSPoint, CSSRect, etc
|
||||
#include "mozilla/Assertions.h" // for MOZ_ASSERT_HELPER2
|
||||
#include "nsISupportsImpl.h"
|
||||
|
||||
|
@ -42,7 +42,7 @@ public:
|
|||
* AsyncPanZoomController::ZoomToRect with the dimensions that we want to zoom
|
||||
* to.
|
||||
*/
|
||||
virtual void HandleDoubleTap(const CSSIntPoint& aPoint,
|
||||
virtual void HandleDoubleTap(const CSSPoint& aPoint,
|
||||
int32_t aModifiers,
|
||||
const ScrollableLayerGuid& aGuid) = 0;
|
||||
|
||||
|
@ -51,7 +51,7 @@ public:
|
|||
* current scroll offset. This should simulate and send to content a mouse
|
||||
* button down, then mouse button up at |aPoint|.
|
||||
*/
|
||||
virtual void HandleSingleTap(const CSSIntPoint& aPoint,
|
||||
virtual void HandleSingleTap(const CSSPoint& aPoint,
|
||||
int32_t aModifiers,
|
||||
const ScrollableLayerGuid& aGuid) = 0;
|
||||
|
||||
|
@ -59,7 +59,7 @@ public:
|
|||
* Requests handling a long tap. |aPoint| is in CSS pixels, relative to the
|
||||
* current scroll offset.
|
||||
*/
|
||||
virtual void HandleLongTap(const CSSIntPoint& aPoint,
|
||||
virtual void HandleLongTap(const CSSPoint& aPoint,
|
||||
int32_t aModifiers,
|
||||
const ScrollableLayerGuid& aGuid) = 0;
|
||||
|
||||
|
@ -68,7 +68,7 @@ public:
|
|||
* relative to the current scroll offset. HandleLongTapUp will always be
|
||||
* preceeded by HandleLongTap
|
||||
*/
|
||||
virtual void HandleLongTapUp(const CSSIntPoint& aPoint,
|
||||
virtual void HandleLongTapUp(const CSSPoint& aPoint,
|
||||
int32_t aModifiers,
|
||||
const ScrollableLayerGuid& aGuid) = 0;
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
#include "AsyncPanZoomController.h" // for AsyncPanZoomController
|
||||
#include "mozilla/layers/APZCTreeManager.h" // for APZCTreeManager
|
||||
#include "base/task.h" // for CancelableTask, etc
|
||||
#include "mozilla/Preferences.h" // for Preferences
|
||||
#include "gfxPrefs.h" // for gfxPrefs
|
||||
#include "mozilla/gfx/BasePoint.h" // for BasePoint
|
||||
#include "mozilla/mozalloc.h" // for operator new
|
||||
#include "nsDebug.h" // for NS_WARN_IF_FALSE
|
||||
|
@ -85,7 +85,7 @@ nsEventStatus GestureEventListener::HandleInputEvent(const MultiTouchInput& aEve
|
|||
|
||||
mAsyncPanZoomController->PostDelayedTask(
|
||||
mLongTapTimeoutTask,
|
||||
Preferences::GetInt("ui.click_hold_context_menus.delay", 500));
|
||||
gfxPrefs::UiClickHoldContextMenusDelay());
|
||||
}
|
||||
} else if (length == 2) {
|
||||
// Another finger has been added; it can't be a tap anymore.
|
||||
|
|
|
@ -137,72 +137,6 @@ DrawQuads(GLContext *aGLContext,
|
|||
aGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
|
||||
}
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
CompositorOGLGonkBackendSpecificData::CompositorOGLGonkBackendSpecificData(CompositorOGL* aCompositor)
|
||||
: mCompositor(aCompositor)
|
||||
{
|
||||
}
|
||||
|
||||
CompositorOGLGonkBackendSpecificData::~CompositorOGLGonkBackendSpecificData()
|
||||
{
|
||||
// Delete all textures by calling EndFrame twice
|
||||
gl()->MakeCurrent();
|
||||
EndFrame();
|
||||
EndFrame();
|
||||
}
|
||||
|
||||
GLContext*
|
||||
CompositorOGLGonkBackendSpecificData::gl() const
|
||||
{
|
||||
return mCompositor->gl();
|
||||
}
|
||||
|
||||
GLuint
|
||||
CompositorOGLGonkBackendSpecificData::GetTexture()
|
||||
{
|
||||
GLuint texture = 0;
|
||||
|
||||
if (!mUnusedTextures.IsEmpty()) {
|
||||
// Try to reuse one from the unused pile first
|
||||
texture = mUnusedTextures[0];
|
||||
mUnusedTextures.RemoveElementAt(0);
|
||||
} else if (gl()->MakeCurrent()) {
|
||||
// There isn't one to reuse, create one.
|
||||
gl()->fGenTextures(1, &texture);
|
||||
}
|
||||
|
||||
if (texture) {
|
||||
mCreatedTextures.AppendElement(texture);
|
||||
}
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
void
|
||||
CompositorOGLGonkBackendSpecificData::EndFrame()
|
||||
{
|
||||
gl()->MakeCurrent();
|
||||
|
||||
// Some platforms have issues unlocking Gralloc buffers even when they're
|
||||
// rebound.
|
||||
if (gfxPrefs::OverzealousGrallocUnlocking()) {
|
||||
mUnusedTextures.AppendElements(mCreatedTextures);
|
||||
mCreatedTextures.Clear();
|
||||
}
|
||||
|
||||
// Delete unused textures
|
||||
for (size_t i = 0; i < mUnusedTextures.Length(); i++) {
|
||||
GLuint texture = mUnusedTextures[i];
|
||||
gl()->fDeleteTextures(1, &texture);
|
||||
}
|
||||
mUnusedTextures.Clear();
|
||||
|
||||
// Move all created textures into the unused pile
|
||||
mUnusedTextures.AppendElements(mCreatedTextures);
|
||||
mCreatedTextures.Clear();
|
||||
}
|
||||
#endif
|
||||
|
||||
CompositorOGL::CompositorOGL(nsIWidget *aWidget, int aSurfaceWidth,
|
||||
int aSurfaceHeight, bool aUseExternalSurfaceSize)
|
||||
: mWidget(aWidget)
|
||||
|
@ -246,38 +180,18 @@ CompositorOGL::CreateContext()
|
|||
return context.forget();
|
||||
}
|
||||
|
||||
GLuint
|
||||
CompositorOGL::GetTemporaryTexture(GLenum aTextureUnit)
|
||||
{
|
||||
size_t index = aTextureUnit - LOCAL_GL_TEXTURE0;
|
||||
// lazily grow the array of temporary textures
|
||||
if (mTextures.Length() <= index) {
|
||||
size_t prevLength = mTextures.Length();
|
||||
mTextures.SetLength(index + 1);
|
||||
for(unsigned int i = prevLength; i <= index; ++i) {
|
||||
mTextures[i] = 0;
|
||||
}
|
||||
}
|
||||
// lazily initialize the temporary textures
|
||||
if (!mTextures[index]) {
|
||||
if (!gl()->MakeCurrent()) {
|
||||
return 0;
|
||||
}
|
||||
gl()->fGenTextures(1, &mTextures[index]);
|
||||
}
|
||||
return mTextures[index];
|
||||
}
|
||||
|
||||
void
|
||||
CompositorOGL::Destroy()
|
||||
{
|
||||
if (gl() && gl()->MakeCurrent()) {
|
||||
if (mTextures.Length() > 0) {
|
||||
gl()->fDeleteTextures(mTextures.Length(), &mTextures[0]);
|
||||
}
|
||||
mVBOs.Flush(gl());
|
||||
}
|
||||
mTextures.SetLength(0);
|
||||
|
||||
if (mTexturePool) {
|
||||
mTexturePool->Clear();
|
||||
mTexturePool = nullptr;
|
||||
}
|
||||
|
||||
if (!mDestroyed) {
|
||||
mDestroyed = true;
|
||||
CleanupResources();
|
||||
|
@ -1366,11 +1280,9 @@ CompositorOGL::EndFrame()
|
|||
|
||||
mCurrentRenderTarget = nullptr;
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
if (mCompositorBackendSpecificData) {
|
||||
static_cast<CompositorOGLGonkBackendSpecificData*>(mCompositorBackendSpecificData.get())->EndFrame();
|
||||
if (mTexturePool) {
|
||||
mTexturePool->EndFrame();
|
||||
}
|
||||
#endif
|
||||
|
||||
mGLContext->SwapBuffers();
|
||||
mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
|
||||
|
@ -1480,17 +1392,6 @@ CompositorOGL::Resume()
|
|||
return true;
|
||||
}
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
CompositorBackendSpecificData*
|
||||
CompositorOGL::GetCompositorBackendSpecificData()
|
||||
{
|
||||
if (!mCompositorBackendSpecificData) {
|
||||
mCompositorBackendSpecificData = new CompositorOGLGonkBackendSpecificData(this);
|
||||
}
|
||||
return mCompositorBackendSpecificData;
|
||||
}
|
||||
#endif
|
||||
|
||||
TemporaryRef<DataTextureSource>
|
||||
CompositorOGL::CreateDataTextureSource(TextureFlags aFlags)
|
||||
{
|
||||
|
@ -1593,5 +1494,120 @@ CompositorOGL::BindAndDrawQuad(ShaderProgramOGL *aProg,
|
|||
aFlipped, aDrawMode);
|
||||
}
|
||||
|
||||
GLuint
|
||||
CompositorOGL::GetTemporaryTexture(GLenum aUnit)
|
||||
{
|
||||
if (!mTexturePool) {
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
mTexturePool = new PerFrameTexturePoolOGL(gl());
|
||||
#else
|
||||
mTexturePool = new PerUnitTexturePoolOGL(gl());
|
||||
#endif
|
||||
}
|
||||
return mTexturePool->GetTexture(aUnit);
|
||||
}
|
||||
|
||||
GLuint
|
||||
PerUnitTexturePoolOGL::GetTexture(GLenum aTextureUnit)
|
||||
{
|
||||
size_t index = aTextureUnit - LOCAL_GL_TEXTURE0;
|
||||
// lazily grow the array of temporary textures
|
||||
if (mTextures.Length() <= index) {
|
||||
size_t prevLength = mTextures.Length();
|
||||
mTextures.SetLength(index + 1);
|
||||
for(unsigned int i = prevLength; i <= index; ++i) {
|
||||
mTextures[i] = 0;
|
||||
}
|
||||
}
|
||||
// lazily initialize the temporary textures
|
||||
if (!mTextures[index]) {
|
||||
if (!mGL->MakeCurrent()) {
|
||||
return 0;
|
||||
}
|
||||
mGL->fGenTextures(1, &mTextures[index]);
|
||||
}
|
||||
return mTextures[index];
|
||||
}
|
||||
|
||||
void
|
||||
PerUnitTexturePoolOGL::DestroyTextures()
|
||||
{
|
||||
if (mGL && mGL->MakeCurrent()) {
|
||||
if (mTextures.Length() > 0) {
|
||||
mGL->fDeleteTextures(mTextures.Length(), &mTextures[0]);
|
||||
}
|
||||
}
|
||||
mTextures.SetLength(0);
|
||||
}
|
||||
|
||||
void
|
||||
PerFrameTexturePoolOGL::DestroyTextures()
|
||||
{
|
||||
if (!mGL->MakeCurrent()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mUnusedTextures.Length() > 0) {
|
||||
mGL->fDeleteTextures(mUnusedTextures.Length(), &mUnusedTextures[0]);
|
||||
mUnusedTextures.Clear();
|
||||
}
|
||||
|
||||
if (mCreatedTextures.Length() > 0) {
|
||||
mGL->fDeleteTextures(mCreatedTextures.Length(), &mCreatedTextures[0]);
|
||||
mCreatedTextures.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
GLuint
|
||||
PerFrameTexturePoolOGL::GetTexture(GLenum)
|
||||
{
|
||||
GLuint texture = 0;
|
||||
|
||||
if (!mUnusedTextures.IsEmpty()) {
|
||||
// Try to reuse one from the unused pile first
|
||||
texture = mUnusedTextures[0];
|
||||
mUnusedTextures.RemoveElementAt(0);
|
||||
} else if (mGL->MakeCurrent()) {
|
||||
// There isn't one to reuse, create one.
|
||||
mGL->fGenTextures(1, &texture);
|
||||
}
|
||||
|
||||
if (texture) {
|
||||
mCreatedTextures.AppendElement(texture);
|
||||
}
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
void
|
||||
PerFrameTexturePoolOGL::EndFrame()
|
||||
{
|
||||
if (!mGL->MakeCurrent()) {
|
||||
// this means the context got destroyed underneith us somehow, and the driver
|
||||
// already has destroyed the textures.
|
||||
mCreatedTextures.Clear();
|
||||
mUnusedTextures.Clear();
|
||||
return;
|
||||
}
|
||||
|
||||
// Some platforms have issues unlocking Gralloc buffers even when they're
|
||||
// rebound.
|
||||
if (gfxPrefs::OverzealousGrallocUnlocking()) {
|
||||
mUnusedTextures.AppendElements(mCreatedTextures);
|
||||
mCreatedTextures.Clear();
|
||||
}
|
||||
|
||||
// Delete unused textures
|
||||
for (size_t i = 0; i < mUnusedTextures.Length(); i++) {
|
||||
GLuint texture = mUnusedTextures[i];
|
||||
mGL->fDeleteTextures(1, &texture);
|
||||
}
|
||||
mUnusedTextures.Clear();
|
||||
|
||||
// Move all created textures into the unused pile
|
||||
mUnusedTextures.AppendElements(mCreatedTextures);
|
||||
mCreatedTextures.Clear();
|
||||
}
|
||||
|
||||
} /* layers */
|
||||
} /* mozilla */
|
||||
|
|
|
@ -55,6 +55,99 @@ class TextureSource;
|
|||
struct Effect;
|
||||
struct EffectChain;
|
||||
|
||||
/**
|
||||
* Interface for pools of temporary gl textures for the compositor.
|
||||
* The textures are fully owned by the pool, so the latter is responsible
|
||||
* calling fDeleteTextures accordingly.
|
||||
* Users of GetTexture receive a texture that is only valid for the duration
|
||||
* of the current frame.
|
||||
* This is primarily intended for direct texturing APIs that need to attach
|
||||
* shared objects (such as an EGLImage) to a gl texture.
|
||||
*/
|
||||
class CompositorTexturePoolOGL : public RefCounted<CompositorTexturePoolOGL>
|
||||
{
|
||||
public:
|
||||
MOZ_DECLARE_REFCOUNTED_TYPENAME(CompositorTexturePoolOGL)
|
||||
|
||||
virtual ~CompositorTexturePoolOGL() {}
|
||||
|
||||
virtual void Clear() = 0;
|
||||
|
||||
virtual GLuint GetTexture(GLenum aUnit) = 0;
|
||||
|
||||
virtual void EndFrame() = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Agressively reuses textures. One gl texture per texture unit in total.
|
||||
* So far this hasn't shown the best results on b2g.
|
||||
*/
|
||||
class PerUnitTexturePoolOGL : public CompositorTexturePoolOGL
|
||||
{
|
||||
public:
|
||||
PerUnitTexturePoolOGL(gl::GLContext* aGL)
|
||||
: mGL(aGL)
|
||||
{}
|
||||
|
||||
virtual ~PerUnitTexturePoolOGL()
|
||||
{
|
||||
DestroyTextures();
|
||||
}
|
||||
|
||||
virtual void Clear() MOZ_OVERRIDE
|
||||
{
|
||||
DestroyTextures();
|
||||
}
|
||||
|
||||
virtual GLuint GetTexture(GLenum aUnit) MOZ_OVERRIDE;
|
||||
|
||||
virtual void EndFrame() MOZ_OVERRIDE {}
|
||||
|
||||
protected:
|
||||
void DestroyTextures();
|
||||
|
||||
nsTArray<GLuint> mTextures;
|
||||
RefPtr<gl::GLContext> mGL;
|
||||
};
|
||||
|
||||
/**
|
||||
* Reuse gl textures from a pool of textures that haven't yet been
|
||||
* used during the current frame.
|
||||
* All the textures that are not used at the end of a frame are
|
||||
* deleted.
|
||||
* This strategy seems to work well with gralloc textures because destroying
|
||||
* unused textures which are bound to gralloc buffers let drivers know that it
|
||||
* can unlock the gralloc buffers.
|
||||
*/
|
||||
class PerFrameTexturePoolOGL : public CompositorTexturePoolOGL
|
||||
{
|
||||
public:
|
||||
PerFrameTexturePoolOGL(gl::GLContext* aGL)
|
||||
: mGL(aGL)
|
||||
{}
|
||||
|
||||
virtual ~PerFrameTexturePoolOGL()
|
||||
{
|
||||
DestroyTextures();
|
||||
}
|
||||
|
||||
virtual void Clear() MOZ_OVERRIDE
|
||||
{
|
||||
DestroyTextures();
|
||||
}
|
||||
|
||||
virtual GLuint GetTexture(GLenum aUnit) MOZ_OVERRIDE;
|
||||
|
||||
virtual void EndFrame() MOZ_OVERRIDE;
|
||||
|
||||
protected:
|
||||
void DestroyTextures();
|
||||
|
||||
RefPtr<gl::GLContext> mGL;
|
||||
nsTArray<GLuint> mCreatedTextures;
|
||||
nsTArray<GLuint> mUnusedTextures;
|
||||
};
|
||||
|
||||
class CompositorOGL : public Compositor
|
||||
{
|
||||
typedef mozilla::gl::GLContext GLContext;
|
||||
|
@ -162,10 +255,6 @@ public:
|
|||
|
||||
virtual nsIWidget* GetWidget() const MOZ_OVERRIDE { return mWidget; }
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
virtual CompositorBackendSpecificData* GetCompositorBackendSpecificData() MOZ_OVERRIDE;
|
||||
#endif
|
||||
|
||||
GLContext* gl() const { return mGLContext; }
|
||||
gfx::SurfaceFormat GetFBOFormat() const {
|
||||
return gfx::SurfaceFormat::R8G8B8A8;
|
||||
|
@ -309,43 +398,17 @@ private:
|
|||
*/
|
||||
GLint FlipY(GLint y) const { return mHeight - y; }
|
||||
|
||||
bool mDestroyed;
|
||||
RefPtr<CompositorTexturePoolOGL> mTexturePool;
|
||||
|
||||
// Textures used for direct texturing of buffers like gralloc.
|
||||
// The index of the texture in this array must correspond to the texture unit.
|
||||
nsTArray<GLuint> mTextures;
|
||||
bool mDestroyed;
|
||||
|
||||
/**
|
||||
* Height of the OpenGL context's primary framebuffer in pixels. Used by
|
||||
* FlipY for the y-flipping calculation.
|
||||
*/
|
||||
GLint mHeight;
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
RefPtr<CompositorBackendSpecificData> mCompositorBackendSpecificData;
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
class CompositorOGLGonkBackendSpecificData : public CompositorBackendSpecificData
|
||||
{
|
||||
public:
|
||||
CompositorOGLGonkBackendSpecificData(CompositorOGL* aCompositor);
|
||||
virtual ~CompositorOGLGonkBackendSpecificData();
|
||||
|
||||
GLuint GetTexture();
|
||||
void EndFrame();
|
||||
|
||||
private:
|
||||
gl::GLContext* gl() const;
|
||||
|
||||
RefPtr<CompositorOGL> mCompositor;
|
||||
|
||||
nsTArray<GLuint> mCreatedTextures;
|
||||
nsTArray<GLuint> mUnusedTextures;
|
||||
};
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -93,7 +93,6 @@ GrallocTextureSourceOGL::GrallocTextureSourceOGL(CompositorOGL* aCompositor,
|
|||
, mGraphicBuffer(aGraphicBuffer)
|
||||
, mEGLImage(0)
|
||||
, mFormat(aFormat)
|
||||
, mNeedsReset(true)
|
||||
{
|
||||
MOZ_ASSERT(mGraphicBuffer.get());
|
||||
}
|
||||
|
@ -107,14 +106,6 @@ GrallocTextureSourceOGL::~GrallocTextureSourceOGL()
|
|||
void
|
||||
GrallocTextureSourceOGL::BindTexture(GLenum aTextureUnit)
|
||||
{
|
||||
/*
|
||||
* The job of this function is to ensure that the texture is tied to the
|
||||
* android::GraphicBuffer, so that texturing will source the GraphicBuffer.
|
||||
*
|
||||
* To this effect we create an EGLImage wrapping this GraphicBuffer,
|
||||
* using EGLImageCreateFromNativeBuffer, and then we tie this EGLImage to our
|
||||
* texture using fEGLImageTargetTexture2D.
|
||||
*/
|
||||
MOZ_ASSERT(gl());
|
||||
if (!IsValid()) {
|
||||
return;
|
||||
|
@ -127,29 +118,22 @@ GrallocTextureSourceOGL::BindTexture(GLenum aTextureUnit)
|
|||
gl()->fActiveTexture(aTextureUnit);
|
||||
gl()->fBindTexture(textureTarget, tex);
|
||||
|
||||
if (mCompositableBackendData) {
|
||||
// There are two paths for locking/unlocking - if mCompositableBackendData is
|
||||
// set, we use the texture on there, otherwise we use
|
||||
// CompositorBackendSpecificData from the compositor and bind the EGLImage
|
||||
// only in Lock().
|
||||
if (!mEGLImage) {
|
||||
mEGLImage = EGLImageCreateFromNativeBuffer(gl(), mGraphicBuffer->getNativeBuffer());
|
||||
}
|
||||
gl()->fEGLImageTargetTexture2D(textureTarget, mEGLImage);
|
||||
}
|
||||
|
||||
gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
|
||||
}
|
||||
|
||||
void GrallocTextureSourceOGL::Lock()
|
||||
{
|
||||
if (mCompositableBackendData) return;
|
||||
|
||||
/*
|
||||
* The job of this function is to ensure that the texture is tied to the
|
||||
* android::GraphicBuffer, so that texturing will source the GraphicBuffer.
|
||||
*
|
||||
* To this effect we create an EGLImage wrapping this GraphicBuffer,
|
||||
* using EGLImageCreateFromNativeBuffer, and then we tie this EGLImage to our
|
||||
* texture using fEGLImageTargetTexture2D.
|
||||
*/
|
||||
MOZ_ASSERT(IsValid());
|
||||
|
||||
CompositorOGLGonkBackendSpecificData* backendData =
|
||||
static_cast<CompositorOGLGonkBackendSpecificData*>(mCompositor->GetCompositorBackendSpecificData());
|
||||
mTexture = backendData->GetTexture();
|
||||
mTexture = mCompositor->GetTemporaryTexture(LOCAL_GL_TEXTURE0);
|
||||
|
||||
GLuint textureTarget = GetTextureTarget();
|
||||
|
||||
|
@ -165,7 +149,7 @@ void GrallocTextureSourceOGL::Lock()
|
|||
bool
|
||||
GrallocTextureSourceOGL::IsValid() const
|
||||
{
|
||||
return !!gl() && !!mGraphicBuffer.get() && (!!mCompositor || !!mCompositableBackendData);
|
||||
return !!gl() && !!mGraphicBuffer.get();
|
||||
}
|
||||
|
||||
gl::GLContext*
|
||||
|
@ -205,51 +189,6 @@ GrallocTextureSourceOGL::GetFormat() const {
|
|||
return mFormat;
|
||||
}
|
||||
|
||||
void
|
||||
GrallocTextureSourceOGL::SetCompositableBackendSpecificData(CompositableBackendSpecificData* aBackendData)
|
||||
{
|
||||
if (!aBackendData) {
|
||||
mCompositableBackendData = nullptr;
|
||||
DeallocateDeviceData();
|
||||
return;
|
||||
}
|
||||
|
||||
if (mCompositableBackendData != aBackendData) {
|
||||
mNeedsReset = true;
|
||||
}
|
||||
|
||||
if (!mNeedsReset) {
|
||||
// Update binding to the EGLImage
|
||||
gl()->MakeCurrent();
|
||||
GLuint tex = GetGLTexture();
|
||||
GLuint textureTarget = GetTextureTarget();
|
||||
gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
|
||||
gl()->fBindTexture(textureTarget, tex);
|
||||
gl()->fEGLImageTargetTexture2D(textureTarget, mEGLImage);
|
||||
return;
|
||||
}
|
||||
|
||||
mCompositableBackendData = aBackendData;
|
||||
|
||||
if (!mCompositor) {
|
||||
return;
|
||||
}
|
||||
|
||||
// delete old EGLImage
|
||||
DeallocateDeviceData();
|
||||
|
||||
gl()->MakeCurrent();
|
||||
GLuint tex = GetGLTexture();
|
||||
GLuint textureTarget = GetTextureTarget();
|
||||
|
||||
gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
|
||||
gl()->fBindTexture(textureTarget, tex);
|
||||
// create new EGLImage
|
||||
mEGLImage = EGLImageCreateFromNativeBuffer(gl(), mGraphicBuffer->getNativeBuffer());
|
||||
gl()->fEGLImageTargetTexture2D(textureTarget, mEGLImage);
|
||||
mNeedsReset = false;
|
||||
}
|
||||
|
||||
gfx::IntSize
|
||||
GrallocTextureSourceOGL::GetSize() const
|
||||
{
|
||||
|
@ -418,11 +357,6 @@ GrallocTextureSourceOGL::GetAsSurface() {
|
|||
GLuint
|
||||
GrallocTextureSourceOGL::GetGLTexture()
|
||||
{
|
||||
if (mCompositableBackendData) {
|
||||
mCompositableBackendData->SetCompositor(mCompositor);
|
||||
return static_cast<CompositableDataGonkOGL*>(mCompositableBackendData.get())->GetTexture();
|
||||
}
|
||||
|
||||
return mTexture;
|
||||
}
|
||||
|
||||
|
|
|
@ -45,8 +45,6 @@ public:
|
|||
return LOCAL_GL_CLAMP_TO_EDGE;
|
||||
}
|
||||
|
||||
virtual void SetCompositableBackendSpecificData(CompositableBackendSpecificData* aBackendData) MOZ_OVERRIDE;
|
||||
|
||||
void DeallocateDeviceData();
|
||||
|
||||
gl::GLContext* gl() const;
|
||||
|
@ -70,7 +68,6 @@ protected:
|
|||
EGLImage mEGLImage;
|
||||
GLuint mTexture;
|
||||
gfx::SurfaceFormat mFormat;
|
||||
bool mNeedsReset;
|
||||
};
|
||||
|
||||
class GrallocTextureHostOGL : public TextureHost
|
||||
|
|
|
@ -155,12 +155,10 @@ WrapMode(gl::GLContext *aGl, bool aAllowRepeat)
|
|||
}
|
||||
|
||||
CompositableDataGonkOGL::CompositableDataGonkOGL()
|
||||
: mTexture(0)
|
||||
{
|
||||
}
|
||||
CompositableDataGonkOGL::~CompositableDataGonkOGL()
|
||||
{
|
||||
DeleteTextureIfPresent();
|
||||
}
|
||||
|
||||
gl::GLContext*
|
||||
|
@ -177,28 +175,6 @@ void CompositableDataGonkOGL::SetCompositor(Compositor* aCompositor)
|
|||
void CompositableDataGonkOGL::ClearData()
|
||||
{
|
||||
CompositableBackendSpecificData::ClearData();
|
||||
DeleteTextureIfPresent();
|
||||
}
|
||||
|
||||
GLuint CompositableDataGonkOGL::GetTexture()
|
||||
{
|
||||
if (!mTexture) {
|
||||
if (gl()->MakeCurrent()) {
|
||||
gl()->fGenTextures(1, &mTexture);
|
||||
}
|
||||
}
|
||||
return mTexture;
|
||||
}
|
||||
|
||||
void
|
||||
CompositableDataGonkOGL::DeleteTextureIfPresent()
|
||||
{
|
||||
if (mTexture) {
|
||||
if (gl()->MakeCurrent()) {
|
||||
gl()->fDeleteTextures(1, &mTexture);
|
||||
}
|
||||
mTexture = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#if MOZ_WIDGET_GONK && ANDROID_VERSION >= 17
|
||||
|
@ -731,19 +707,6 @@ TextureImageDeprecatedTextureHostOGL::UpdateImpl(const SurfaceDescriptor& aImage
|
|||
return;
|
||||
}
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
if (mCompositableBackendData) {
|
||||
// on gonk, this class is used as a fallback from gralloc buffer.
|
||||
// There is a case this class is used with GrallocDeprecatedTextureHostOGL
|
||||
// under same CompositableHost. if it happens, a gralloc buffer of
|
||||
// GrallocDeprecatedTextureHostOGL needs to be unbounded from a texture,
|
||||
// when the gralloc buffer is not rendered.
|
||||
// Establish the unbound by deleting the texture.
|
||||
// See Bug 916264.
|
||||
static_cast<CompositableDataGonkOGL*>(mCompositableBackendData.get())->DeleteTextureIfPresent();
|
||||
}
|
||||
#endif
|
||||
|
||||
AutoOpenSurface surf(OPEN_READ_ONLY, aImage);
|
||||
gfx::IntSize size = surf.Size();
|
||||
TextureImage::ImageFormat format = surf.ImageFormat();
|
||||
|
@ -1196,7 +1159,7 @@ GLuint
|
|||
GrallocDeprecatedTextureHostOGL::GetGLTexture()
|
||||
{
|
||||
mCompositableBackendData->SetCompositor(mCompositor);
|
||||
return static_cast<CompositableDataGonkOGL*>(mCompositableBackendData.get())->GetTexture();
|
||||
return mCompositor->GetTemporaryTexture(LOCAL_GL_TEXTURE0);
|
||||
}
|
||||
|
||||
#endif // MOZ_WIDGET_GONK
|
||||
|
|
|
@ -72,12 +72,9 @@ public:
|
|||
|
||||
virtual void SetCompositor(Compositor* aCompositor) MOZ_OVERRIDE;
|
||||
virtual void ClearData() MOZ_OVERRIDE;
|
||||
GLuint GetTexture();
|
||||
void DeleteTextureIfPresent();
|
||||
gl::GLContext* gl() const;
|
||||
protected:
|
||||
RefPtr<CompositorOGL> mCompositor;
|
||||
GLuint mTexture;
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
@ -54,10 +54,10 @@ class MockContentController : public GeckoContentController {
|
|||
public:
|
||||
MOCK_METHOD1(RequestContentRepaint, void(const FrameMetrics&));
|
||||
MOCK_METHOD2(AcknowledgeScrollUpdate, void(const FrameMetrics::ViewID&, const uint32_t& aScrollGeneration));
|
||||
MOCK_METHOD3(HandleDoubleTap, void(const CSSIntPoint&, int32_t, const ScrollableLayerGuid&));
|
||||
MOCK_METHOD3(HandleSingleTap, void(const CSSIntPoint&, int32_t, const ScrollableLayerGuid&));
|
||||
MOCK_METHOD3(HandleLongTap, void(const CSSIntPoint&, int32_t, const ScrollableLayerGuid&));
|
||||
MOCK_METHOD3(HandleLongTapUp, void(const CSSIntPoint&, int32_t, const ScrollableLayerGuid&));
|
||||
MOCK_METHOD3(HandleDoubleTap, void(const CSSPoint&, int32_t, const ScrollableLayerGuid&));
|
||||
MOCK_METHOD3(HandleSingleTap, void(const CSSPoint&, int32_t, const ScrollableLayerGuid&));
|
||||
MOCK_METHOD3(HandleLongTap, void(const CSSPoint&, int32_t, const ScrollableLayerGuid&));
|
||||
MOCK_METHOD3(HandleLongTapUp, void(const CSSPoint&, int32_t, const ScrollableLayerGuid&));
|
||||
MOCK_METHOD3(SendAsyncScrollDOMEvent, void(bool aIsRoot, const CSSRect &aContentRect, const CSSSize &aScrollableSize));
|
||||
MOCK_METHOD2(PostDelayedTask, void(Task* aTask, int aDelayMs));
|
||||
};
|
||||
|
@ -686,7 +686,7 @@ TEST_F(AsyncPanZoomControllerTester, OverScrollPanning) {
|
|||
EXPECT_EQ(pointOut, ScreenPoint(0, 90));
|
||||
}
|
||||
|
||||
TEST(AsyncPanZoomController, ShortPress) {
|
||||
TEST_F(AsyncPanZoomControllerTester, ShortPress) {
|
||||
nsRefPtr<MockContentControllerDelayed> mcc = new NiceMock<MockContentControllerDelayed>();
|
||||
nsRefPtr<TestAPZCTreeManager> tm = new TestAPZCTreeManager();
|
||||
nsRefPtr<TestAsyncPanZoomController> apzc = new TestAsyncPanZoomController(
|
||||
|
@ -704,13 +704,13 @@ TEST(AsyncPanZoomController, ShortPress) {
|
|||
// touchdown is fully processed. The ordering here is important.
|
||||
mcc->CheckHasDelayedTask();
|
||||
|
||||
EXPECT_CALL(*mcc, HandleSingleTap(CSSIntPoint(10, 10), 0, apzc->GetGuid())).Times(1);
|
||||
EXPECT_CALL(*mcc, HandleSingleTap(CSSPoint(10, 10), 0, apzc->GetGuid())).Times(1);
|
||||
mcc->RunDelayedTask();
|
||||
|
||||
apzc->Destroy();
|
||||
}
|
||||
|
||||
TEST(AsyncPanZoomController, MediumPress) {
|
||||
TEST_F(AsyncPanZoomControllerTester, MediumPress) {
|
||||
nsRefPtr<MockContentControllerDelayed> mcc = new NiceMock<MockContentControllerDelayed>();
|
||||
nsRefPtr<TestAPZCTreeManager> tm = new TestAPZCTreeManager();
|
||||
nsRefPtr<TestAsyncPanZoomController> apzc = new TestAsyncPanZoomController(
|
||||
|
@ -728,7 +728,7 @@ TEST(AsyncPanZoomController, MediumPress) {
|
|||
// touchdown is fully processed. The ordering here is important.
|
||||
mcc->CheckHasDelayedTask();
|
||||
|
||||
EXPECT_CALL(*mcc, HandleSingleTap(CSSIntPoint(10, 10), 0, apzc->GetGuid())).Times(1);
|
||||
EXPECT_CALL(*mcc, HandleSingleTap(CSSPoint(10, 10), 0, apzc->GetGuid())).Times(1);
|
||||
mcc->RunDelayedTask();
|
||||
|
||||
apzc->Destroy();
|
||||
|
@ -761,11 +761,11 @@ DoLongPressTest(bool aShouldUseTouchAction, uint32_t aBehavior) {
|
|||
InSequence s;
|
||||
|
||||
EXPECT_CALL(check, Call("preHandleLongTap"));
|
||||
EXPECT_CALL(*mcc, HandleLongTap(CSSIntPoint(10, 10), 0, apzc->GetGuid())).Times(1);
|
||||
EXPECT_CALL(*mcc, HandleLongTap(CSSPoint(10, 10), 0, apzc->GetGuid())).Times(1);
|
||||
EXPECT_CALL(check, Call("postHandleLongTap"));
|
||||
|
||||
EXPECT_CALL(check, Call("preHandleLongTapUp"));
|
||||
EXPECT_CALL(*mcc, HandleLongTapUp(CSSIntPoint(10, 10), 0, apzc->GetGuid())).Times(1);
|
||||
EXPECT_CALL(*mcc, HandleLongTapUp(CSSPoint(10, 10), 0, apzc->GetGuid())).Times(1);
|
||||
EXPECT_CALL(check, Call("postHandleLongTapUp"));
|
||||
}
|
||||
|
||||
|
@ -791,7 +791,7 @@ DoLongPressTest(bool aShouldUseTouchAction, uint32_t aBehavior) {
|
|||
apzc->Destroy();
|
||||
}
|
||||
|
||||
TEST(AsyncPanZoomController, LongPressPreventDefault) {
|
||||
TEST_F(AsyncPanZoomControllerTester, LongPressPreventDefault) {
|
||||
// We have to initialize both an integer time and TimeStamp time because
|
||||
// TimeStamp doesn't have any ToXXX() functions for converting back to
|
||||
// primitives.
|
||||
|
@ -824,7 +824,7 @@ TEST(AsyncPanZoomController, LongPressPreventDefault) {
|
|||
InSequence s;
|
||||
|
||||
EXPECT_CALL(check, Call("preHandleLongTap"));
|
||||
EXPECT_CALL(*mcc, HandleLongTap(CSSIntPoint(touchX, touchStartY), 0, apzc->GetGuid())).Times(1);
|
||||
EXPECT_CALL(*mcc, HandleLongTap(CSSPoint(touchX, touchStartY), 0, apzc->GetGuid())).Times(1);
|
||||
EXPECT_CALL(check, Call("postHandleLongTap"));
|
||||
}
|
||||
|
||||
|
@ -866,11 +866,11 @@ TEST(AsyncPanZoomController, LongPressPreventDefault) {
|
|||
apzc->Destroy();
|
||||
}
|
||||
|
||||
TEST(AsyncPanZoomController, LongPress) {
|
||||
TEST_F(AsyncPanZoomControllerTester, LongPress) {
|
||||
DoLongPressTest(false, mozilla::layers::AllowedTouchBehavior::NONE);
|
||||
}
|
||||
|
||||
TEST(AsyncPanZoomController, LongPressPanAndZoom) {
|
||||
TEST_F(AsyncPanZoomControllerTester, LongPressPanAndZoom) {
|
||||
DoLongPressTest(true, mozilla::layers::AllowedTouchBehavior::HORIZONTAL_PAN
|
||||
| mozilla::layers::AllowedTouchBehavior::VERTICAL_PAN
|
||||
| mozilla::layers::AllowedTouchBehavior::ZOOM);
|
||||
|
|
|
@ -178,6 +178,8 @@ private:
|
|||
|
||||
DECL_GFX_PREF(Live, "nglayout.debug.widget_update_flashing", WidgetUpdateFlashing, bool, false);
|
||||
|
||||
DECL_GFX_PREF(Live, "ui.click_hold_context_menus.delay", UiClickHoldContextMenusDelay, int32_t, 500);
|
||||
|
||||
DECL_GFX_PREF(Once, "webgl.force-layers-readback", WebGLForceLayersReadback, bool, false);
|
||||
|
||||
public:
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
|
||||
function testReduce() {
|
||||
function sum(a, b) {
|
||||
var r = a + b;
|
||||
}
|
||||
var array = build(8 * 0X0aaec , function() { return 1; });
|
||||
var parResult = array.reducePar(sum);
|
||||
}
|
||||
for (var ix = 0; ix < 3; ++ix) {
|
||||
testReduce();
|
||||
}
|
||||
function build(n, f) {
|
||||
var result = [];
|
||||
for (var i = 0; i < n; i++)
|
||||
result.push(f(i));
|
||||
return result;
|
||||
}
|
||||
function seq_scan(array, f) {
|
||||
for (var i = 1; i < array.length; i++) {
|
||||
}
|
||||
}
|
||||
function assertAlmostEq(v1, v2) {
|
||||
if (e1 instanceof Array && e2 instanceof Array) {
|
||||
for (prop in e1) {
|
||||
if (e1.hasOwnProperty(prop)) { }
|
||||
}
|
||||
}
|
||||
}
|
||||
function assertEqArray(a, b) {
|
||||
for (var i = 0, l = a.length; i < l; i++) {
|
||||
try { } catch (e) { }
|
||||
}
|
||||
}
|
||||
function assertParallelExecWillRecover(opFunction) {
|
||||
assertParallelExecSucceeds(
|
||||
function(m) {},
|
||||
function(r) {}
|
||||
);
|
||||
}
|
|
@ -506,8 +506,9 @@ jit::FinishOffThreadBuilder(IonBuilder *builder)
|
|||
{
|
||||
ExecutionMode executionMode = builder->info().executionMode();
|
||||
|
||||
// Clear the recompiling flag if it would have failed.
|
||||
if (builder->script()->hasIonScript())
|
||||
// Clear the recompiling flag of the old ionScript, since we continue to
|
||||
// use the old ionScript if recompiling fails.
|
||||
if (executionMode == SequentialExecution && builder->script()->hasIonScript())
|
||||
builder->script()->ionScript()->clearRecompiling();
|
||||
|
||||
// Clean up if compilation did not succeed.
|
||||
|
|
|
@ -539,7 +539,7 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
virtual void HandleDoubleTap(const CSSIntPoint& aPoint,
|
||||
virtual void HandleDoubleTap(const CSSPoint& aPoint,
|
||||
int32_t aModifiers,
|
||||
const ScrollableLayerGuid& aGuid) MOZ_OVERRIDE
|
||||
{
|
||||
|
@ -558,7 +558,7 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
virtual void HandleSingleTap(const CSSIntPoint& aPoint,
|
||||
virtual void HandleSingleTap(const CSSPoint& aPoint,
|
||||
int32_t aModifiers,
|
||||
const ScrollableLayerGuid& aGuid) MOZ_OVERRIDE
|
||||
{
|
||||
|
@ -577,7 +577,7 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
virtual void HandleLongTap(const CSSIntPoint& aPoint,
|
||||
virtual void HandleLongTap(const CSSPoint& aPoint,
|
||||
int32_t aModifiers,
|
||||
const ScrollableLayerGuid& aGuid) MOZ_OVERRIDE
|
||||
{
|
||||
|
@ -596,7 +596,7 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
virtual void HandleLongTapUp(const CSSIntPoint& aPoint,
|
||||
virtual void HandleLongTapUp(const CSSPoint& aPoint,
|
||||
int32_t aModifiers,
|
||||
const ScrollableLayerGuid& aGuid) MOZ_OVERRIDE
|
||||
{
|
||||
|
|
|
@ -141,7 +141,7 @@ HTTP(..) == bug533251.html bug533251-ref.html
|
|||
HTTP(..) == font-familiy-whitespace-1.html font-familiy-whitespace-1-ref.html
|
||||
HTTP(..) != font-familiy-whitespace-1.html font-familiy-whitespace-1-notref.html
|
||||
|
||||
skip-if(B2G) fails-if(Android) HTTP(..) == ivs-1.html ivs-1-ref.html # bug 773482
|
||||
skip-if(B2G) HTTP(..) == ivs-1.html ivs-1-ref.html # bug 773482
|
||||
|
||||
skip-if(B2G) HTTP(..) == missing-names.html missing-names-ref.html # bug 773482
|
||||
|
||||
|
|
|
@ -20,6 +20,8 @@ css_properties.js: host_ListCSSProperties$(HOST_BIN_SUFFIX) css_properties_like_
|
|||
./host_ListCSSProperties$(HOST_BIN_SUFFIX) > $@
|
||||
cat $(srcdir)/css_properties_like_longhand.js >> $@
|
||||
|
||||
GARBAGE += css_properties.jsm
|
||||
MOCHITEST_FILES += css_properties.js
|
||||
GARBAGE += css_properties.js
|
||||
TEST_FILES := css_properties.js
|
||||
TEST_DEST = $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)
|
||||
INSTALL_TARGETS += TEST
|
||||
endif
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
[DEFAULT]
|
||||
skip-if = buildapp == 'b2g'
|
||||
|
||||
[test_bug386386.html]
|
||||
[test_bug394800.xhtml]
|
||||
|
|
|
@ -827,17 +827,15 @@ pref("browser.snippets.syncPromo.enabled", true);
|
|||
|
||||
#ifdef MOZ_ANDROID_SYNTHAPKS
|
||||
// The URL of the APK factory from which we obtain APKs for webapps.
|
||||
// This currently points to the development server.
|
||||
pref("browser.webapps.apkFactoryUrl", "http://dapk.net/application.apk");
|
||||
pref("browser.webapps.apkFactoryUrl", "https://controller.apk.firefox.com/application.apk");
|
||||
|
||||
// How frequently to check for webapp updates, in seconds (86400 is daily).
|
||||
pref("browser.webapps.updateInterval", 86400);
|
||||
|
||||
// The URL of the service that checks for updates.
|
||||
// This currently points to the development server.
|
||||
// To test updates, set this to http://apk-update-checker.paas.allizom.org,
|
||||
// which is a test server that always reports all apps as having updates.
|
||||
pref("browser.webapps.updateCheckUrl", "http://dapk.net/app_updates");
|
||||
pref("browser.webapps.updateCheckUrl", "https://controller.apk.firefox.com/app_updates");
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -848,3 +846,7 @@ pref("home.sync.updateMode", 0);
|
|||
|
||||
// How frequently to check if we should sync home provider data.
|
||||
pref("home.sync.checkIntervalSecs", 3600);
|
||||
|
||||
#ifdef NIGHTLY_BUILD
|
||||
pref("devtools.debugger.remote-enabled", true);
|
||||
#endif
|
||||
|
|
|
@ -42,7 +42,6 @@ import org.mozilla.gecko.home.SearchEngine;
|
|||
import org.mozilla.gecko.menu.GeckoMenu;
|
||||
import org.mozilla.gecko.preferences.GeckoPreferences;
|
||||
import org.mozilla.gecko.prompts.Prompt;
|
||||
import org.mozilla.gecko.prompts.PromptListItem;
|
||||
import org.mozilla.gecko.sync.setup.SyncAccounts;
|
||||
import org.mozilla.gecko.toolbar.AutocompleteHandler;
|
||||
import org.mozilla.gecko.toolbar.BrowserToolbar;
|
||||
|
@ -1447,7 +1446,7 @@ abstract public class BrowserApp extends GeckoApp
|
|||
// If we failed to load a favicon, we use the default favicon instead.
|
||||
Tabs.getInstance()
|
||||
.updateFaviconForURL(pageUrl,
|
||||
(favicon == null) ? Favicons.sDefaultFavicon : favicon);
|
||||
(favicon == null) ? Favicons.defaultFavicon : favicon);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1694,16 +1693,22 @@ abstract public class BrowserApp extends GeckoApp
|
|||
mHomePager = (HomePager) homePagerStub.inflate();
|
||||
|
||||
final HomeBanner homeBanner = (HomeBanner) findViewById(R.id.home_banner);
|
||||
mHomePager.setBanner(homeBanner);
|
||||
|
||||
// Remove the banner from the view hierarchy if it is dismissed.
|
||||
homeBanner.setOnDismissListener(new HomeBanner.OnDismissListener() {
|
||||
@Override
|
||||
public void onDismiss() {
|
||||
mHomePager.setBanner(null);
|
||||
mHomePagerContainer.removeView(homeBanner);
|
||||
}
|
||||
});
|
||||
// Never show the home banner in guest mode.
|
||||
if (GeckoProfile.get(this).inGuestMode()) {
|
||||
mHomePagerContainer.removeView(homeBanner);
|
||||
} else {
|
||||
mHomePager.setBanner(homeBanner);
|
||||
|
||||
// Remove the banner from the view hierarchy if it is dismissed.
|
||||
homeBanner.setOnDismissListener(new HomeBanner.OnDismissListener() {
|
||||
@Override
|
||||
public void onDismiss() {
|
||||
mHomePager.setBanner(null);
|
||||
mHomePagerContainer.removeView(homeBanner);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
mHomePagerContainer.setVisibility(View.VISIBLE);
|
||||
|
|
|
@ -1121,10 +1121,13 @@ public class GeckoAppShell
|
|||
/**
|
||||
* Given the inputs to <code>getOpenURIIntent</code>, plus an optional
|
||||
* package name and class name, create and fire an intent to open the
|
||||
* provided URI.
|
||||
* provided URI. If a class name is specified but a package name is not,
|
||||
* we will default to using the current fennec package.
|
||||
*
|
||||
* @param targetURI the string spec of the URI to open.
|
||||
* @param mimeType an optional MIME type string.
|
||||
* @param packageName an optional app package name.
|
||||
* @param className an optional intent class name.
|
||||
* @param action an Android action specifier, such as
|
||||
* <code>Intent.ACTION_SEND</code>.
|
||||
* @param title the title to use in <code>ACTION_SEND</code> intents.
|
||||
|
@ -1145,8 +1148,13 @@ public class GeckoAppShell
|
|||
return false;
|
||||
}
|
||||
|
||||
if (packageName.length() > 0 && className.length() > 0) {
|
||||
intent.setClassName(packageName, className);
|
||||
if (!TextUtils.isEmpty(className)) {
|
||||
if (!TextUtils.isEmpty(packageName)) {
|
||||
intent.setClassName(packageName, className);
|
||||
} else {
|
||||
// Default to using the fennec app context.
|
||||
intent.setClassName(context, className);
|
||||
}
|
||||
}
|
||||
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||
|
|
|
@ -13,7 +13,6 @@ import org.mozilla.gecko.Tab;
|
|||
import org.mozilla.gecko.Tabs;
|
||||
import org.mozilla.gecko.db.BrowserDB;
|
||||
import org.mozilla.gecko.favicons.cache.FaviconCache;
|
||||
import org.mozilla.gecko.gfx.BitmapUtils;
|
||||
import org.mozilla.gecko.util.GeckoJarReader;
|
||||
import org.mozilla.gecko.util.NonEvictingLruCache;
|
||||
import org.mozilla.gecko.util.ThreadUtils;
|
||||
|
@ -29,12 +28,9 @@ import android.util.SparseArray;
|
|||
import java.io.File;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class Favicons {
|
||||
private static final String LOGTAG = "GeckoFavicons";
|
||||
|
@ -53,25 +49,25 @@ public class Favicons {
|
|||
public static final int FLAG_PERSIST = 2;
|
||||
public static final int FLAG_SCALE = 4;
|
||||
|
||||
protected static Context sContext;
|
||||
protected static Context context;
|
||||
|
||||
// The default Favicon to show if no other can be found.
|
||||
public static Bitmap sDefaultFavicon;
|
||||
public static Bitmap defaultFavicon;
|
||||
|
||||
// The density-adjusted default Favicon dimensions.
|
||||
public static int sDefaultFaviconSize;
|
||||
public static int defaultFaviconSize;
|
||||
|
||||
// The density-adjusted maximum Favicon dimensions.
|
||||
public static int sLargestFaviconSize;
|
||||
public static int largestFaviconSize;
|
||||
|
||||
private static final SparseArray<LoadFaviconTask> sLoadTasks = new SparseArray<LoadFaviconTask>();
|
||||
private static final SparseArray<LoadFaviconTask> loadTasks = new SparseArray<LoadFaviconTask>();
|
||||
|
||||
// Cache to hold mappings between page URLs and Favicon URLs. Used to avoid going to the DB when
|
||||
// doing so is not necessary.
|
||||
private static final NonEvictingLruCache<String, String> sPageURLMappings = new NonEvictingLruCache<String, String>(NUM_PAGE_URL_MAPPINGS_TO_STORE);
|
||||
private static final NonEvictingLruCache<String, String> pageURLMappings = new NonEvictingLruCache<String, String>(NUM_PAGE_URL_MAPPINGS_TO_STORE);
|
||||
|
||||
public static String getFaviconURLForPageURLFromCache(String pageURL) {
|
||||
return sPageURLMappings.get(pageURL);
|
||||
return pageURLMappings.get(pageURL);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -79,10 +75,10 @@ public class Favicons {
|
|||
* Useful for short-circuiting local database access.
|
||||
*/
|
||||
public static void putFaviconURLForPageURLInCache(String pageURL, String faviconURL) {
|
||||
sPageURLMappings.put(pageURL, faviconURL);
|
||||
pageURLMappings.put(pageURL, faviconURL);
|
||||
}
|
||||
|
||||
private static FaviconCache sFaviconsCache;
|
||||
private static FaviconCache faviconsCache;
|
||||
|
||||
/**
|
||||
* Returns either NOT_LOADING, or LOADED if the onFaviconLoaded call could
|
||||
|
@ -117,7 +113,7 @@ public class Favicons {
|
|||
* Returns null otherwise.
|
||||
*/
|
||||
public static Bitmap getSizedFaviconForPageFromCache(final String pageURL, int targetSize) {
|
||||
final String faviconURL = sPageURLMappings.get(pageURL);
|
||||
final String faviconURL = pageURLMappings.get(pageURL);
|
||||
if (faviconURL == null) {
|
||||
return null;
|
||||
}
|
||||
|
@ -143,7 +139,7 @@ public class Favicons {
|
|||
// Do we know the favicon URL for this page already?
|
||||
String cacheURL = faviconURL;
|
||||
if (cacheURL == null) {
|
||||
cacheURL = sPageURLMappings.get(pageURL);
|
||||
cacheURL = pageURLMappings.get(pageURL);
|
||||
}
|
||||
|
||||
// If there's no favicon URL given, try and hit the cache with the default one.
|
||||
|
@ -153,7 +149,7 @@ public class Favicons {
|
|||
|
||||
// If it's something we can't even figure out a default URL for, just give up.
|
||||
if (cacheURL == null) {
|
||||
return dispatchResult(pageURL, null, sDefaultFavicon, listener);
|
||||
return dispatchResult(pageURL, null, defaultFavicon, listener);
|
||||
}
|
||||
|
||||
Bitmap cachedIcon = getSizedFaviconFromCache(cacheURL, targetSize);
|
||||
|
@ -162,8 +158,8 @@ public class Favicons {
|
|||
}
|
||||
|
||||
// Check if favicon has failed.
|
||||
if (sFaviconsCache.isFailedFavicon(cacheURL)) {
|
||||
return dispatchResult(pageURL, cacheURL, sDefaultFavicon, listener);
|
||||
if (faviconsCache.isFailedFavicon(cacheURL)) {
|
||||
return dispatchResult(pageURL, cacheURL, defaultFavicon, listener);
|
||||
}
|
||||
|
||||
// Failing that, try and get one from the database or internet.
|
||||
|
@ -181,7 +177,7 @@ public class Favicons {
|
|||
* null if no applicable Favicon exists in the cache.
|
||||
*/
|
||||
public static Bitmap getSizedFaviconFromCache(String faviconURL, int targetSize) {
|
||||
return sFaviconsCache.getFaviconForDimensions(faviconURL, targetSize);
|
||||
return faviconsCache.getFaviconForDimensions(faviconURL, targetSize);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -201,10 +197,10 @@ public class Favicons {
|
|||
public static int getSizedFaviconForPageFromLocal(final String pageURL, final int targetSize, final OnFaviconLoadedListener callback) {
|
||||
// Firstly, try extremely hard to cheat.
|
||||
// Have we cached this favicon URL? If we did, we can consult the memcache right away.
|
||||
String targetURL = sPageURLMappings.get(pageURL);
|
||||
String targetURL = pageURLMappings.get(pageURL);
|
||||
if (targetURL != null) {
|
||||
// Check if favicon has failed.
|
||||
if (sFaviconsCache.isFailedFavicon(targetURL)) {
|
||||
if (faviconsCache.isFailedFavicon(targetURL)) {
|
||||
return dispatchResult(pageURL, targetURL, null, callback);
|
||||
}
|
||||
|
||||
|
@ -219,15 +215,15 @@ public class Favicons {
|
|||
// No joy using in-memory resources. Go to background thread and ask the database.
|
||||
LoadFaviconTask task = new LoadFaviconTask(ThreadUtils.getBackgroundHandler(), pageURL, targetURL, 0, callback, targetSize, true);
|
||||
int taskId = task.getId();
|
||||
synchronized(sLoadTasks) {
|
||||
sLoadTasks.put(taskId, task);
|
||||
synchronized(loadTasks) {
|
||||
loadTasks.put(taskId, task);
|
||||
}
|
||||
task.execute();
|
||||
return taskId;
|
||||
}
|
||||
|
||||
public static int getSizedFaviconForPageFromLocal(final String pageURL, final OnFaviconLoadedListener callback) {
|
||||
return getSizedFaviconForPageFromLocal(pageURL, sDefaultFaviconSize, callback);
|
||||
return getSizedFaviconForPageFromLocal(pageURL, defaultFaviconSize, callback);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -250,7 +246,7 @@ public class Favicons {
|
|||
}
|
||||
}
|
||||
|
||||
targetURL = BrowserDB.getFaviconUrlForHistoryUrl(sContext.getContentResolver(), pageURL);
|
||||
targetURL = BrowserDB.getFaviconUrlForHistoryUrl(context.getContentResolver(), pageURL);
|
||||
if (targetURL == null) {
|
||||
// Nothing in the history database. Fall back to the default URL and hope for the best.
|
||||
targetURL = guessDefaultFaviconURL(pageURL);
|
||||
|
@ -286,8 +282,8 @@ public class Favicons {
|
|||
LoadFaviconTask task = new LoadFaviconTask(ThreadUtils.getBackgroundHandler(), pageUrl, faviconUrl, flags, listener, targetSize, false);
|
||||
|
||||
int taskId = task.getId();
|
||||
synchronized(sLoadTasks) {
|
||||
sLoadTasks.put(taskId, task);
|
||||
synchronized(loadTasks) {
|
||||
loadTasks.put(taskId, task);
|
||||
}
|
||||
|
||||
task.execute();
|
||||
|
@ -296,7 +292,7 @@ public class Favicons {
|
|||
}
|
||||
|
||||
public static void putFaviconInMemCache(String pageUrl, Bitmap image) {
|
||||
sFaviconsCache.putSingleFavicon(pageUrl, image);
|
||||
faviconsCache.putSingleFavicon(pageUrl, image);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -308,7 +304,7 @@ public class Favicons {
|
|||
* @param images An iterator over the new favicons to put in the cache.
|
||||
*/
|
||||
public static void putFaviconsInMemCache(String pageUrl, Iterator<Bitmap> images, boolean permanently) {
|
||||
sFaviconsCache.putFavicons(pageUrl, images, permanently);
|
||||
faviconsCache.putFavicons(pageUrl, images, permanently);
|
||||
}
|
||||
|
||||
public static void putFaviconsInMemCache(String pageUrl, Iterator<Bitmap> images) {
|
||||
|
@ -316,12 +312,12 @@ public class Favicons {
|
|||
}
|
||||
|
||||
public static void clearMemCache() {
|
||||
sFaviconsCache.evictAll();
|
||||
sPageURLMappings.evictAll();
|
||||
faviconsCache.evictAll();
|
||||
pageURLMappings.evictAll();
|
||||
}
|
||||
|
||||
public static void putFaviconInFailedCache(String faviconURL) {
|
||||
sFaviconsCache.putFailed(faviconURL);
|
||||
faviconsCache.putFailed(faviconURL);
|
||||
}
|
||||
|
||||
public static boolean cancelFaviconLoad(int taskId) {
|
||||
|
@ -330,13 +326,14 @@ public class Favicons {
|
|||
}
|
||||
|
||||
boolean cancelled;
|
||||
synchronized (sLoadTasks) {
|
||||
if (sLoadTasks.indexOfKey(taskId) < 0)
|
||||
synchronized (loadTasks) {
|
||||
if (loadTasks.indexOfKey(taskId) < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Log.d(LOGTAG, "Cancelling favicon load (" + taskId + ")");
|
||||
|
||||
LoadFaviconTask task = sLoadTasks.get(taskId);
|
||||
LoadFaviconTask task = loadTasks.get(taskId);
|
||||
cancelled = task.cancel(false);
|
||||
}
|
||||
return cancelled;
|
||||
|
@ -346,12 +343,12 @@ public class Favicons {
|
|||
Log.d(LOGTAG, "Closing Favicons database");
|
||||
|
||||
// Cancel any pending tasks
|
||||
synchronized (sLoadTasks) {
|
||||
final int count = sLoadTasks.size();
|
||||
synchronized (loadTasks) {
|
||||
final int count = loadTasks.size();
|
||||
for (int i = 0; i < count; i++) {
|
||||
cancelFaviconLoad(sLoadTasks.keyAt(i));
|
||||
cancelFaviconLoad(loadTasks.keyAt(i));
|
||||
}
|
||||
sLoadTasks.clear();
|
||||
loadTasks.clear();
|
||||
}
|
||||
|
||||
LoadFaviconTask.closeHTTPClient();
|
||||
|
@ -364,7 +361,7 @@ public class Favicons {
|
|||
* @return The dominant colour of the provided Favicon.
|
||||
*/
|
||||
public static int getFaviconColor(String url) {
|
||||
return sFaviconsCache.getDominantColor(url);
|
||||
return faviconsCache.getDominantColor(url);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -376,24 +373,24 @@ public class Favicons {
|
|||
*/
|
||||
public static void attachToContext(Context context) throws Exception {
|
||||
final Resources res = context.getResources();
|
||||
sContext = context;
|
||||
Favicons.context = context;
|
||||
|
||||
// Decode the default Favicon ready for use.
|
||||
sDefaultFavicon = BitmapFactory.decodeResource(res, R.drawable.favicon);
|
||||
if (sDefaultFavicon == null) {
|
||||
defaultFavicon = BitmapFactory.decodeResource(res, R.drawable.favicon);
|
||||
if (defaultFavicon == null) {
|
||||
throw new Exception("Null default favicon was returned from the resources system!");
|
||||
}
|
||||
|
||||
sDefaultFaviconSize = res.getDimensionPixelSize(R.dimen.favicon_bg);
|
||||
defaultFaviconSize = res.getDimensionPixelSize(R.dimen.favicon_bg);
|
||||
|
||||
// Screen-density-adjusted upper limit on favicon size. Favicons larger than this are
|
||||
// downscaled to this size or discarded.
|
||||
sLargestFaviconSize = context.getResources().getDimensionPixelSize(R.dimen.favicon_largest_interesting_size);
|
||||
sFaviconsCache = new FaviconCache(FAVICON_CACHE_SIZE_BYTES, sLargestFaviconSize);
|
||||
largestFaviconSize = context.getResources().getDimensionPixelSize(R.dimen.favicon_largest_interesting_size);
|
||||
faviconsCache = new FaviconCache(FAVICON_CACHE_SIZE_BYTES, largestFaviconSize);
|
||||
|
||||
// Initialize page mappings for each of our special pages.
|
||||
for (String url : AboutPages.getDefaultIconPages()) {
|
||||
sPageURLMappings.putWithoutEviction(url, BUILT_IN_FAVICON_URL);
|
||||
pageURLMappings.putWithoutEviction(url, BUILT_IN_FAVICON_URL);
|
||||
}
|
||||
|
||||
// Load and cache the built-in favicon in each of its sizes.
|
||||
|
@ -453,8 +450,8 @@ public class Favicons {
|
|||
}
|
||||
|
||||
public static void removeLoadTask(int taskId) {
|
||||
synchronized(sLoadTasks) {
|
||||
sLoadTasks.delete(taskId);
|
||||
synchronized(loadTasks) {
|
||||
loadTasks.delete(taskId);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -464,7 +461,7 @@ public class Favicons {
|
|||
* @param faviconURL Favicon URL to check for failure.
|
||||
*/
|
||||
static boolean isFailedFavicon(String faviconURL) {
|
||||
return sFaviconsCache.isFailedFavicon(faviconURL);
|
||||
return faviconsCache.isFailedFavicon(faviconURL);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -22,7 +22,7 @@ import org.mozilla.gecko.favicons.decoders.LoadFaviconResult;
|
|||
import org.mozilla.gecko.util.GeckoJarReader;
|
||||
import org.mozilla.gecko.util.ThreadUtils;
|
||||
import org.mozilla.gecko.util.UiAsyncTask;
|
||||
import static org.mozilla.gecko.favicons.Favicons.sContext;
|
||||
import static org.mozilla.gecko.favicons.Favicons.context;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
@ -53,21 +53,21 @@ public class LoadFaviconTask extends UiAsyncTask<Void, Void, Bitmap> {
|
|||
// by the server.
|
||||
private static final int DEFAULT_FAVICON_BUFFER_SIZE = 25000;
|
||||
|
||||
private static AtomicInteger mNextFaviconLoadId = new AtomicInteger(0);
|
||||
private int mId;
|
||||
private String mPageUrl;
|
||||
private String mFaviconUrl;
|
||||
private OnFaviconLoadedListener mListener;
|
||||
private int mFlags;
|
||||
private static AtomicInteger nextFaviconLoadId = new AtomicInteger(0);
|
||||
private int id;
|
||||
private String pageUrl;
|
||||
private String faviconURL;
|
||||
private OnFaviconLoadedListener listener;
|
||||
private int flags;
|
||||
|
||||
private final boolean mOnlyFromLocal;
|
||||
private final boolean onlyFromLocal;
|
||||
|
||||
// Assuming square favicons, judging by width only is acceptable.
|
||||
protected int mTargetWidth;
|
||||
private LinkedList<LoadFaviconTask> mChainees;
|
||||
private boolean mIsChaining;
|
||||
protected int targetWidth;
|
||||
private LinkedList<LoadFaviconTask> chainees;
|
||||
private boolean isChaining;
|
||||
|
||||
static AndroidHttpClient sHttpClient = AndroidHttpClient.newInstance(GeckoAppShell.getGeckoInterface().getDefaultUAString());
|
||||
static AndroidHttpClient httpClient = AndroidHttpClient.newInstance(GeckoAppShell.getGeckoInterface().getDefaultUAString());
|
||||
|
||||
public LoadFaviconTask(Handler backgroundThreadHandler,
|
||||
String pageUrl, String faviconUrl, int flags,
|
||||
|
@ -76,33 +76,33 @@ public class LoadFaviconTask extends UiAsyncTask<Void, Void, Bitmap> {
|
|||
}
|
||||
public LoadFaviconTask(Handler backgroundThreadHandler,
|
||||
String pageUrl, String faviconUrl, int flags,
|
||||
OnFaviconLoadedListener aListener, int targetSize, boolean fromLocal) {
|
||||
OnFaviconLoadedListener listener, int targetWidth, boolean onlyFromLocal) {
|
||||
super(backgroundThreadHandler);
|
||||
|
||||
mId = mNextFaviconLoadId.incrementAndGet();
|
||||
id = nextFaviconLoadId.incrementAndGet();
|
||||
|
||||
mPageUrl = pageUrl;
|
||||
mFaviconUrl = faviconUrl;
|
||||
mListener = aListener;
|
||||
mFlags = flags;
|
||||
mTargetWidth = targetSize;
|
||||
mOnlyFromLocal = fromLocal;
|
||||
this.pageUrl = pageUrl;
|
||||
this.faviconURL = faviconUrl;
|
||||
this.listener = listener;
|
||||
this.flags = flags;
|
||||
this.targetWidth = targetWidth;
|
||||
this.onlyFromLocal = onlyFromLocal;
|
||||
}
|
||||
|
||||
// Runs in background thread
|
||||
private LoadFaviconResult loadFaviconFromDb() {
|
||||
ContentResolver resolver = sContext.getContentResolver();
|
||||
return BrowserDB.getFaviconForFaviconUrl(resolver, mFaviconUrl);
|
||||
ContentResolver resolver = context.getContentResolver();
|
||||
return BrowserDB.getFaviconForFaviconUrl(resolver, faviconURL);
|
||||
}
|
||||
|
||||
// Runs in background thread
|
||||
private void saveFaviconToDb(final byte[] encodedFavicon) {
|
||||
if ((mFlags & FLAG_PERSIST) == 0) {
|
||||
if ((flags & FLAG_PERSIST) == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
ContentResolver resolver = sContext.getContentResolver();
|
||||
BrowserDB.updateFaviconForUrl(resolver, mPageUrl, encodedFavicon, mFaviconUrl);
|
||||
ContentResolver resolver = context.getContentResolver();
|
||||
BrowserDB.updateFaviconForUrl(resolver, pageUrl, encodedFavicon, faviconURL);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -121,7 +121,7 @@ public class LoadFaviconTask extends UiAsyncTask<Void, Void, Bitmap> {
|
|||
}
|
||||
|
||||
HttpGet request = new HttpGet(faviconURI);
|
||||
HttpResponse response = sHttpClient.execute(request);
|
||||
HttpResponse response = httpClient.execute(request);
|
||||
if (response == null) {
|
||||
return null;
|
||||
}
|
||||
|
@ -172,7 +172,7 @@ public class LoadFaviconTask extends UiAsyncTask<Void, Void, Bitmap> {
|
|||
if (uri.startsWith("jar:jar:")) {
|
||||
Log.d(LOGTAG, "Fetching favicon from JAR.");
|
||||
try {
|
||||
return GeckoJarReader.getBitmap(sContext.getResources(), uri);
|
||||
return GeckoJarReader.getBitmap(context.getResources(), uri);
|
||||
} catch (Exception e) {
|
||||
// Just about anything could happen here.
|
||||
Log.w(LOGTAG, "Error fetching favicon from JAR.", e);
|
||||
|
@ -287,27 +287,27 @@ public class LoadFaviconTask extends UiAsyncTask<Void, Void, Bitmap> {
|
|||
|
||||
// Handle the case of malformed favicon URL.
|
||||
// If favicon is empty, fall back to the stored one.
|
||||
if (TextUtils.isEmpty(mFaviconUrl)) {
|
||||
if (TextUtils.isEmpty(faviconURL)) {
|
||||
// Try to get the favicon URL from the memory cache.
|
||||
storedFaviconUrl = Favicons.getFaviconURLForPageURLFromCache(mPageUrl);
|
||||
storedFaviconUrl = Favicons.getFaviconURLForPageURLFromCache(pageUrl);
|
||||
|
||||
// If that failed, try to get the URL from the database.
|
||||
if (storedFaviconUrl == null) {
|
||||
storedFaviconUrl = Favicons.getFaviconURLForPageURL(mPageUrl);
|
||||
storedFaviconUrl = Favicons.getFaviconURLForPageURL(pageUrl);
|
||||
if (storedFaviconUrl != null) {
|
||||
// If that succeeded, cache the URL loaded from the database in memory.
|
||||
Favicons.putFaviconURLForPageURLInCache(mPageUrl, storedFaviconUrl);
|
||||
Favicons.putFaviconURLForPageURLInCache(pageUrl, storedFaviconUrl);
|
||||
}
|
||||
}
|
||||
|
||||
// If we found a faviconURL - use it.
|
||||
if (storedFaviconUrl != null) {
|
||||
mFaviconUrl = storedFaviconUrl;
|
||||
faviconURL = storedFaviconUrl;
|
||||
} else {
|
||||
// If we don't have a stored one, fall back to the default.
|
||||
mFaviconUrl = Favicons.guessDefaultFaviconURL(mPageUrl);
|
||||
faviconURL = Favicons.guessDefaultFaviconURL(pageUrl);
|
||||
|
||||
if (TextUtils.isEmpty(mFaviconUrl)) {
|
||||
if (TextUtils.isEmpty(faviconURL)) {
|
||||
return null;
|
||||
}
|
||||
isUsingDefaultURL = true;
|
||||
|
@ -316,7 +316,7 @@ public class LoadFaviconTask extends UiAsyncTask<Void, Void, Bitmap> {
|
|||
|
||||
// Check if favicon has failed - if so, give up. We need this check because, sometimes, we
|
||||
// didn't know the real Favicon URL until we asked the database.
|
||||
if (Favicons.isFailedFavicon(mFaviconUrl)) {
|
||||
if (Favicons.isFailedFavicon(faviconURL)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -329,10 +329,10 @@ public class LoadFaviconTask extends UiAsyncTask<Void, Void, Bitmap> {
|
|||
// If there is, just join the queue and wait for it to finish. If not, we carry on.
|
||||
synchronized(loadsInFlight) {
|
||||
// Another load of the current Favicon is already underway
|
||||
LoadFaviconTask existingTask = loadsInFlight.get(mFaviconUrl);
|
||||
LoadFaviconTask existingTask = loadsInFlight.get(faviconURL);
|
||||
if (existingTask != null && !existingTask.isCancelled()) {
|
||||
existingTask.chainTasks(this);
|
||||
mIsChaining = true;
|
||||
isChaining = true;
|
||||
|
||||
// If we are chaining, we want to keep the first task started to do this job as the one
|
||||
// in the hashmap so subsequent tasks will add themselves to its chaining list.
|
||||
|
@ -341,7 +341,7 @@ public class LoadFaviconTask extends UiAsyncTask<Void, Void, Bitmap> {
|
|||
|
||||
// We do not want to update the hashmap if the task has chained - other tasks need to
|
||||
// chain onto the same parent task.
|
||||
loadsInFlight.put(mFaviconUrl, this);
|
||||
loadsInFlight.put(faviconURL, this);
|
||||
}
|
||||
|
||||
if (isCancelled()) {
|
||||
|
@ -354,20 +354,20 @@ public class LoadFaviconTask extends UiAsyncTask<Void, Void, Bitmap> {
|
|||
return pushToCacheAndGetResult(loadedBitmaps);
|
||||
}
|
||||
|
||||
if (mOnlyFromLocal || isCancelled()) {
|
||||
if (onlyFromLocal || isCancelled()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Let's see if it's in a JAR.
|
||||
image = fetchJARFavicon(mFaviconUrl);
|
||||
image = fetchJARFavicon(faviconURL);
|
||||
if (imageIsValid(image)) {
|
||||
// We don't want to put this into the DB.
|
||||
Favicons.putFaviconInMemCache(mFaviconUrl, image);
|
||||
Favicons.putFaviconInMemCache(faviconURL, image);
|
||||
return image;
|
||||
}
|
||||
|
||||
try {
|
||||
loadedBitmaps = downloadFavicon(new URI(mFaviconUrl));
|
||||
loadedBitmaps = downloadFavicon(new URI(faviconURL));
|
||||
} catch (URISyntaxException e) {
|
||||
Log.e(LOGTAG, "The provided favicon URL is not valid");
|
||||
return null;
|
||||
|
@ -381,7 +381,7 @@ public class LoadFaviconTask extends UiAsyncTask<Void, Void, Bitmap> {
|
|||
}
|
||||
|
||||
if (isUsingDefaultURL) {
|
||||
Favicons.putFaviconInFailedCache(mFaviconUrl);
|
||||
Favicons.putFaviconInFailedCache(faviconURL);
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -390,16 +390,16 @@ public class LoadFaviconTask extends UiAsyncTask<Void, Void, Bitmap> {
|
|||
}
|
||||
|
||||
// If we're not already trying the default URL, try it now.
|
||||
final String guessed = Favicons.guessDefaultFaviconURL(mPageUrl);
|
||||
final String guessed = Favicons.guessDefaultFaviconURL(pageUrl);
|
||||
if (guessed == null) {
|
||||
Favicons.putFaviconInFailedCache(mFaviconUrl);
|
||||
Favicons.putFaviconInFailedCache(faviconURL);
|
||||
return null;
|
||||
}
|
||||
|
||||
image = fetchJARFavicon(guessed);
|
||||
if (imageIsValid(image)) {
|
||||
// We don't want to put this into the DB.
|
||||
Favicons.putFaviconInMemCache(mFaviconUrl, image);
|
||||
Favicons.putFaviconInMemCache(faviconURL, image);
|
||||
return image;
|
||||
}
|
||||
|
||||
|
@ -428,8 +428,8 @@ public class LoadFaviconTask extends UiAsyncTask<Void, Void, Bitmap> {
|
|||
* we are under extreme memory pressure and find ourselves dropping the cache immediately.
|
||||
*/
|
||||
private Bitmap pushToCacheAndGetResult(LoadFaviconResult loadedBitmaps) {
|
||||
Favicons.putFaviconsInMemCache(mFaviconUrl, loadedBitmaps.getBitmaps());
|
||||
Bitmap result = Favicons.getSizedFaviconFromCache(mFaviconUrl, mTargetWidth);
|
||||
Favicons.putFaviconsInMemCache(faviconURL, loadedBitmaps.getBitmaps());
|
||||
Bitmap result = Favicons.getSizedFaviconFromCache(faviconURL, targetWidth);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -441,7 +441,7 @@ public class LoadFaviconTask extends UiAsyncTask<Void, Void, Bitmap> {
|
|||
|
||||
@Override
|
||||
protected void onPostExecute(Bitmap image) {
|
||||
if (mIsChaining) {
|
||||
if (isChaining) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -450,10 +450,10 @@ public class LoadFaviconTask extends UiAsyncTask<Void, Void, Bitmap> {
|
|||
|
||||
synchronized (loadsInFlight) {
|
||||
// Prevent any other tasks from chaining on this one.
|
||||
loadsInFlight.remove(mFaviconUrl);
|
||||
loadsInFlight.remove(faviconURL);
|
||||
}
|
||||
|
||||
// Since any update to mChainees is done while holding the loadsInFlight lock, once we reach
|
||||
// Since any update to chainees is done while holding the loadsInFlight lock, once we reach
|
||||
// this point no further updates to that list can possibly take place (As far as other tasks
|
||||
// are concerned, there is no longer a task to chain from. The above block will have waited
|
||||
// for any tasks that were adding themselves to the list before reaching this point.)
|
||||
|
@ -463,8 +463,8 @@ public class LoadFaviconTask extends UiAsyncTask<Void, Void, Bitmap> {
|
|||
// actually happens outside of the strange situations unit tests create.
|
||||
|
||||
// Share the result with all chained tasks.
|
||||
if (mChainees != null) {
|
||||
for (LoadFaviconTask t : mChainees) {
|
||||
if (chainees != null) {
|
||||
for (LoadFaviconTask t : chainees) {
|
||||
// In the case that we just decoded multiple favicons, either we're passing the right
|
||||
// image now, or the call into the cache in processResult will fetch the right one.
|
||||
t.processResult(image);
|
||||
|
@ -473,35 +473,35 @@ public class LoadFaviconTask extends UiAsyncTask<Void, Void, Bitmap> {
|
|||
}
|
||||
|
||||
private void processResult(Bitmap image) {
|
||||
Favicons.removeLoadTask(mId);
|
||||
Favicons.removeLoadTask(id);
|
||||
Bitmap scaled = image;
|
||||
|
||||
// Notify listeners, scaling if required.
|
||||
if (mTargetWidth != -1 && image != null && image.getWidth() != mTargetWidth) {
|
||||
scaled = Favicons.getSizedFaviconFromCache(mFaviconUrl, mTargetWidth);
|
||||
if (targetWidth != -1 && image != null && image.getWidth() != targetWidth) {
|
||||
scaled = Favicons.getSizedFaviconFromCache(faviconURL, targetWidth);
|
||||
}
|
||||
|
||||
Favicons.dispatchResult(mPageUrl, mFaviconUrl, scaled, mListener);
|
||||
Favicons.dispatchResult(pageUrl, faviconURL, scaled, listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCancelled() {
|
||||
Favicons.removeLoadTask(mId);
|
||||
Favicons.removeLoadTask(id);
|
||||
|
||||
synchronized(loadsInFlight) {
|
||||
// Only remove from the hashmap if the task there is the one that's being canceled.
|
||||
// Cancellation of a task that would have chained is not interesting to the hashmap.
|
||||
final LoadFaviconTask primary = loadsInFlight.get(mFaviconUrl);
|
||||
final LoadFaviconTask primary = loadsInFlight.get(faviconURL);
|
||||
if (primary == this) {
|
||||
loadsInFlight.remove(mFaviconUrl);
|
||||
loadsInFlight.remove(faviconURL);
|
||||
return;
|
||||
}
|
||||
if (primary == null) {
|
||||
// This shouldn't happen.
|
||||
return;
|
||||
}
|
||||
if (primary.mChainees != null) {
|
||||
primary.mChainees.remove(this);
|
||||
if (primary.chainees != null) {
|
||||
primary.chainees.remove(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -518,15 +518,15 @@ public class LoadFaviconTask extends UiAsyncTask<Void, Void, Bitmap> {
|
|||
* @param aChainee LoadFaviconTask
|
||||
*/
|
||||
private void chainTasks(LoadFaviconTask aChainee) {
|
||||
if (mChainees == null) {
|
||||
mChainees = new LinkedList<LoadFaviconTask>();
|
||||
if (chainees == null) {
|
||||
chainees = new LinkedList<LoadFaviconTask>();
|
||||
}
|
||||
|
||||
mChainees.add(aChainee);
|
||||
chainees.add(aChainee);
|
||||
}
|
||||
|
||||
int getId() {
|
||||
return mId;
|
||||
return id;
|
||||
}
|
||||
|
||||
static void closeHTTPClient() {
|
||||
|
@ -534,8 +534,8 @@ public class LoadFaviconTask extends UiAsyncTask<Void, Void, Bitmap> {
|
|||
// the connection pool, which typically involves closing a connection --
|
||||
// which counts as network activity.
|
||||
if (ThreadUtils.isOnBackgroundThread()) {
|
||||
if (sHttpClient != null) {
|
||||
sHttpClient.close();
|
||||
if (httpClient != null) {
|
||||
httpClient.close();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||
* When a favicon at a particular URL is decoded, it will yield one or more bitmaps.
|
||||
* While in memory, these bitmaps are stored in a list, sorted in ascending order of size, in a
|
||||
* FaviconsForURL object.
|
||||
* The collection of FaviconsForURL objects currently in the cache is stored in mBackingMap, keyed
|
||||
* The collection of FaviconsForURL objects currently in the cache is stored in backingMap, keyed
|
||||
* by favicon URL.
|
||||
*
|
||||
* A second map exists for permanent cache entries -- ones that are never expired. These entries
|
||||
|
@ -59,7 +59,7 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||
* as well as the bitmap, a pointer to the encapsulating FaviconsForURL object (Used by the LRU
|
||||
* culler), the size of the encapsulated image, a flag indicating if this is a primary favicon, and
|
||||
* a flag indicating if the entry is invalid.
|
||||
* All FaviconCacheElement objects are tracked in the mOrdering LinkedList. This is used to record
|
||||
* All FaviconCacheElement objects are tracked in the ordering LinkedList. This is used to record
|
||||
* LRU information about FaviconCacheElements. In particular, the most recently used FaviconCacheElement
|
||||
* will be at the start of the list, the least recently used at the end of the list.
|
||||
*
|
||||
|
@ -98,7 +98,7 @@ public class FaviconCache {
|
|||
private static final int NUM_FAVICON_SIZES = 4;
|
||||
|
||||
// Dimensions of the largest favicon to store in the cache. Everything is downscaled to this.
|
||||
public final int mMaxCachedWidth;
|
||||
public final int maxCachedWidth;
|
||||
|
||||
// Retry failed favicons after 20 minutes.
|
||||
public static final long FAILURE_RETRY_MILLISECONDS = 1000 * 60 * 20;
|
||||
|
@ -107,16 +107,16 @@ public class FaviconCache {
|
|||
// Since favicons may be container formats holding multiple icons, the underlying type holds a
|
||||
// sorted list of bitmap payloads in ascending order of size. The underlying type may be queried
|
||||
// for the least larger payload currently present.
|
||||
private final ConcurrentHashMap<String, FaviconsForURL> mBackingMap = new ConcurrentHashMap<String, FaviconsForURL>();
|
||||
private final ConcurrentHashMap<String, FaviconsForURL> backingMap = new ConcurrentHashMap<String, FaviconsForURL>();
|
||||
|
||||
// And the same, but never evicted.
|
||||
private final ConcurrentHashMap<String, FaviconsForURL> mPermanentBackingMap = new ConcurrentHashMap<String, FaviconsForURL>();
|
||||
private final ConcurrentHashMap<String, FaviconsForURL> permanentBackingMap = new ConcurrentHashMap<String, FaviconsForURL>();
|
||||
|
||||
// A linked list used to implement a queue, defining the LRU properties of the cache. Elements
|
||||
// contained within the various FaviconsForURL objects are held here, the least recently used
|
||||
// of which at the end of the list. When space needs to be reclaimed, the appropriate bitmap is
|
||||
// culled.
|
||||
private final LinkedList<FaviconCacheElement> mOrdering = new LinkedList<FaviconCacheElement>();
|
||||
private final LinkedList<FaviconCacheElement> ordering = new LinkedList<FaviconCacheElement>();
|
||||
|
||||
// The above structures, if used correctly, enable this cache to exhibit LRU semantics across all
|
||||
// favicon payloads in the system, as well as enabling the dynamic selection from the cache of
|
||||
|
@ -124,60 +124,48 @@ public class FaviconCache {
|
|||
// are provided by the underlying file format).
|
||||
|
||||
// Current size, in bytes, of the bitmap data present in the LRU cache.
|
||||
private final AtomicInteger mCurrentSize = new AtomicInteger(0);
|
||||
private final AtomicInteger currentSize = new AtomicInteger(0);
|
||||
|
||||
// The maximum quantity, in bytes, of bitmap data which may be stored in the cache.
|
||||
private final int mMaxSizeBytes;
|
||||
private final int maxSizeBytes;
|
||||
|
||||
// Tracks the number of ongoing read operations. Enables the first one in to lock writers out and
|
||||
// the last one out to let them in.
|
||||
private final AtomicInteger mOngoingReads = new AtomicInteger(0);
|
||||
private final AtomicInteger ongoingReads = new AtomicInteger(0);
|
||||
|
||||
// Used to ensure transaction fairness - each txn acquires and releases this as the first operation.
|
||||
// The effect is an orderly, inexpensive ordering enforced on txns to prevent writer starvation.
|
||||
private final Semaphore mTurnSemaphore = new Semaphore(1);
|
||||
private final Semaphore turnSemaphore = new Semaphore(1);
|
||||
|
||||
// A deviation from the usual MRSW solution - this semaphore is used to guard modification to the
|
||||
// ordering map. This allows for read transactions to update the most-recently-used value without
|
||||
// needing to take out the write lock.
|
||||
private final Semaphore mReorderingSemaphore = new Semaphore(1);
|
||||
private final Semaphore reorderingSemaphore = new Semaphore(1);
|
||||
|
||||
// The semaphore one must acquire in order to perform a write.
|
||||
private final Semaphore mWriteLock = new Semaphore(1);
|
||||
private final Semaphore writeLock = new Semaphore(1);
|
||||
|
||||
/**
|
||||
* Called by txns performing only reads as they start. Prevents writer starvation with a turn
|
||||
* semaphore and locks writers out if this is the first concurrent reader txn starting up.
|
||||
*/
|
||||
private void startRead() {
|
||||
mTurnSemaphore.acquireUninterruptibly();
|
||||
mTurnSemaphore.release();
|
||||
turnSemaphore.acquireUninterruptibly();
|
||||
turnSemaphore.release();
|
||||
|
||||
if (mOngoingReads.incrementAndGet() == 1) {
|
||||
if (ongoingReads.incrementAndGet() == 1) {
|
||||
// First one in. Wait for writers to finish and lock them out.
|
||||
mWriteLock.acquireUninterruptibly();
|
||||
writeLock.acquireUninterruptibly();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An alternative to startWrite to be used when in a read transaction and wanting to upgrade it
|
||||
* to a write transaction. Such a transaction should be terminated with finishWrite.
|
||||
*/
|
||||
private void upgradeReadToWrite() {
|
||||
mTurnSemaphore.acquireUninterruptibly();
|
||||
if (mOngoingReads.decrementAndGet() == 0) {
|
||||
mWriteLock.release();
|
||||
}
|
||||
mWriteLock.acquireUninterruptibly();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by transactions performing only reads as they finish. Ensures that if this is the last
|
||||
* concluding read transaction then then writers are subsequently allowed in.
|
||||
*/
|
||||
private void finishRead() {
|
||||
if (mOngoingReads.decrementAndGet() == 0) {
|
||||
mWriteLock.release();
|
||||
if (ongoingReads.decrementAndGet() == 0) {
|
||||
writeLock.release();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -186,21 +174,21 @@ public class FaviconCache {
|
|||
* Upon return, no other txns will be executing concurrently.
|
||||
*/
|
||||
private void startWrite() {
|
||||
mTurnSemaphore.acquireUninterruptibly();
|
||||
mWriteLock.acquireUninterruptibly();
|
||||
turnSemaphore.acquireUninterruptibly();
|
||||
writeLock.acquireUninterruptibly();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by a concluding write transaction - unlocks the structure.
|
||||
*/
|
||||
private void finishWrite() {
|
||||
mTurnSemaphore.release();
|
||||
mWriteLock.release();
|
||||
turnSemaphore.release();
|
||||
writeLock.release();
|
||||
}
|
||||
|
||||
public FaviconCache(int maxSize, int maxWidthToCache) {
|
||||
mMaxSizeBytes = maxSize;
|
||||
mMaxCachedWidth = maxWidthToCache;
|
||||
maxSizeBytes = maxSize;
|
||||
maxCachedWidth = maxWidthToCache;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -217,57 +205,42 @@ public class FaviconCache {
|
|||
|
||||
startRead();
|
||||
|
||||
boolean isExpired = false;
|
||||
boolean isAborting = false;
|
||||
|
||||
try {
|
||||
// If we don't have it in the cache, it certainly isn't a known failure.
|
||||
// Non-evictable favicons are never failed, so we don't need to
|
||||
// check mPermanentBackingMap.
|
||||
if (!mBackingMap.containsKey(faviconURL)) {
|
||||
// check permanentBackingMap.
|
||||
if (!backingMap.containsKey(faviconURL)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
FaviconsForURL container = mBackingMap.get(faviconURL);
|
||||
FaviconsForURL container = backingMap.get(faviconURL);
|
||||
|
||||
// If the has failed flag is not set, it's certainly not a known failure.
|
||||
if (!container.mHasFailed) {
|
||||
if (!container.hasFailed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final long failureTimestamp = container.mDownloadTimestamp;
|
||||
final long failureTimestamp = container.downloadTimestamp;
|
||||
|
||||
// Calculate elapsed time since the failing download.
|
||||
final long failureDiff = System.currentTimeMillis() - failureTimestamp;
|
||||
|
||||
// If long enough has passed, mark it as no longer a failure.
|
||||
if (failureDiff > FAILURE_RETRY_MILLISECONDS) {
|
||||
isExpired = true;
|
||||
} else {
|
||||
// If the expiry is still in effect, return. Otherwise, continue and unmark the failure.
|
||||
if (failureDiff < FAILURE_RETRY_MILLISECONDS) {
|
||||
return true;
|
||||
}
|
||||
} catch (Exception unhandled) {
|
||||
// Handle any exception thrown and return the locks to a sensible state.
|
||||
finishRead();
|
||||
|
||||
// Flag to prevent finally from doubly-unlocking.
|
||||
isAborting = true;
|
||||
Log.e(LOGTAG, "FaviconCache exception!", unhandled);
|
||||
return true;
|
||||
} finally {
|
||||
if (!isAborting) {
|
||||
if (isExpired) {
|
||||
// No longer expired.
|
||||
upgradeReadToWrite();
|
||||
} else {
|
||||
finishRead();
|
||||
}
|
||||
}
|
||||
finishRead();
|
||||
}
|
||||
|
||||
startWrite();
|
||||
|
||||
// If the entry is no longer failed, remove the record of it from the cache.
|
||||
try {
|
||||
recordRemoved(mBackingMap.get(faviconURL));
|
||||
mBackingMap.remove(faviconURL);
|
||||
recordRemoved(backingMap.remove(faviconURL));
|
||||
return false;
|
||||
} finally {
|
||||
finishWrite();
|
||||
|
@ -282,14 +255,12 @@ public class FaviconCache {
|
|||
public void putFailed(String faviconURL) {
|
||||
startWrite();
|
||||
|
||||
if (mBackingMap.containsKey(faviconURL)) {
|
||||
recordRemoved(mBackingMap.get(faviconURL));
|
||||
try {
|
||||
FaviconsForURL container = new FaviconsForURL(0, true);
|
||||
recordRemoved(backingMap.put(faviconURL, container));
|
||||
} finally {
|
||||
finishWrite();
|
||||
}
|
||||
|
||||
FaviconsForURL container = new FaviconsForURL(0, true);
|
||||
mBackingMap.put(faviconURL, container);
|
||||
|
||||
finishWrite();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -309,9 +280,7 @@ public class FaviconCache {
|
|||
return null;
|
||||
}
|
||||
|
||||
boolean doingWrites = false;
|
||||
boolean shouldComputeColour = false;
|
||||
boolean isAborting = false;
|
||||
boolean wasPermanent = false;
|
||||
FaviconsForURL container;
|
||||
final Bitmap newBitmap;
|
||||
|
@ -319,9 +288,9 @@ public class FaviconCache {
|
|||
startRead();
|
||||
|
||||
try {
|
||||
container = mPermanentBackingMap.get(faviconURL);
|
||||
container = permanentBackingMap.get(faviconURL);
|
||||
if (container == null) {
|
||||
container = mBackingMap.get(faviconURL);
|
||||
container = backingMap.get(faviconURL);
|
||||
if (container == null) {
|
||||
// We don't have it!
|
||||
return null;
|
||||
|
@ -338,22 +307,22 @@ public class FaviconCache {
|
|||
// cacheElementIndex now holds either the index of the next least largest bitmap from
|
||||
// targetSize, or -1 if targetSize > all bitmaps.
|
||||
if (cacheElementIndex != -1) {
|
||||
// If cacheElementIndex is not the sentinel value, then it is a valid index into mFavicons.
|
||||
cacheElement = container.mFavicons.get(cacheElementIndex);
|
||||
// If cacheElementIndex is not the sentinel value, then it is a valid index into favicons.
|
||||
cacheElement = container.favicons.get(cacheElementIndex);
|
||||
|
||||
if (cacheElement.mInvalidated) {
|
||||
if (cacheElement.invalidated) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// If we found exactly what we wanted - we're done.
|
||||
if (cacheElement.mImageSize == targetSize) {
|
||||
setMostRecentlyUsed(cacheElement);
|
||||
return cacheElement.mFaviconPayload;
|
||||
if (cacheElement.imageSize == targetSize) {
|
||||
setMostRecentlyUsedWithinRead(cacheElement);
|
||||
return cacheElement.faviconPayload;
|
||||
}
|
||||
} else {
|
||||
// We requested an image larger than all primaries. Set the element to start the search
|
||||
// from to the element beyond the end of the array, so the search runs backwards.
|
||||
cacheElementIndex = container.mFavicons.size();
|
||||
cacheElementIndex = container.favicons.size();
|
||||
}
|
||||
|
||||
// We did not find exactly what we wanted, but now have set cacheElementIndex to the index
|
||||
|
@ -370,17 +339,12 @@ public class FaviconCache {
|
|||
|
||||
if (targetSize == -1) {
|
||||
// We got the biggest primary, so that's what we'll return.
|
||||
return cacheElement.mFaviconPayload;
|
||||
return cacheElement.faviconPayload;
|
||||
}
|
||||
|
||||
// Having got this far, we'll be needing to write the new secondary to the cache, which
|
||||
// involves us falling through to the next try block. This flag lets us do this (Other
|
||||
// paths prior to this end in returns.)
|
||||
doingWrites = true;
|
||||
|
||||
// Scaling logic...
|
||||
Bitmap largestElementBitmap = cacheElement.mFaviconPayload;
|
||||
int largestSize = cacheElement.mImageSize;
|
||||
Bitmap largestElementBitmap = cacheElement.faviconPayload;
|
||||
int largestSize = cacheElement.imageSize;
|
||||
|
||||
if (largestSize >= targetSize) {
|
||||
// The largest we have is larger than the target - downsize to target.
|
||||
|
@ -401,24 +365,16 @@ public class FaviconCache {
|
|||
}
|
||||
}
|
||||
} catch (Exception unhandled) {
|
||||
isAborting = true;
|
||||
|
||||
// Handle any exception thrown and return the locks to a sensible state.
|
||||
finishRead();
|
||||
|
||||
// Flag to prevent finally from doubly-unlocking.
|
||||
Log.e(LOGTAG, "FaviconCache exception!", unhandled);
|
||||
return null;
|
||||
} finally {
|
||||
if (!isAborting) {
|
||||
if (doingWrites) {
|
||||
upgradeReadToWrite();
|
||||
} else {
|
||||
finishRead();
|
||||
}
|
||||
}
|
||||
finishRead();
|
||||
}
|
||||
|
||||
startWrite();
|
||||
try {
|
||||
if (shouldComputeColour) {
|
||||
// And since we failed, we'll need the dominant colour.
|
||||
|
@ -432,8 +388,9 @@ public class FaviconCache {
|
|||
FaviconCacheElement newElement = container.addSecondary(newBitmap, targetSize);
|
||||
|
||||
if (!wasPermanent) {
|
||||
setMostRecentlyUsed(newElement);
|
||||
mCurrentSize.addAndGet(newElement.sizeOf());
|
||||
if (setMostRecentlyUsedWithinWrite(newElement)) {
|
||||
currentSize.addAndGet(newElement.sizeOf());
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
finishWrite();
|
||||
|
@ -452,19 +409,18 @@ public class FaviconCache {
|
|||
startRead();
|
||||
|
||||
try {
|
||||
FaviconsForURL element = mPermanentBackingMap.get(key);
|
||||
FaviconsForURL element = permanentBackingMap.get(key);
|
||||
if (element == null) {
|
||||
element = mBackingMap.get(key);
|
||||
element = backingMap.get(key);
|
||||
}
|
||||
|
||||
if (element == null) {
|
||||
Log.w(LOGTAG, "Cannot compute dominant color of non-cached favicon. Cache fullness " +
|
||||
mCurrentSize.get() + '/' + mMaxSizeBytes);
|
||||
currentSize.get() + '/' + maxSizeBytes);
|
||||
finishRead();
|
||||
return 0xFFFFFF;
|
||||
}
|
||||
|
||||
|
||||
return element.ensureDominantColor();
|
||||
} finally {
|
||||
finishRead();
|
||||
|
@ -472,8 +428,8 @@ public class FaviconCache {
|
|||
}
|
||||
|
||||
/**
|
||||
* Remove all payloads stored in the given container from the LRU cache. Must be called while
|
||||
* holding the write lock.
|
||||
* Remove all payloads stored in the given container from the LRU cache.
|
||||
* Must be called while holding the write lock.
|
||||
*
|
||||
* @param wasRemoved The container to purge from the cache.
|
||||
*/
|
||||
|
@ -485,40 +441,59 @@ public class FaviconCache {
|
|||
|
||||
int sizeRemoved = 0;
|
||||
|
||||
for (FaviconCacheElement e : wasRemoved.mFavicons) {
|
||||
for (FaviconCacheElement e : wasRemoved.favicons) {
|
||||
sizeRemoved += e.sizeOf();
|
||||
mOrdering.remove(e);
|
||||
ordering.remove(e);
|
||||
}
|
||||
|
||||
mCurrentSize.addAndGet(-sizeRemoved);
|
||||
currentSize.addAndGet(-sizeRemoved);
|
||||
}
|
||||
|
||||
private Bitmap produceCacheableBitmap(Bitmap favicon) {
|
||||
// Never cache the default Favicon, or the null Favicon.
|
||||
if (favicon == Favicons.sDefaultFavicon || favicon == null) {
|
||||
if (favicon == Favicons.defaultFavicon || favicon == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Some sites serve up insanely huge Favicons (Seen 512x512 ones...)
|
||||
// While we want to cache nice big icons, we apply a limit based on screen density for the
|
||||
// sake of space.
|
||||
if (favicon.getWidth() > mMaxCachedWidth) {
|
||||
return Bitmap.createScaledBitmap(favicon, mMaxCachedWidth, mMaxCachedWidth, true);
|
||||
if (favicon.getWidth() > maxCachedWidth) {
|
||||
return Bitmap.createScaledBitmap(favicon, maxCachedWidth, maxCachedWidth, true);
|
||||
}
|
||||
|
||||
return favicon;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set an existing element as the most recently used element. May be called from either type of
|
||||
* transaction.
|
||||
* Set an existing element as the most recently used element. Intended for use from read transactions. While
|
||||
* write transactions may safely use this method, it will perform slightly worse than its unsafe counterpart below.
|
||||
*
|
||||
* @param element The element that is to become the most recently used one.
|
||||
* @return true if this element already existed in the list, false otherwise. (Useful for preventing multiple-insertion.)
|
||||
*/
|
||||
private void setMostRecentlyUsed(FaviconCacheElement element) {
|
||||
mReorderingSemaphore.acquireUninterruptibly();
|
||||
mOrdering.remove(element);
|
||||
mOrdering.offer(element);
|
||||
mReorderingSemaphore.release();
|
||||
private boolean setMostRecentlyUsedWithinRead(FaviconCacheElement element) {
|
||||
reorderingSemaphore.acquireUninterruptibly();
|
||||
try {
|
||||
boolean contained = ordering.remove(element);
|
||||
ordering.offer(element);
|
||||
return contained;
|
||||
} finally {
|
||||
reorderingSemaphore.release();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Functionally equivalent to setMostRecentlyUsedWithinRead, but operates without taking the reordering semaphore.
|
||||
* Only safe for use when called from a write transaction, or there is a risk of concurrent modification.
|
||||
*
|
||||
* @param element The element that is to become the most recently used one.
|
||||
* @return true if this element already existed in the list, false otherwise. (Useful for preventing multiple-insertion.)
|
||||
*/
|
||||
private boolean setMostRecentlyUsedWithinWrite(FaviconCacheElement element) {
|
||||
boolean contained = ordering.remove(element);
|
||||
ordering.offer(element);
|
||||
return contained;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -546,13 +521,13 @@ public class FaviconCache {
|
|||
startWrite();
|
||||
try {
|
||||
// Set the new element as the most recently used one.
|
||||
setMostRecentlyUsed(newElement);
|
||||
setMostRecentlyUsedWithinWrite(newElement);
|
||||
|
||||
mCurrentSize.addAndGet(newElement.sizeOf());
|
||||
currentSize.addAndGet(newElement.sizeOf());
|
||||
|
||||
// Update the value in the LruCache...
|
||||
FaviconsForURL wasRemoved;
|
||||
wasRemoved = mBackingMap.put(faviconURL, toInsert);
|
||||
wasRemoved = backingMap.put(faviconURL, toInsert);
|
||||
|
||||
recordRemoved(wasRemoved);
|
||||
} finally {
|
||||
|
@ -584,42 +559,23 @@ public class FaviconCache {
|
|||
sizeGained += newElement.sizeOf();
|
||||
}
|
||||
|
||||
startRead();
|
||||
|
||||
boolean abortingRead = false;
|
||||
|
||||
// Not using setMostRecentlyUsed, because the elements are known to be new. This can be done
|
||||
// without taking the write lock, via the magic of the reordering semaphore.
|
||||
mReorderingSemaphore.acquireUninterruptibly();
|
||||
try {
|
||||
if (!permanently) {
|
||||
for (FaviconCacheElement newElement : toInsert.mFavicons) {
|
||||
mOrdering.offer(newElement);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
abortingRead = true;
|
||||
mReorderingSemaphore.release();
|
||||
finishRead();
|
||||
|
||||
Log.e(LOGTAG, "Favicon cache exception!", e);
|
||||
return;
|
||||
} finally {
|
||||
if (!abortingRead) {
|
||||
mReorderingSemaphore.release();
|
||||
upgradeReadToWrite();
|
||||
}
|
||||
}
|
||||
|
||||
startWrite();
|
||||
try {
|
||||
if (permanently) {
|
||||
mPermanentBackingMap.put(faviconURL, toInsert);
|
||||
} else {
|
||||
mCurrentSize.addAndGet(sizeGained);
|
||||
|
||||
// Update the value in the LruCache...
|
||||
recordRemoved(mBackingMap.put(faviconURL, toInsert));
|
||||
permanentBackingMap.put(faviconURL, toInsert);
|
||||
return;
|
||||
}
|
||||
|
||||
for (FaviconCacheElement newElement : toInsert.favicons) {
|
||||
setMostRecentlyUsedWithinWrite(newElement);
|
||||
}
|
||||
|
||||
// In the event this insertion is being made to a key that already held a value, the subsequent recordRemoved
|
||||
// call will subtract the size of the old value, preventing double-counting.
|
||||
currentSize.addAndGet(sizeGained);
|
||||
|
||||
// Update the value in the LruCache...
|
||||
recordRemoved(backingMap.put(faviconURL, toInsert));
|
||||
} finally {
|
||||
finishWrite();
|
||||
}
|
||||
|
@ -632,24 +588,24 @@ public class FaviconCache {
|
|||
* Otherwise, do nothing.
|
||||
*/
|
||||
private void cullIfRequired() {
|
||||
Log.d(LOGTAG, "Favicon cache fullness: " + mCurrentSize.get() + '/' + mMaxSizeBytes);
|
||||
Log.d(LOGTAG, "Favicon cache fullness: " + currentSize.get() + '/' + maxSizeBytes);
|
||||
|
||||
if (mCurrentSize.get() <= mMaxSizeBytes) {
|
||||
if (currentSize.get() <= maxSizeBytes) {
|
||||
return;
|
||||
}
|
||||
|
||||
startWrite();
|
||||
try {
|
||||
while (mCurrentSize.get() > mMaxSizeBytes) {
|
||||
while (currentSize.get() > maxSizeBytes) {
|
||||
// Cull the least recently used element.
|
||||
|
||||
FaviconCacheElement victim;
|
||||
victim = mOrdering.poll();
|
||||
victim = ordering.poll();
|
||||
|
||||
mCurrentSize.addAndGet(-victim.sizeOf());
|
||||
currentSize.addAndGet(-victim.sizeOf());
|
||||
victim.onEvictedFromCache();
|
||||
|
||||
Log.d(LOGTAG, "After cull: " + mCurrentSize.get() + '/' + mMaxSizeBytes);
|
||||
Log.d(LOGTAG, "After cull: " + currentSize.get() + '/' + maxSizeBytes);
|
||||
}
|
||||
} finally {
|
||||
finishWrite();
|
||||
|
@ -664,9 +620,9 @@ public class FaviconCache {
|
|||
|
||||
// Note that we neither clear, nor track the size of, the permanent map.
|
||||
try {
|
||||
mCurrentSize.set(0);
|
||||
mBackingMap.clear();
|
||||
mOrdering.clear();
|
||||
currentSize.set(0);
|
||||
backingMap.clear();
|
||||
ordering.clear();
|
||||
|
||||
} finally {
|
||||
finishWrite();
|
||||
|
|
|
@ -12,49 +12,49 @@ import android.graphics.Bitmap;
|
|||
*/
|
||||
public class FaviconCacheElement implements Comparable<FaviconCacheElement> {
|
||||
// Was this Favicon computed via scaling another primary Favicon, or is this a primary Favicon?
|
||||
final boolean mIsPrimary;
|
||||
final boolean isPrimary;
|
||||
|
||||
// The Favicon bitmap.
|
||||
Bitmap mFaviconPayload;
|
||||
Bitmap faviconPayload;
|
||||
|
||||
// If set, mFaviconPayload is absent. Since the underlying ICO may contain multiple primary
|
||||
// If set, faviconPayload is absent. Since the underlying ICO may contain multiple primary
|
||||
// payloads, primary payloads are never truly deleted from the cache, but instead have their
|
||||
// payload deleted and this flag set on their FaviconCacheElement. That way, the cache always
|
||||
// has a record of the existence of a primary payload, even if it is no longer in the cache.
|
||||
// This means that when a request comes in that will be best served using a primary that is in
|
||||
// the database but no longer cached, we know that it exists and can go get it (Useful when ICO
|
||||
// support is added).
|
||||
volatile boolean mInvalidated;
|
||||
volatile boolean invalidated;
|
||||
|
||||
final int mImageSize;
|
||||
final int imageSize;
|
||||
|
||||
// Used for LRU pruning.
|
||||
final FaviconsForURL mBackpointer;
|
||||
final FaviconsForURL backpointer;
|
||||
|
||||
public FaviconCacheElement(Bitmap payload, boolean isPrimary, int imageSize, FaviconsForURL backpointer) {
|
||||
mFaviconPayload = payload;
|
||||
mIsPrimary = isPrimary;
|
||||
mImageSize = imageSize;
|
||||
mBackpointer = backpointer;
|
||||
public FaviconCacheElement(Bitmap payload, boolean primary, int size, FaviconsForURL backpointer) {
|
||||
this.faviconPayload = payload;
|
||||
this.isPrimary = primary;
|
||||
this.imageSize = size;
|
||||
this.backpointer = backpointer;
|
||||
}
|
||||
|
||||
public FaviconCacheElement(Bitmap payload, boolean isPrimary, FaviconsForURL backpointer) {
|
||||
mFaviconPayload = payload;
|
||||
mIsPrimary = isPrimary;
|
||||
mBackpointer = backpointer;
|
||||
public FaviconCacheElement(Bitmap faviconPayload, boolean isPrimary, FaviconsForURL backpointer) {
|
||||
this.faviconPayload = faviconPayload;
|
||||
this.isPrimary = isPrimary;
|
||||
this.backpointer = backpointer;
|
||||
|
||||
if (payload != null) {
|
||||
mImageSize = payload.getWidth();
|
||||
if (faviconPayload != null) {
|
||||
imageSize = faviconPayload.getWidth();
|
||||
} else {
|
||||
mImageSize = 0;
|
||||
imageSize = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public int sizeOf() {
|
||||
if (mInvalidated) {
|
||||
if (invalidated) {
|
||||
return 0;
|
||||
}
|
||||
return mFaviconPayload.getRowBytes() * mFaviconPayload.getHeight();
|
||||
return faviconPayload.getRowBytes() * faviconPayload.getHeight();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -68,20 +68,20 @@ public class FaviconCacheElement implements Comparable<FaviconCacheElement> {
|
|||
*/
|
||||
@Override
|
||||
public int compareTo(FaviconCacheElement another) {
|
||||
if (mInvalidated && !another.mInvalidated) {
|
||||
if (invalidated && !another.invalidated) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!mInvalidated && another.mInvalidated) {
|
||||
if (!invalidated && another.invalidated) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (mInvalidated) {
|
||||
if (invalidated) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
final int w1 = mImageSize;
|
||||
final int w2 = another.mImageSize;
|
||||
final int w1 = imageSize;
|
||||
final int w2 = another.imageSize;
|
||||
if (w1 > w2) {
|
||||
return 1;
|
||||
} else if (w2 > w1) {
|
||||
|
@ -96,20 +96,20 @@ public class FaviconCacheElement implements Comparable<FaviconCacheElement> {
|
|||
* If primary, drop the payload and set invalid. If secondary, just unlink from parent node.
|
||||
*/
|
||||
public void onEvictedFromCache() {
|
||||
if (mIsPrimary) {
|
||||
if (isPrimary) {
|
||||
// So we keep a record of which primaries exist in the database for this URL, we
|
||||
// don't actually delete the entry for primaries. Instead, we delete their payload
|
||||
// and flag them as invalid. This way, we can later figure out that what a request
|
||||
// really want is one of the primaries that have been dropped from the cache, and we
|
||||
// can go get it.
|
||||
mInvalidated = true;
|
||||
mFaviconPayload = null;
|
||||
invalidated = true;
|
||||
faviconPayload = null;
|
||||
} else {
|
||||
// Secondaries don't matter - just delete them.
|
||||
if (mBackpointer == null) {
|
||||
if (backpointer == null) {
|
||||
return;
|
||||
}
|
||||
mBackpointer.mFavicons.remove(this);
|
||||
backpointer.favicons.remove(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,21 +14,21 @@ import java.util.Collections;
|
|||
public class FaviconsForURL {
|
||||
private static final String LOGTAG = "FaviconForURL";
|
||||
|
||||
private volatile int mDominantColor = -1;
|
||||
private volatile int dominantColor = -1;
|
||||
|
||||
final long mDownloadTimestamp;
|
||||
final ArrayList<FaviconCacheElement> mFavicons;
|
||||
final long downloadTimestamp;
|
||||
final ArrayList<FaviconCacheElement> favicons;
|
||||
|
||||
public final boolean mHasFailed;
|
||||
public final boolean hasFailed;
|
||||
|
||||
public FaviconsForURL(int size) {
|
||||
this(size, false);
|
||||
}
|
||||
|
||||
public FaviconsForURL(int size, boolean hasFailed) {
|
||||
mHasFailed = hasFailed;
|
||||
mDownloadTimestamp = System.currentTimeMillis();
|
||||
mFavicons = new ArrayList<FaviconCacheElement>(size);
|
||||
public FaviconsForURL(int size, boolean failed) {
|
||||
hasFailed = failed;
|
||||
downloadTimestamp = System.currentTimeMillis();
|
||||
favicons = new ArrayList<FaviconCacheElement>(size);
|
||||
}
|
||||
|
||||
public FaviconCacheElement addSecondary(Bitmap favicon, int imageSize) {
|
||||
|
@ -42,15 +42,19 @@ public class FaviconsForURL {
|
|||
private FaviconCacheElement addInternal(Bitmap favicon, boolean isPrimary, int imageSize) {
|
||||
FaviconCacheElement c = new FaviconCacheElement(favicon, isPrimary, imageSize, this);
|
||||
|
||||
int index = Collections.binarySearch(mFavicons, c);
|
||||
int index = Collections.binarySearch(favicons, c);
|
||||
|
||||
// We've already got an equivalent one. We don't care about this new one. This only occurs in certain obscure
|
||||
// case conditions.
|
||||
if (index >= 0) {
|
||||
return favicons.get(index);
|
||||
}
|
||||
|
||||
// binarySearch returns -x - 1 where x is the insertion point of the element. Convert
|
||||
// this to the actual insertion point..
|
||||
if (index < 0) {
|
||||
index++;
|
||||
index = -index;
|
||||
}
|
||||
mFavicons.add(index, c);
|
||||
index++;
|
||||
index = -index;
|
||||
favicons.add(index, c);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
@ -66,7 +70,7 @@ public class FaviconsForURL {
|
|||
// Create a dummy object to hold the target value for comparable.
|
||||
FaviconCacheElement dummy = new FaviconCacheElement(null, false, targetSize, null);
|
||||
|
||||
int index = Collections.binarySearch(mFavicons, dummy);
|
||||
int index = Collections.binarySearch(favicons, dummy);
|
||||
|
||||
// The search routine returns the index of an element equal to dummy, if present.
|
||||
// Otherwise, it returns -x - 1, where x is the index in the ArrayList where dummy would be
|
||||
|
@ -78,11 +82,11 @@ public class FaviconsForURL {
|
|||
|
||||
// index is now 'x', as described above.
|
||||
|
||||
// The routine will return mFavicons.size() as the index iff dummy is larger than all elements
|
||||
// The routine will return favicons.size() as the index iff dummy is larger than all elements
|
||||
// present (So the "index at which it should be inserted" is the index after the end.
|
||||
// In this case, we set the sentinel value -1 to indicate that we just requested something
|
||||
// larger than all primaries.
|
||||
if (index == mFavicons.size()) {
|
||||
if (index == favicons.size()) {
|
||||
index = -1;
|
||||
}
|
||||
|
||||
|
@ -97,19 +101,19 @@ public class FaviconsForURL {
|
|||
* primary at all (The input index may be a secondary which is larger than the actual available
|
||||
* primary.)
|
||||
*
|
||||
* @param fromIndex The index into mFavicons from which to start the search.
|
||||
* @param fromIndex The index into favicons from which to start the search.
|
||||
* @return The FaviconCacheElement of the next valid primary from the given index. If none exists,
|
||||
* then returns the previous valid primary. If none exists, returns null (Insanity.).
|
||||
*/
|
||||
public FaviconCacheElement getNextPrimary(final int fromIndex) {
|
||||
final int numIcons = mFavicons.size();
|
||||
final int numIcons = favicons.size();
|
||||
|
||||
int searchIndex = fromIndex;
|
||||
while (searchIndex < numIcons) {
|
||||
FaviconCacheElement element = mFavicons.get(searchIndex);
|
||||
FaviconCacheElement element = favicons.get(searchIndex);
|
||||
|
||||
if (element.mIsPrimary) {
|
||||
if (element.mInvalidated) {
|
||||
if (element.isPrimary) {
|
||||
if (element.invalidated) {
|
||||
// We return null here, despite the possible existence of other primaries,
|
||||
// because we know the most suitable primary for this request exists, but is
|
||||
// no longer in the cache. By returning null, we cause the caller to load the
|
||||
|
@ -124,10 +128,10 @@ public class FaviconsForURL {
|
|||
// No larger primary available. Let's look for smaller ones...
|
||||
searchIndex = fromIndex - 1;
|
||||
while (searchIndex >= 0) {
|
||||
FaviconCacheElement element = mFavicons.get(searchIndex);
|
||||
FaviconCacheElement element = favicons.get(searchIndex);
|
||||
|
||||
if (element.mIsPrimary) {
|
||||
if (element.mInvalidated) {
|
||||
if (element.isPrimary) {
|
||||
if (element.invalidated) {
|
||||
return null;
|
||||
}
|
||||
return element;
|
||||
|
@ -144,17 +148,17 @@ public class FaviconsForURL {
|
|||
* Ensure the dominant colour field is populated for this favicon.
|
||||
*/
|
||||
public int ensureDominantColor() {
|
||||
if (mDominantColor == -1) {
|
||||
if (dominantColor == -1) {
|
||||
// Find a payload, any payload, that is not invalidated.
|
||||
for (FaviconCacheElement element : mFavicons) {
|
||||
if (!element.mInvalidated) {
|
||||
mDominantColor = BitmapUtils.getDominantColor(element.mFaviconPayload);
|
||||
return mDominantColor;
|
||||
for (FaviconCacheElement element : favicons) {
|
||||
if (!element.invalidated) {
|
||||
dominantColor = BitmapUtils.getDominantColor(element.faviconPayload);
|
||||
return dominantColor;
|
||||
}
|
||||
}
|
||||
mDominantColor = 0xFFFFFF;
|
||||
dominantColor = 0xFFFFFF;
|
||||
}
|
||||
|
||||
return mDominantColor;
|
||||
return dominantColor;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -89,14 +89,14 @@ public class FaviconDecoder {
|
|||
LoadFaviconResult result;
|
||||
if (isDecodableByAndroid(buffer, offset)) {
|
||||
result = new LoadFaviconResult();
|
||||
result.mOffset = offset;
|
||||
result.mLength = length;
|
||||
result.mIsICO = false;
|
||||
result.offset = offset;
|
||||
result.length = length;
|
||||
result.isICO = false;
|
||||
|
||||
// We assume here that decodeByteArray doesn't hold on to the entire supplied
|
||||
// buffer -- worst case, each of our buffers will be twice the necessary size.
|
||||
result.mBitmapsDecoded = new SingleBitmapIterator(BitmapUtils.decodeByteArray(buffer, offset, length));
|
||||
result.mFaviconBytes = buffer;
|
||||
result.bitmapsDecoded = new SingleBitmapIterator(BitmapUtils.decodeByteArray(buffer, offset, length));
|
||||
result.faviconBytes = buffer;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -193,10 +193,10 @@ public class FaviconDecoder {
|
|||
* Iterator to hold a single bitmap.
|
||||
*/
|
||||
static class SingleBitmapIterator implements Iterator<Bitmap> {
|
||||
private Bitmap mBitmap;
|
||||
private Bitmap bitmap;
|
||||
|
||||
public SingleBitmapIterator(Bitmap b) {
|
||||
mBitmap = b;
|
||||
bitmap = b;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -207,22 +207,22 @@ public class FaviconDecoder {
|
|||
* @return The bitmap carried by this SingleBitmapIterator.
|
||||
*/
|
||||
public Bitmap peek() {
|
||||
return mBitmap;
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return mBitmap != null;
|
||||
return bitmap != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bitmap next() {
|
||||
if (mBitmap == null) {
|
||||
if (bitmap == null) {
|
||||
throw new NoSuchElementException("Element already returned from SingleBitmapIterator.");
|
||||
}
|
||||
|
||||
Bitmap ret = mBitmap;
|
||||
mBitmap = null;
|
||||
Bitmap ret = bitmap;
|
||||
bitmap = null;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -10,7 +10,6 @@ import org.mozilla.gecko.gfx.BitmapUtils;
|
|||
|
||||
import android.util.SparseArray;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
|
@ -79,55 +78,55 @@ public class ICODecoder implements Iterable<Bitmap> {
|
|||
public static final int ICO_ICONDIRENTRY_LENGTH_BYTES = 16;
|
||||
|
||||
// The buffer containing bytes to attempt to decode.
|
||||
private byte[] mDecodand;
|
||||
private byte[] decodand;
|
||||
|
||||
// The region of the decodand to decode.
|
||||
private int mOffset;
|
||||
private int mLen;
|
||||
private int offset;
|
||||
private int len;
|
||||
|
||||
private IconDirectoryEntry[] mIconDirectory;
|
||||
private boolean mIsValid;
|
||||
private boolean mHasDecoded;
|
||||
private IconDirectoryEntry[] iconDirectory;
|
||||
private boolean isValid;
|
||||
private boolean hasDecoded;
|
||||
|
||||
public ICODecoder(byte[] buffer, int offset, int len) {
|
||||
mDecodand = buffer;
|
||||
mOffset = offset;
|
||||
mLen = len;
|
||||
public ICODecoder(byte[] decodand, int offset, int len) {
|
||||
this.decodand = decodand;
|
||||
this.offset = offset;
|
||||
this.len = len;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode the Icon Directory for this ICO and store the result in mIconDirectory.
|
||||
* Decode the Icon Directory for this ICO and store the result in iconDirectory.
|
||||
*
|
||||
* @return true if ICO decoding was considered to probably be a success, false if it certainly
|
||||
* was a failure.
|
||||
*/
|
||||
private boolean decodeIconDirectoryAndPossiblyPrune() {
|
||||
mHasDecoded = true;
|
||||
hasDecoded = true;
|
||||
|
||||
// Fail if the end of the described range is out of bounds.
|
||||
if (mOffset + mLen > mDecodand.length) {
|
||||
if (offset + len > decodand.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Fail if we don't have enough space for the header.
|
||||
if (mLen < ICO_HEADER_LENGTH_BYTES) {
|
||||
if (len < ICO_HEADER_LENGTH_BYTES) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check that the reserved fields in the header are indeed zero, and that the type field
|
||||
// specifies ICO. If not, we've probably been given something that isn't really an ICO.
|
||||
if (mDecodand[mOffset] != 0 ||
|
||||
mDecodand[mOffset + 1] != 0 ||
|
||||
mDecodand[mOffset + 2] != 1 ||
|
||||
mDecodand[mOffset + 3] != 0) {
|
||||
if (decodand[offset] != 0 ||
|
||||
decodand[offset + 1] != 0 ||
|
||||
decodand[offset + 2] != 1 ||
|
||||
decodand[offset + 3] != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Here, and in many other places, byte values are ANDed with 0xFF. This is because Java
|
||||
// bytes are signed - to obtain a numerical value of a longer type which holds the unsigned
|
||||
// interpretation of the byte of interest, we do this.
|
||||
int numEncodedImages = (mDecodand[mOffset + 4] & 0xFF) |
|
||||
(mDecodand[mOffset + 5] & 0xFF) << 8;
|
||||
int numEncodedImages = (decodand[offset + 4] & 0xFF) |
|
||||
(decodand[offset + 5] & 0xFF) << 8;
|
||||
|
||||
|
||||
// Fail if there are no images or the field is corrupt.
|
||||
|
@ -139,12 +138,12 @@ public class ICODecoder implements Iterable<Bitmap> {
|
|||
|
||||
// Fail if there is not enough space in the buffer for the stated number of icondir entries,
|
||||
// let alone the data.
|
||||
if (mLen < headerAndDirectorySize) {
|
||||
if (len < headerAndDirectorySize) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Put the pointer on the first byte of the first Icon Directory Entry.
|
||||
int bufferIndex = mOffset + ICO_HEADER_LENGTH_BYTES;
|
||||
int bufferIndex = offset + ICO_HEADER_LENGTH_BYTES;
|
||||
|
||||
// We now iterate over the Icon Directory, decoding each entry as we go. We also need to
|
||||
// discard all entries except one >= the maximum interesting size.
|
||||
|
@ -157,35 +156,35 @@ public class ICODecoder implements Iterable<Bitmap> {
|
|||
|
||||
for (int i = 0; i < numEncodedImages; i++, bufferIndex += ICO_ICONDIRENTRY_LENGTH_BYTES) {
|
||||
// Decode the Icon Directory Entry at this offset.
|
||||
IconDirectoryEntry newEntry = IconDirectoryEntry.createFromBuffer(mDecodand, mOffset, mLen, bufferIndex);
|
||||
newEntry.mIndex = i;
|
||||
IconDirectoryEntry newEntry = IconDirectoryEntry.createFromBuffer(decodand, offset, len, bufferIndex);
|
||||
newEntry.index = i;
|
||||
|
||||
if (newEntry.mIsErroneous) {
|
||||
if (newEntry.isErroneous) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (newEntry.mWidth > Favicons.sLargestFaviconSize) {
|
||||
if (newEntry.width > Favicons.largestFaviconSize) {
|
||||
// If we already have a smaller image larger than the maximum size of interest, we
|
||||
// don't care about the new one which is larger than the smallest image larger than
|
||||
// the maximum size.
|
||||
if (newEntry.mWidth >= minimumMaximum) {
|
||||
if (newEntry.width >= minimumMaximum) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Remove the previous minimum-maximum.
|
||||
preferenceArray.delete(minimumMaximum);
|
||||
|
||||
minimumMaximum = newEntry.mWidth;
|
||||
minimumMaximum = newEntry.width;
|
||||
}
|
||||
|
||||
IconDirectoryEntry oldEntry = preferenceArray.get(newEntry.mWidth);
|
||||
IconDirectoryEntry oldEntry = preferenceArray.get(newEntry.width);
|
||||
if (oldEntry == null) {
|
||||
preferenceArray.put(newEntry.mWidth, newEntry);
|
||||
preferenceArray.put(newEntry.width, newEntry);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (oldEntry.compareTo(newEntry) < 0) {
|
||||
preferenceArray.put(newEntry.mWidth, newEntry);
|
||||
preferenceArray.put(newEntry.width, newEntry);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -197,24 +196,24 @@ public class ICODecoder implements Iterable<Bitmap> {
|
|||
}
|
||||
|
||||
// Allocate space for the icon directory entries in the decoded directory.
|
||||
mIconDirectory = new IconDirectoryEntry[count];
|
||||
iconDirectory = new IconDirectoryEntry[count];
|
||||
|
||||
// The size of the data in the buffer that we find useful.
|
||||
int retainedSpace = ICO_HEADER_LENGTH_BYTES;
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
IconDirectoryEntry e = preferenceArray.valueAt(i);
|
||||
retainedSpace += ICO_ICONDIRENTRY_LENGTH_BYTES + e.mPayloadSize;
|
||||
mIconDirectory[i] = e;
|
||||
retainedSpace += ICO_ICONDIRENTRY_LENGTH_BYTES + e.payloadSize;
|
||||
iconDirectory[i] = e;
|
||||
}
|
||||
|
||||
mIsValid = true;
|
||||
isValid = true;
|
||||
|
||||
// Set the number of images field in the buffer to reflect the number of retained entries.
|
||||
mDecodand[mOffset + 4] = (byte) mIconDirectory.length;
|
||||
mDecodand[mOffset + 5] = (byte) (mIconDirectory.length >>> 8);
|
||||
decodand[offset + 4] = (byte) iconDirectory.length;
|
||||
decodand[offset + 5] = (byte) (iconDirectory.length >>> 8);
|
||||
|
||||
if ((mLen - retainedSpace) > COMPACT_THRESHOLD) {
|
||||
if ((len - retainedSpace) > COMPACT_THRESHOLD) {
|
||||
compactingCopy(retainedSpace);
|
||||
}
|
||||
|
||||
|
@ -228,19 +227,19 @@ public class ICODecoder implements Iterable<Bitmap> {
|
|||
byte[] buf = new byte[spaceRetained];
|
||||
|
||||
// Copy the header.
|
||||
System.arraycopy(mDecodand, mOffset, buf, 0, ICO_HEADER_LENGTH_BYTES);
|
||||
System.arraycopy(decodand, offset, buf, 0, ICO_HEADER_LENGTH_BYTES);
|
||||
|
||||
int headerPtr = ICO_HEADER_LENGTH_BYTES;
|
||||
|
||||
int payloadPtr = ICO_HEADER_LENGTH_BYTES + (mIconDirectory.length * ICO_ICONDIRENTRY_LENGTH_BYTES);
|
||||
int payloadPtr = ICO_HEADER_LENGTH_BYTES + (iconDirectory.length * ICO_ICONDIRENTRY_LENGTH_BYTES);
|
||||
|
||||
int ind = 0;
|
||||
for (IconDirectoryEntry entry : mIconDirectory) {
|
||||
for (IconDirectoryEntry entry : iconDirectory) {
|
||||
// Copy this entry.
|
||||
System.arraycopy(mDecodand, mOffset + entry.getOffset(), buf, headerPtr, ICO_ICONDIRENTRY_LENGTH_BYTES);
|
||||
System.arraycopy(decodand, offset + entry.getOffset(), buf, headerPtr, ICO_ICONDIRENTRY_LENGTH_BYTES);
|
||||
|
||||
// Copy its payload.
|
||||
System.arraycopy(mDecodand, mOffset + entry.mPayloadOffset, buf, payloadPtr, entry.mPayloadSize);
|
||||
System.arraycopy(decodand, offset + entry.payloadOffset, buf, payloadPtr, entry.payloadSize);
|
||||
|
||||
// Update the offset field.
|
||||
buf[headerPtr + 12] = (byte) payloadPtr;
|
||||
|
@ -248,17 +247,17 @@ public class ICODecoder implements Iterable<Bitmap> {
|
|||
buf[headerPtr + 14] = (byte) (payloadPtr >>> 16);
|
||||
buf[headerPtr + 15] = (byte) (payloadPtr >>> 24);
|
||||
|
||||
entry.mPayloadOffset = payloadPtr;
|
||||
entry.mIndex = ind;
|
||||
entry.payloadOffset = payloadPtr;
|
||||
entry.index = ind;
|
||||
|
||||
payloadPtr += entry.mPayloadSize;
|
||||
payloadPtr += entry.payloadSize;
|
||||
headerPtr += ICO_ICONDIRENTRY_LENGTH_BYTES;
|
||||
ind++;
|
||||
}
|
||||
|
||||
mDecodand = buf;
|
||||
mOffset = 0;
|
||||
mLen = spaceRetained;
|
||||
decodand = buf;
|
||||
offset = 0;
|
||||
len = spaceRetained;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -269,16 +268,16 @@ public class ICODecoder implements Iterable<Bitmap> {
|
|||
* fails.
|
||||
*/
|
||||
public Bitmap decodeBitmapAtIndex(int index) {
|
||||
final IconDirectoryEntry iconDirEntry = mIconDirectory[index];
|
||||
final IconDirectoryEntry iconDirEntry = iconDirectory[index];
|
||||
|
||||
if (iconDirEntry.mPayloadIsPNG) {
|
||||
if (iconDirEntry.payloadIsPNG) {
|
||||
// PNG payload. Simply extract it and decode it.
|
||||
return BitmapUtils.decodeByteArray(mDecodand, mOffset + iconDirEntry.mPayloadOffset, iconDirEntry.mPayloadSize);
|
||||
return BitmapUtils.decodeByteArray(decodand, offset + iconDirEntry.payloadOffset, iconDirEntry.payloadSize);
|
||||
}
|
||||
|
||||
// The payload is a BMP, so we need to do some magic to get the decoder to do what we want.
|
||||
// We construct an ICO containing just the image we want, and let Android do the rest.
|
||||
byte[] decodeTarget = new byte[ICO_HEADER_LENGTH_BYTES + ICO_ICONDIRENTRY_LENGTH_BYTES + iconDirEntry.mPayloadSize];
|
||||
byte[] decodeTarget = new byte[ICO_HEADER_LENGTH_BYTES + ICO_ICONDIRENTRY_LENGTH_BYTES + iconDirEntry.payloadSize];
|
||||
|
||||
// Set the type field in the ICO header.
|
||||
decodeTarget[2] = 1;
|
||||
|
@ -287,11 +286,11 @@ public class ICODecoder implements Iterable<Bitmap> {
|
|||
decodeTarget[4] = 1;
|
||||
|
||||
// Copy the ICONDIRENTRY we need into the new buffer.
|
||||
System.arraycopy(mDecodand, mOffset + iconDirEntry.getOffset(), decodeTarget, ICO_HEADER_LENGTH_BYTES, ICO_ICONDIRENTRY_LENGTH_BYTES);
|
||||
System.arraycopy(decodand, offset + iconDirEntry.getOffset(), decodeTarget, ICO_HEADER_LENGTH_BYTES, ICO_ICONDIRENTRY_LENGTH_BYTES);
|
||||
|
||||
// Copy the payload into the new buffer.
|
||||
final int singlePayloadOffset = ICO_HEADER_LENGTH_BYTES + ICO_ICONDIRENTRY_LENGTH_BYTES;
|
||||
System.arraycopy(mDecodand, mOffset + iconDirEntry.mPayloadOffset, decodeTarget, singlePayloadOffset, iconDirEntry.mPayloadSize);
|
||||
System.arraycopy(decodand, offset + iconDirEntry.payloadOffset, decodeTarget, singlePayloadOffset, iconDirEntry.payloadSize);
|
||||
|
||||
// Update the offset field of the ICONDIRENTRY to make the new ICO valid.
|
||||
decodeTarget[ICO_HEADER_LENGTH_BYTES + 12] = (byte) singlePayloadOffset;
|
||||
|
@ -311,12 +310,12 @@ public class ICODecoder implements Iterable<Bitmap> {
|
|||
@Override
|
||||
public ICOIterator iterator() {
|
||||
// If a previous call to decode concluded this ICO is invalid, abort.
|
||||
if (mHasDecoded && !mIsValid) {
|
||||
if (hasDecoded && !isValid) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// If we've not been decoded before, but now fail to make any sense of the ICO, abort.
|
||||
if (!mHasDecoded) {
|
||||
if (!hasDecoded) {
|
||||
if (!decodeIconDirectoryAndPossiblyPrune()) {
|
||||
return null;
|
||||
}
|
||||
|
@ -339,11 +338,11 @@ public class ICODecoder implements Iterable<Bitmap> {
|
|||
|
||||
LoadFaviconResult result = new LoadFaviconResult();
|
||||
|
||||
result.mBitmapsDecoded = bitmaps;
|
||||
result.mFaviconBytes = mDecodand;
|
||||
result.mOffset = mOffset;
|
||||
result.mLength = mLen;
|
||||
result.mIsICO = true;
|
||||
result.bitmapsDecoded = bitmaps;
|
||||
result.faviconBytes = decodand;
|
||||
result.offset = offset;
|
||||
result.length = len;
|
||||
result.isICO = true;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -356,12 +355,12 @@ public class ICODecoder implements Iterable<Bitmap> {
|
|||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return mIndex < mIconDirectory.length;
|
||||
return mIndex < iconDirectory.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bitmap next() {
|
||||
if (mIndex > mIconDirectory.length) {
|
||||
if (mIndex > iconDirectory.length) {
|
||||
throw new NoSuchElementException("No more elements in this ICO.");
|
||||
}
|
||||
return decodeBitmapAtIndex(mIndex++);
|
||||
|
@ -369,10 +368,10 @@ public class ICODecoder implements Iterable<Bitmap> {
|
|||
|
||||
@Override
|
||||
public void remove() {
|
||||
if (mIconDirectory[mIndex] == null) {
|
||||
if (iconDirectory[mIndex] == null) {
|
||||
throw new IllegalStateException("Remove already called for element " + mIndex);
|
||||
}
|
||||
mIconDirectory[mIndex] = null;
|
||||
iconDirectory[mIndex] = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,28 +9,28 @@ package org.mozilla.gecko.favicons.decoders;
|
|||
*/
|
||||
public class IconDirectoryEntry implements Comparable<IconDirectoryEntry> {
|
||||
|
||||
public static int sMaxBPP;
|
||||
public static int maxBPP;
|
||||
|
||||
int mWidth;
|
||||
int mHeight;
|
||||
int mPaletteSize;
|
||||
int mBitsPerPixel;
|
||||
int mPayloadSize;
|
||||
int mPayloadOffset;
|
||||
boolean mPayloadIsPNG;
|
||||
int width;
|
||||
int height;
|
||||
int paletteSize;
|
||||
int bitsPerPixel;
|
||||
int payloadSize;
|
||||
int payloadOffset;
|
||||
boolean payloadIsPNG;
|
||||
|
||||
// Tracks the index in the Icon Directory of this entry. Useful only for pruning.
|
||||
int mIndex;
|
||||
boolean mIsErroneous;
|
||||
int index;
|
||||
boolean isErroneous;
|
||||
|
||||
public IconDirectoryEntry(int width, int height, int paletteSize, int bitsPerPixel, int payloadSize, int payloadOffset, boolean payloadIsPNG) {
|
||||
mWidth = width;
|
||||
mHeight = height;
|
||||
mPaletteSize = paletteSize;
|
||||
mBitsPerPixel = bitsPerPixel;
|
||||
mPayloadSize = payloadSize;
|
||||
mPayloadOffset = payloadOffset;
|
||||
mPayloadIsPNG = payloadIsPNG;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.paletteSize = paletteSize;
|
||||
this.bitsPerPixel = bitsPerPixel;
|
||||
this.payloadSize = payloadSize;
|
||||
this.payloadOffset = payloadOffset;
|
||||
this.payloadIsPNG = payloadIsPNG;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -40,7 +40,7 @@ public class IconDirectoryEntry implements Comparable<IconDirectoryEntry> {
|
|||
*/
|
||||
public static IconDirectoryEntry getErroneousEntry() {
|
||||
IconDirectoryEntry ret = new IconDirectoryEntry(-1, -1, -1, -1, -1, -1, false);
|
||||
ret.mIsErroneous = true;
|
||||
ret.isErroneous = true;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -118,63 +118,63 @@ public class IconDirectoryEntry implements Comparable<IconDirectoryEntry> {
|
|||
* Get the number of bytes from the start of the ICO file to the beginning of this entry.
|
||||
*/
|
||||
public int getOffset() {
|
||||
return ICODecoder.ICO_HEADER_LENGTH_BYTES + (mIndex * ICODecoder.ICO_ICONDIRENTRY_LENGTH_BYTES);
|
||||
return ICODecoder.ICO_HEADER_LENGTH_BYTES + (index * ICODecoder.ICO_ICONDIRENTRY_LENGTH_BYTES);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(IconDirectoryEntry another) {
|
||||
if (mWidth > another.mWidth) {
|
||||
if (width > another.width) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (mWidth < another.mWidth) {
|
||||
if (width < another.width) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Where both images exceed the max BPP, take the smaller of the two BPP values.
|
||||
if (mBitsPerPixel >= sMaxBPP && another.mBitsPerPixel >= sMaxBPP) {
|
||||
if (mBitsPerPixel < another.mBitsPerPixel) {
|
||||
if (bitsPerPixel >= maxBPP && another.bitsPerPixel >= maxBPP) {
|
||||
if (bitsPerPixel < another.bitsPerPixel) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (mBitsPerPixel > another.mBitsPerPixel) {
|
||||
if (bitsPerPixel > another.bitsPerPixel) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise, take the larger of the BPP values.
|
||||
if (mBitsPerPixel > another.mBitsPerPixel) {
|
||||
if (bitsPerPixel > another.bitsPerPixel) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (mBitsPerPixel < another.mBitsPerPixel) {
|
||||
if (bitsPerPixel < another.bitsPerPixel) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Prefer large palettes.
|
||||
if (mPaletteSize > another.mPaletteSize) {
|
||||
if (paletteSize > another.paletteSize) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (mPaletteSize < another.mPaletteSize) {
|
||||
if (paletteSize < another.paletteSize) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Prefer smaller payloads.
|
||||
if (mPayloadSize < another.mPayloadSize) {
|
||||
if (payloadSize < another.payloadSize) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (mPayloadSize > another.mPayloadSize) {
|
||||
if (payloadSize > another.payloadSize) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// If all else fails, prefer PNGs over BMPs. They tend to be smaller.
|
||||
if (mPayloadIsPNG && !another.mPayloadIsPNG) {
|
||||
if (payloadIsPNG && !another.payloadIsPNG) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!mPayloadIsPNG && another.mPayloadIsPNG) {
|
||||
if (!payloadIsPNG && another.payloadIsPNG) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -182,20 +182,20 @@ public class IconDirectoryEntry implements Comparable<IconDirectoryEntry> {
|
|||
}
|
||||
|
||||
public static void setMaxBPP(int maxBPP) {
|
||||
sMaxBPP = maxBPP;
|
||||
IconDirectoryEntry.maxBPP = maxBPP;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "IconDirectoryEntry{" +
|
||||
"\nmWidth=" + mWidth +
|
||||
", \nmHeight=" + mHeight +
|
||||
", \nmPaletteSize=" + mPaletteSize +
|
||||
", \nmBitsPerPixel=" + mBitsPerPixel +
|
||||
", \nmPayloadSize=" + mPayloadSize +
|
||||
", \nmPayloadOffset=" + mPayloadOffset +
|
||||
", \nmPayloadIsPNG=" + mPayloadIsPNG +
|
||||
", \nmIndex=" + mIndex +
|
||||
"\nwidth=" + width +
|
||||
", \nheight=" + height +
|
||||
", \npaletteSize=" + paletteSize +
|
||||
", \nbitsPerPixel=" + bitsPerPixel +
|
||||
", \npayloadSize=" + payloadSize +
|
||||
", \npayloadOffset=" + payloadOffset +
|
||||
", \npayloadIsPNG=" + payloadIsPNG +
|
||||
", \nindex=" + index +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,15 +21,15 @@ import java.util.Iterator;
|
|||
public class LoadFaviconResult {
|
||||
private static final String LOGTAG = "LoadFaviconResult";
|
||||
|
||||
byte[] mFaviconBytes;
|
||||
int mOffset;
|
||||
int mLength;
|
||||
byte[] faviconBytes;
|
||||
int offset;
|
||||
int length;
|
||||
|
||||
boolean mIsICO;
|
||||
Iterator<Bitmap> mBitmapsDecoded;
|
||||
boolean isICO;
|
||||
Iterator<Bitmap> bitmapsDecoded;
|
||||
|
||||
public Iterator<Bitmap> getBitmaps() {
|
||||
return mBitmapsDecoded;
|
||||
return bitmapsDecoded;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -40,17 +40,17 @@ public class LoadFaviconResult {
|
|||
*/
|
||||
public byte[] getBytesForDatabaseStorage() {
|
||||
// Begin by normalising the buffer.
|
||||
if (mOffset != 0 || mLength != mFaviconBytes.length) {
|
||||
final byte[] normalised = new byte[mLength];
|
||||
System.arraycopy(mFaviconBytes, mOffset, normalised, 0, mLength);
|
||||
mOffset = 0;
|
||||
mFaviconBytes = normalised;
|
||||
if (offset != 0 || length != faviconBytes.length) {
|
||||
final byte[] normalised = new byte[length];
|
||||
System.arraycopy(faviconBytes, offset, normalised, 0, length);
|
||||
offset = 0;
|
||||
faviconBytes = normalised;
|
||||
}
|
||||
|
||||
// For results containing a single image, we re-encode the result as a PNG in an effort to
|
||||
// save space.
|
||||
if (!mIsICO) {
|
||||
Bitmap favicon = ((FaviconDecoder.SingleBitmapIterator) mBitmapsDecoded).peek();
|
||||
if (!isICO) {
|
||||
Bitmap favicon = ((FaviconDecoder.SingleBitmapIterator) bitmapsDecoded).peek();
|
||||
byte[] data = null;
|
||||
ByteArrayOutputStream stream = new ByteArrayOutputStream();
|
||||
|
||||
|
@ -68,7 +68,7 @@ public class LoadFaviconResult {
|
|||
// We may instead want to consider re-encoding the entire ICO as a collection of efficiently
|
||||
// encoded PNGs. This may not be worth the CPU time (Indeed, the encoding of single-image
|
||||
// favicons may also not be worth the time/space tradeoff.).
|
||||
return mFaviconBytes;
|
||||
return faviconBytes;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -568,7 +568,7 @@ public class BrowserSearch extends HomeFragment
|
|||
mSuggestionsOptInPrompt = ((ViewStub) mView.findViewById(R.id.suggestions_opt_in_prompt)).inflate();
|
||||
|
||||
TextView promptText = (TextView) mSuggestionsOptInPrompt.findViewById(R.id.suggestions_prompt_title);
|
||||
promptText.setText(getResources().getString(R.string.suggestions_prompt, mSearchEngines.get(0).name));
|
||||
promptText.setText(getResources().getString(R.string.suggestions_prompt));
|
||||
|
||||
final View yesButton = mSuggestionsOptInPrompt.findViewById(R.id.suggestions_prompt_yes);
|
||||
final View noButton = mSuggestionsOptInPrompt.findViewById(R.id.suggestions_prompt_no);
|
||||
|
|
|
@ -378,9 +378,7 @@ just addresses the organization to follow, e.g. "This site is run by " -->
|
|||
from Android">
|
||||
<!ENTITY bookmarkhistory_import_wait "Please wait...">
|
||||
|
||||
<!-- Localization note (suggestions_prompt2): The placeholder &formatS; will be
|
||||
replaced with the name of the search engine. -->
|
||||
<!ENTITY suggestions_prompt2 "Would you like to turn on &formatS; search suggestions?">
|
||||
<!ENTITY suggestions_prompt3 "Would you like to turn on search suggestions?">
|
||||
|
||||
<!-- Localization note (suggestion_for_engine): The placeholder &formatS1; will be
|
||||
replaced with the name of the search engine. The placeholder &formatS2; will be
|
||||
|
|
|
@ -133,13 +133,13 @@ public class SearchEnginePreference extends CustomListPreference {
|
|||
if (mFaviconView != null) {
|
||||
desiredWidth = mFaviconView.getWidth();
|
||||
} else {
|
||||
// sLargestFaviconSize is initialized when Favicons is attached to a
|
||||
// largestFaviconSize is initialized when Favicons is attached to a
|
||||
// context, which occurs during GeckoApp.onCreate. That might not
|
||||
// ever happen (leaving it at 0), so we fall back.
|
||||
if (Favicons.sLargestFaviconSize == 0) {
|
||||
if (Favicons.largestFaviconSize == 0) {
|
||||
desiredWidth = 128;
|
||||
} else {
|
||||
desiredWidth = Favicons.sLargestFaviconSize;
|
||||
desiredWidth = Favicons.largestFaviconSize;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -370,7 +370,7 @@
|
|||
<string name="updater_apply_select">&updater_apply_select2;</string>
|
||||
|
||||
<!-- Search suggestions opt-in -->
|
||||
<string name="suggestions_prompt">&suggestions_prompt2;</string>
|
||||
<string name="suggestions_prompt">&suggestions_prompt3;</string>
|
||||
|
||||
<string name="suggestion_for_engine">&suggestion_for_engine;</string>
|
||||
|
||||
|
|
|
@ -70,8 +70,6 @@ skip-if = processor == "x86"
|
|||
[testPasswordProvider]
|
||||
# [testPermissions] # see bug 757475
|
||||
[testPictureLinkContextMenu]
|
||||
# disabled on Android 2.3; bug 979612
|
||||
skip-if = android_version == "10"
|
||||
[testPrefsObserver]
|
||||
[testPrivateBrowsing]
|
||||
[testPromptGridInput]
|
||||
|
|
|
@ -13,6 +13,7 @@ Cu.import("resource://gre/modules/Task.jsm");
|
|||
|
||||
const TEST_DATASET_ID = "test-dataset-id";
|
||||
const TEST_URL = "http://test.com";
|
||||
const TEST_TITLE = "Test";
|
||||
|
||||
const PREF_SYNC_CHECK_INTERVAL_SECS = "home.sync.checkIntervalSecs";
|
||||
const TEST_INTERVAL_SECS = 1;
|
||||
|
@ -47,7 +48,7 @@ add_test(function test_periodic_sync() {
|
|||
add_task(function test_save_and_delete() {
|
||||
// Use the HomeProvider API to save some data.
|
||||
let storage = HomeProvider.getStorage(TEST_DATASET_ID);
|
||||
yield storage.save([{ url: TEST_URL }]);
|
||||
yield storage.save([{ title: TEST_TITLE, url: TEST_URL }]);
|
||||
|
||||
// Peek in the DB to make sure we have the right data.
|
||||
let db = yield Sqlite.openConnection({ path: DB_PATH });
|
||||
|
@ -71,4 +72,61 @@ add_task(function test_save_and_delete() {
|
|||
db.close();
|
||||
});
|
||||
|
||||
add_task(function test_row_validation() {
|
||||
// Use the HomeProvider API to save some data.
|
||||
let storage = HomeProvider.getStorage(TEST_DATASET_ID);
|
||||
|
||||
let invalidRows = [
|
||||
{ url: "url" },
|
||||
{ title: "title" },
|
||||
{ description: "description" },
|
||||
{ image_url: "image_url" }
|
||||
];
|
||||
|
||||
// None of these save calls should save anything
|
||||
for (let row of invalidRows) {
|
||||
try {
|
||||
yield storage.save([row]);
|
||||
} catch (e if e instanceof HomeProvider.ValidationError) {
|
||||
// Just catch and ignore validation errors
|
||||
}
|
||||
}
|
||||
|
||||
// Peek in the DB to make sure we have the right data.
|
||||
let db = yield Sqlite.openConnection({ path: DB_PATH });
|
||||
|
||||
// Make sure no data has been saved.
|
||||
let result = yield db.execute("SELECT * FROM items");
|
||||
do_check_eq(result.length, 0);
|
||||
|
||||
db.close();
|
||||
});
|
||||
|
||||
add_task(function test_save_transaction() {
|
||||
// Use the HomeProvider API to save some data.
|
||||
let storage = HomeProvider.getStorage(TEST_DATASET_ID);
|
||||
|
||||
// One valid, one invalid
|
||||
let rows = [
|
||||
{ title: TEST_TITLE, url: TEST_URL },
|
||||
{ image_url: "image_url" }
|
||||
];
|
||||
|
||||
// Try to save all the rows at once
|
||||
try {
|
||||
yield storage.save(rows);
|
||||
} catch (e if e instanceof HomeProvider.ValidationError) {
|
||||
// Just catch and ignore validation errors
|
||||
}
|
||||
|
||||
// Peek in the DB to make sure we have the right data.
|
||||
let db = yield Sqlite.openConnection({ path: DB_PATH });
|
||||
|
||||
// Make sure no data has been saved.
|
||||
let result = yield db.execute("SELECT * FROM items");
|
||||
do_check_eq(result.length, 0);
|
||||
|
||||
db.close();
|
||||
});
|
||||
|
||||
run_next_test();
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче