Compare commits

...
Author SHA1 Message Date
wolfbeast 8ee235ca5d Version bump for minor bugfix release. 2018-08-30 16:59:46 +02:00
wolfbeast cc54bbe952 Revert "Bug 1388020. r=nical, a=RyanVM"
This reverts commit e7189e33f5.
2018-08-30 12:36:03 +02:00
wolfbeast 73b202b1e5 Revert "Bug 1444668 - Avoid allocating large AssemblerBuffers. r=luke, r=bbouvier, a=RyanVM"
This reverts commit 9472136272.
2018-08-30 12:33:56 +02:00
wolfbeast 21042963de Version bump for win rebuild with less aggressive build config. 2018-08-26 17:44:06 +02:00
wolfbeast d443656df5 Version bump for release builds. 2018-08-07 14:20:47 +02:00
Matt A. Tobin 29a8db7280 Fix include path 2018-08-06 18:02:27 +02:00
Matt A. Tobin daa52eef9a Add a slightly modified version of the gecko/44 search service and use it when building Pale Moon 2018-08-06 18:02:10 +02:00
Matt A. Tobin 95ce1f0d63 Move the "native" search service to a subdirectory 2018-08-06 18:01:49 +02:00
SpockMan02 4dadef2740 Restore some osx icons 2018-08-06 11:12:29 +02:00
SpockMan02 b5d8e6d28f Revert osx editBookmarkOverlay.css to osx version 2018-08-06 11:12:16 +02:00
adeshkp fc0477a98e Fix constructor in nsHtml5AtomTable.cpp
Follow up to 2bc00ef to fix build bustage
2018-08-06 11:10:24 +02:00
adeshkp 36d06b9e75 Improve nsHtml5AtomTable performance (#693)
* cpp change
* h change
2018-08-06 11:10:10 +02:00
wolfbeast 51bdd3efbc Make AC option for devtools (client) an enable_bool to align with the default. 2018-08-04 08:21:29 +02:00
janekptacijarabaci bc2584493a [PALEMOON] Bug 863773 - Changes the way plugin handlers are loaded at the preferences applications pane. Uses enabledPlugin attribute from each navigator.mimeTypes to find the actual plugin used to handle the mime type 2018-08-04 08:07:02 +02:00
janekptacijarabaci 0f38772573 [PALEMOON] Bug 1034043 - Fix remaining use of "awlaysAsk" attribute in applications pref pane 2018-08-04 08:06:49 +02:00
janekptacijarabaci ef81277925 [PALEMOON] Bug 480242 - "Always ask" doesn't work for Plugins 2018-08-04 08:06:36 +02:00
janekptacijarabaci 8b20931e12 [PALEMOON] Bug 757726 - Populate Preferences' Applications list using PluginHost 2018-08-04 08:06:24 +02:00
SpockMan02 b247982d37 Restore Mac bookmark doorhanger styling 2018-08-04 08:05:34 +02:00
43 changed files with 6132 additions and 190 deletions

No files matched your search

@@ -8,15 +8,10 @@
//****************************************************************************//
// Constants & Enumeration Values
/*
#ifndef XP_MACOSX
*/
var Cc = Components.classes;
var Ci = Components.interfaces;
var Cr = Components.results;
/*
#endif
*/
Components.utils.import('resource://gre/modules/Services.jsm');
const TYPE_MAYBE_FEED = "application/vnd.mozilla.maybe.feed";
@@ -158,7 +153,7 @@ function isFeedType(t) {
*
* We create an instance of this wrapper for each entry we might display
* in the prefpane, and we compose the instances from various sources,
* including navigator.plugins and the handler service.
* including plugins and the handler service.
*
* We don't implement all the original nsIHandlerInfo functionality,
* just the stuff that the prefpane needs.
@@ -272,7 +267,7 @@ HandlerInfoWrapper.prototype = {
// What to do with content of this type.
get preferredAction() {
// If we have an enabled plugin, then the action is to use that plugin.
if (this.plugin && !this.isDisabledPluginType)
if (this.pluginName && !this.isDisabledPluginType)
return kActionUsePlugin;
// If the action is to use a helper app, but we don't have a preferred
@@ -293,6 +288,14 @@ HandlerInfoWrapper.prototype = {
},
set preferredAction(aNewValue) {
// If the action is to use the plugin,
// we must set the preferred action to "save to disk".
// But only if it's not currently the preferred action.
if ((aNewValue == kActionUsePlugin) &&
(this.preferredAction != Ci.nsIHandlerInfo.saveToDisk)) {
aNewValue = Ci.nsIHandlerInfo.saveToDisk;
}
// We don't modify the preferred action if the new action is to use a plugin
// because handler info objects don't understand our custom "use plugin"
// value. Also, leaving it untouched means that we can automatically revert
@@ -308,7 +311,7 @@ HandlerInfoWrapper.prototype = {
// of any user configuration, and the default in that case is to always ask,
// even though we never ask for content handled by a plugin, so special case
// plugin-handled types by returning false here.
if (this.plugin && this.handledOnlyByPlugin)
if (this.pluginName && this.handledOnlyByPlugin)
return false;
// If this is a protocol type and the preferred action is "save to disk",
@@ -1064,24 +1067,22 @@ var gApplicationsPane = {
* check the pref ourselves to find out if it's enabled.
*/
_loadPluginHandlers: function() {
for (let i = 0; i < navigator.plugins.length; ++i) {
let plugin = navigator.plugins[i];
for (let j = 0; j < plugin.length; ++j) {
let type = plugin[j].type;
"use strict";
let handlerInfoWrapper;
if (type in this._handledTypes)
handlerInfoWrapper = this._handledTypes[type];
else {
let wrappedHandlerInfo =
this._mimeSvc.getFromTypeAndExtension(type, null);
handlerInfoWrapper = new HandlerInfoWrapper(type, wrappedHandlerInfo);
handlerInfoWrapper.handledOnlyByPlugin = true;
this._handledTypes[type] = handlerInfoWrapper;
}
let mimeTypes = navigator.mimeTypes;
handlerInfoWrapper.plugin = plugin;
for (let mimeType of mimeTypes) {
let handlerInfoWrapper;
if (mimeType.type in this._handledTypes) {
handlerInfoWrapper = this._handledTypes[mimeType.type];
} else {
let wrappedHandlerInfo =
this._mimeSvc.getFromTypeAndExtension(mimeType.type, null);
handlerInfoWrapper = new HandlerInfoWrapper(mimeType.type, wrappedHandlerInfo);
handlerInfoWrapper.handledOnlyByPlugin = true;
this._handledTypes[mimeType.type] = handlerInfoWrapper;
}
handlerInfoWrapper.pluginName = mimeType.enabledPlugin.name;
}
},
@@ -1274,7 +1275,7 @@ var gApplicationsPane = {
case kActionUsePlugin:
return this._prefsBundle.getFormattedString("usePluginIn",
[aHandlerInfo.plugin.name,
[aHandlerInfo.pluginName,
this._brandShortName]);
}
},
@@ -1368,7 +1369,7 @@ var gApplicationsPane = {
{
var askMenuItem = document.createElement("menuitem");
askMenuItem.setAttribute("alwaysAsk", "true");
askMenuItem.setAttribute("action", Ci.nsIHandlerInfo.alwaysAsk);
let label;
if (isFeedType(handlerInfo.type))
label = this._prefsBundle.getFormattedString("previewInApp",
@@ -1456,11 +1457,11 @@ var gApplicationsPane = {
}
// Create a menu item for the plugin.
if (handlerInfo.plugin) {
if (handlerInfo.pluginName) {
var pluginMenuItem = document.createElement("menuitem");
pluginMenuItem.setAttribute("action", kActionUsePlugin);
let label = this._prefsBundle.getFormattedString("usePluginIn",
[handlerInfo.plugin.name,
[handlerInfo.pluginName,
this._brandShortName]);
pluginMenuItem.setAttribute("label", label);
pluginMenuItem.setAttribute("tooltiptext", label);
@@ -1614,33 +1615,31 @@ var gApplicationsPane = {
var typeItem = this._list.selectedItem;
var handlerInfo = this._handledTypes[typeItem.type];
if (aActionItem.hasAttribute("alwaysAsk")) {
let action = parseInt(aActionItem.getAttribute("action"));
// Set the plugin state if we're enabling or disabling a plugin.
if (action == kActionUsePlugin)
handlerInfo.enablePluginType();
else if (handlerInfo.pluginName && !handlerInfo.isDisabledPluginType)
handlerInfo.disablePluginType();
// Set the preferred application handler.
// We leave the existing preferred app in the list when we set
// the preferred action to something other than useHelperApp so that
// legacy datastores that don't have the preferred app in the list
// of possible apps still include the preferred app in the list of apps
// the user can choose to handle the type.
if (action == Ci.nsIHandlerInfo.useHelperApp)
handlerInfo.preferredApplicationHandler = aActionItem.handlerApp;
// Set the "always ask" flag.
if (action == Ci.nsIHandlerInfo.alwaysAsk)
handlerInfo.alwaysAskBeforeHandling = true;
}
else if (aActionItem.hasAttribute("action")) {
let action = parseInt(aActionItem.getAttribute("action"));
// Set the plugin state if we're enabling or disabling a plugin.
if (action == kActionUsePlugin)
handlerInfo.enablePluginType();
else if (handlerInfo.plugin && !handlerInfo.isDisabledPluginType)
handlerInfo.disablePluginType();
// Set the preferred application handler.
// We leave the existing preferred app in the list when we set
// the preferred action to something other than useHelperApp so that
// legacy datastores that don't have the preferred app in the list
// of possible apps still include the preferred app in the list of apps
// the user can choose to handle the type.
if (action == Ci.nsIHandlerInfo.useHelperApp)
handlerInfo.preferredApplicationHandler = aActionItem.handlerApp;
// Set the "always ask" flag.
else
handlerInfo.alwaysAskBeforeHandling = false;
// Set the preferred action.
handlerInfo.preferredAction = action;
}
// Set the preferred action.
handlerInfo.preferredAction = action;
handlerInfo.store();
+1 -1
View File
@@ -1 +1 @@
28.0.0b5
28.0.1
+251
View File
@@ -1340,6 +1340,257 @@ richlistitem[type~="action"][actiontype="switchtab"][selected="true"] > .ac-url-
min-width: 27em;
}
/* BOOKMARKING PANEL */
#editBookmarkPanelStarIcon {
list-style-image: url("chrome://browser/skin/places/starred48.png");
width: 48px;
height: 48px;
}
#editBookmarkPanelStarIcon[unstarred] {
list-style-image: url("chrome://browser/skin/places/unstarred48.png");
}
#editBookmarkPanelTitle {
font-size: 130%;
font-weight: bold;
}
#editBMPanel_rows > row {
margin-bottom: 8px;
}
#editBMPanel_rows > row:last-of-type {
margin-bottom: 0;
}
/**** Input elements ****/
#editBMPanel_rows > row > textbox,
#editBMPanel_rows > row > hbox > textbox {
-moz-appearance: none;
background: linear-gradient(#fafafa, #fff);
background-clip: padding-box;
border-radius: 3px;
border: 1px solid rgba(0,0,0,.3) !important;
box-shadow: inset 0 1px 1px 1px rgba(0,0,0,.05),
0 1px rgba(255,255,255,.3);
margin: 0;
padding: 3px 6px;
}
#editBMPanel_rows > row > textbox[focused="true"],
#editBMPanel_rows > row > hbox > textbox[focused="true"] {
border-color: -moz-mac-focusring !important;
box-shadow: @focusRingShadow@;
}
/**** HUD style buttons ****/
.editBookmarkPanelHeaderButton,
.editBookmarkPanelBottomButton {
@hudButton@
margin: 0;
min-width: 82px;
min-height: 22px;
}
.editBookmarkPanelHeaderButton:hover:active,
.editBookmarkPanelBottomButton:hover:active {
@hudButtonPressed@
}
.editBookmarkPanelHeaderButton:-moz-focusring,
.editBookmarkPanelBottomButton:-moz-focusring {
@hudButtonFocused@
}
.editBookmarkPanelBottomButton[default="true"] {
background-color: #666;
}
#editBookmarkPanelHeader {
margin-bottom: 6px;
}
.editBookmarkPanelBottomButton:last-child {
-moz-margin-start: 8px;
}
/* The following elements come from editBookmarkOverlay.xul. Styling that's
specific to the editBookmarkPanel should be in browser.css. Styling that
should be shared by all editBookmarkOverlay.xul consumers should be in
editBookmarkOverlay.css. */
#editBMPanel_newFolderBox {
background: linear-gradient(#fff, #f2f2f2);
background-origin: padding-box;
background-clip: padding-box;
border-radius: 0 0 3px 3px;
border: 1px solid #a5a5a5;
box-shadow: inset 0 1px rgba(255,255,255,.8),
inset 0 0 1px rgba(255,255, 255,.25),
0 1px rgba(255,255,255,.3);
margin: 0;
padding: 0;
height: 20px;
}
#editBMPanel_newFolderButton {
-moz-appearance: none;
border: 0 solid #a5a5a5;
-moz-border-end-width: 1px;
padding: 0 9px;
margin: 0;
min-width: 21px;
min-height: 20px;
height: 20px;
color: #fff;
list-style-image: url("chrome://browser/skin/panel-plus-sign.png");
position: relative;
}
#editBMPanel_newFolderButton:hover:active {
background: linear-gradient(rgba(40,40,40,.9), rgba(70,70,70,.9));
box-shadow: inset 0 0 3px rgba(0,0,0,.2), inset 0 1px 7px rgba(0,0,0,.4);
}
#editBMPanel_newFolderButton:-moz-focusring {
@hudButtonFocused@
}
#editBMPanel_newFolderButton .button-text {
display: none;
}
#editBMPanel_folderMenuList {
@hudButton@
background-clip: padding-box;
margin: 0;
min-height: 22px;
padding-top: 2px;
padding-bottom: 1px;
-moz-padding-start: 8px;
-moz-padding-end: 4px;
}
#editBMPanel_folderMenuList:-moz-focusring {
@hudButtonFocused@
}
#editBMPanel_folderMenuList[open="true"],
#editBMPanel_folderMenuList:hover:active {
@hudButtonPressed@
}
#editBMPanel_folderMenuList > .menulist-dropmarker {
-moz-appearance: none;
display: -moz-box;
background-color: transparent;
border: 0;
margin: 0;
padding: 0;
-moz-padding-end: 4px;
width: 7px;
}
#editBMPanel_folderMenuList > .menulist-dropmarker > .dropmarker-icon {
list-style-image: url("chrome://global/skin/icons/panel-dropmarker.png");
}
/**** folder tree and tag selector ****/
#editBMPanel_folderTree,
#editBMPanel_tagsSelector {
-moz-appearance: none;
background: linear-gradient(#fafafa, #fff);
background-clip: padding-box;
border-radius: 3px;
border: 1px solid rgba(0,0,0,.3);
box-shadow: inset 0 1px 1px 1px rgba(0,0,0,.05),
0 1px rgba(255,255,255,.3);
margin: 0;
}
#editBMPanel_folderTree:-moz-focusring,
#editBMPanel_tagsSelector:-moz-focusring {
border-color: -moz-mac-focusring;
box-shadow: @focusRingShadow@;
}
#editBMPanel_folderTree {
border-bottom: none;
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
/* Implements editBookmarkPanel resizing on folderTree un-collapse. */
margin: 0 !important;
min-width: 27em;
position: relative;
}
/**** expanders ****/
#editBookmarkPanel .expander-up,
#editBookmarkPanel .expander-down {
@hudButton@
margin: 0;
-moz-margin-start: 4px;
min-width: 27px;
min-height: 22px;
}
#editBookmarkPanel .expander-up:-moz-focusring,
#editBookmarkPanel .expander-down:-moz-focusring {
@hudButtonFocused@
}
#editBookmarkPanel .expander-up:hover:active,
#editBookmarkPanel .expander-down:hover:active {
@hudButtonPressed@
}
#editBookmarkPanel .expander-up {
list-style-image: url("chrome://browser/skin/panel-expander-open.png");
}
#editBookmarkPanel .expander-down {
list-style-image: url("chrome://browser/skin/panel-expander-closed.png");
}
#editBookmarkPanel .expander-up > .button-box > .button-icon,
#editBookmarkPanel .expander-down > .button-box > .button-icon {
margin: 1px 0 0;
}
#editBookmarkPanel .expander-up > .button-box > .button-text,
#editBookmarkPanel .expander-down > .button-box > .button-text {
display: none;
}
@media (min-resolution: 2dppx) {
#editBookmarkPanel .expander-up {
list-style-image: url("chrome://browser/skin/panel-expander-open@2x.png");
}
#editBookmarkPanel .expander-down {
list-style-image: url("chrome://browser/skin/panel-expander-closed@2x.png");
}
#editBookmarkPanel .expander-up > .button-box > .button-icon,
#editBookmarkPanel .expander-down > .button-box > .button-icon {
width: 9px;
}
}
#editBMPanel_tagsField > .autocomplete-textbox-container > .textbox-input-box > html|*.textbox-input::-moz-placeholder {
opacity: 1.0;
color: #bbb;
}
.editBMPanel_rowLabel {
text-align: end;
}
/* ::::: content area ::::: */
#sidebar {
+9
View File
@@ -41,6 +41,11 @@ browser.jar:
skin/classic/browser/mixed-content-blocked-64.png
skin/classic/browser/monitor.png
skin/classic/browser/monitor_16-10.png
skin/classic/browser/panel-expander-closed.png
skin/classic/browser/panel-expander-closed@2x.png
skin/classic/browser/panel-expander-open.png
skin/classic/browser/panel-expander-open@2x.png
skin/classic/browser/panel-plus-sign.png
skin/classic/browser/pageInfo.css
skin/classic/browser/pageInfo.png
skin/classic/browser/page-livemarks.png
@@ -116,6 +121,8 @@ browser.jar:
skin/classic/browser/places/libraryToolbar.png (places/libraryToolbar.png)
skin/classic/browser/places/starred48.png (places/starred48.png)
skin/classic/browser/places/unstarred48.png (places/unstarred48.png)
skin/classic/browser/places/unfiledBookmarks.png (places/unfiledBookmarks.png)
skin/classic/browser/places/unfiledBookmarks@2x.png (places/unfiledBookmarks@2x.png)
skin/classic/browser/places/tag.png (places/tag.png)
skin/classic/browser/places/tag@2x.png (places/tag@2x.png)
skin/classic/browser/places/history.png (places/history.png)
@@ -123,6 +130,8 @@ browser.jar:
skin/classic/browser/places/allBookmarks.png (places/allBookmarks.png)
skin/classic/browser/places/unsortedBookmarks.png (places/unsortedBookmarks.png)
skin/classic/browser/places/downloads.png (places/downloads.png)
skin/classic/browser/places/expander-closed-active.png (places/expander-closed-active.png)
skin/classic/browser/places/expander-open-active.png (places/expander-open-active.png)
skin/classic/browser/places/livemark-item.png (places/livemark-item.png)
skin/classic/browser/places/expander-closed.png (places/expander-closed.png)
skin/classic/browser/places/expander-open.png (places/expander-open.png)
Binary file not shown.

After

Width:  |  Height:  |  Size: 155 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 362 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 155 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 356 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 212 B

@@ -2,8 +2,12 @@
* 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/. */
@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
@namespace html url("http://www.w3.org/1999/xhtml");
/**** folder menulist ****/
.folder-icon > .menulist-label-box > .menulist-icon {
.folder-icon > .menulist-label-box > .menulist-icon,
.folder-icon > .menu-iconic-left > .menu-iconic-icon {
width: 16px;
height: 16px;
}
@@ -16,27 +20,41 @@
list-style-image: url("chrome://global/skin/tree/folder.png") !important;
}
@media (min-resolution: 2dppx) {
.folder-icon {
list-style-image: url("chrome://global/skin/tree/folder@2x.png") !important;
}
}
.menulist-icon {
margin: 0 !important;
}
/**** expanders ****/
.expander-up,
.expander-down {
min-width: 0;
-moz-appearance: none;
margin: 0;
-moz-margin-end: 4px;
}
.expander-up > .button-box,
.expander-down > .button-box {
margin-left: 8px;
padding: 0;
min-width: 0;
}
.expander-up {
list-style-image: url("chrome://global/skin/icons/collapse.png");
list-style-image: url("chrome://browser/skin/places/expander-open.png");
}
.expander-down {
list-style-image: url("chrome://global/skin/icons/expand.png");
list-style-image: url("chrome://browser/skin/places/expander-closed.png");
}
.expander-down:hover:active {
list-style-image: url("chrome://browser/skin/places/expander-closed-active.png");
}
.expander-up:hover:active {
list-style-image: url("chrome://browser/skin/places/expander-open-active.png");
}
#editBookmarkPanelContent {
@@ -44,8 +62,7 @@
}
#editBMPanel_folderTree {
margin-top: 2px;
margin-bottom: 2px;
margin: 6px 4px 0 4px;
}
/* Hide the value column of the tag autocomplete popup
@@ -58,22 +75,31 @@
}
/* ::::: bookmark panel dropdown icons ::::: */
/* ----- BOOKMARK PANEL DROPDOWN MENU ITEMS ----- */
#editBMPanel_folderMenuList[selectedIndex="0"],
#editBMPanel_toolbarFolderItem {
list-style-image: url("chrome://browser/skin/places/bookmarksToolbar.png") !important;
-moz-image-region: auto !important;
list-style-image: url("chrome://browser/skin/places/bookmarksToolbar.png") !important;
}
#editBMPanel_folderMenuList[selectedIndex="1"],
#editBMPanel_bmRootItem {
list-style-image: url("chrome://browser/skin/places/bookmarksMenu.png") !important;
-moz-image-region: auto !important;
list-style-image: url("chrome://browser/skin/places/bookmarksMenu.png") !important;
}
#editBMPanel_folderMenuList[selectedIndex="2"],
#editBMPanel_unfiledRootItem {
list-style-image: url("chrome://browser/skin/places/unsortedBookmarks.png") !important;
-moz-image-region: auto !important;
list-style-image: url("chrome://browser/skin/places/unfiledBookmarks.png") !important;
}
@media (min-resolution: 2dppx) {
#editBMPanel_folderMenuList[selectedIndex="0"],
#editBMPanel_toolbarFolderItem {
list-style-image: url("chrome://browser/skin/places/bookmarksToolbar@2x.png") !important;
}
#editBMPanel_folderMenuList[selectedIndex="2"],
#editBMPanel_unfiledRootItem {
list-style-image: url("chrome://browser/skin/places/unfiledBookmarks@2x.png") !important;
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 586 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

-3
View File
@@ -149,9 +149,6 @@ BasicTextureImage::DirectUpdate(gfx::DataSourceSurface* aSurf, const nsIntRegion
&uploadSize,
needInit,
aFrom);
if (mTextureFormat == SurfaceFormat::UNKNOWN) {
return false;
}
if (uploadSize > 0) {
UpdateUploadSize(uploadSize);
+1 -30
View File
@@ -27,23 +27,6 @@ DataOffset(const IntPoint& aPoint, int32_t aStride, SurfaceFormat aFormat)
return data;
}
static bool
CheckUploadBounds(const IntSize& aDst, const IntSize& aSrc, const IntPoint& aOffset)
{
if (aOffset.x < 0 || aOffset.y < 0 ||
aOffset.x >= aSrc.width ||
aOffset.y >= aSrc.height) {
MOZ_ASSERT_UNREACHABLE("Offset outside source bounds");
return false;
}
if (aDst.width > (aSrc.width - aOffset.x) ||
aDst.height > (aSrc.height - aOffset.y)) {
MOZ_ASSERT_UNREACHABLE("Source has insufficient data");
return false;
}
return true;
}
static GLint GetAddressAlignment(ptrdiff_t aAddress)
{
if (!(aAddress & 0x7)) {
@@ -392,7 +375,6 @@ TexImage2DHelper(GLContext* gl,
SurfaceFormat
UploadImageDataToTexture(GLContext* gl,
unsigned char* aData,
const gfx::IntSize& aDataSize,
int32_t aStride,
SurfaceFormat aFormat,
const nsIntRegion& aDstRegion,
@@ -516,10 +498,6 @@ UploadImageDataToTexture(GLContext* gl,
// Upload each rect in the region to the texture
for (auto iter = aDstRegion.RectIter(); !iter.Done(); iter.Next()) {
const IntRect& rect = iter.Get();
if (!CheckUploadBounds(rect.Size(), aDataSize, rect.TopLeft())) {
return SurfaceFormat::UNKNOWN;
}
const unsigned char* rectData =
aData + DataOffset(rect.TopLeft(), aStride, aFormat);
@@ -556,17 +534,10 @@ UploadSurfaceToTexture(GLContext* gl,
int32_t stride = aSurface->Stride();
SurfaceFormat format = aSurface->GetFormat();
gfx::IntSize size = aSurface->GetSize();
if (!CheckUploadBounds(aSize, size, aSrcPoint)) {
return SurfaceFormat::UNKNOWN;
}
unsigned char* data = aSurface->GetData() +
DataOffset(aSrcPoint, stride, format);
size.width -= aSrcPoint.x;
size.height -= aSrcPoint.y;
return UploadImageDataToTexture(gl, data, size, stride, format,
return UploadImageDataToTexture(gl, data, stride, format,
aDstRegion, aTexture, aSize,
aOutUploadSize, aNeedInit,
aTextureUnit, aTextureTarget);
-2
View File
@@ -28,7 +28,6 @@ class GLContext;
* \param gl The GL Context to use.
* \param aData Start of image data of surface to upload.
* Corresponds to the first pixel of the texture.
* \param aDataSize The image data's size.
* \param aStride The image data's stride.
* \param aFormat The image data's format.
* \param aDstRegion Region of the texture to upload.
@@ -47,7 +46,6 @@ class GLContext;
gfx::SurfaceFormat
UploadImageDataToTexture(GLContext* gl,
unsigned char* aData,
const gfx::IntSize& aDataSize,
int32_t aStride,
gfx::SurfaceFormat aFormat,
const nsIntRegion& aDstRegion,
-4
View File
@@ -119,10 +119,6 @@ TextureImageEGL::DirectUpdate(gfx::DataSourceSurface* aSurf, const nsIntRegion&
&uploadSize,
needInit,
aFrom);
if (mTextureFormat == SurfaceFormat::UNKNOWN) {
return false;
}
if (uploadSize > 0) {
UpdateUploadSize(uploadSize);
}
+2 -1
View File
@@ -890,7 +890,8 @@ BufferTextureHost::Upload(nsIntRegion *aRegion)
mFirstSource = mCompositor->CreateDataTextureSource(mFlags|TextureFlags::RGB_FROM_YCBCR);
mFirstSource->SetOwner(this);
}
return mFirstSource->Update(surf, aRegion);
mFirstSource->Update(surf, aRegion);
return true;
}
RefPtr<DataTextureSource> srcY;
+3 -1
View File
@@ -161,7 +161,9 @@ TextureImageTextureSourceOGL::Update(gfx::DataSourceSurface* aSurface,
}
}
return mTexImage->UpdateFromDataSource(aSurface, aDestRegion, aSrcOffset);
mTexImage->UpdateFromDataSource(aSurface, aDestRegion, aSrcOffset);
return true;
}
void
-6
View File
@@ -2214,12 +2214,6 @@ MacroAssembler::finish()
}
MacroAssemblerSpecific::finish();
MOZ_RELEASE_ASSERT(size() <= MaxCodeBytesPerProcess,
"AssemblerBuffer should ensure we don't exceed MaxCodeBytesPerProcess");
if (bytesNeeded() > MaxCodeBytesPerProcess)
setOOM();
}
void
+8
View File
@@ -385,6 +385,14 @@ class PageBitSet
#endif
};
// Limit on the number of bytes of executable memory to prevent JIT spraying
// attacks.
#if JS_BITS_PER_WORD == 32
static const size_t MaxCodeBytesPerProcess = 128 * 1024 * 1024;
#else
static const size_t MaxCodeBytesPerProcess = 1 * 1024 * 1024 * 1024;
#endif
// Per-process executable memory allocator. It reserves a block of memory of
// MaxCodeBytesPerProcess bytes, then allocates/deallocates pages from that.
//
-8
View File
@@ -17,14 +17,6 @@ namespace jit {
// alignment though.
static const size_t ExecutableCodePageSize = 64 * 1024;
// Limit on the number of bytes of executable memory to prevent JIT spraying
// attacks.
#if JS_BITS_PER_WORD == 32
static const size_t MaxCodeBytesPerProcess = 128 * 1024 * 1024;
#else
static const size_t MaxCodeBytesPerProcess = 1 * 1024 * 1024 * 1024;
#endif
enum class ProtectionSetting {
Protected, // Not readable, writable, or executable.
Writable,
-4
View File
@@ -181,10 +181,6 @@ class AssemblerBuffer
protected:
virtual Slice* newSlice(LifoAlloc& a) {
if (size() > MaxCodeBytesPerProcess - sizeof(Slice)) {
fail_oom();
return nullptr;
}
Slice* tmp = static_cast<Slice*>(a.alloc(sizeof(Slice)));
if (!tmp) {
fail_oom();
@@ -68,33 +68,6 @@ namespace js {
namespace jit {
// AllocPolicy for AssemblerBuffer. OOMs when trying to allocate more than
// MaxCodeBytesPerProcess bytes. Use private inheritance to make sure we
// explicitly have to expose SystemAllocPolicy methods.
class AssemblerBufferAllocPolicy : private SystemAllocPolicy
{
public:
using SystemAllocPolicy::checkSimulatedOOM;
using SystemAllocPolicy::reportAllocOverflow;
using SystemAllocPolicy::free_;
template <typename T> T* pod_realloc(T* p, size_t oldSize, size_t newSize) {
static_assert(sizeof(T) == 1,
"AssemblerBufferAllocPolicy should only be used with byte vectors");
MOZ_ASSERT(oldSize <= MaxCodeBytesPerProcess);
if (MOZ_UNLIKELY(newSize > MaxCodeBytesPerProcess))
return nullptr;
return SystemAllocPolicy::pod_realloc<T>(p, oldSize, newSize);
}
template <typename T> T* pod_malloc(size_t numElems) {
static_assert(sizeof(T) == 1,
"AssemblerBufferAllocPolicy should only be used with byte vectors");
if (MOZ_UNLIKELY(numElems > MaxCodeBytesPerProcess))
return nullptr;
return SystemAllocPolicy::pod_malloc<T>(numElems);
}
};
class AssemblerBuffer
{
template<size_t size, typename T>
@@ -120,9 +93,6 @@ namespace jit {
void ensureSpace(size_t space)
{
// This should only be called with small |space| values to ensure
// we don't overflow below.
MOZ_ASSERT(space <= 16);
if (MOZ_UNLIKELY(!m_buffer.reserve(m_buffer.length() + space)))
oomDetected();
}
@@ -198,7 +168,7 @@ namespace jit {
m_buffer.clear();
}
PageProtectingVector<unsigned char, 256, AssemblerBufferAllocPolicy> m_buffer;
PageProtectingVector<unsigned char, 256, SystemAllocPolicy> m_buffer;
bool m_oom;
};
+4 -4
View File
@@ -4568,10 +4568,10 @@ AC_SUBST(MOZ_DEVTOOLS_SERVER)
dnl ========================================================
dnl = Disable Mozilla Developer Tools (client)
dnl ========================================================
MOZ_ARG_DISABLE_BOOL(devtools,
[ --disable-devtools Disable Mozilla Developer Tools (client)],
MOZ_DEVTOOLS=,
MOZ_DEVTOOLS=1)
MOZ_ARG_ENABLE_BOOL(devtools,
[ --enable-devtools Enable Mozilla Developer Tools (client)],
MOZ_DEVTOOLS=1,
MOZ_DEVTOOLS=)
if test -n "$MOZ_DEVTOOLS"; then
if test ! -n "$MOZ_DEVTOOLS_SERVER"; then
+11
View File
@@ -24,6 +24,7 @@ nsHtml5AtomEntry::~nsHtml5AtomEntry()
}
nsHtml5AtomTable::nsHtml5AtomTable()
: mRecentlyUsedParserAtoms{}
{
#ifdef DEBUG
NS_GetMainThread(getter_AddRefs(mPermittedLookupThread));
@@ -44,13 +45,23 @@ nsHtml5AtomTable::GetAtom(const nsAString& aKey)
NS_ASSERTION(mPermittedLookupThread == currentThread, "Wrong thread!");
}
#endif
uint32_t index = mozilla::HashString(aKey) % RECENTLY_USED_PARSER_ATOMS_SIZE;
nsIAtom* cachedAtom = mRecentlyUsedParserAtoms[index];
if (cachedAtom && cachedAtom->Equals(aKey)) {
return cachedAtom;
}
nsIAtom* atom = NS_GetStaticAtom(aKey);
if (atom) {
mRecentlyUsedParserAtoms[index] = atom;
return atom;
}
nsHtml5AtomEntry* entry = mTable.PutEntry(aKey);
if (!entry) {
return nullptr;
}
mRecentlyUsedParserAtoms[index] = entry->GetAtom();
return entry->GetAtom();
}
+6
View File
@@ -11,6 +11,8 @@
#include "nsIAtom.h"
#include "nsIThread.h"
#define RECENTLY_USED_PARSER_ATOMS_SIZE 31
class nsHtml5Atom;
class nsHtml5AtomEntry : public nsStringHashKey
@@ -87,6 +89,9 @@ class nsHtml5AtomTable
*/
void Clear()
{
for (uint32_t i = 0; i < RECENTLY_USED_PARSER_ATOMS_SIZE; ++i) {
mRecentlyUsedParserAtoms[i] = nullptr;
}
mTable.Clear();
}
@@ -99,6 +104,7 @@ class nsHtml5AtomTable
private:
nsTHashtable<nsHtml5AtomEntry> mTable;
nsIAtom* mRecentlyUsedParserAtoms[RECENTLY_USED_PARSER_ATOMS_SIZE];
#ifdef DEBUG
nsCOMPtr<nsIThread> mPermittedLookupThread;
#endif
@@ -0,0 +1,31 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
EXTRA_COMPONENTS += [
'nsSearchSuggestions.js',
]
EXTRA_PP_COMPONENTS += [
'nsSearchService.js',
]
if CONFIG['MOZ_PHOENIX'] or CONFIG['MOZ_FENNEC'] or CONFIG['MOZ_XULRUNNER']:
DEFINES['HAVE_SIDEBAR'] = True
EXTRA_COMPONENTS += [
'nsSidebar.js',
]
EXTRA_JS_MODULES += [
'SearchSuggestionController.jsm',
]
EXTRA_PP_COMPONENTS += [
'toolkitsearch.manifest',
]
EXTRA_JS_MODULES += [
'SearchStaticData.jsm',
]
+4 -25
View File
@@ -6,31 +6,10 @@
XPCSHELL_TESTS_MANIFESTS += ['tests/xpcshell/xpcshell.ini']
EXTRA_COMPONENTS += [
'nsSearchSuggestions.js',
]
EXTRA_PP_COMPONENTS += [
'nsSearchService.js',
]
if CONFIG['MOZ_PHOENIX'] or CONFIG['MOZ_FENNEC'] or CONFIG['MOZ_XULRUNNER']:
DEFINES['HAVE_SIDEBAR'] = True
EXTRA_COMPONENTS += [
'nsSidebar.js',
]
EXTRA_JS_MODULES += [
'SearchSuggestionController.jsm',
]
EXTRA_PP_COMPONENTS += [
'toolkitsearch.manifest',
]
EXTRA_JS_MODULES += [
'SearchStaticData.jsm',
]
if CONFIG['MC_PALEMOON']:
DIRS += ['orginal']
else:
DIRS += ['current']
with Files('**'):
BUG_COMPONENT = ('Firefox', 'Search')
@@ -0,0 +1,43 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
* This module contains additional data about default search engines that is the
* same across all languages. This information is defined outside of the actual
* search engine definition files, so that localizers don't need to update them
* when a change is made.
*
* This separate module is also easily overridable, in case a hotfix is needed.
* No high-level processing logic is applied here.
*/
"use strict";
this.EXPORTED_SYMBOLS = [
"SearchStaticData",
];
const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
// To update this list of known alternate domains, just cut-and-paste from
// https://www.google.com/supported_domains
const gGoogleDomainsSource = ".google.com .google.ad .google.ae .google.com.af .google.com.ag .google.com.ai .google.al .google.am .google.co.ao .google.com.ar .google.as .google.at .google.com.au .google.az .google.ba .google.com.bd .google.be .google.bf .google.bg .google.com.bh .google.bi .google.bj .google.com.bn .google.com.bo .google.com.br .google.bs .google.bt .google.co.bw .google.by .google.com.bz .google.ca .google.cd .google.cf .google.cg .google.ch .google.ci .google.co.ck .google.cl .google.cm .google.cn .google.com.co .google.co.cr .google.com.cu .google.cv .google.com.cy .google.cz .google.de .google.dj .google.dk .google.dm .google.com.do .google.dz .google.com.ec .google.ee .google.com.eg .google.es .google.com.et .google.fi .google.com.fj .google.fm .google.fr .google.ga .google.ge .google.gg .google.com.gh .google.com.gi .google.gl .google.gm .google.gp .google.gr .google.com.gt .google.gy .google.com.hk .google.hn .google.hr .google.ht .google.hu .google.co.id .google.ie .google.co.il .google.im .google.co.in .google.iq .google.is .google.it .google.je .google.com.jm .google.jo .google.co.jp .google.co.ke .google.com.kh .google.ki .google.kg .google.co.kr .google.com.kw .google.kz .google.la .google.com.lb .google.li .google.lk .google.co.ls .google.lt .google.lu .google.lv .google.com.ly .google.co.ma .google.md .google.me .google.mg .google.mk .google.ml .google.com.mm .google.mn .google.ms .google.com.mt .google.mu .google.mv .google.mw .google.com.mx .google.com.my .google.co.mz .google.com.na .google.com.nf .google.com.ng .google.com.ni .google.ne .google.nl .google.no .google.com.np .google.nr .google.nu .google.co.nz .google.com.om .google.com.pa .google.com.pe .google.com.pg .google.com.ph .google.com.pk .google.pl .google.pn .google.com.pr .google.ps .google.pt .google.com.py .google.com.qa .google.ro .google.ru .google.rw .google.com.sa .google.com.sb .google.sc .google.se .google.com.sg .google.sh .google.si .google.sk .google.com.sl .google.sn .google.so .google.sm .google.sr .google.st .google.com.sv .google.td .google.tg .google.co.th .google.com.tj .google.tk .google.tl .google.tm .google.tn .google.to .google.com.tr .google.tt .google.com.tw .google.co.tz .google.com.ua .google.co.ug .google.co.uk .google.com.uy .google.co.uz .google.com.vc .google.co.ve .google.vg .google.co.vi .google.com.vn .google.vu .google.ws .google.rs .google.co.za .google.co.zm .google.co.zw .google.cat";
const gGoogleDomains = gGoogleDomainsSource.split(" ").map(d => "www" + d);
this.SearchStaticData = {
/**
* Returns a list of alternate domains for a given search engine domain.
*
* @param aDomain
* Lowercase host name to look up. For example, if this argument is
* "www.google.com" or "www.google.co.uk", the function returns the
* full list of supported Google domains.
*
* @return Array containing one entry for each alternate host name, or empty
* array if none is known. The returned array should not be modified.
*/
getAlternateDomains: function (aDomain) {
return gGoogleDomains.indexOf(aDomain) == -1 ? [] : gGoogleDomains;
},
};
@@ -0,0 +1,396 @@
/* 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/. */
"use strict";
this.EXPORTED_SYMBOLS = ["SearchSuggestionController"];
const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/Promise.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "NS_ASSERT", "resource://gre/modules/debug.js");
const SEARCH_RESPONSE_SUGGESTION_JSON = "application/x-suggestions+json";
const DEFAULT_FORM_HISTORY_PARAM = "searchbar-history";
const HTTP_OK = 200;
const REMOTE_TIMEOUT = 500; // maximum time (ms) to wait before giving up on a remote suggestions
const BROWSER_SUGGEST_PREF = "browser.search.suggest.enabled";
/**
* Remote search suggestions will be shown if gRemoteSuggestionsEnabled
* is true. Global because only one pref observer is needed for all instances.
*/
var gRemoteSuggestionsEnabled = Services.prefs.getBoolPref(BROWSER_SUGGEST_PREF);
Services.prefs.addObserver(BROWSER_SUGGEST_PREF, function(aSubject, aTopic, aData) {
gRemoteSuggestionsEnabled = Services.prefs.getBoolPref(BROWSER_SUGGEST_PREF);
}, false);
/**
* SearchSuggestionController.jsm exists as a helper module to allow multiple consumers to request and display
* search suggestions from a given engine, regardless of the base implementation. Much of this
* code was originally in nsSearchSuggestions.js until it was refactored to separate it from the
* nsIAutoCompleteSearch dependency.
* One instance of SearchSuggestionController should be used per field since form history results are cached.
*/
/**
* @param {function} [callback] - Callback for search suggestion results. You can use the promise
* returned by the search method instead if you prefer.
* @constructor
*/
this.SearchSuggestionController = function SearchSuggestionController(callback = null) {
this._callback = callback;
};
this.SearchSuggestionController.prototype = {
/**
* The maximum number of local form history results to return. This limit is
* only enforced if remote results are also returned.
*/
maxLocalResults: 5,
/**
* The maximum number of remote search engine results to return.
* We'll actually only display at most
* maxRemoteResults - <displayed local results count> remote results.
*/
maxRemoteResults: 10,
/**
* The maximum time (ms) to wait before giving up on a remote suggestions.
*/
remoteTimeout: REMOTE_TIMEOUT,
/**
* The additional parameter used when searching form history.
*/
formHistoryParam: DEFAULT_FORM_HISTORY_PARAM,
// Private properties
/**
* The last form history result used to improve the performance of subsequent searches.
* This shouldn't be used for any other purpose as it is never cleared and therefore could be stale.
*/
_formHistoryResult: null,
/**
* The remote server timeout timer, if applicable. The timer starts when form history
* search is completed.
*/
_remoteResultTimer: null,
/**
* The deferred for the remote results before its promise is resolved.
*/
_deferredRemoteResult: null,
/**
* The optional result callback registered from the constructor.
*/
_callback: null,
/**
* The XMLHttpRequest object for remote results.
*/
_request: null,
// Public methods
/**
* Fetch search suggestions from all of the providers. Fetches in progress will be stopped and
* results from them will not be provided.
*
* @param {string} searchTerm - the term to provide suggestions for
* @param {bool} privateMode - whether the request is being made in the context of private browsing
* @param {nsISearchEngine} engine - search engine for the suggestions.
*
* @return {Promise} resolving to an object containing results or null.
*/
fetch: function(searchTerm, privateMode, engine) {
// There is no smart filtering from previous results here (as there is when looking through
// history/form data) because the result set returned by the server is different for every typed
// value - e.g. "ocean breathes" does not return a subset of the results returned for "ocean".
this.stop();
if (!Services.search.isInitialized) {
throw new Error("Search not initialized yet (how did you get here?)");
}
if (typeof privateMode === "undefined") {
throw new Error("The privateMode argument is required to avoid unintentional privacy leaks");
}
if (!(engine instanceof Ci.nsISearchEngine)) {
throw new Error("Invalid search engine");
}
if (!this.maxLocalResults && !this.maxRemoteResults) {
throw new Error("Zero results expected, what are you trying to do?");
}
if (this.maxLocalResults < 0 || this.maxRemoteResults < 0) {
throw new Error("Number of requested results must be positive");
}
// Array of promises to resolve before returning results.
let promises = [];
this._searchString = searchTerm;
// Remote results
if (searchTerm && gRemoteSuggestionsEnabled && this.maxRemoteResults &&
engine.supportsResponseType(SEARCH_RESPONSE_SUGGESTION_JSON)) {
this._deferredRemoteResult = this._fetchRemote(searchTerm, engine, privateMode);
promises.push(this._deferredRemoteResult.promise);
}
// Local results from form history
if (this.maxLocalResults) {
let deferredHistoryResult = this._fetchFormHistory(searchTerm);
promises.push(deferredHistoryResult.promise);
}
function handleRejection(reason) {
if (reason == "HTTP request aborted") {
// Do nothing since this is normal.
return null;
}
Cu.reportError("SearchSuggestionController rejection: " + reason);
return null;
}
return Promise.all(promises).then(this._dedupeAndReturnResults.bind(this), handleRejection);
},
/**
* Stop pending fetches so no results are returned from them.
*
* Note: If there was no remote results fetched, the fetching cannot be stopped and local results
* will still be returned because stopping relies on aborting the XMLHTTPRequest to reject the
* promise for Promise.all.
*/
stop: function() {
if (this._request) {
this._request.abort();
} else if (!this.maxRemoteResults) {
Cu.reportError("SearchSuggestionController: Cannot stop fetching if remote results were not "+
"requested");
}
this._reset();
},
// Private methods
_fetchFormHistory: function(searchTerm) {
let deferredFormHistory = Promise.defer();
let acSearchObserver = {
// Implements nsIAutoCompleteSearch
onSearchResult: (search, result) => {
this._formHistoryResult = result;
if (this._request) {
this._remoteResultTimer = Cc["@mozilla.org/timer;1"].
createInstance(Ci.nsITimer);
this._remoteResultTimer.initWithCallback(this._onRemoteTimeout.bind(this),
this.remoteTimeout || REMOTE_TIMEOUT,
Ci.nsITimer.TYPE_ONE_SHOT);
}
switch (result.searchResult) {
case Ci.nsIAutoCompleteResult.RESULT_SUCCESS:
case Ci.nsIAutoCompleteResult.RESULT_NOMATCH:
if (result.searchString !== this._searchString) {
deferredFormHistory.resolve("Unexpected response, this._searchString does not match form history response");
return;
}
let fhEntries = [];
for (let i = 0; i < result.matchCount; ++i) {
fhEntries.push(result.getValueAt(i));
}
deferredFormHistory.resolve({
result: fhEntries,
formHistoryResult: result,
});
break;
case Ci.nsIAutoCompleteResult.RESULT_FAILURE:
case Ci.nsIAutoCompleteResult.RESULT_IGNORED:
deferredFormHistory.resolve("Form History returned RESULT_FAILURE or RESULT_IGNORED");
break;
}
},
};
let formHistory = Cc["@mozilla.org/autocomplete/search;1?name=form-history"].
createInstance(Ci.nsIAutoCompleteSearch);
formHistory.startSearch(searchTerm, this.formHistoryParam || DEFAULT_FORM_HISTORY_PARAM,
this._formHistoryResult,
acSearchObserver);
return deferredFormHistory;
},
/**
* Fetch suggestions from the search engine over the network.
*/
_fetchRemote: function(searchTerm, engine, privateMode) {
let deferredResponse = Promise.defer();
this._request = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].
createInstance(Ci.nsIXMLHttpRequest);
let submission = engine.getSubmission(searchTerm,
SEARCH_RESPONSE_SUGGESTION_JSON);
let method = (submission.postData ? "POST" : "GET");
this._request.open(method, submission.uri.spec, true);
if (this._request.channel instanceof Ci.nsIPrivateBrowsingChannel) {
this._request.channel.setPrivate(privateMode);
}
this._request.mozBackgroundRequest = true; // suppress dialogs and fail silently
this._request.addEventListener("load", this._onRemoteLoaded.bind(this, deferredResponse));
this._request.addEventListener("error", (evt) => deferredResponse.resolve("HTTP error"));
// Reject for an abort assuming it's always from .stop() in which case we shouldn't return local
// or remote results for existing searches.
this._request.addEventListener("abort", (evt) => deferredResponse.reject("HTTP request aborted"));
this._request.send(submission.postData);
return deferredResponse;
},
/**
* Called when the request completed successfully (thought the HTTP status could be anything)
* so we can handle the response data.
* @private
*/
_onRemoteLoaded: function(deferredResponse) {
if (!this._request) {
deferredResponse.resolve("Got HTTP response after the request was cancelled");
return;
}
let status, serverResults;
try {
status = this._request.status;
} catch (e) {
// The XMLHttpRequest can throw NS_ERROR_NOT_AVAILABLE.
deferredResponse.resolve("Unknown HTTP status: " + e);
return;
}
if (status != HTTP_OK || this._request.responseText == "") {
deferredResponse.resolve("Non-200 status or empty HTTP response: " + status);
return;
}
try {
serverResults = JSON.parse(this._request.responseText);
} catch(ex) {
deferredResponse.resolve("Failed to parse suggestion JSON: " + ex);
return;
}
if (!serverResults[0] ||
this._searchString.localeCompare(serverResults[0], undefined,
{ sensitivity: "base" })) {
// something is wrong here so drop remote results
deferredResponse.resolve("Unexpected response, this._searchString does not match remote response");
return;
}
let results = serverResults[1] || [];
deferredResponse.resolve({ result: results });
},
/**
* Called when this._remoteResultTimer fires indicating the remote request took too long.
*/
_onRemoteTimeout: function () {
this._request = null;
// FIXME: bug 387341
// Need to break the cycle between us and the timer.
this._remoteResultTimer = null;
// The XMLHTTPRequest for suggest results is taking too long
// so send out the form history results and cancel the request.
if (this._deferredRemoteResult) {
this._deferredRemoteResult.resolve("HTTP Timeout");
this._deferredRemoteResult = null;
}
},
/**
* @param {Array} suggestResults - an array of result objects from different sources (local or remote)
* @return {Object}
*/
_dedupeAndReturnResults: function(suggestResults) {
if (this._searchString === null) {
// _searchString can be null if stop() was called and remote suggestions
// were disabled (stopping if we are fetching remote suggestions will
// cause a promise rejection before we reach _dedupeAndReturnResults).
return null;
}
let results = {
term: this._searchString,
remote: [],
local: [],
formHistoryResult: null,
};
for (let result of suggestResults) {
if (typeof result === "string") { // Failure message
Cu.reportError("SearchSuggestionController: " + result);
} else if (result.formHistoryResult) { // Local results have a formHistoryResult property.
results.formHistoryResult = result.formHistoryResult;
results.local = result.result || [];
} else { // Remote result
results.remote = result.result || [];
}
}
// If we have remote results, cap the number of local results
if (results.remote.length) {
results.local = results.local.slice(0, this.maxLocalResults);
}
// We don't want things to appear in both history and suggestions so remove entries from
// remote results that are already in local.
if (results.remote.length && results.local.length) {
for (let i = 0; i < results.local.length; ++i) {
let term = results.local[i];
let dupIndex = results.remote.indexOf(term);
if (dupIndex != -1) {
results.remote.splice(dupIndex, 1);
}
}
}
// Trim the number of results to the maximum requested (now that we've pruned dupes).
results.remote =
results.remote.slice(0, this.maxRemoteResults - results.local.length);
if (this._callback) {
this._callback(results);
}
this._reset();
return results;
},
_reset: function() {
this._request = null;
if (this._remoteResultTimer) {
this._remoteResultTimer.cancel();
this._remoteResultTimer = null;
}
this._deferredRemoteResult = null;
this._searchString = null;
},
};
/**
* Determines whether the given engine offers search suggestions.
*
* @param {nsISearchEngine} engine - The search engine
* @return {boolean} True if the engine offers suggestions and false otherwise.
*/
this.SearchSuggestionController.engineOffersSuggestions = function(engine) {
return engine.supportsResponseType(SEARCH_RESPONSE_SUGGESTION_JSON);
};
@@ -0,0 +1,31 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
EXTRA_COMPONENTS += [
'nsSearchSuggestions.js',
]
EXTRA_PP_COMPONENTS += [
'nsSearchService.js',
]
if CONFIG['MOZ_PHOENIX'] or CONFIG['MOZ_FENNEC'] or CONFIG['MOZ_XULRUNNER']:
DEFINES['HAVE_SIDEBAR'] = True
EXTRA_COMPONENTS += [
'nsSidebar.js',
]
EXTRA_JS_MODULES += [
'SearchSuggestionController.jsm',
]
EXTRA_PP_COMPONENTS += [
'toolkitsearch.manifest',
]
EXTRA_JS_MODULES += [
'SearchStaticData.jsm',
]
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,197 @@
/* 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/. */
const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/nsFormAutoCompleteResult.jsm");
Cu.import("resource://gre/modules/Services.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "SearchSuggestionController",
"resource://gre/modules/SearchSuggestionController.jsm");
/**
* SuggestAutoComplete is a base class that implements nsIAutoCompleteSearch
* and can collect results for a given search by using this._suggestionController.
* We do it this way since the AutoCompleteController in Mozilla requires a
* unique XPCOM Service for every search provider, even if the logic for two
* providers is identical.
* @constructor
*/
function SuggestAutoComplete() {
this._init();
}
SuggestAutoComplete.prototype = {
_init: function() {
this._suggestionController = new SearchSuggestionController(obj => this.onResultsReturned(obj));
this._suggestionController.maxLocalResults = this._historyLimit;
},
get _suggestionLabel() {
let bundle = Services.strings.createBundle("chrome://global/locale/search/search.properties");
let label = bundle.GetStringFromName("suggestion_label");
Object.defineProperty(SuggestAutoComplete.prototype, "_suggestionLabel", {value: label});
return label;
},
/**
* The object implementing nsIAutoCompleteObserver that we notify when
* we have found results
* @private
*/
_listener: null,
/**
* Maximum number of history items displayed. This is capped at 7
* because the primary consumer (Firefox search bar) displays 10 rows
* by default, and so we want to leave some space for suggestions
* to be visible.
*/
_historyLimit: 7,
/**
* Callback for handling results from SearchSuggestionController.jsm
* @private
*/
onResultsReturned: function(results) {
let finalResults = [];
let finalComments = [];
// If form history has results, add them to the list.
for (let i = 0; i < results.local.length; ++i) {
finalResults.push(results.local[i]);
finalComments.push("");
}
// If there are remote matches, add them.
if (results.remote.length) {
// "comments" column values for suggestions starts as empty strings
let comments = new Array(results.remote.length).fill("", 1);
comments[0] = this._suggestionLabel;
// now put the history results above the suggestions
finalResults = finalResults.concat(results.remote);
finalComments = finalComments.concat(comments);
}
// Notify the FE of our new results
this.onResultsReady(results.term, finalResults, finalComments, results.formHistoryResult);
},
/**
* Notifies the front end of new results.
* @param searchString the user's query string
* @param results an array of results to the search
* @param comments an array of metadata corresponding to the results
* @private
*/
onResultsReady: function(searchString, results, comments, formHistoryResult) {
if (this._listener) {
// Create a copy of the results array to use as labels, since
// FormAutoCompleteResult doesn't like being passed the same array
// for both.
let labels = results.slice();
let result = new FormAutoCompleteResult(
searchString,
Ci.nsIAutoCompleteResult.RESULT_SUCCESS,
0,
"",
results,
labels,
comments,
formHistoryResult);
this._listener.onSearchResult(this, result);
// Null out listener to make sure we don't notify it twice
this._listener = null;
}
},
/**
* Initiates the search result gathering process. Part of
* nsIAutoCompleteSearch implementation.
*
* @param searchString the user's query string
* @param searchParam unused, "an extra parameter"; even though
* this parameter and the next are unused, pass
* them through in case the form history
* service wants them
* @param previousResult unused, a client-cached store of the previous
* generated resultset for faster searching.
* @param listener object implementing nsIAutoCompleteObserver which
* we notify when results are ready.
*/
startSearch: function(searchString, searchParam, previousResult, listener) {
// Don't reuse a previous form history result when it no longer applies.
if (!previousResult)
this._formHistoryResult = null;
var formHistorySearchParam = searchParam.split("|")[0];
// Receive the information about the privacy mode of the window to which
// this search box belongs. The front-end's search.xml bindings passes this
// information in the searchParam parameter. The alternative would have
// been to modify nsIAutoCompleteSearch to add an argument to startSearch
// and patch all of autocomplete to be aware of this, but the searchParam
// argument is already an opaque argument, so this solution is hopefully
// less hackish (although still gross.)
var privacyMode = (searchParam.split("|")[1] == "private");
// Start search immediately if possible, otherwise once the search
// service is initialized
if (Services.search.isInitialized) {
this._triggerSearch(searchString, formHistorySearchParam, listener, privacyMode);
return;
}
Services.search.init((function startSearch_cb(aResult) {
if (!Components.isSuccessCode(aResult)) {
Cu.reportError("Could not initialize search service, bailing out: " + aResult);
return;
}
this._triggerSearch(searchString, formHistorySearchParam, listener, privacyMode);
}).bind(this));
},
/**
* Actual implementation of search.
*/
_triggerSearch: function(searchString, searchParam, listener, privacyMode) {
this._listener = listener;
this._suggestionController.fetch(searchString,
privacyMode,
Services.search.currentEngine);
},
/**
* Ends the search result gathering process. Part of nsIAutoCompleteSearch
* implementation.
*/
stopSearch: function() {
this._suggestionController.stop();
},
// nsISupports
QueryInterface: XPCOMUtils.generateQI([Ci.nsIAutoCompleteSearch,
Ci.nsIAutoCompleteObserver])
};
/**
* SearchSuggestAutoComplete is a service implementation that handles suggest
* results specific to web searches.
* @constructor
*/
function SearchSuggestAutoComplete() {
// This calls _init() in the parent class (SuggestAutoComplete) via the
// prototype, below.
this._init();
}
SearchSuggestAutoComplete.prototype = {
classID: Components.ID("{aa892eb4-ffbf-477d-9f9a-06c995ae9f27}"),
__proto__: SuggestAutoComplete.prototype,
serviceURL: ""
};
var component = [SearchSuggestAutoComplete];
this.NSGetFactory = XPCOMUtils.generateNSGetFactory(component);
@@ -0,0 +1,57 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 4 -*- */
/* 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/. */
const { interfaces: Ci, utils: Cu } = Components;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
// File extension for Sherlock search plugin description files
const SHERLOCK_FILE_EXT_REGEXP = /\.src$/i;
function nsSidebar() {
}
nsSidebar.prototype = {
init: function(window) {
this.window = window;
this.mm = window.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDocShell)
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIContentFrameMessageManager);
},
// Deprecated, only left here to avoid breaking old browser-detection scripts.
addSearchEngine: function(engineURL, iconURL, suggestedTitle, suggestedCategory) {
if (SHERLOCK_FILE_EXT_REGEXP.test(engineURL)) {
Cu.reportError("Installing Sherlock search plugins is no longer supported.");
return;
}
this.AddSearchProvider(engineURL);
},
// This function implements window.external.AddSearchProvider().
// The capitalization, although nonstandard here, is to match other browsers'
// APIs and is therefore important.
AddSearchProvider: function(engineURL) {
this.mm.sendAsyncMessage("Search:AddEngine", {
pageURL: this.window.document.documentURIObject.spec,
engineURL
});
},
// This function exists to implement window.external.IsSearchProviderInstalled(),
// for compatibility with other browsers. The function has been deprecated
// and so will not be implemented.
IsSearchProviderInstalled: function(engineURL) {
return 0;
},
classID: Components.ID("{22117140-9c6e-11d3-aaf1-00805f8a4905}"),
QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports,
Ci.nsIDOMGlobalPropertyInitializer])
}
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([nsSidebar]);
@@ -0,0 +1,10 @@
component {7319788a-fe93-4db3-9f39-818cf08f4256} nsSearchService.js process=main
contract @mozilla.org/browser/search-service;1 {7319788a-fe93-4db3-9f39-818cf08f4256} process=main
# 21600 == 6 hours
category update-timer nsSearchService @mozilla.org/browser/search-service;1,getService,search-engine-update-timer,browser.search.update.interval,21600
component {aa892eb4-ffbf-477d-9f9a-06c995ae9f27} nsSearchSuggestions.js
contract @mozilla.org/autocomplete/search;1?name=search-autocomplete {aa892eb4-ffbf-477d-9f9a-06c995ae9f27}
#ifdef HAVE_SIDEBAR
component {22117140-9c6e-11d3-aaf1-00805f8a4905} nsSidebar.js
contract @mozilla.org/sidebar;1 {22117140-9c6e-11d3-aaf1-00805f8a4905}
#endif