Merge last PGO-safe changeset from inbound to central
1
aclocal.m4
vendored
@ -18,6 +18,7 @@ builtin(include, build/autoconf/lto.m4)dnl
|
||||
builtin(include, build/autoconf/gcc-pr49911.m4)dnl
|
||||
builtin(include, build/autoconf/frameptr.m4)dnl
|
||||
builtin(include, build/autoconf/compiler-opts.m4)dnl
|
||||
builtin(include, build/autoconf/expandlibs.m4)dnl
|
||||
|
||||
MOZ_PROG_CHECKMSYS()
|
||||
|
||||
|
@ -850,7 +850,7 @@ nsContextMenu.prototype = {
|
||||
let uri = makeURI(this.mediaURL);
|
||||
let url = uri.QueryInterface(Ci.nsIURL);
|
||||
if (url.fileBaseName)
|
||||
name = url.fileBaseName + ".jpg";
|
||||
name = decodeURI(url.fileBaseName) + ".jpg";
|
||||
} catch (e) { }
|
||||
if (!name)
|
||||
name = "snapshot.jpg";
|
||||
|
@ -47,20 +47,6 @@
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
#technicalContent > h2, #expertContent > h2 {
|
||||
cursor: pointer;
|
||||
-moz-padding-start: 20px;
|
||||
position: relative;
|
||||
left: -20px;
|
||||
}
|
||||
|
||||
body[dir="rtl"] #technicalContent > h2,
|
||||
body[dir="rtl"] #expertContent > h2 {
|
||||
left: auto;
|
||||
right: -20px;
|
||||
}
|
||||
|
||||
div[collapsed] > p,
|
||||
div[collapsed] > div {
|
||||
.expander[collapsed] + * {
|
||||
display: none;
|
||||
}
|
||||
|
@ -260,18 +260,18 @@
|
||||
|
||||
<!-- The following sections can be unhidden by default by setting the
|
||||
"browser.xul.error_pages.expert_bad_cert" pref to true -->
|
||||
<div id="technicalContent" collapsed="true">
|
||||
<h2 onclick="toggle('technicalContent');" id="technicalContentHeading">&certerror.technical.heading;</h2>
|
||||
<p id="technicalContentText"/>
|
||||
</div>
|
||||
<h2 id="technicalContent" class="expander" collapsed="true">
|
||||
<button onclick="toggle('technicalContent');">&certerror.technical.heading;</button>
|
||||
</h2>
|
||||
<p id="technicalContentText"/>
|
||||
|
||||
<div id="expertContent" collapsed="true">
|
||||
<h2 onclick="toggle('expertContent');" id="expertContentHeading">&certerror.expert.heading;</h2>
|
||||
<div>
|
||||
<p>&certerror.expert.content;</p>
|
||||
<p>&certerror.expert.contentPara2;</p>
|
||||
<button id='exceptionDialogButton'>&certerror.addException.label;</button>
|
||||
</div>
|
||||
<h2 id="expertContent" class="expander" collapsed="true">
|
||||
<button onclick="toggle('expertContent');">&certerror.expert.heading;</button>
|
||||
</h2>
|
||||
<div>
|
||||
<p>&certerror.expert.content;</p>
|
||||
<p>&certerror.expert.contentPara2;</p>
|
||||
<button id='exceptionDialogButton'>&certerror.addException.label;</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -56,6 +56,7 @@
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsStringAPI.h"
|
||||
#include "nsXULAppAPI.h"
|
||||
#include "nsIPrefLocalizedString.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace browser {
|
||||
@ -200,7 +201,18 @@ AppendDistroSearchDirs(nsIProperties* aDirSvc, nsCOMArray<nsIFile> &array)
|
||||
localePlugins->AppendNative(NS_LITERAL_CSTRING("locale"));
|
||||
|
||||
nsCString locale;
|
||||
rv = prefs->GetCharPref("general.useragent.locale", getter_Copies(locale));
|
||||
nsCOMPtr<nsIPrefLocalizedString> prefString;
|
||||
rv = prefs->GetComplexValue("general.useragent.locale",
|
||||
NS_GET_IID(nsIPrefLocalizedString),
|
||||
getter_AddRefs(prefString));
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
nsAutoString wLocale;
|
||||
prefString->GetData(getter_Copies(wLocale));
|
||||
CopyUTF16toUTF8(wLocale, locale);
|
||||
} else {
|
||||
rv = prefs->GetCharPref("general.useragent.locale", getter_Copies(locale));
|
||||
}
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
|
||||
nsCOMPtr<nsIFile> curLocalePlugins;
|
||||
|
@ -657,7 +657,9 @@ PlacesViewBase.prototype = {
|
||||
aPlacesNode._siteURI = aLivemark.siteURI;
|
||||
if (aNewState == Ci.nsINavHistoryContainerResultNode.STATE_OPENED) {
|
||||
aLivemark.registerForUpdates(aPlacesNode, this);
|
||||
// Prioritize the current livemark.
|
||||
aLivemark.reload();
|
||||
PlacesUtils.livemarks.reloadLivemarks();
|
||||
if (shouldInvalidate)
|
||||
this.invalidateContainer(aPlacesNode);
|
||||
}
|
||||
@ -900,11 +902,6 @@ PlacesToolbar.prototype = {
|
||||
__proto__: PlacesViewBase.prototype,
|
||||
|
||||
_cbEvents: ["dragstart", "dragover", "dragexit", "dragend", "drop",
|
||||
#ifdef XP_UNIX
|
||||
#ifndef XP_MACOSX
|
||||
"mousedown", "mouseup",
|
||||
#endif
|
||||
#endif
|
||||
"mousemove", "mouseover", "mouseout"],
|
||||
|
||||
QueryInterface: function PT_QueryInterface(aIID) {
|
||||
@ -1101,16 +1098,6 @@ PlacesToolbar.prototype = {
|
||||
case "mouseout":
|
||||
this._onMouseOut(aEvent);
|
||||
break;
|
||||
#ifdef XP_UNIX
|
||||
#ifndef XP_MACOSX
|
||||
case "mouseup":
|
||||
this._onMouseUp(aEvent);
|
||||
break;
|
||||
case "mousedown":
|
||||
this._onMouseDown(aEvent);
|
||||
break;
|
||||
#endif
|
||||
#endif
|
||||
case "popupshowing":
|
||||
this._onPopupShowing(aEvent);
|
||||
break;
|
||||
@ -1538,14 +1525,6 @@ PlacesToolbar.prototype = {
|
||||
draggedElt.getAttribute("type") == "menu") {
|
||||
// If the drag gesture on a container is toward down we open instead
|
||||
// of dragging.
|
||||
#ifdef XP_UNIX
|
||||
#ifndef XP_MACOSX
|
||||
if (this._mouseDownTimer) {
|
||||
this._mouseDownTimer.cancel();
|
||||
this._mouseDownTimer = null;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
let translateY = this._cachedMouseMoveEvent.clientY - aEvent.clientY;
|
||||
let translateX = this._cachedMouseMoveEvent.clientX - aEvent.clientX;
|
||||
if ((translateY) >= Math.abs(translateX/2)) {
|
||||
@ -1718,47 +1697,6 @@ PlacesToolbar.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
#ifdef XP_UNIX
|
||||
#ifndef XP_MACOSX
|
||||
_onMouseDown: function PT__onMouseDown(aEvent) {
|
||||
let target = aEvent.target;
|
||||
if (aEvent.button == 0 &&
|
||||
target.localName == "toolbarbutton" &&
|
||||
target.getAttribute("type") == "menu") {
|
||||
this._allowPopupShowing = false;
|
||||
// On Linux we can open the popup only after a delay.
|
||||
// Indeed as soon as the menupopup opens we are unable to start a
|
||||
// drag aEvent. See bug 500081 for details.
|
||||
this._mouseDownTimer = Cc["@mozilla.org/timer;1"].
|
||||
createInstance(Ci.nsITimer);
|
||||
let callback = {
|
||||
_self: this,
|
||||
_target: target,
|
||||
notify: function(timer) {
|
||||
this._target.open = true;
|
||||
this._mouseDownTimer = null;
|
||||
}
|
||||
};
|
||||
|
||||
this._mouseDownTimer.initWithCallback(callback, 300,
|
||||
Ci.nsITimer.TYPE_ONE_SHOT);
|
||||
}
|
||||
},
|
||||
|
||||
_onMouseUp: function PT__onMouseUp(aEvent) {
|
||||
if (aEvent.button != 0)
|
||||
return;
|
||||
|
||||
if (this._mouseDownTimer) {
|
||||
// On a click (down/up), we should open the menu popup.
|
||||
this._mouseDownTimer.cancel();
|
||||
this._mouseDownTimer = null;
|
||||
aEvent.target.open = true;
|
||||
}
|
||||
},
|
||||
#endif
|
||||
#endif
|
||||
|
||||
_onMouseMove: function PT__onMouseMove(aEvent) {
|
||||
// Used in dragStart to prevent dragging folders when dragging down.
|
||||
this._cachedMouseMoveEvent = aEvent;
|
||||
|
@ -90,7 +90,6 @@
|
||||
observes="paneElementsBroadcaster"/>
|
||||
<textbox id="editBMPanel_feedLocationField"
|
||||
class="uri-element"
|
||||
onblur="gEditItemOverlay.onFeedLocationFieldBlur();"
|
||||
observes="paneElementsBroadcaster"/>
|
||||
</row>
|
||||
|
||||
@ -102,7 +101,6 @@
|
||||
observes="paneElementsBroadcaster"/>
|
||||
<textbox id="editBMPanel_siteLocationField"
|
||||
class="uri-element"
|
||||
onblur="gEditItemOverlay.onSiteLocationFieldBlur();"
|
||||
observes="paneElementsBroadcaster"/>
|
||||
</row>
|
||||
|
||||
|
@ -896,7 +896,9 @@ PlacesTreeView.prototype = {
|
||||
aNode._feedURI = aLivemark.feedURI;
|
||||
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);
|
||||
}
|
||||
|
@ -86,21 +86,24 @@ body[dir="rtl"] #errorPageContainer {
|
||||
-moz-margin-start: 80px;
|
||||
}
|
||||
|
||||
#technicalContent > h2, #expertContent > h2 {
|
||||
background : url("chrome://browser/skin/section_expanded.png") left 0 no-repeat;
|
||||
.expander > button {
|
||||
-moz-padding-start: 20px;
|
||||
-moz-margin-start: -20px;
|
||||
background: url("chrome://browser/skin/aboutCertError_sectionExpanded.png") left center no-repeat;
|
||||
border: none;
|
||||
font: inherit;
|
||||
color: inherit;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
body[dir="rtl"] #technicalContent > h2,
|
||||
body[dir="rtl"] #expertContent > h2 {
|
||||
background-position: right 0;
|
||||
body[dir="rtl"] .expander > button {
|
||||
background-position: right center;
|
||||
}
|
||||
|
||||
#technicalContent[collapsed] > h2,
|
||||
#expertContent[collapsed] > h2{
|
||||
background-image: url("chrome://browser/skin/section_collapsed.png");
|
||||
.expander[collapsed] > button {
|
||||
background-image: url("chrome://browser/skin/aboutCertError_sectionCollapsed.png");
|
||||
}
|
||||
|
||||
body[dir="rtl"] #technicalContent[collapsed] > h2,
|
||||
body[dir="rtl"] #expertContent[collapsed] > h2 {
|
||||
background-image: url("chrome://browser/skin/section_collapsed-rtl.png");
|
||||
body[dir="rtl"] .expander[collapsed] > button {
|
||||
background-image: url("chrome://browser/skin/aboutCertError_sectionCollapsed-rtl.png");
|
||||
}
|
||||
|
Before Width: | Height: | Size: 791 B After Width: | Height: | Size: 791 B |
Before Width: | Height: | Size: 776 B After Width: | Height: | Size: 776 B |
Before Width: | Height: | Size: 767 B After Width: | Height: | Size: 767 B |
@ -1,8 +0,0 @@
|
||||
#close {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
background: url(KUI-close.png) center center no-repeat;
|
||||
}
|
@ -5,14 +5,16 @@ browser.jar:
|
||||
* skin/classic/browser/aboutPrivateBrowsing.css (aboutPrivateBrowsing.css)
|
||||
* skin/classic/browser/aboutSessionRestore.css (aboutSessionRestore.css)
|
||||
skin/classic/browser/aboutSessionRestore-window-icon.png
|
||||
skin/classic/browser/aboutCertError.css (aboutCertError.css)
|
||||
skin/classic/browser/aboutCertError.css
|
||||
skin/classic/browser/aboutCertError_sectionCollapsed.png
|
||||
skin/classic/browser/aboutCertError_sectionCollapsed-rtl.png
|
||||
skin/classic/browser/aboutCertError_sectionExpanded.png
|
||||
#ifdef MOZ_SERVICES_SYNC
|
||||
skin/classic/browser/aboutSyncTabs.css
|
||||
#endif
|
||||
skin/classic/browser/actionicon-tab.png
|
||||
* skin/classic/browser/browser.css (browser.css)
|
||||
* skin/classic/browser/engineManager.css (engineManager.css)
|
||||
skin/classic/browser/fullscreen-video.css
|
||||
skin/classic/browser/Geolocation-16.png
|
||||
skin/classic/browser/Geolocation-64.png
|
||||
skin/classic/browser/Go-arrow.png
|
||||
@ -27,9 +29,6 @@ browser.jar:
|
||||
skin/classic/browser/Privacy-16.png
|
||||
skin/classic/browser/Privacy-48.png
|
||||
skin/classic/browser/searchbar.css (searchbar.css)
|
||||
skin/classic/browser/section_collapsed.png
|
||||
skin/classic/browser/section_collapsed-rtl.png
|
||||
skin/classic/browser/section_expanded.png
|
||||
skin/classic/browser/Secure.png
|
||||
skin/classic/browser/Security-broken.png
|
||||
skin/classic/browser/setDesktopBackground.css
|
||||
|
@ -86,21 +86,24 @@ body[dir="rtl"] #errorPageContainer {
|
||||
-moz-margin-start: 80px;
|
||||
}
|
||||
|
||||
#technicalContent > h2, #expertContent > h2 {
|
||||
background : url("chrome://browser/skin/section_expanded.png") left 0 no-repeat;
|
||||
.expander > button {
|
||||
-moz-padding-start: 20px;
|
||||
-moz-margin-start: -20px;
|
||||
background: url("chrome://browser/skin/aboutCertError_sectionExpanded.png") left center no-repeat;
|
||||
border: none;
|
||||
font: inherit;
|
||||
color: inherit;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
body[dir="rtl"] #technicalContent > h2,
|
||||
body[dir="rtl"] #expertContent > h2 {
|
||||
background-position: right 0;
|
||||
body[dir="rtl"] .expander > button {
|
||||
background-position: right center;
|
||||
}
|
||||
|
||||
#technicalContent[collapsed] > h2,
|
||||
#expertContent[collapsed] > h2{
|
||||
background-image: url("chrome://browser/skin/section_collapsed.png");
|
||||
.expander[collapsed] > button {
|
||||
background-image: url("chrome://browser/skin/aboutCertError_sectionCollapsed.png");
|
||||
}
|
||||
|
||||
body[dir="rtl"] #technicalContent[collapsed] > h2,
|
||||
body[dir="rtl"] #expertContent[collapsed] > h2 {
|
||||
background-image: url("chrome://browser/skin/section_collapsed-rtl.png");
|
||||
body[dir="rtl"] .expander[collapsed] > button {
|
||||
background-image: url("chrome://browser/skin/aboutCertError_sectionCollapsed-rtl.png");
|
||||
}
|
||||
|
Before Width: | Height: | Size: 791 B After Width: | Height: | Size: 791 B |
Before Width: | Height: | Size: 776 B After Width: | Height: | Size: 776 B |
Before Width: | Height: | Size: 767 B After Width: | Height: | Size: 767 B |
@ -1,8 +0,0 @@
|
||||
#close {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
background: url(KUI-close.png) center center no-repeat;
|
||||
}
|
@ -4,14 +4,16 @@ browser.jar:
|
||||
* skin/classic/browser/aboutPrivateBrowsing.css (aboutPrivateBrowsing.css)
|
||||
* skin/classic/browser/aboutSessionRestore.css (aboutSessionRestore.css)
|
||||
skin/classic/browser/aboutSessionRestore-window-icon.png
|
||||
skin/classic/browser/aboutCertError.css (aboutCertError.css)
|
||||
skin/classic/browser/aboutCertError.css
|
||||
skin/classic/browser/aboutCertError_sectionCollapsed.png
|
||||
skin/classic/browser/aboutCertError_sectionCollapsed-rtl.png
|
||||
skin/classic/browser/aboutCertError_sectionExpanded.png
|
||||
#ifdef MOZ_SERVICES_SYNC
|
||||
skin/classic/browser/aboutSyncTabs.css
|
||||
#endif
|
||||
skin/classic/browser/actionicon-tab.png
|
||||
* skin/classic/browser/browser.css (browser.css)
|
||||
* skin/classic/browser/engineManager.css (engineManager.css)
|
||||
skin/classic/browser/fullscreen-video.css
|
||||
skin/classic/browser/Geolocation-16.png
|
||||
skin/classic/browser/Geolocation-64.png
|
||||
skin/classic/browser/home.png
|
||||
@ -36,9 +38,6 @@ browser.jar:
|
||||
skin/classic/browser/searchbar-dropmarker.png
|
||||
skin/classic/browser/searchbar.css
|
||||
skin/classic/browser/Search.png
|
||||
skin/classic/browser/section_collapsed.png
|
||||
skin/classic/browser/section_collapsed-rtl.png
|
||||
skin/classic/browser/section_expanded.png
|
||||
skin/classic/browser/Secure-Glyph-White.png
|
||||
skin/classic/browser/keyhole-circle.png
|
||||
skin/classic/browser/Toolbar.png
|
||||
|
@ -86,21 +86,24 @@ body[dir="rtl"] #errorPageContainer {
|
||||
-moz-margin-start: 80px;
|
||||
}
|
||||
|
||||
#technicalContent > h2, #expertContent > h2 {
|
||||
background : url("chrome://browser/skin/section_expanded.png") left center no-repeat;
|
||||
.expander > button {
|
||||
-moz-padding-start: 20px;
|
||||
-moz-margin-start: -20px;
|
||||
background: url("chrome://browser/skin/aboutCertError_sectionExpanded.png") left center no-repeat;
|
||||
border: none;
|
||||
font: inherit;
|
||||
color: inherit;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
body[dir="rtl"] #technicalContent > h2,
|
||||
body[dir="rtl"] #expertContent > h2 {
|
||||
body[dir="rtl"] .expander > button {
|
||||
background-position: right center;
|
||||
}
|
||||
|
||||
#technicalContent[collapsed] > h2,
|
||||
#expertContent[collapsed] > h2{
|
||||
background-image: url("chrome://browser/skin/section_collapsed.png");
|
||||
.expander[collapsed] > button {
|
||||
background-image: url("chrome://browser/skin/aboutCertError_sectionCollapsed.png");
|
||||
}
|
||||
|
||||
body[dir="rtl"] #technicalContent[collapsed] > h2,
|
||||
body[dir="rtl"] #expertContent[collapsed] > h2 {
|
||||
background-image: url("chrome://browser/skin/section_collapsed-rtl.png");
|
||||
body[dir="rtl"] .expander[collapsed] > button {
|
||||
background-image: url("chrome://browser/skin/aboutCertError_sectionCollapsed-rtl.png");
|
||||
}
|
||||
|
Before Width: | Height: | Size: 791 B After Width: | Height: | Size: 791 B |
Before Width: | Height: | Size: 776 B After Width: | Height: | Size: 776 B |
Before Width: | Height: | Size: 767 B After Width: | Height: | Size: 767 B |
@ -1,8 +0,0 @@
|
||||
#close {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
background: url(KUI-close.png) center center no-repeat;
|
||||
}
|
@ -7,7 +7,10 @@ browser.jar:
|
||||
* skin/classic/browser/aboutPrivateBrowsing.css (aboutPrivateBrowsing.css)
|
||||
* skin/classic/browser/aboutSessionRestore.css (aboutSessionRestore.css)
|
||||
skin/classic/browser/aboutSessionRestore-window-icon.png (preferences/application.png)
|
||||
skin/classic/browser/aboutCertError.css (aboutCertError.css)
|
||||
skin/classic/browser/aboutCertError.css
|
||||
skin/classic/browser/aboutCertError_sectionCollapsed.png
|
||||
skin/classic/browser/aboutCertError_sectionCollapsed-rtl.png
|
||||
skin/classic/browser/aboutCertError_sectionExpanded.png
|
||||
#ifdef MOZ_SERVICES_SYNC
|
||||
skin/classic/browser/aboutSyncTabs.css
|
||||
#endif
|
||||
@ -16,7 +19,6 @@ browser.jar:
|
||||
skin/classic/browser/appmenu-dropmarker.png
|
||||
* skin/classic/browser/browser.css (browser.css)
|
||||
* skin/classic/browser/engineManager.css (engineManager.css)
|
||||
skin/classic/browser/fullscreen-video.css
|
||||
skin/classic/browser/Geolocation-16.png
|
||||
skin/classic/browser/Geolocation-64.png
|
||||
skin/classic/browser/Info.png (Info.png)
|
||||
@ -38,9 +40,6 @@ browser.jar:
|
||||
skin/classic/browser/toolbarbutton-dropdown-arrow-inverted.png
|
||||
* skin/classic/browser/searchbar.css (searchbar.css)
|
||||
skin/classic/browser/searchbar-dropdown-arrow.png
|
||||
skin/classic/browser/section_collapsed.png
|
||||
skin/classic/browser/section_collapsed-rtl.png
|
||||
skin/classic/browser/section_expanded.png
|
||||
skin/classic/browser/setDesktopBackground.css
|
||||
skin/classic/browser/menu-back.png (menu-back.png)
|
||||
skin/classic/browser/menu-forward.png (menu-forward.png)
|
||||
@ -177,7 +176,10 @@ browser.jar:
|
||||
* skin/classic/aero/browser/aboutPrivateBrowsing.css (aboutPrivateBrowsing.css)
|
||||
* skin/classic/aero/browser/aboutSessionRestore.css (aboutSessionRestore.css)
|
||||
skin/classic/aero/browser/aboutSessionRestore-window-icon.png (aboutSessionRestore-window-icon-aero.png)
|
||||
skin/classic/aero/browser/aboutCertError.css (aboutCertError.css)
|
||||
skin/classic/aero/browser/aboutCertError.css
|
||||
skin/classic/aero/browser/aboutCertError_sectionCollapsed.png
|
||||
skin/classic/aero/browser/aboutCertError_sectionCollapsed-rtl.png
|
||||
skin/classic/aero/browser/aboutCertError_sectionExpanded.png
|
||||
#ifdef MOZ_SERVICES_SYNC
|
||||
skin/classic/aero/browser/aboutSyncTabs.css
|
||||
#endif
|
||||
@ -186,7 +188,6 @@ browser.jar:
|
||||
skin/classic/aero/browser/appmenu-icons.png
|
||||
* skin/classic/aero/browser/browser.css (browser-aero.css)
|
||||
* skin/classic/aero/browser/engineManager.css (engineManager.css)
|
||||
skin/classic/aero/browser/fullscreen-video.css
|
||||
skin/classic/aero/browser/Geolocation-16.png
|
||||
skin/classic/aero/browser/Geolocation-64.png
|
||||
skin/classic/aero/browser/Info.png (Info-aero.png)
|
||||
@ -208,9 +209,6 @@ browser.jar:
|
||||
skin/classic/aero/browser/toolbarbutton-dropdown-arrow-inverted.png
|
||||
* skin/classic/aero/browser/searchbar.css (searchbar.css)
|
||||
skin/classic/aero/browser/searchbar-dropdown-arrow.png (searchbar-dropdown-arrow-aero.png)
|
||||
skin/classic/aero/browser/section_collapsed.png
|
||||
skin/classic/aero/browser/section_collapsed-rtl.png
|
||||
skin/classic/aero/browser/section_expanded.png
|
||||
skin/classic/aero/browser/setDesktopBackground.css
|
||||
skin/classic/aero/browser/menu-back.png (menu-back-aero.png)
|
||||
skin/classic/aero/browser/menu-forward.png (menu-forward-aero.png)
|
||||
|
@ -9,5 +9,76 @@ if test "$CLANG_CXX"; then
|
||||
## from C.
|
||||
_WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wno-unknown-warning-option -Wno-return-type-c-linkage"
|
||||
fi
|
||||
])
|
||||
|
||||
if test "$GNU_CC"; then
|
||||
CFLAGS="$CFLAGS -ffunction-sections -fdata-sections"
|
||||
CXXFLAGS="$CXXFLAGS -ffunction-sections -fdata-sections"
|
||||
fi
|
||||
|
||||
dnl ========================================================
|
||||
dnl = Identical Code Folding
|
||||
dnl ========================================================
|
||||
|
||||
MOZ_ARG_DISABLE_BOOL(icf,
|
||||
[ --disable-icf Disable Identical Code Folding],
|
||||
MOZ_DISABLE_ICF=1,
|
||||
MOZ_DISABLE_ICF= )
|
||||
|
||||
if test "$GNU_CC" -a "$GCC_USE_GNU_LD" -a -z "$MOZ_DISABLE_ICF"; then
|
||||
AC_CACHE_CHECK([whether the linker supports Identical Code Folding],
|
||||
LD_SUPPORTS_ICF,
|
||||
[echo 'int foo() {return 42;}' \
|
||||
'int bar() {return 42;}' \
|
||||
'int main() {return foo() - bar();}' > conftest.${ac_ext}
|
||||
# If the linker supports ICF, foo and bar symbols will have
|
||||
# the same address
|
||||
if AC_TRY_COMMAND([${CC-cc} -o conftest${ac_exeext} $LDFLAGS -Wl,--icf=safe -ffunction-sections conftest.${ac_ext} $LIBS 1>&2]) &&
|
||||
test -s conftest${ac_exeext} &&
|
||||
objdump -t conftest${ac_exeext} | awk changequote(<<, >>)'{a[<<$>>6] = <<$>>1} END {if (a["foo"] && (a["foo"] != a["bar"])) { exit 1 }}'changequote([, ]); then
|
||||
LD_SUPPORTS_ICF=yes
|
||||
else
|
||||
LD_SUPPORTS_ICF=no
|
||||
fi
|
||||
rm -rf conftest*])
|
||||
if test "$LD_SUPPORTS_ICF" = yes; then
|
||||
_SAVE_LDFLAGS="$LDFLAGS -Wl,--icf=safe"
|
||||
LDFLAGS="$LDFLAGS -Wl,--icf=safe -Wl,--print-icf-sections"
|
||||
AC_TRY_LINK([], [],
|
||||
[LD_PRINT_ICF_SECTIONS=-Wl,--print-icf-sections],
|
||||
[LD_PRINT_ICF_SECTIONS=])
|
||||
AC_SUBST([LD_PRINT_ICF_SECTIONS])
|
||||
LDFLAGS="$_SAVE_LDFLAGS"
|
||||
fi
|
||||
fi
|
||||
|
||||
dnl ========================================================
|
||||
dnl = Automatically remove dead symbols
|
||||
dnl ========================================================
|
||||
|
||||
if test "$GNU_CC" -a "$GCC_USE_GNU_LD" -a -n "$MOZ_DEBUG_FLAGS"; then
|
||||
dnl See bug 670659
|
||||
AC_CACHE_CHECK([whether removing dead symbols breaks debugging],
|
||||
GC_SECTIONS_BREAKS_DEBUG_RANGES,
|
||||
[echo 'int foo() {return 42;}' \
|
||||
'int bar() {return 1;}' \
|
||||
'int main() {return foo();}' > conftest.${ac_ext}
|
||||
if AC_TRY_COMMAND([${CC-cc} -o conftest.${ac_objext} $CFLAGS $MOZ_DEBUG_FLAGS -c conftest.${ac_ext} 1>&2]) &&
|
||||
AC_TRY_COMMAND([${CC-cc} -o conftest${ac_exeext} $LDFLAGS $MOZ_DEBUG_FLAGS -Wl,--gc-sections conftest.${ac_objext} $LIBS 1>&2]) &&
|
||||
test -s conftest${ac_exeext} -a -s conftest.${ac_objext}; then
|
||||
if test "`$PYTHON "$_topsrcdir"/build/autoconf/check_debug_ranges.py conftest.${ac_objext} conftest.${ac_ext}`" = \
|
||||
"`$PYTHON "$_topsrcdir"/build/autoconf/check_debug_ranges.py conftest${ac_exeext} conftest.${ac_ext}`"; then
|
||||
GC_SECTIONS_BREAKS_DEBUG_RANGES=no
|
||||
else
|
||||
GC_SECTIONS_BREAKS_DEBUG_RANGES=yes
|
||||
fi
|
||||
else
|
||||
dnl We really don't expect to get here, but just in case
|
||||
GC_SECTIONS_BREAKS_DEBUG_RANGES="no, but it's broken in some other way"
|
||||
fi
|
||||
rm -rf conftest*])
|
||||
if test "$GC_SECTIONS_BREAKS_DEBUG_RANGES" = no; then
|
||||
DSO_LDOPTS="$DSO_LDOPTS -Wl,--gc-sections"
|
||||
fi
|
||||
fi
|
||||
|
||||
])
|
||||
|
56
build/autoconf/expandlibs.m4
Normal file
@ -0,0 +1,56 @@
|
||||
AC_DEFUN([MOZ_EXPAND_LIBS],
|
||||
[
|
||||
dnl ========================================================
|
||||
dnl =
|
||||
dnl = Check what kind of list files are supported by the
|
||||
dnl = linker
|
||||
dnl =
|
||||
dnl ========================================================
|
||||
|
||||
AC_CACHE_CHECK(what kind of list files are supported by the linker,
|
||||
EXPAND_LIBS_LIST_STYLE,
|
||||
[echo "int main() {return 0;}" > conftest.${ac_ext}
|
||||
if AC_TRY_COMMAND(${CC-cc} -o conftest.${OBJ_SUFFIX} -c $CFLAGS $CPPFLAGS conftest.${ac_ext} 1>&5) && test -s conftest.${OBJ_SUFFIX}; then
|
||||
echo "INPUT(conftest.${OBJ_SUFFIX})" > conftest.list
|
||||
if AC_TRY_COMMAND(${CC-cc} -o conftest${ac_exeext} $LDFLAGS conftest.list $LIBS 1>&5) && test -s conftest${ac_exeext}; then
|
||||
EXPAND_LIBS_LIST_STYLE=linkerscript
|
||||
else
|
||||
echo "conftest.${OBJ_SUFFIX}" > conftest.list
|
||||
if AC_TRY_COMMAND(${CC-cc} -o conftest${ac_exeext} $LDFLAGS @conftest.list $LIBS 1>&5) && test -s conftest${ac_exeext}; then
|
||||
EXPAND_LIBS_LIST_STYLE=list
|
||||
else
|
||||
EXPAND_LIBS_LIST_STYLE=none
|
||||
fi
|
||||
fi
|
||||
else
|
||||
dnl We really don't expect to get here, but just in case
|
||||
AC_ERROR([couldn't compile a simple C file])
|
||||
fi
|
||||
rm -rf conftest*])
|
||||
|
||||
LIBS_DESC_SUFFIX=desc
|
||||
AC_SUBST(LIBS_DESC_SUFFIX)
|
||||
AC_SUBST(EXPAND_LIBS_LIST_STYLE)
|
||||
|
||||
if test "$GCC_USE_GNU_LD"; then
|
||||
AC_CACHE_CHECK(what kind of ordering can be done with the linker,
|
||||
EXPAND_LIBS_ORDER_STYLE,
|
||||
[> conftest.order
|
||||
_SAVE_LDFLAGS="$LDFLAGS"
|
||||
LDFLAGS="${LDFLAGS} -Wl,--section-ordering-file,conftest.order"
|
||||
AC_TRY_LINK([], [],
|
||||
EXPAND_LIBS_ORDER_STYLE=section-ordering-file,
|
||||
EXPAND_LIBS_ORDER_STYLE=)
|
||||
LDFLAGS="$_SAVE_LDFLAGS"
|
||||
if test -z "$EXPAND_LIBS_ORDER_STYLE"; then
|
||||
if AC_TRY_COMMAND(${CC-cc} ${DSO_LDOPTS} ${LDFLAGS} -o ${DLL_PREFIX}conftest${DLL_SUFFIX} -Wl,--verbose 2> /dev/null | sed -n '/^===/,/^===/p' | grep '\.text'); then
|
||||
EXPAND_LIBS_ORDER_STYLE=linkerscript
|
||||
else
|
||||
EXPAND_LIBS_ORDER_STYLE=none
|
||||
fi
|
||||
rm -f ${DLL_PREFIX}conftest${DLL_SUFFIX}
|
||||
fi])
|
||||
fi
|
||||
AC_SUBST(EXPAND_LIBS_ORDER_STYLE)
|
||||
|
||||
])
|
@ -789,8 +789,12 @@ EXPAND_LIBS_GEN = $(PYTHON) $(topsrcdir)/config/pythonpath.py -I$(DEPTH)/config
|
||||
EXPAND_AR = $(EXPAND_LIBS_EXEC) --extract -- $(AR)
|
||||
EXPAND_CC = $(EXPAND_LIBS_EXEC) --uselist -- $(CC)
|
||||
EXPAND_CCC = $(EXPAND_LIBS_EXEC) --uselist -- $(CCC)
|
||||
EXPAND_LD = $(EXPAND_LIBS_EXEC) --uselist $(if $(REORDER),--reorder $(REORDER))-- $(LD)
|
||||
EXPAND_MKSHLIB = $(EXPAND_LIBS_EXEC) --uselist $(if $(REORDER),--reorder $(REORDER))-- $(MKSHLIB)
|
||||
EXPAND_LD = $(EXPAND_LIBS_EXEC) --uselist -- $(LD)
|
||||
EXPAND_MKSHLIB_ARGS = --uselist
|
||||
ifdef SYMBOL_ORDER
|
||||
EXPAND_MKSHLIB_ARGS += --symbol-order $(SYMBOL_ORDER)
|
||||
endif
|
||||
EXPAND_MKSHLIB = $(EXPAND_LIBS_EXEC) $(EXPAND_MKSHLIB_ARGS) -- $(MKSHLIB)
|
||||
|
||||
ifdef STDCXX_COMPAT
|
||||
ifneq ($(OS_ARCH),Darwin)
|
||||
|
@ -54,3 +54,5 @@ DLL_SUFFIX = normalize_suffix("@DLL_SUFFIX@")
|
||||
IMPORT_LIB_SUFFIX = normalize_suffix("@IMPORT_LIB_SUFFIX@")
|
||||
LIBS_DESC_SUFFIX = normalize_suffix("@LIBS_DESC_SUFFIX@")
|
||||
EXPAND_LIBS_LIST_STYLE = "@EXPAND_LIBS_LIST_STYLE@"
|
||||
EXPAND_LIBS_ORDER_STYLE = "@EXPAND_LIBS_ORDER_STYLE@"
|
||||
LD_PRINT_ICF_SECTIONS = "@LD_PRINT_ICF_SECTIONS@"
|
||||
|
@ -49,9 +49,9 @@ EXPAND_LIBS_LIST_STYLE variable: 'list' for MSVC style lists (@file.list)
|
||||
or 'linkerscript' for GNU ld linker scripts.
|
||||
See https://bugzilla.mozilla.org/show_bug.cgi?id=584474#c59 for more details.
|
||||
|
||||
With the --reorder argument, followed by a file name, it will reorder the
|
||||
object files from the command line according to the order given in the file.
|
||||
Implies --extract.
|
||||
With the --symbol-order argument, followed by a file name, it will add the
|
||||
relevant linker options to change the order in which the linker puts the
|
||||
symbols appear in the resulting binary. Only works for ELF targets.
|
||||
'''
|
||||
from __future__ import with_statement
|
||||
import sys
|
||||
@ -62,6 +62,18 @@ from optparse import OptionParser
|
||||
import subprocess
|
||||
import tempfile
|
||||
import shutil
|
||||
import subprocess
|
||||
import re
|
||||
|
||||
# The are the insert points for a GNU ld linker script, assuming a more
|
||||
# or less "standard" default linker script. This is not a dict because
|
||||
# order is important.
|
||||
SECTION_INSERT_BEFORE = [
|
||||
('.text', '.fini'),
|
||||
('.rodata', '.rodata1'),
|
||||
('.data.rel.ro', '.dynamic'),
|
||||
('.data', '.data1'),
|
||||
]
|
||||
|
||||
class ExpandArgsMore(ExpandArgs):
|
||||
''' Meant to be used as 'with ExpandArgsMore(args) as ...: '''
|
||||
@ -119,6 +131,7 @@ class ExpandArgsMore(ExpandArgs):
|
||||
content = ["%s\n" % obj for obj in objs]
|
||||
ref = "@" + tmp
|
||||
else:
|
||||
os.close(fd)
|
||||
os.remove(tmp)
|
||||
return
|
||||
self.tmp.append(tmp)
|
||||
@ -129,21 +142,163 @@ class ExpandArgsMore(ExpandArgs):
|
||||
newlist = self[0:idx] + [ref] + [item for item in self[idx:] if item not in objs]
|
||||
self[0:] = newlist
|
||||
|
||||
def reorder(self, order_list):
|
||||
'''Given a list of file names without OBJ_SUFFIX, rearrange self
|
||||
so that the object file names it contains are ordered according to
|
||||
that list.
|
||||
'''
|
||||
objs = [o for o in self if isObject(o)]
|
||||
if not objs: return
|
||||
idx = self.index(objs[0])
|
||||
# Keep everything before the first object, then the ordered objects,
|
||||
# then any other objects, then any non-objects after the first object
|
||||
objnames = dict([(os.path.splitext(os.path.basename(o))[0], o) for o in objs])
|
||||
self[0:] = self[0:idx] + [objnames[o] for o in order_list if o in objnames] + \
|
||||
[o for o in objs if os.path.splitext(os.path.basename(o))[0] not in order_list] + \
|
||||
[x for x in self[idx:] if not isObject(x)]
|
||||
def _getFoldedSections(self):
|
||||
'''Returns a dict about folded sections.
|
||||
When section A and B are folded into section C, the dict contains:
|
||||
{ 'A': 'C',
|
||||
'B': 'C',
|
||||
'C': ['A', 'B'] }'''
|
||||
if not conf.LD_PRINT_ICF_SECTIONS:
|
||||
return {}
|
||||
|
||||
proc = subprocess.Popen(self + [conf.LD_PRINT_ICF_SECTIONS], stdout = subprocess.PIPE, stderr = subprocess.PIPE)
|
||||
(stdout, stderr) = proc.communicate()
|
||||
result = {}
|
||||
# gold's --print-icf-sections output looks like the following:
|
||||
# ld: ICF folding section '.section' in file 'file.o'into '.section' in file 'file.o'
|
||||
# In terms of words, chances are this will change in the future,
|
||||
# especially considering "into" is misplaced. Splitting on quotes
|
||||
# seems safer.
|
||||
for l in stderr.split('\n'):
|
||||
quoted = l.split("'")
|
||||
if len(quoted) > 5 and quoted[1] != quoted[5]:
|
||||
result[quoted[1]] = quoted[5]
|
||||
if quoted[5] in result:
|
||||
result[quoted[5]].append(quoted[1])
|
||||
else:
|
||||
result[quoted[5]] = [quoted[1]]
|
||||
return result
|
||||
|
||||
def _getOrderedSections(self, ordered_symbols):
|
||||
'''Given an ordered list of symbols, returns the corresponding list
|
||||
of sections following the order.'''
|
||||
if not conf.EXPAND_LIBS_ORDER_STYLE in ['linkerscript', 'section-ordering-file']:
|
||||
raise Exception('EXPAND_LIBS_ORDER_STYLE "%s" is not supported' % conf.EXPAND_LIBS_ORDER_STYLE)
|
||||
finder = SectionFinder([arg for arg in self if isObject(arg) or os.path.splitext(arg)[1] == conf.LIB_SUFFIX])
|
||||
folded = self._getFoldedSections()
|
||||
sections = set()
|
||||
ordered_sections = []
|
||||
for symbol in ordered_symbols:
|
||||
symbol_sections = finder.getSections(symbol)
|
||||
all_symbol_sections = []
|
||||
for section in symbol_sections:
|
||||
if section in folded:
|
||||
if isinstance(folded[section], str):
|
||||
section = folded[section]
|
||||
all_symbol_sections.append(section)
|
||||
all_symbol_sections.extend(folded[section])
|
||||
else:
|
||||
all_symbol_sections.append(section)
|
||||
for section in all_symbol_sections:
|
||||
if not section in sections:
|
||||
ordered_sections.append(section)
|
||||
sections.add(section)
|
||||
return ordered_sections
|
||||
|
||||
def orderSymbols(self, order):
|
||||
'''Given a file containing a list of symbols, adds the appropriate
|
||||
argument to make the linker put the symbols in that order.'''
|
||||
with open(order) as file:
|
||||
sections = self._getOrderedSections([l.strip() for l in file.readlines() if l.strip()])
|
||||
split_sections = {}
|
||||
linked_sections = [s[0] for s in SECTION_INSERT_BEFORE]
|
||||
for s in sections:
|
||||
for linked_section in linked_sections:
|
||||
if s.startswith(linked_section):
|
||||
if linked_section in split_sections:
|
||||
split_sections[linked_section].append(s)
|
||||
else:
|
||||
split_sections[linked_section] = [s]
|
||||
break
|
||||
content = []
|
||||
# Order is important
|
||||
linked_sections = [s for s in linked_sections if s in split_sections]
|
||||
|
||||
if conf.EXPAND_LIBS_ORDER_STYLE == 'section-ordering-file':
|
||||
option = '-Wl,--section-ordering-file,%s'
|
||||
content = sections
|
||||
for linked_section in linked_sections:
|
||||
content.extend(split_sections[linked_section])
|
||||
content.append('%s.*' % linked_section)
|
||||
content.append(linked_section)
|
||||
|
||||
elif conf.EXPAND_LIBS_ORDER_STYLE == 'linkerscript':
|
||||
option = '-Wl,-T,%s'
|
||||
section_insert_before = dict(SECTION_INSERT_BEFORE)
|
||||
for linked_section in linked_sections:
|
||||
content.append('SECTIONS {')
|
||||
content.append(' %s : {' % linked_section)
|
||||
content.extend(' *(%s)' % s for s in split_sections[linked_section])
|
||||
content.append(' }')
|
||||
content.append('}')
|
||||
content.append('INSERT BEFORE %s' % section_insert_before[linked_section])
|
||||
else:
|
||||
raise Exception('EXPAND_LIBS_ORDER_STYLE "%s" is not supported' % conf.EXPAND_LIBS_ORDER_STYLE)
|
||||
|
||||
fd, tmp = tempfile.mkstemp(dir=os.curdir)
|
||||
f = os.fdopen(fd, "w")
|
||||
f.write('\n'.join(content)+'\n')
|
||||
f.close()
|
||||
self.tmp.append(tmp)
|
||||
self.append(option % tmp)
|
||||
|
||||
class SectionFinder(object):
|
||||
'''Instances of this class allow to map symbol names to sections in
|
||||
object files.'''
|
||||
|
||||
def __init__(self, objs):
|
||||
'''Creates an instance, given a list of object files.'''
|
||||
if not conf.EXPAND_LIBS_ORDER_STYLE in ['linkerscript', 'section-ordering-file']:
|
||||
raise Exception('EXPAND_LIBS_ORDER_STYLE "%s" is not supported' % conf.EXPAND_LIBS_ORDER_STYLE)
|
||||
self.mapping = {}
|
||||
for obj in objs:
|
||||
if not isObject(obj) and os.path.splitext(obj)[1] != conf.LIB_SUFFIX:
|
||||
raise Exception('%s is not an object nor a static library' % obj)
|
||||
for symbol, section in SectionFinder._getSymbols(obj):
|
||||
sym = SectionFinder._normalize(symbol)
|
||||
if sym in self.mapping:
|
||||
if not section in self.mapping[sym]:
|
||||
self.mapping[sym].append(section)
|
||||
else:
|
||||
self.mapping[sym] = [section]
|
||||
|
||||
def getSections(self, symbol):
|
||||
'''Given a symbol, returns a list of sections containing it or the
|
||||
corresponding thunks. When the given symbol is a thunk, returns the
|
||||
list of sections containing its corresponding normal symbol and the
|
||||
other thunks for that symbol.'''
|
||||
sym = SectionFinder._normalize(symbol)
|
||||
if sym in self.mapping:
|
||||
return self.mapping[sym]
|
||||
return []
|
||||
|
||||
@staticmethod
|
||||
def _normalize(symbol):
|
||||
'''For normal symbols, return the given symbol. For thunks, return
|
||||
the corresponding normal symbol.'''
|
||||
if re.match('^_ZThn[0-9]+_', symbol):
|
||||
return re.sub('^_ZThn[0-9]+_', '_Z', symbol)
|
||||
return symbol
|
||||
|
||||
@staticmethod
|
||||
def _getSymbols(obj):
|
||||
'''Returns a list of (symbol, section) contained in the given object
|
||||
file.'''
|
||||
proc = subprocess.Popen(['objdump', '-t', obj], stdout = subprocess.PIPE, stderr = subprocess.PIPE)
|
||||
(stdout, stderr) = proc.communicate()
|
||||
syms = []
|
||||
for line in stdout.splitlines():
|
||||
# Each line has the following format:
|
||||
# <addr> [lgu!][w ][C ][W ][Ii ][dD ][FfO ] <section>\t<length> <symbol>
|
||||
tmp = line.split(' ',1)
|
||||
# This gives us ["<addr>", "[lgu!][w ][C ][W ][Ii ][dD ][FfO ] <section>\t<length> <symbol>"]
|
||||
# We only need to consider cases where "<section>\t<length> <symbol>" is present,
|
||||
# and where the [FfO] flag is either F (function) or O (object).
|
||||
if len(tmp) > 1 and len(tmp[1]) > 6 and tmp[1][6] in ['O', 'F']:
|
||||
tmp = tmp[1][8:].split()
|
||||
# That gives us ["<section>","<length>", "<symbol>"]
|
||||
syms.append((tmp[-1], tmp[0]))
|
||||
return syms
|
||||
|
||||
def main():
|
||||
parser = OptionParser()
|
||||
@ -153,17 +308,16 @@ def main():
|
||||
help="use a list file for objects when executing a command")
|
||||
parser.add_option("--verbose", action="store_true", dest="verbose",
|
||||
help="display executed command and temporary files content")
|
||||
parser.add_option("--reorder", dest="reorder",
|
||||
help="reorder the objects according to the given list", metavar="FILE")
|
||||
parser.add_option("--symbol-order", dest="symbol_order", metavar="FILE",
|
||||
help="use the given list of symbols to order symbols in the resulting binary when using with a linker")
|
||||
|
||||
(options, args) = parser.parse_args()
|
||||
|
||||
with ExpandArgsMore(args) as args:
|
||||
if options.extract or options.reorder:
|
||||
if options.extract:
|
||||
args.extract()
|
||||
if options.reorder:
|
||||
with open(options.reorder) as file:
|
||||
args.reorder([l.strip() for l in file.readlines()])
|
||||
if options.symbol_order:
|
||||
args.orderSymbols(options.symbol_order)
|
||||
if options.uselist:
|
||||
args.makelist()
|
||||
|
||||
|
@ -38,7 +38,7 @@ config = sys.modules['expandlibs_config'] = imp.new_module('expandlibs_config')
|
||||
|
||||
from expandlibs import LibDescriptor, ExpandArgs, relativize
|
||||
from expandlibs_gen import generate
|
||||
from expandlibs_exec import ExpandArgsMore
|
||||
from expandlibs_exec import ExpandArgsMore, SectionFinder
|
||||
|
||||
def Lib(name):
|
||||
return config.LIB_PREFIX + name + config.LIB_SUFFIX
|
||||
@ -267,28 +267,101 @@ class TestExpandArgsMore(TestExpandInit):
|
||||
# Restore subprocess.call
|
||||
subprocess.call = subprocess_call
|
||||
|
||||
def test_reorder(self):
|
||||
'''Test object reordering'''
|
||||
# We don't care about AR_EXTRACT testing, which is done in test_extract
|
||||
config.AR_EXTRACT = ''
|
||||
class FakeProcess(object):
|
||||
def __init__(self, out, err = ''):
|
||||
self.out = out
|
||||
self.err = err
|
||||
|
||||
# ExpandArgsMore does the same as ExpandArgs
|
||||
with ExpandArgsMore(['foo', '-bar'] + self.arg_files + [self.tmpfile('liby', Lib('y'))]) as args:
|
||||
self.assertRelEqual(args, ['foo', '-bar'] + self.files + self.liby_files + self.libx_files)
|
||||
def communicate(self):
|
||||
return (self.out, self.err)
|
||||
|
||||
# Use an order containing object files from libraries
|
||||
order_files = [self.libx_files[1], self.libx_files[0], self.liby_files[2], self.files[1]]
|
||||
order = [os.path.splitext(os.path.basename(f))[0] for f in order_files]
|
||||
args.reorder(order[:2] + ['unknown'] + order[2:])
|
||||
OBJDUMPS = {
|
||||
'foo.o': '''
|
||||
00000000 g F .text\t00000001 foo
|
||||
00000000 g F .text._Z6foobarv\t00000001 _Z6foobarv
|
||||
00000000 g F .text.hello\t00000001 hello
|
||||
00000000 g F .text._ZThn4_6foobarv\t00000001 _ZThn4_6foobarv
|
||||
''',
|
||||
'bar.o': '''
|
||||
00000000 g F .text.hi\t00000001 hi
|
||||
00000000 g F .text.hot._Z6barbazv\t00000001 .hidden _Z6barbazv
|
||||
''',
|
||||
}
|
||||
|
||||
PRINT_ICF = '''
|
||||
ld: ICF folding section '.text.hello' in file 'foo.o'into '.text.hi' in file 'bar.o'
|
||||
ld: ICF folding section '.foo' in file 'foo.o'into '.foo' in file 'bar.o'
|
||||
'''
|
||||
|
||||
class SubprocessPopen(object):
|
||||
def __init__(self, test):
|
||||
self.test = test
|
||||
|
||||
def __call__(self, args, stdout = None, stderr = None):
|
||||
self.test.assertEqual(stdout, subprocess.PIPE)
|
||||
self.test.assertEqual(stderr, subprocess.PIPE)
|
||||
if args[0] == 'objdump':
|
||||
self.test.assertEqual(args[1], '-t')
|
||||
self.test.assertTrue(args[2] in OBJDUMPS)
|
||||
return FakeProcess(OBJDUMPS[args[2]])
|
||||
else:
|
||||
return FakeProcess('', PRINT_ICF)
|
||||
|
||||
class TestSectionFinder(unittest.TestCase):
|
||||
def test_getSections(self):
|
||||
'''Test SectionFinder'''
|
||||
# Divert subprocess.Popen
|
||||
subprocess_popen = subprocess.Popen
|
||||
subprocess.Popen = SubprocessPopen(self)
|
||||
config.EXPAND_LIBS_ORDER_STYLE = 'linkerscript'
|
||||
config.OBJ_SUFFIX = '.o'
|
||||
config.LIB_SUFFIX = '.a'
|
||||
finder = SectionFinder(['foo.o', 'bar.o'])
|
||||
self.assertEqual(finder.getSections('foobar'), [])
|
||||
self.assertEqual(finder.getSections('_Z6barbazv'), ['.text.hot._Z6barbazv'])
|
||||
self.assertEqual(finder.getSections('_Z6foobarv'), ['.text._Z6foobarv', '.text._ZThn4_6foobarv'])
|
||||
self.assertEqual(finder.getSections('_ZThn4_6foobarv'), ['.text._Z6foobarv', '.text._ZThn4_6foobarv'])
|
||||
subprocess.Popen = subprocess_popen
|
||||
|
||||
class TestSymbolOrder(unittest.TestCase):
|
||||
def test_getOrderedSections(self):
|
||||
'''Test ExpandMoreArgs' _getOrderedSections'''
|
||||
# Divert subprocess.Popen
|
||||
subprocess_popen = subprocess.Popen
|
||||
subprocess.Popen = SubprocessPopen(self)
|
||||
config.EXPAND_LIBS_ORDER_STYLE = 'linkerscript'
|
||||
config.OBJ_SUFFIX = '.o'
|
||||
config.LIB_SUFFIX = '.a'
|
||||
config.LD_PRINT_ICF_SECTIONS = ''
|
||||
args = ExpandArgsMore(['foo', '-bar', 'bar.o', 'foo.o'])
|
||||
self.assertEqual(args._getOrderedSections(['_Z6foobarv', '_Z6barbazv']), ['.text._Z6foobarv', '.text._ZThn4_6foobarv', '.text.hot._Z6barbazv'])
|
||||
self.assertEqual(args._getOrderedSections(['_ZThn4_6foobarv', '_Z6barbazv']), ['.text._Z6foobarv', '.text._ZThn4_6foobarv', '.text.hot._Z6barbazv'])
|
||||
subprocess.Popen = subprocess_popen
|
||||
|
||||
def test_getFoldedSections(self):
|
||||
'''Test ExpandMoreArgs' _getFoldedSections'''
|
||||
# Divert subprocess.Popen
|
||||
subprocess_popen = subprocess.Popen
|
||||
subprocess.Popen = SubprocessPopen(self)
|
||||
config.LD_PRINT_ICF_SECTIONS = '-Wl,--print-icf-sections'
|
||||
args = ExpandArgsMore(['foo', '-bar', 'bar.o', 'foo.o'])
|
||||
self.assertEqual(args._getFoldedSections(), {'.text.hello': '.text.hi', '.text.hi': ['.text.hello']})
|
||||
subprocess.Popen = subprocess_popen
|
||||
|
||||
def test_getOrderedSectionsWithICF(self):
|
||||
'''Test ExpandMoreArgs' _getOrderedSections, with ICF'''
|
||||
# Divert subprocess.Popen
|
||||
subprocess_popen = subprocess.Popen
|
||||
subprocess.Popen = SubprocessPopen(self)
|
||||
config.EXPAND_LIBS_ORDER_STYLE = 'linkerscript'
|
||||
config.OBJ_SUFFIX = '.o'
|
||||
config.LIB_SUFFIX = '.a'
|
||||
config.LD_PRINT_ICF_SECTIONS = '-Wl,--print-icf-sections'
|
||||
args = ExpandArgsMore(['foo', '-bar', 'bar.o', 'foo.o'])
|
||||
self.assertEqual(args._getOrderedSections(['hello', '_Z6barbazv']), ['.text.hi', '.text.hello', '.text.hot._Z6barbazv'])
|
||||
self.assertEqual(args._getOrderedSections(['_ZThn4_6foobarv', 'hi', '_Z6barbazv']), ['.text._Z6foobarv', '.text._ZThn4_6foobarv', '.text.hi', '.text.hello', '.text.hot._Z6barbazv'])
|
||||
subprocess.Popen = subprocess_popen
|
||||
|
||||
# self.files has objects at #1, #2, #4
|
||||
self.assertRelEqual(args[:3], ['foo', '-bar'] + self.files[:1])
|
||||
self.assertRelEqual(args[3:7], order_files)
|
||||
self.assertRelEqual(args[7:9], [self.files[2], self.files[4]])
|
||||
self.assertRelEqual(args[9:11], self.liby_files[:2])
|
||||
self.assertRelEqual(args[11:12], [self.libx_files[2]])
|
||||
self.assertRelEqual(args[12:14], [self.files[3], self.files[5]])
|
||||
self.assertRelEqual(args[14:], [self.liby_files[3]])
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main(testRunner=MozTestRunner())
|
||||
|
107
configure.in
@ -2524,6 +2524,8 @@ ia64*-hpux*)
|
||||
no_x=yes
|
||||
if test -n "$gonkdir"; then
|
||||
_PLATFORM_DEFAULT_TOOLKIT=cairo-gonk
|
||||
MOZ_B2G_RIL=1
|
||||
MOZ_B2G_BT=1
|
||||
else
|
||||
_PLATFORM_DEFAULT_TOOLKIT=cairo-android
|
||||
MOZ_LINKER=1
|
||||
@ -5038,7 +5040,6 @@ cairo-gonk)
|
||||
TK_LIBS='$(MOZ_CAIRO_LIBS)'
|
||||
MOZ_WEBGL=1
|
||||
MOZ_PDF_PRINTING=1
|
||||
MOZ_B2G_RIL=1
|
||||
MOZ_TOUCH=1
|
||||
;;
|
||||
|
||||
@ -7179,78 +7180,6 @@ if test -n "$MOZ_DEBUG" -o -n "$MOZ_DEBUG_SYMBOLS"; then
|
||||
export MOZ_DEBUG_SYMBOLS
|
||||
fi
|
||||
|
||||
dnl ========================================================
|
||||
dnl = Identical Code Folding
|
||||
dnl ========================================================
|
||||
|
||||
MOZ_ARG_DISABLE_BOOL(icf,
|
||||
[ --disable-icf Disable Identical Code Folding],
|
||||
MOZ_DISABLE_ICF=1,
|
||||
MOZ_DISABLE_ICF= )
|
||||
|
||||
if test "$GNU_CC" -a "$GCC_USE_GNU_LD" -a -z "$MOZ_DISABLE_ICF"; then
|
||||
AC_CACHE_CHECK([whether the linker supports Identical Code Folding],
|
||||
LD_SUPPORTS_ICF,
|
||||
[echo 'int foo() {return 42;}' \
|
||||
'int bar() {return 42;}' \
|
||||
'int main() {return foo() - bar();}' > conftest.${ac_ext}
|
||||
# If the linker supports ICF, foo and bar symbols will have
|
||||
# the same address
|
||||
if AC_TRY_COMMAND([${CC-cc} -o conftest${ac_exeext} $LDFLAGS -Wl,--icf=safe -ffunction-sections conftest.${ac_ext} $LIBS 1>&2]) &&
|
||||
test -s conftest${ac_exeext} &&
|
||||
objdump -t conftest${ac_exeext} | awk '{a[[$6]] = $1} END {if (a[["foo"]] && (a[["foo"]] != a[["bar"]])) { exit 1 }}'; then
|
||||
LD_SUPPORTS_ICF=yes
|
||||
else
|
||||
LD_SUPPORTS_ICF=no
|
||||
fi
|
||||
rm -rf conftest*])
|
||||
if test "$LD_SUPPORTS_ICF" = yes; then
|
||||
LDFLAGS="$LDFLAGS -Wl,--icf=safe"
|
||||
CFLAGS="$CFLAGS -ffunction-sections"
|
||||
CXXFLAGS="$CXXFLAGS -ffunction-sections"
|
||||
fi
|
||||
fi
|
||||
|
||||
dnl ========================================================
|
||||
dnl = Automatically remove dead symbols
|
||||
dnl ========================================================
|
||||
|
||||
if test "$GNU_CC" -a "$GCC_USE_GNU_LD" -a -n "$MOZ_DEBUG_FLAGS"; then
|
||||
dnl See bug 670659
|
||||
AC_CACHE_CHECK([whether removing dead symbols breaks debugging],
|
||||
GC_SECTIONS_BREAKS_DEBUG_RANGES,
|
||||
[echo 'int foo() {return 42;}' \
|
||||
'int bar() {return 1;}' \
|
||||
'int main() {return foo();}' > conftest.${ac_ext}
|
||||
if AC_TRY_COMMAND([${CC-cc} -o conftest.${ac_objext} $CFLAGS $MOZ_DEBUG_FLAGS -ffunction-sections -c conftest.${ac_ext} 1>&2]) &&
|
||||
AC_TRY_COMMAND([${CC-cc} -o conftest${ac_exeext} $LDFLAGS $MOZ_DEBUG_FLAGS -Wl,--gc-sections conftest.${ac_objext} $LIBS 1>&2]) &&
|
||||
test -s conftest${ac_exeext} -a -s conftest.${ac_objext}; then
|
||||
if test "`$PYTHON "$_topsrcdir"/build/unix/check_debug_ranges.py conftest.${ac_objext} conftest.${ac_ext}`" = \
|
||||
"`$PYTHON "$_topsrcdir"/build/unix/check_debug_ranges.py conftest${ac_exeext} conftest.${ac_ext}`"; then
|
||||
GC_SECTIONS_BREAKS_DEBUG_RANGES=no
|
||||
else
|
||||
GC_SECTIONS_BREAKS_DEBUG_RANGES=yes
|
||||
fi
|
||||
else
|
||||
dnl We really don't expect to get here, but just in case
|
||||
GC_SECTIONS_BREAKS_DEBUG_RANGES="no, but it's broken in some other way"
|
||||
fi
|
||||
rm -rf conftest*])
|
||||
if test "$GC_SECTIONS_BREAKS_DEBUG_RANGES" = no; then
|
||||
DSO_LDOPTS="$DSO_LDOPTS -Wl,--gc-sections"
|
||||
case "$CFLAGS" in
|
||||
*-ffunction-sections*)
|
||||
CFLAGS="$CFLAGS -fdata-sections"
|
||||
CXXFLAGS="$CXXFLAGS -fdata-sections"
|
||||
;;
|
||||
*)
|
||||
CFLAGS="$CFLAGS -ffunction-sections -fdata-sections"
|
||||
CXXFLAGS="$CXXFLAGS -ffunction-sections -fdata-sections"
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
fi
|
||||
|
||||
dnl ========================================================
|
||||
dnl = Enable any treating of compile warnings as errors
|
||||
dnl ========================================================
|
||||
@ -8072,37 +8001,7 @@ fi # ! SKIP_COMPILER_CHECKS
|
||||
AC_DEFINE(CPP_THROW_NEW, [throw()])
|
||||
AC_LANG_C
|
||||
|
||||
dnl ========================================================
|
||||
dnl =
|
||||
dnl = Check what kind of list files are supported by the
|
||||
dnl = linker
|
||||
dnl =
|
||||
dnl ========================================================
|
||||
|
||||
AC_CACHE_CHECK(what kind of list files are supported by the linker,
|
||||
EXPAND_LIBS_LIST_STYLE,
|
||||
[echo "int main() {return 0;}" > conftest.${ac_ext}
|
||||
if AC_TRY_COMMAND(${CC-cc} -o conftest.${OBJ_SUFFIX} -c $CFLAGS $CPPFLAGS conftest.${ac_ext} 1>&2) && test -s conftest.${OBJ_SUFFIX}; then
|
||||
echo "INPUT(conftest.${OBJ_SUFFIX})" > conftest.list
|
||||
if AC_TRY_COMMAND(${CC-cc} -o conftest${ac_exeext} $LDFLAGS conftest.list $LIBS 1>&2) && test -s conftest${ac_exeext}; then
|
||||
EXPAND_LIBS_LIST_STYLE=linkerscript
|
||||
else
|
||||
echo "conftest.${OBJ_SUFFIX}" > conftest.list
|
||||
if AC_TRY_COMMAND(${CC-cc} -o conftest${ac_exeext} $LDFLAGS @conftest.list $LIBS 1>&2) && test -s conftest${ac_exeext}; then
|
||||
EXPAND_LIBS_LIST_STYLE=list
|
||||
else
|
||||
EXPAND_LIBS_LIST_STYLE=none
|
||||
fi
|
||||
fi
|
||||
else
|
||||
dnl We really don't expect to get here, but just in case
|
||||
AC_ERROR([couldn't compile a simple C file])
|
||||
fi
|
||||
rm -rf conftest*])
|
||||
|
||||
LIBS_DESC_SUFFIX=desc
|
||||
AC_SUBST(LIBS_DESC_SUFFIX)
|
||||
AC_SUBST(EXPAND_LIBS_LIST_STYLE)
|
||||
MOZ_EXPAND_LIBS
|
||||
|
||||
dnl ========================================================
|
||||
dnl =
|
||||
|
@ -65,7 +65,6 @@ nsINodeList.h \
|
||||
nsIScriptElement.h \
|
||||
nsIStyleSheetLinkingElement.h \
|
||||
nsIContentSerializer.h \
|
||||
nsIHTMLToTextSink.h \
|
||||
nsIXPathEvaluatorInternal.h \
|
||||
mozISanitizingSerializer.h \
|
||||
nsCaseTreatment.h \
|
||||
|
@ -441,6 +441,16 @@ public:
|
||||
*/
|
||||
static bool IsHTMLWhitespace(PRUnichar aChar);
|
||||
|
||||
/**
|
||||
* Is the HTML local name a block element?
|
||||
*/
|
||||
static bool IsHTMLBlock(nsIAtom* aLocalName);
|
||||
|
||||
/**
|
||||
* Is the HTML local name a void element?
|
||||
*/
|
||||
static bool IsHTMLVoid(nsIAtom* aLocalName);
|
||||
|
||||
/**
|
||||
* Parse a margin string of format 'top, right, bottom, left' into
|
||||
* an nsIntMargin.
|
||||
@ -838,11 +848,22 @@ public:
|
||||
* Fill (with the parameters given) the localized string named |aKey| in
|
||||
* properties file |aFile|.
|
||||
*/
|
||||
private:
|
||||
static nsresult FormatLocalizedString(PropertiesFile aFile,
|
||||
const char* aKey,
|
||||
const PRUnichar **aParams,
|
||||
const PRUnichar** aParams,
|
||||
PRUint32 aParamsLength,
|
||||
nsXPIDLString& aResult);
|
||||
|
||||
public:
|
||||
template<PRUint32 N>
|
||||
static nsresult FormatLocalizedString(PropertiesFile aFile,
|
||||
const char* aKey,
|
||||
const PRUnichar* (&aParams)[N],
|
||||
nsXPIDLString& aResult)
|
||||
{
|
||||
return FormatLocalizedString(aFile, aKey, aParams, N, aResult);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if aDocument is a chrome document
|
||||
|
@ -1,66 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1998
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _nsIPlainTextSink_h__
|
||||
#define _nsIPlainTextSink_h__
|
||||
|
||||
#include "nsISupports.h"
|
||||
#include "nsStringGlue.h"
|
||||
|
||||
#define NS_PLAINTEXTSINK_CONTRACTID "@mozilla.org/layout/plaintextsink;1"
|
||||
|
||||
/* starting interface: nsIContentSerializer */
|
||||
#define NS_IHTMLTOTEXTSINK_IID_STR "b12b5643-07cb-401e-aabb-64b2dcd2717f"
|
||||
|
||||
#define NS_IHTMLTOTEXTSINK_IID \
|
||||
{0xb12b5643, 0x07cb, 0x401e, \
|
||||
{ 0xaa, 0xbb, 0x64, 0xb2, 0xdc, 0xd2, 0x71, 0x7f }}
|
||||
|
||||
|
||||
class nsIHTMLToTextSink : public nsISupports {
|
||||
public:
|
||||
|
||||
NS_DECLARE_STATIC_IID_ACCESSOR(NS_IHTMLTOTEXTSINK_IID)
|
||||
|
||||
NS_IMETHOD Initialize(nsAString* aOutString,
|
||||
PRUint32 aFlags, PRUint32 aWrapCol) = 0;
|
||||
// This function violates string ownership rules, see impl.
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(nsIHTMLToTextSink, NS_IHTMLTOTEXTSINK_IID)
|
||||
|
||||
#endif
|
@ -1190,6 +1190,72 @@ nsContentUtils::IsHTMLWhitespace(PRUnichar aChar)
|
||||
aChar == PRUnichar(0x0020);
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool
|
||||
nsContentUtils::IsHTMLBlock(nsIAtom* aLocalName)
|
||||
{
|
||||
return
|
||||
(aLocalName == nsGkAtoms::address) ||
|
||||
(aLocalName == nsGkAtoms::article) ||
|
||||
(aLocalName == nsGkAtoms::aside) ||
|
||||
(aLocalName == nsGkAtoms::blockquote) ||
|
||||
(aLocalName == nsGkAtoms::center) ||
|
||||
(aLocalName == nsGkAtoms::dir) ||
|
||||
(aLocalName == nsGkAtoms::div) ||
|
||||
(aLocalName == nsGkAtoms::dl) || // XXX why not dt and dd?
|
||||
(aLocalName == nsGkAtoms::fieldset) ||
|
||||
(aLocalName == nsGkAtoms::figure) || // XXX shouldn't figcaption be on this list
|
||||
(aLocalName == nsGkAtoms::footer) ||
|
||||
(aLocalName == nsGkAtoms::form) ||
|
||||
(aLocalName == nsGkAtoms::h1) ||
|
||||
(aLocalName == nsGkAtoms::h2) ||
|
||||
(aLocalName == nsGkAtoms::h3) ||
|
||||
(aLocalName == nsGkAtoms::h4) ||
|
||||
(aLocalName == nsGkAtoms::h5) ||
|
||||
(aLocalName == nsGkAtoms::h6) ||
|
||||
(aLocalName == nsGkAtoms::header) ||
|
||||
(aLocalName == nsGkAtoms::hgroup) ||
|
||||
(aLocalName == nsGkAtoms::hr) ||
|
||||
(aLocalName == nsGkAtoms::li) ||
|
||||
(aLocalName == nsGkAtoms::listing) ||
|
||||
(aLocalName == nsGkAtoms::menu) ||
|
||||
(aLocalName == nsGkAtoms::multicol) || // XXX get rid of this one?
|
||||
(aLocalName == nsGkAtoms::nav) ||
|
||||
(aLocalName == nsGkAtoms::ol) ||
|
||||
(aLocalName == nsGkAtoms::p) ||
|
||||
(aLocalName == nsGkAtoms::pre) ||
|
||||
(aLocalName == nsGkAtoms::section) ||
|
||||
(aLocalName == nsGkAtoms::table) ||
|
||||
(aLocalName == nsGkAtoms::ul) ||
|
||||
(aLocalName == nsGkAtoms::xmp);
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool
|
||||
nsContentUtils::IsHTMLVoid(nsIAtom* aLocalName)
|
||||
{
|
||||
return
|
||||
(aLocalName == nsGkAtoms::area) ||
|
||||
(aLocalName == nsGkAtoms::base) ||
|
||||
(aLocalName == nsGkAtoms::basefont) ||
|
||||
(aLocalName == nsGkAtoms::bgsound) ||
|
||||
(aLocalName == nsGkAtoms::br) ||
|
||||
(aLocalName == nsGkAtoms::col) ||
|
||||
(aLocalName == nsGkAtoms::command) ||
|
||||
(aLocalName == nsGkAtoms::embed) ||
|
||||
(aLocalName == nsGkAtoms::frame) ||
|
||||
(aLocalName == nsGkAtoms::hr) ||
|
||||
(aLocalName == nsGkAtoms::img) ||
|
||||
(aLocalName == nsGkAtoms::input) ||
|
||||
(aLocalName == nsGkAtoms::keygen) ||
|
||||
(aLocalName == nsGkAtoms::link) ||
|
||||
(aLocalName == nsGkAtoms::meta) ||
|
||||
(aLocalName == nsGkAtoms::param) ||
|
||||
(aLocalName == nsGkAtoms::source) ||
|
||||
(aLocalName == nsGkAtoms::track) ||
|
||||
(aLocalName == nsGkAtoms::wbr);
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool
|
||||
nsContentUtils::ParseIntMarginValue(const nsAString& aString, nsIntMargin& result)
|
||||
|
@ -2736,6 +2736,9 @@ nsGenericElement::RemoveAttribute(const nsAString& aName)
|
||||
const nsAttrName* name = InternalGetExistingAttrNameFromQName(aName);
|
||||
|
||||
if (!name) {
|
||||
// If there is no canonical nsAttrName for this attribute name, then the
|
||||
// attribute does not exist and we can't get its namespace ID and
|
||||
// local name below, so we return early.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -2889,8 +2892,9 @@ nsGenericElement::RemoveAttributeNS(const nsAString& aNamespaceURI,
|
||||
nsContentUtils::NameSpaceManager()->GetNameSpaceID(aNamespaceURI);
|
||||
|
||||
if (nsid == kNameSpaceID_Unknown) {
|
||||
// Unknown namespace means no attr...
|
||||
|
||||
// If the namespace ID is unknown, it means there can't possibly be an
|
||||
// existing attribute. We would need a known namespace ID to pass into
|
||||
// UnsetAttr, so we return early if we don't have one.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -142,6 +142,7 @@ GK_ATOM(before_end, "before_end")
|
||||
GK_ATOM(before_start, "before_start")
|
||||
GK_ATOM(below, "below")
|
||||
GK_ATOM(bgcolor, "bgcolor")
|
||||
GK_ATOM(bgsound, "bgsound")
|
||||
GK_ATOM(big, "big")
|
||||
GK_ATOM(binding, "binding")
|
||||
GK_ATOM(bindings, "bindings")
|
||||
@ -493,6 +494,7 @@ GK_ATOM(keepcurrentinview, "keepcurrentinview")
|
||||
GK_ATOM(key, "key")
|
||||
GK_ATOM(keycode, "keycode")
|
||||
GK_ATOM(keydown, "keydown")
|
||||
GK_ATOM(keygen, "keygen")
|
||||
GK_ATOM(keypress, "keypress")
|
||||
GK_ATOM(keyset, "keyset")
|
||||
GK_ATOM(keytext, "keytext")
|
||||
|
@ -65,6 +65,6 @@ static const nsStaticAtom GkAtoms_info[] = {
|
||||
|
||||
void nsGkAtoms::AddRefAtoms()
|
||||
{
|
||||
NS_RegisterStaticAtoms(GkAtoms_info, ArrayLength(GkAtoms_info));
|
||||
NS_RegisterStaticAtoms(GkAtoms_info);
|
||||
}
|
||||
|
||||
|
@ -45,14 +45,11 @@
|
||||
#define nsPlainTextSerializer_h__
|
||||
|
||||
#include "nsIContentSerializer.h"
|
||||
#include "nsIHTMLContentSink.h"
|
||||
#include "nsHTMLTags.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsString.h"
|
||||
#include "nsILineBreaker.h"
|
||||
#include "nsIContent.h"
|
||||
#include "nsIAtom.h"
|
||||
#include "nsIHTMLToTextSink.h"
|
||||
#include "nsIDocumentEncoder.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
@ -62,9 +59,7 @@ class Element;
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
class nsPlainTextSerializer : public nsIContentSerializer,
|
||||
public nsIHTMLContentSink,
|
||||
public nsIHTMLToTextSink
|
||||
class nsPlainTextSerializer : public nsIContentSerializer
|
||||
{
|
||||
public:
|
||||
nsPlainTextSerializer();
|
||||
@ -100,35 +95,8 @@ public:
|
||||
NS_IMETHOD AppendDocumentStart(nsIDocument *aDocument,
|
||||
nsAString& aStr);
|
||||
|
||||
// nsIContentSink
|
||||
NS_IMETHOD WillParse(void) { return NS_OK; }
|
||||
NS_IMETHOD WillInterrupt(void) { return NS_OK; }
|
||||
NS_IMETHOD WillResume(void) { return NS_OK; }
|
||||
NS_IMETHOD SetParser(nsParserBase* aParser) { return NS_OK; }
|
||||
NS_IMETHOD OpenContainer(const nsIParserNode& aNode);
|
||||
NS_IMETHOD CloseContainer(const nsHTMLTag aTag);
|
||||
NS_IMETHOD AddLeaf(const nsIParserNode& aNode);
|
||||
virtual void FlushPendingNotifications(mozFlushType aType) { }
|
||||
NS_IMETHOD SetDocumentCharset(nsACString& aCharset) { return NS_OK; }
|
||||
virtual nsISupports *GetTarget() { return nsnull; }
|
||||
|
||||
// nsIHTMLContentSink
|
||||
NS_IMETHOD OpenHead();
|
||||
NS_IMETHOD IsEnabled(PRInt32 aTag, bool* aReturn);
|
||||
NS_IMETHOD NotifyTagObservers(nsIParserNode* aNode) { return NS_OK; }
|
||||
|
||||
NS_IMETHOD BeginContext(PRInt32 aPosition) { return NS_OK; }
|
||||
NS_IMETHOD EndContext(PRInt32 aPosition) { return NS_OK; }
|
||||
NS_IMETHOD DidProcessTokens(void) { return NS_OK; }
|
||||
NS_IMETHOD WillProcessAToken(void) { return NS_OK; }
|
||||
NS_IMETHOD DidProcessAToken(void) { return NS_OK; }
|
||||
|
||||
// nsIHTMLToTextSink
|
||||
NS_IMETHOD Initialize(nsAString* aOutString,
|
||||
PRUint32 aFlags, PRUint32 aWrapCol);
|
||||
|
||||
protected:
|
||||
nsresult GetAttributeValue(const nsIParserNode* node, nsIAtom* aName, nsString& aValueRet);
|
||||
nsresult GetAttributeValue(nsIAtom* aName, nsString& aValueRet);
|
||||
void AddToLine(const PRUnichar* aStringToAdd, PRInt32 aLength);
|
||||
void EndLine(bool softlinebreak, bool aBreakBySpace = false);
|
||||
void EnsureVerticalSpace(PRInt32 noOfRows);
|
||||
@ -136,17 +104,20 @@ protected:
|
||||
void OutputQuotesAndIndent(bool stripTrailingSpaces=false);
|
||||
void Output(nsString& aString);
|
||||
void Write(const nsAString& aString);
|
||||
bool IsBlockLevel(PRInt32 aId);
|
||||
bool IsContainer(PRInt32 aId);
|
||||
bool IsInPre();
|
||||
bool IsInOL();
|
||||
bool IsCurrentNodeConverted(const nsIParserNode* aNode);
|
||||
static PRInt32 GetIdForContent(nsIContent* aContent);
|
||||
nsresult DoOpenContainer(const nsIParserNode* aNode, PRInt32 aTag);
|
||||
nsresult DoCloseContainer(PRInt32 aTag);
|
||||
nsresult DoAddLeaf(const nsIParserNode* aNode,
|
||||
PRInt32 aTag,
|
||||
const nsAString& aText);
|
||||
bool IsCurrentNodeConverted();
|
||||
bool MustSuppressLeaf();
|
||||
|
||||
/**
|
||||
* Returns the local name of the element as an atom if the element is an
|
||||
* HTML element and the atom is a static atom. Otherwise, nsnull is returned.
|
||||
*/
|
||||
static nsIAtom* GetIdForContent(nsIContent* aContent);
|
||||
nsresult DoOpenContainer(nsIAtom* aTag);
|
||||
nsresult DoCloseContainer(nsIAtom* aTag);
|
||||
nsresult DoAddLeaf(nsIAtom* aTag);
|
||||
void DoAddText(bool aIsWhitespace, const nsAString& aText);
|
||||
|
||||
// Inlined functions
|
||||
inline bool MayWrap()
|
||||
@ -240,14 +211,15 @@ protected:
|
||||
nsAutoTArray<bool, 8> mHasWrittenCellsForRow;
|
||||
|
||||
// Values gotten in OpenContainer that is (also) needed in CloseContainer
|
||||
nsAutoTArray<bool, 8> mCurrentNodeIsConverted;
|
||||
nsAutoTArray<bool, 8> mIsInCiteBlockquote;
|
||||
|
||||
// The output data
|
||||
nsAString* mOutputString;
|
||||
|
||||
// The tag stack: the stack of tags we're operating on, so we can nest:
|
||||
nsHTMLTag *mTagStack;
|
||||
// The tag stack: the stack of tags we're operating on, so we can nest.
|
||||
// The stack only ever points to static atoms, so they don't need to be
|
||||
// refcounted.
|
||||
nsIAtom** mTagStack;
|
||||
PRUint32 mTagStackIndex;
|
||||
|
||||
// Content in the stack above this index should be ignored:
|
||||
|
@ -269,7 +269,6 @@ HandleMailtoSubject(nsCString& aPath) {
|
||||
nsContentUtils::eFORMS_PROPERTIES,
|
||||
"DefaultFormSubject",
|
||||
formatStrings,
|
||||
ArrayLength(formatStrings),
|
||||
subjectStr);
|
||||
if (NS_FAILED(rv))
|
||||
return;
|
||||
|
@ -3830,7 +3830,7 @@ nsHTMLInputElement::GetValidationMessage(nsAString& aValidationMessage,
|
||||
const PRUnichar* params[] = { strMaxLength.get(), strTextLength.get() };
|
||||
rv = nsContentUtils::FormatLocalizedString(nsContentUtils::eDOM_PROPERTIES,
|
||||
"FormValidationTextTooLong",
|
||||
params, 2, message);
|
||||
params, message);
|
||||
aValidationMessage = message;
|
||||
break;
|
||||
}
|
||||
@ -3889,7 +3889,7 @@ nsHTMLInputElement::GetValidationMessage(nsAString& aValidationMessage,
|
||||
const PRUnichar* params[] = { title.get() };
|
||||
rv = nsContentUtils::FormatLocalizedString(nsContentUtils::eDOM_PROPERTIES,
|
||||
"FormValidationPatternMismatchWithTitle",
|
||||
params, 1, message);
|
||||
params, message);
|
||||
}
|
||||
aValidationMessage = message;
|
||||
break;
|
||||
|
@ -1423,7 +1423,7 @@ nsHTMLTextAreaElement::GetValidationMessage(nsAString& aValidationMessage,
|
||||
const PRUnichar* params[] = { strMaxLength.get(), strTextLength.get() };
|
||||
rv = nsContentUtils::FormatLocalizedString(nsContentUtils::eDOM_PROPERTIES,
|
||||
"FormValidationTextTooLong",
|
||||
params, 2, message);
|
||||
params, message);
|
||||
aValidationMessage = message;
|
||||
}
|
||||
break;
|
||||
|
@ -1466,10 +1466,14 @@ nsSVGElement::MaybeSerializeAttrBeforeRemoval(nsIAtom* aName, bool aNotify)
|
||||
return;
|
||||
}
|
||||
|
||||
const nsAttrValue* attrValue = mAttrsAndChildren.GetAttr(aName);
|
||||
if (!attrValue)
|
||||
return;
|
||||
|
||||
nsAutoString serializedValue;
|
||||
mAttrsAndChildren.GetAttr(aName)->ToString(serializedValue);
|
||||
nsAttrValue attrValue(serializedValue);
|
||||
mAttrsAndChildren.SetAndTakeAttr(aName, attrValue);
|
||||
attrValue->ToString(serializedValue);
|
||||
nsAttrValue oldAttrValue(serializedValue);
|
||||
mAttrsAndChildren.SetAndTakeAttr(aName, oldAttrValue);
|
||||
}
|
||||
|
||||
/* static */
|
||||
|
@ -61,6 +61,13 @@ function run_tests()
|
||||
lengths[0].valueAsString = "10";
|
||||
lengths[0].convertToSpecifiedUnits(SVGLength.SVG_LENGTHTYPE_NUMBER);
|
||||
lengths[0].newValueSpecifiedUnits(SVGLength.SVG_LENGTHTYPE_NUMBER, 10);
|
||||
// -- Attribute removal
|
||||
eventChecker.expect("remove");
|
||||
text.removeAttribute("x");
|
||||
// -- Non-existent attribute removal
|
||||
eventChecker.expect("");
|
||||
text.removeAttribute("x");
|
||||
text.removeAttributeNS(null, "x");
|
||||
eventChecker.finish();
|
||||
|
||||
SimpleTest.finish();
|
||||
|
@ -50,6 +50,13 @@ function run_tests()
|
||||
numbers[0].value = 17;
|
||||
numbers[1].value = 20;
|
||||
text.setAttribute("rotate", "17 20 30");
|
||||
// -- Attribute removal
|
||||
eventChecker.expect("remove");
|
||||
text.removeAttribute("rotate");
|
||||
// -- Non-existent attribute removal
|
||||
eventChecker.expect("");
|
||||
text.removeAttribute("rotate");
|
||||
text.removeAttributeNS(null, "rotate");
|
||||
eventChecker.finish();
|
||||
|
||||
SimpleTest.finish();
|
||||
|
@ -105,6 +105,15 @@ function run_tests()
|
||||
list[0].x = 20;
|
||||
list[1].y = 34;
|
||||
path.setAttribute("d", "M20,5 L12,34");
|
||||
|
||||
// -- Attribute removal
|
||||
eventChecker.expect("remove");
|
||||
path.removeAttribute("d");
|
||||
|
||||
// -- Non-existent attribute removal
|
||||
eventChecker.expect("");
|
||||
path.removeAttribute("d");
|
||||
path.removeAttributeNS(null, "d");
|
||||
eventChecker.finish();
|
||||
|
||||
SimpleTest.finish();
|
||||
|
@ -50,6 +50,13 @@ function run_tests()
|
||||
points[0].x = 30;
|
||||
points[1].y = 380;
|
||||
polyline.setAttribute("points", "30,375 150,380");
|
||||
// -- Attribute removal
|
||||
eventChecker.expect("remove");
|
||||
polyline.removeAttribute("points");
|
||||
// -- Non-existent attribute removal
|
||||
eventChecker.expect("");
|
||||
polyline.removeAttribute("points");
|
||||
polyline.removeAttributeNS(null, "points");
|
||||
eventChecker.finish();
|
||||
|
||||
SimpleTest.finish();
|
||||
|
@ -424,6 +424,16 @@ function testMutationEvents(g)
|
||||
eventChecker.expect("");
|
||||
g.setAttribute("transform", "matrix(1, 0, 0, 1, 0, 0)");
|
||||
list[0].setMatrix(mx);
|
||||
|
||||
// Attribute removal
|
||||
eventChecker.expect("remove");
|
||||
g.removeAttribute("transform");
|
||||
|
||||
// Non-existent attribute removal
|
||||
eventChecker.expect("");
|
||||
g.removeAttribute("transform");
|
||||
g.removeAttributeNS(null, "transform");
|
||||
|
||||
eventChecker.finish();
|
||||
}
|
||||
|
||||
|
@ -835,6 +835,7 @@ function run_baseVal_API_tests()
|
||||
|
||||
eventChecker.expect("remove add");
|
||||
t.element.removeAttribute(t.attr_name);
|
||||
t.element.removeAttributeNS(null, t.attr_name);
|
||||
res = t.baseVal.appendItem(item);
|
||||
eventChecker.finish();
|
||||
}
|
||||
|
@ -38,6 +38,7 @@ function runTests()
|
||||
filter.setAttribute("class", "foo");
|
||||
filter.className.baseVal = "bar";
|
||||
filter.removeAttribute("class");
|
||||
filter.removeAttributeNS(null, "class");
|
||||
filter.className.baseVal = "foo";
|
||||
|
||||
eventChecker.expect("");
|
||||
@ -57,6 +58,7 @@ function runTests()
|
||||
marker.markerWidth.baseVal.newValueSpecifiedUnits(
|
||||
SVGLength.SVG_LENGTHTYPE_MM, 11);
|
||||
marker.removeAttribute("markerWidth");
|
||||
marker.removeAttributeNS(null, "markerWidth");
|
||||
marker.markerWidth.baseVal.value = 8;
|
||||
|
||||
eventChecker.expect("remove add modify");
|
||||
@ -84,6 +86,7 @@ function runTests()
|
||||
convolve.setAttribute("divisor", "12.5");
|
||||
convolve.divisor.baseVal = 6;
|
||||
convolve.removeAttribute("divisor");
|
||||
convolve.removeAttributeNS(null, "divisor");
|
||||
convolve.divisor.baseVal = 8;
|
||||
|
||||
eventChecker.expect("");
|
||||
@ -97,6 +100,7 @@ function runTests()
|
||||
blur.setAttribute("stdDeviation", "5, 6");
|
||||
blur.stdDeviationX.baseVal = 8;
|
||||
blur.removeAttribute("stdDeviation");
|
||||
blur.removeAttributeNS(null, "stdDeviation");
|
||||
blur.setAttribute("stdDeviation", "2, 3");
|
||||
|
||||
eventChecker.expect("");
|
||||
@ -111,6 +115,7 @@ function runTests()
|
||||
convolve.setAttribute("targetX", "12");
|
||||
convolve.targetX.baseVal = 6;
|
||||
convolve.removeAttribute("targetX");
|
||||
convolve.removeAttributeNS(null, "targetX");
|
||||
convolve.targetX.baseVal = 8;
|
||||
|
||||
// Check redundant change when comparing typed value to attribute value
|
||||
@ -129,6 +134,7 @@ function runTests()
|
||||
filter.setAttribute("filterRes", "60, 70");
|
||||
filter.filterResX.baseVal = 50;
|
||||
filter.removeAttribute("filterRes");
|
||||
filter.removeAttributeNS(null, "filterRes");
|
||||
filter.setAttribute("filterRes", "50, 60");
|
||||
|
||||
eventChecker.expect("");
|
||||
@ -149,6 +155,7 @@ function runTests()
|
||||
marker.orientAngle.baseVal.newValueSpecifiedUnits(
|
||||
SVGAngle.SVG_ANGLETYPE_GRAD, 45);
|
||||
marker.removeAttribute("orient");
|
||||
marker.removeAttributeNS(null, "orient");
|
||||
marker.orientAngle.baseVal.value = 40;
|
||||
|
||||
eventChecker.expect("");
|
||||
@ -167,6 +174,7 @@ function runTests()
|
||||
convolve.setAttribute("preserveAlpha", "true");
|
||||
convolve.preserveAlpha.baseVal = false;
|
||||
convolve.removeAttribute("preserveAlpha");
|
||||
convolve.removeAttributeNS(null, "preserveAlpha");
|
||||
convolve.preserveAlpha.baseVal = true;
|
||||
|
||||
eventChecker.expect("");
|
||||
@ -180,6 +188,7 @@ function runTests()
|
||||
convolve.setAttribute("edgeMode", "none");
|
||||
convolve.edgeMode.baseVal = SVGFEConvolveMatrixElement.SVG_EDGEMODE_WRAP;
|
||||
convolve.removeAttribute("edgeMode");
|
||||
convolve.removeAttributeNS(null, "edgeMode");
|
||||
convolve.edgeMode.baseVal = SVGFEConvolveMatrixElement.SVG_EDGEMODE_NONE;
|
||||
|
||||
eventChecker.expect("");
|
||||
@ -194,6 +203,7 @@ function runTests()
|
||||
convolve.setAttribute("result", "bar");
|
||||
convolve.result.baseVal = "foo";
|
||||
convolve.removeAttribute("result");
|
||||
convolve.removeAttributeNS(null, "result");
|
||||
convolve.result.baseVal = "bar";
|
||||
|
||||
eventChecker.expect("");
|
||||
@ -209,6 +219,7 @@ function runTests()
|
||||
marker.preserveAspectRatio.baseVal.align =
|
||||
SVGPreserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMAXYMAX;
|
||||
marker.removeAttribute("preserveAspectRatio");
|
||||
marker.removeAttributeNS(null, "preserveAspectRatio");
|
||||
marker.preserveAspectRatio.baseVal.align =
|
||||
SVGPreserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMIDYMIN;
|
||||
|
||||
@ -224,6 +235,7 @@ function runTests()
|
||||
marker.setAttribute("viewBox", "1 2 3 4");
|
||||
marker.viewBox.baseVal.height = 5;
|
||||
marker.removeAttribute("viewBox");
|
||||
marker.removeAttributeNS(null, "viewBox");
|
||||
marker.viewBox.baseVal.height = 4;
|
||||
|
||||
eventChecker.ignoreEvents();
|
||||
|
@ -113,7 +113,7 @@ function report(testName, success) {
|
||||
]]></script>
|
||||
<script type="text/javascript"><![CDATA[
|
||||
try {
|
||||
let (x=1) (x);
|
||||
eval("let (x=1) (x)");
|
||||
var success = false;
|
||||
}
|
||||
catch (e) { success = true; }
|
||||
|
@ -1933,12 +1933,6 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
|
||||
|
||||
bool reUseInnerWindow = aForceReuseInnerWindow || wouldReuseInnerWindow;
|
||||
|
||||
// Remember the old document's principal.
|
||||
nsIPrincipal *oldPrincipal = nsnull;
|
||||
if (oldDoc) {
|
||||
oldPrincipal = oldDoc->NodePrincipal();
|
||||
}
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
// Set mDocument even if this is an outer window to avoid
|
||||
@ -1956,6 +1950,7 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
|
||||
nsGlobalWindow *currentInner = GetCurrentInnerWindowInternal();
|
||||
|
||||
nsRefPtr<nsGlobalWindow> newInnerWindow;
|
||||
bool createdInnerWindow = false;
|
||||
|
||||
bool thisChrome = IsChromeWindow();
|
||||
|
||||
@ -2034,6 +2029,7 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
|
||||
"Failed to get script global and holder");
|
||||
|
||||
mCreatingInnerWindow = false;
|
||||
createdInnerWindow = true;
|
||||
Thaw();
|
||||
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
@ -2114,6 +2110,19 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
|
||||
}
|
||||
}
|
||||
|
||||
// If we created a new inner window above, we need to do the last little bit
|
||||
// of initialization now that the dust has settled.
|
||||
if (createdInnerWindow) {
|
||||
nsIXPConnect *xpc = nsContentUtils::XPConnect();
|
||||
nsCOMPtr<nsIXPConnectWrappedNative> wrapper;
|
||||
nsresult rv = xpc->GetWrappedNativeOfJSObject(cx, newInnerWindow->mJSObject,
|
||||
getter_AddRefs(wrapper));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ABORT_IF_FALSE(wrapper, "bad wrapper");
|
||||
rv = wrapper->FinishInitForWrappedGlobal();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
JSAutoEnterCompartment ac;
|
||||
if (!ac.enter(cx, mJSObject)) {
|
||||
NS_ERROR("unable to enter a compartment");
|
||||
@ -4693,7 +4702,7 @@ nsGlobalWindow::MakeScriptDialogTitle(nsAString &aOutTitle)
|
||||
nsXPIDLString tempString;
|
||||
nsContentUtils::FormatLocalizedString(nsContentUtils::eCOMMON_DIALOG_PROPERTIES,
|
||||
"ScriptDlgHeading",
|
||||
formatStrings, ArrayLength(formatStrings),
|
||||
formatStrings,
|
||||
tempString);
|
||||
aOutTitle = tempString;
|
||||
}
|
||||
|
@ -147,6 +147,9 @@ static PRLogModuleInfo* gJSDiagnostics;
|
||||
// Force a CC after this long if there's anything in the purple buffer.
|
||||
#define NS_CC_FORCED (2 * 60 * PR_USEC_PER_SEC) // 2 min
|
||||
|
||||
// Don't allow an incremental GC to lock out the CC for too long.
|
||||
#define NS_MAX_CC_LOCKEDOUT_TIME (5 * PR_USEC_PER_SEC) // 5 seconds
|
||||
|
||||
// Trigger a CC if the purple buffer exceeds this size when we check it.
|
||||
#define NS_CC_PURPLE_LIMIT 250
|
||||
|
||||
@ -160,8 +163,8 @@ static nsITimer *sCCTimer;
|
||||
|
||||
static PRTime sLastCCEndTime;
|
||||
|
||||
static bool sGCHasRun;
|
||||
static bool sCCLockedOut;
|
||||
static PRTime sCCLockedOutTime;
|
||||
|
||||
static js::GCSliceCallback sPrevGCSliceCallback;
|
||||
|
||||
@ -812,7 +815,7 @@ nsJSContext::DOMOperationCallback(JSContext *cx)
|
||||
const PRUnichar *formatParams[] = { filenameUTF16.get() };
|
||||
rv = nsContentUtils::FormatLocalizedString(nsContentUtils::eDOM_PROPERTIES,
|
||||
"KillScriptLocation",
|
||||
formatParams, 1,
|
||||
formatParams,
|
||||
scriptLocation);
|
||||
|
||||
if (NS_SUCCEEDED(rv) && scriptLocation) {
|
||||
@ -2314,19 +2317,11 @@ nsresult
|
||||
nsJSContext::SetOuterObject(JSObject* aOuterObject)
|
||||
{
|
||||
// Force our context's global object to be the outer.
|
||||
// NB: JS_SetGlobalObject sets mContext->compartment.
|
||||
JS_SetGlobalObject(mContext, aOuterObject);
|
||||
|
||||
// NB: JS_SetGlobalObject sets mContext->compartment.
|
||||
// Set up the prototype for the outer object.
|
||||
JSObject *inner = JS_GetParent(aOuterObject);
|
||||
|
||||
nsIXPConnect *xpc = nsContentUtils::XPConnect();
|
||||
nsCOMPtr<nsIXPConnectWrappedNative> wrapper;
|
||||
nsresult rv = xpc->GetWrappedNativeOfJSObject(mContext, inner,
|
||||
getter_AddRefs(wrapper));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ABORT_IF_FALSE(wrapper, "bad wrapper");
|
||||
|
||||
wrapper->FinishInitForWrappedGlobal();
|
||||
JS_SetPrototype(mContext, aOuterObject, JS_GetPrototype(inner));
|
||||
|
||||
return NS_OK;
|
||||
@ -3318,9 +3313,24 @@ TimerFireForgetSkippable(PRUint32 aSuspected, bool aRemoveChildless)
|
||||
static void
|
||||
CCTimerFired(nsITimer *aTimer, void *aClosure)
|
||||
{
|
||||
if (sDidShutdown || sCCLockedOut) {
|
||||
if (sDidShutdown) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (sCCLockedOut) {
|
||||
PRTime now = PR_Now();
|
||||
if (sCCLockedOutTime == 0) {
|
||||
sCCLockedOutTime = now;
|
||||
return;
|
||||
}
|
||||
if (now - sCCLockedOutTime < NS_MAX_CC_LOCKEDOUT_TIME) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Finish the current incremental GC
|
||||
nsJSContext::GarbageCollectNow(js::gcreason::CC_FORCED, nsGCNormal);
|
||||
}
|
||||
|
||||
++sCCTimerFireCount;
|
||||
|
||||
// During early timer fires, we only run forgetSkippable. During the first
|
||||
@ -3486,6 +3496,8 @@ nsJSContext::KillShrinkGCBuffersTimer()
|
||||
void
|
||||
nsJSContext::KillCCTimer()
|
||||
{
|
||||
sCCLockedOutTime = 0;
|
||||
|
||||
if (sCCTimer) {
|
||||
sCCTimer->Cancel();
|
||||
|
||||
@ -3524,9 +3536,10 @@ DOMGCSliceCallback(JSRuntime *aRt, js::GCProgress aProgress, const js::GCDescrip
|
||||
}
|
||||
}
|
||||
|
||||
// Prevent cycle collections during incremental GC.
|
||||
// Prevent cycle collections and shrinking during incremental GC.
|
||||
if (aProgress == js::GC_CYCLE_BEGIN) {
|
||||
sCCLockedOut = true;
|
||||
nsJSContext::KillShrinkGCBuffersTimer();
|
||||
} else if (aProgress == js::GC_CYCLE_END) {
|
||||
sCCLockedOut = false;
|
||||
}
|
||||
@ -3534,43 +3547,31 @@ DOMGCSliceCallback(JSRuntime *aRt, js::GCProgress aProgress, const js::GCDescrip
|
||||
// The GC has more work to do, so schedule another GC slice.
|
||||
if (aProgress == js::GC_SLICE_END) {
|
||||
nsJSContext::KillGCTimer();
|
||||
nsJSContext::KillCCTimer();
|
||||
|
||||
nsJSContext::PokeGC(js::gcreason::INTER_SLICE_GC, NS_INTERSLICE_GC_DELAY);
|
||||
}
|
||||
|
||||
if (aProgress == js::GC_CYCLE_END) {
|
||||
// May need to kill the inter-slice GC timer
|
||||
nsJSContext::KillGCTimer();
|
||||
|
||||
sCCollectedWaitingForGC = 0;
|
||||
sCleanupSinceLastGC = false;
|
||||
|
||||
if (sGCTimer) {
|
||||
// If we were waiting for a GC to happen, kill the timer.
|
||||
nsJSContext::KillGCTimer();
|
||||
|
||||
if (aDesc.isCompartment) {
|
||||
// If this is a compartment GC, restart it. We still want
|
||||
// a full GC to happen. Compartment GCs usually happen as a
|
||||
// result of last-ditch or MaybeGC. In both cases its
|
||||
// result of last-ditch or MaybeGC. In both cases it is
|
||||
// probably a time of heavy activity and we want to delay
|
||||
// the full GC, but we do want it to happen eventually.
|
||||
if (aDesc.isCompartment) {
|
||||
nsJSContext::PokeGC(js::gcreason::POST_COMPARTMENT);
|
||||
|
||||
// We poked the GC, so we can kill any pending CC here.
|
||||
nsJSContext::KillCCTimer();
|
||||
}
|
||||
} else {
|
||||
// If this was a full GC, poke the CC to run soon.
|
||||
if (!aDesc.isCompartment) {
|
||||
sGCHasRun = true;
|
||||
sNeedsFullCC = true;
|
||||
nsJSContext::MaybePokeCC();
|
||||
}
|
||||
nsJSContext::PokeGC(js::gcreason::POST_COMPARTMENT);
|
||||
}
|
||||
|
||||
// If we didn't end up scheduling a GC, make sure that we release GC buffers
|
||||
// soon after canceling previous shrinking attempt.
|
||||
nsJSContext::KillShrinkGCBuffersTimer();
|
||||
if (!sGCTimer) {
|
||||
sNeedsFullCC = true;
|
||||
nsJSContext::MaybePokeCC();
|
||||
|
||||
if (!aDesc.isCompartment) {
|
||||
// Avoid shrinking during heavy activity, which is suggested by
|
||||
// compartment GC.
|
||||
nsJSContext::PokeShrinkGCBuffers();
|
||||
}
|
||||
}
|
||||
@ -3669,8 +3670,8 @@ nsJSRuntime::Startup()
|
||||
{
|
||||
// initialize all our statics, so that we can restart XPCOM
|
||||
sGCTimer = sCCTimer = nsnull;
|
||||
sGCHasRun = false;
|
||||
sCCLockedOut = false;
|
||||
sCCLockedOutTime = 0;
|
||||
sLastCCEndTime = 0;
|
||||
sPendingLoadCount = 0;
|
||||
sLoadingInProgress = false;
|
||||
|
@ -9,15 +9,61 @@
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsXPCOMCIDInternal.h"
|
||||
#include "mozilla/LazyIdleThread.h"
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include "BluetoothAdapter.h"
|
||||
|
||||
#if defined(MOZ_WIDGET_GONK)
|
||||
#include <bluedroid/bluetooth.h>
|
||||
#endif
|
||||
|
||||
USING_BLUETOOTH_NAMESPACE
|
||||
|
||||
static struct BluedroidFunctions {
|
||||
bool initialized;
|
||||
bool tried_initialization;
|
||||
|
||||
BluedroidFunctions() :
|
||||
initialized(false),
|
||||
tried_initialization(false)
|
||||
{
|
||||
}
|
||||
|
||||
int (* bt_enable)();
|
||||
int (* bt_disable)();
|
||||
int (* bt_is_enabled)();
|
||||
} sBluedroidFunctions;
|
||||
|
||||
static bool EnsureBluetoothInit() {
|
||||
if (sBluedroidFunctions.tried_initialization)
|
||||
{
|
||||
return sBluedroidFunctions.initialized;
|
||||
}
|
||||
|
||||
sBluedroidFunctions.initialized = false;
|
||||
sBluedroidFunctions.tried_initialization = true;
|
||||
|
||||
void* handle = dlopen("libbluedroid.so", RTLD_LAZY);
|
||||
|
||||
if(!handle) {
|
||||
NS_ERROR("Failed to open libbluedroid.so, bluetooth cannot run");
|
||||
return false;
|
||||
}
|
||||
|
||||
sBluedroidFunctions.bt_enable = (int (*)())dlsym(handle, "bt_enable");
|
||||
if(sBluedroidFunctions.bt_enable == NULL) {
|
||||
NS_ERROR("Failed to attach bt_enable function");
|
||||
return false;
|
||||
}
|
||||
sBluedroidFunctions.bt_disable = (int (*)())dlsym(handle, "bt_disable");
|
||||
if(sBluedroidFunctions.bt_disable == NULL) {
|
||||
NS_ERROR("Failed to attach bt_disable function");
|
||||
return false;
|
||||
}
|
||||
sBluedroidFunctions.bt_is_enabled = (int (*)())dlsym(handle, "bt_is_enabled");
|
||||
if(sBluedroidFunctions.bt_is_enabled == NULL) {
|
||||
NS_ERROR("Failed to attach bt_is_enabled function");
|
||||
return false;
|
||||
}
|
||||
sBluedroidFunctions.initialized = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
class ToggleBtResultTask : public nsRunnable
|
||||
{
|
||||
public:
|
||||
@ -54,7 +100,7 @@ class ToggleBtResultTask : public nsRunnable
|
||||
class ToggleBtTask : public nsRunnable
|
||||
{
|
||||
public:
|
||||
ToggleBtTask(bool onOff, BluetoothAdapter* adapterPtr)
|
||||
ToggleBtTask(bool onOff, BluetoothAdapter* adapterPtr)
|
||||
: mOnOff(onOff),
|
||||
mAdapterPtr(adapterPtr)
|
||||
{
|
||||
@ -65,18 +111,20 @@ class ToggleBtTask : public nsRunnable
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
|
||||
if(!EnsureBluetoothInit()) {
|
||||
NS_ERROR("Failed to load bluedroid library.\n");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
bool result;
|
||||
|
||||
//Toggle BT here
|
||||
#if defined(MOZ_WIDGET_GONK)
|
||||
|
||||
if (mOnOff) {
|
||||
result = bt_enable();
|
||||
result = sBluedroidFunctions.bt_enable();
|
||||
} else {
|
||||
result = bt_disable();
|
||||
result = sBluedroidFunctions.bt_disable();
|
||||
}
|
||||
#else
|
||||
result = true;
|
||||
#endif
|
||||
|
||||
// Create a result thread and pass it to Main Thread,
|
||||
nsCOMPtr<nsIRunnable> resultRunnable = new ToggleBtResultTask(mAdapterPtr, result);
|
||||
@ -89,8 +137,8 @@ class ToggleBtTask : public nsRunnable
|
||||
}
|
||||
|
||||
private:
|
||||
nsRefPtr<BluetoothAdapter> mAdapterPtr;
|
||||
bool mOnOff;
|
||||
nsRefPtr<BluetoothAdapter> mAdapterPtr;
|
||||
};
|
||||
|
||||
DOMCI_DATA(BluetoothAdapter, BluetoothAdapter)
|
||||
@ -123,18 +171,37 @@ BluetoothAdapter::BluetoothAdapter()
|
||||
NS_IMETHODIMP
|
||||
BluetoothAdapter::GetPower(bool* aPower)
|
||||
{
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
if(!EnsureBluetoothInit()) {
|
||||
NS_ERROR("Failed to load bluedroid library.\n");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
*aPower = sBluedroidFunctions.bt_is_enabled();
|
||||
#else
|
||||
*aPower = mPower;
|
||||
|
||||
#endif
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
BluetoothAdapter::SetPower(bool aPower)
|
||||
{
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
// Platform specific check for gonk until object is divided in
|
||||
// different implementations per platform. Linux doesn't require
|
||||
// bluetooth firmware loading, but code should work otherwise.
|
||||
if(!EnsureBluetoothInit()) {
|
||||
NS_ERROR("Failed to load bluedroid library.\n");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
#endif
|
||||
if (mPower != aPower) {
|
||||
mPower = aPower;
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
return ToggleBluetoothAsync();
|
||||
#endif
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
@ -1,26 +1,32 @@
|
||||
<html>
|
||||
<script>
|
||||
function check(elt, expectProxy, message) {
|
||||
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
|
||||
var utils = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
|
||||
.getInterface(Components.interfaces.nsIDOMWindowUtils);
|
||||
var result = ((utils.getClassName(elt) === 'Proxy') === expectProxy)
|
||||
? "PASS"
|
||||
: "FAIL";
|
||||
function check(elt, expectAccess, prop) {
|
||||
var access = false;
|
||||
try {
|
||||
elt[prop];
|
||||
access = true;
|
||||
}
|
||||
catch (e) {}
|
||||
return access === expectAccess;
|
||||
}
|
||||
|
||||
function sendMessage(success, sameOrigin, prop) {
|
||||
var result = success ? 'PASS' : 'FAIL';
|
||||
var message;
|
||||
if (sameOrigin)
|
||||
message = 'Can access |' + prop + '| if same origin';
|
||||
else
|
||||
message = 'Cannot access |' + prop + '| if not same origin';
|
||||
parent.postMessage(result + ',' + message, '*');
|
||||
}
|
||||
|
||||
try {
|
||||
// true if same origin, throws otherwise
|
||||
var sameOrigin = parent.location.href !== '';
|
||||
} catch (e) {
|
||||
sameOrigin = false;
|
||||
var sameOrigin = location.host !== 'example.org';
|
||||
var pass = check(frameElement, sameOrigin, 'src');
|
||||
if (!pass) {
|
||||
sendMessage(false, sameOrigin, 'src');
|
||||
} else {
|
||||
pass = check(parent.location, sameOrigin, 'href');
|
||||
sendMessage(pass, sameOrigin, 'href');
|
||||
}
|
||||
|
||||
check(frameElement, !sameOrigin,
|
||||
sameOrigin
|
||||
? 'no wrapper needed if same origin'
|
||||
: 'wrapper needed if not same origin');
|
||||
</script>
|
||||
</html>
|
||||
|
@ -1,7 +1,7 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test for location object behaviors</title>
|
||||
<title>Test for same-origin and cross-origin wrapping of frameElement</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
@ -14,6 +14,14 @@
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
//
|
||||
// This test has sort of morphed over time to become less and less useful.
|
||||
// In the past, we had special security policy for frameElement, but that's
|
||||
// more or less gone away with compartment/proxy wrapping. So we just go
|
||||
// through the motions to make sure that, indeed, frameElement is subject
|
||||
// to the same-origin policy.
|
||||
//
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
var count = 0;
|
||||
|
@ -2925,7 +2925,7 @@ WorkerPrivate::Dispatch(WorkerRunnable* aEvent, EventQueue* aQueue)
|
||||
}
|
||||
|
||||
if (aQueue == &mControlQueue && mJSContext) {
|
||||
JS_TriggerOperationCallback(mJSContext);
|
||||
JS_TriggerOperationCallback(JS_GetRuntime(mJSContext));
|
||||
}
|
||||
|
||||
mCondVar.Notify();
|
||||
|
@ -85,5 +85,5 @@ nsEditProperty::RegisterAtoms()
|
||||
#undef EDITOR_ATOM
|
||||
};
|
||||
|
||||
NS_RegisterStaticAtoms(property_atoms, ArrayLength(property_atoms));
|
||||
NS_RegisterStaticAtoms(property_atoms);
|
||||
}
|
||||
|
@ -134,7 +134,7 @@ nsTextServicesDocument::RegisterAtoms()
|
||||
#undef TS_ATOM
|
||||
};
|
||||
|
||||
NS_RegisterStaticAtoms(ts_atoms, ArrayLength(ts_atoms));
|
||||
NS_RegisterStaticAtoms(ts_atoms);
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsTextServicesDocument)
|
||||
|
@ -1540,8 +1540,17 @@ PRUint32 nsWindowWatcher::CalculateChromeFlags(const char *aFeatures,
|
||||
nsIWebBrowserChrome::CHROME_DEPENDENT : 0;
|
||||
chromeFlags |= WinHasOption(aFeatures, "modal", 0, nsnull) ?
|
||||
(nsIWebBrowserChrome::CHROME_MODAL | nsIWebBrowserChrome::CHROME_DEPENDENT) : 0;
|
||||
chromeFlags |= WinHasOption(aFeatures, "dialog", 0, nsnull) ?
|
||||
nsIWebBrowserChrome::CHROME_OPENAS_DIALOG : 0;
|
||||
|
||||
/* On mobile we want to ignore the dialog window feature, since the mobile UI
|
||||
does not provide any affordance for dialog windows. This does not interfere
|
||||
with dialog windows created through openDialog. */
|
||||
bool disableDialogFeature = false;
|
||||
nsCOMPtr<nsIPrefBranch> branch = do_QueryInterface(prefs);
|
||||
branch->GetBoolPref("dom.disable_window_open_dialog_feature", &disableDialogFeature);
|
||||
if (!disableDialogFeature) {
|
||||
chromeFlags |= WinHasOption(aFeatures, "dialog", 0, nsnull) ?
|
||||
nsIWebBrowserChrome::CHROME_OPENAS_DIALOG : 0;
|
||||
}
|
||||
|
||||
/* and dialogs need to have the last word. assume dialogs are dialogs,
|
||||
and opened as chrome, unless explicitly told otherwise. */
|
||||
|
@ -42,6 +42,9 @@
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/Util.h"
|
||||
|
||||
#include "nsIScreen.h"
|
||||
#include "nsIScreenManager.h"
|
||||
|
||||
#if defined(XP_UNIX)
|
||||
|
||||
#ifdef MOZ_WIDGET_GTK2
|
||||
@ -2190,13 +2193,6 @@ static const EGLint kEGLConfigAttribsRGBA32[] = {
|
||||
LOCAL_EGL_NONE
|
||||
};
|
||||
|
||||
// This struct is used only by CreateConfig below, but ISO C++98 forbids
|
||||
// instantiating a template dependent on a locally-defined type. Boo-urns!
|
||||
struct EGLAttribs {
|
||||
gfxASurface::gfxImageFormat mFormat;
|
||||
const EGLint* mAttribs;
|
||||
};
|
||||
|
||||
// Return true if a suitable EGLConfig was found and pass it out
|
||||
// through aConfig. Return false otherwise.
|
||||
//
|
||||
@ -2205,47 +2201,41 @@ struct EGLAttribs {
|
||||
static bool
|
||||
CreateConfig(EGLConfig* aConfig)
|
||||
{
|
||||
EGLAttribs attribsToTry[] = {
|
||||
#ifdef MOZ_GFX_OPTIMIZE_MOBILE
|
||||
// Prefer r5g6b5 for potential savings in memory bandwidth.
|
||||
// This needs to be reevaluated for newer devices.
|
||||
{ gfxASurface::ImageFormatRGB16_565, kEGLConfigAttribsRGB16 },
|
||||
#endif
|
||||
{ gfxASurface::ImageFormatARGB32, kEGLConfigAttribsRGBA32 },
|
||||
};
|
||||
nsCOMPtr<nsIScreenManager> screenMgr = do_GetService("@mozilla.org/gfx/screenmanager;1");
|
||||
nsCOMPtr<nsIScreen> screen;
|
||||
screenMgr->GetPrimaryScreen(getter_AddRefs(screen));
|
||||
PRInt32 depth = 24;
|
||||
screen->GetColorDepth(&depth);
|
||||
|
||||
EGLConfig configs[64];
|
||||
for (unsigned i = 0; i < ArrayLength(attribsToTry); ++i) {
|
||||
const EGLAttribs& attribs = attribsToTry[i];
|
||||
EGLint ncfg = ArrayLength(configs);
|
||||
gfxASurface::gfxImageFormat format;
|
||||
const EGLint* attribs = depth == 16 ? kEGLConfigAttribsRGB16 :
|
||||
kEGLConfigAttribsRGBA32;
|
||||
EGLint ncfg = ArrayLength(configs);
|
||||
|
||||
if (!sEGLLibrary.fChooseConfig(EGL_DISPLAY(), attribs.mAttribs,
|
||||
configs, ncfg, &ncfg) ||
|
||||
ncfg < 1)
|
||||
if (!sEGLLibrary.fChooseConfig(EGL_DISPLAY(), attribs,
|
||||
configs, ncfg, &ncfg) ||
|
||||
ncfg < 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int j = 0; j < ncfg; ++j) {
|
||||
EGLConfig config = configs[j];
|
||||
EGLint r, g, b, a;
|
||||
|
||||
if (sEGLLibrary.fGetConfigAttrib(EGL_DISPLAY(), config,
|
||||
LOCAL_EGL_RED_SIZE, &r) &&
|
||||
sEGLLibrary.fGetConfigAttrib(EGL_DISPLAY(), config,
|
||||
LOCAL_EGL_GREEN_SIZE, &g) &&
|
||||
sEGLLibrary.fGetConfigAttrib(EGL_DISPLAY(), config,
|
||||
LOCAL_EGL_BLUE_SIZE, &b) &&
|
||||
sEGLLibrary.fGetConfigAttrib(EGL_DISPLAY(), config,
|
||||
LOCAL_EGL_ALPHA_SIZE, &a) &&
|
||||
((depth == 16 && r == 5 && g == 6 && b == 5) ||
|
||||
(depth == 24 && r == 8 && g == 8 && b == 8 && a == 8)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int j = 0; j < ncfg; ++j) {
|
||||
EGLConfig config = configs[j];
|
||||
EGLint r, g, b, a;
|
||||
|
||||
if (sEGLLibrary.fGetConfigAttrib(EGL_DISPLAY(), config,
|
||||
LOCAL_EGL_RED_SIZE, &r) &&
|
||||
sEGLLibrary.fGetConfigAttrib(EGL_DISPLAY(), config,
|
||||
LOCAL_EGL_GREEN_SIZE, &g) &&
|
||||
sEGLLibrary.fGetConfigAttrib(EGL_DISPLAY(), config,
|
||||
LOCAL_EGL_BLUE_SIZE, &b) &&
|
||||
sEGLLibrary.fGetConfigAttrib(EGL_DISPLAY(), config,
|
||||
LOCAL_EGL_ALPHA_SIZE, &a) &&
|
||||
((gfxASurface::ImageFormatRGB16_565 == attribs.mFormat &&
|
||||
r == 5 && g == 6 && b == 5) ||
|
||||
(gfxASurface::ImageFormatARGB32 == attribs.mFormat &&
|
||||
r == 8 && g == 8 && b == 8 && a == 8)))
|
||||
{
|
||||
*aConfig = config;
|
||||
return true;
|
||||
}
|
||||
*aConfig = config;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
@ -58,5 +58,5 @@ static const nsStaticAtom atoms[] = {
|
||||
|
||||
void gfxAtoms::RegisterAtoms()
|
||||
{
|
||||
NS_RegisterStaticAtoms(atoms, ArrayLength(atoms));
|
||||
NS_RegisterStaticAtoms(atoms);
|
||||
}
|
||||
|
@ -68,6 +68,10 @@ using namespace mozilla;
|
||||
gfxPlatform::GetLog(eGfxLog_fontinit), \
|
||||
PR_LOG_DEBUG)
|
||||
|
||||
#define LOG_CMAPDATA_ENABLED() PR_LOG_TEST( \
|
||||
gfxPlatform::GetLog(eGfxLog_cmapdata), \
|
||||
PR_LOG_DEBUG)
|
||||
|
||||
// font info loader constants
|
||||
|
||||
// avoid doing this during startup even on slow machines but try to start
|
||||
@ -371,6 +375,16 @@ gfxDWriteFontEntry::ReadCMAP()
|
||||
rv = gfxFontUtils::ReadCMAP(cmap, buffer.Length(),
|
||||
mCharacterMap, mUVSOffset,
|
||||
unicodeFont, symbolFont);
|
||||
#ifdef PR_LOGGING
|
||||
LOG_FONTLIST(("(fontlist-cmap) name: %s, size: %d\n",
|
||||
NS_ConvertUTF16toUTF8(mName).get(), mCharacterMap.GetSize()));
|
||||
if (LOG_CMAPDATA_ENABLED()) {
|
||||
char prefix[256];
|
||||
sprintf(prefix, "(cmapdata) name: %.220s",
|
||||
NS_ConvertUTF16toUTF8(mName).get());
|
||||
mCharacterMap.Dump(prefix, eGfxLog_cmapdata);
|
||||
}
|
||||
#endif
|
||||
mHasCmapTable = NS_SUCCEEDED(rv);
|
||||
return rv;
|
||||
}
|
||||
@ -411,6 +425,12 @@ gfxDWriteFontEntry::ReadCMAP()
|
||||
#ifdef PR_LOGGING
|
||||
LOG_FONTLIST(("(fontlist-cmap) name: %s, size: %d\n",
|
||||
NS_ConvertUTF16toUTF8(mName).get(), mCharacterMap.GetSize()));
|
||||
if (LOG_CMAPDATA_ENABLED()) {
|
||||
char prefix[256];
|
||||
sprintf(prefix, "(cmapdata) name: %.220s",
|
||||
NS_ConvertUTF16toUTF8(mName).get());
|
||||
mCharacterMap.Dump(prefix, eGfxLog_cmapdata);
|
||||
}
|
||||
#endif
|
||||
|
||||
mHasCmapTable = NS_SUCCEEDED(rv);
|
||||
@ -1174,3 +1194,182 @@ gfxDWriteFontList::ResolveFontName(const nsAString& aFontName,
|
||||
|
||||
return gfxPlatformFontList::ResolveFontName(aFontName, aResolvedFontName);
|
||||
}
|
||||
|
||||
static nsresult GetFamilyName(IDWriteFont *aFont, nsString& aFamilyName)
|
||||
{
|
||||
HRESULT hr;
|
||||
nsRefPtr<IDWriteFontFamily> family;
|
||||
|
||||
// clean out previous value
|
||||
aFamilyName.Truncate();
|
||||
|
||||
hr = aFont->GetFontFamily(getter_AddRefs(family));
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
nsRefPtr<IDWriteLocalizedStrings> familyNames;
|
||||
|
||||
hr = family->GetFamilyNames(getter_AddRefs(familyNames));
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
UINT32 index = 0;
|
||||
BOOL exists = false;
|
||||
|
||||
hr = familyNames->FindLocaleName(L"en-us", &index, &exists);
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
// If the specified locale doesn't exist, select the first on the list.
|
||||
if (!exists) {
|
||||
index = 0;
|
||||
}
|
||||
|
||||
nsAutoTArray<WCHAR, 32> name;
|
||||
UINT32 length;
|
||||
|
||||
hr = familyNames->GetStringLength(index, &length);
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
if (!name.SetLength(length + 1)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
hr = familyNames->GetString(index, name.Elements(), length + 1);
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
aFamilyName.Assign(name.Elements());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// bug 705594 - the method below doesn't actually do any "drawing", it's only
|
||||
// used to invoke the DirectWrite layout engine to determine the fallback font
|
||||
// for a given character.
|
||||
|
||||
IFACEMETHODIMP FontFallbackRenderer::DrawGlyphRun(
|
||||
__maybenull void* clientDrawingContext,
|
||||
FLOAT baselineOriginX,
|
||||
FLOAT baselineOriginY,
|
||||
DWRITE_MEASURING_MODE measuringMode,
|
||||
__in DWRITE_GLYPH_RUN const* glyphRun,
|
||||
__in DWRITE_GLYPH_RUN_DESCRIPTION const* glyphRunDescription,
|
||||
__maybenull IUnknown* clientDrawingEffect
|
||||
)
|
||||
{
|
||||
if (!mSystemFonts) {
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
nsRefPtr<IDWriteFont> font;
|
||||
hr = mSystemFonts->GetFontFromFontFace(glyphRun->fontFace,
|
||||
getter_AddRefs(font));
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
// copy the family name
|
||||
hr = GetFamilyName(font, mFamilyName);
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
// Arial is used as the default fallback font
|
||||
// so if it matches ==> no font found
|
||||
if (mFamilyName.EqualsLiteral("Arial")) {
|
||||
mFamilyName.Truncate();
|
||||
return E_FAIL;
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
gfxFontEntry*
|
||||
gfxDWriteFontList::GlobalFontFallback(const PRUint32 aCh,
|
||||
PRInt32 aRunScript,
|
||||
const gfxFontStyle* aMatchStyle,
|
||||
PRUint32& aCmapCount)
|
||||
{
|
||||
bool useCmaps = gfxPlatform::GetPlatform()->UseCmapsDuringSystemFallback();
|
||||
|
||||
if (useCmaps) {
|
||||
return gfxPlatformFontList::GlobalFontFallback(aCh,
|
||||
aRunScript,
|
||||
aMatchStyle,
|
||||
aCmapCount);
|
||||
}
|
||||
|
||||
HRESULT hr;
|
||||
|
||||
nsRefPtr<IDWriteFactory> dwFactory =
|
||||
gfxWindowsPlatform::GetPlatform()->GetDWriteFactory();
|
||||
if (!dwFactory) {
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
// initialize fallback renderer
|
||||
if (!mFallbackRenderer) {
|
||||
mFallbackRenderer = new FontFallbackRenderer(dwFactory);
|
||||
}
|
||||
|
||||
// initialize text format
|
||||
if (!mFallbackFormat) {
|
||||
hr = dwFactory->CreateTextFormat(L"Arial", NULL,
|
||||
DWRITE_FONT_WEIGHT_REGULAR,
|
||||
DWRITE_FONT_STYLE_NORMAL,
|
||||
DWRITE_FONT_STRETCH_NORMAL,
|
||||
72.0f, L"en-us",
|
||||
getter_AddRefs(mFallbackFormat));
|
||||
if (FAILED(hr)) {
|
||||
return nsnull;
|
||||
}
|
||||
}
|
||||
|
||||
// set up string with fallback character
|
||||
wchar_t str[16];
|
||||
PRUint32 strLen;
|
||||
|
||||
if (IS_IN_BMP(aCh)) {
|
||||
str[0] = static_cast<wchar_t> (aCh);
|
||||
str[1] = 0;
|
||||
strLen = 1;
|
||||
} else {
|
||||
str[0] = static_cast<wchar_t> (H_SURROGATE(aCh));
|
||||
str[1] = static_cast<wchar_t> (L_SURROGATE(aCh));
|
||||
str[2] = 0;
|
||||
strLen = 2;
|
||||
}
|
||||
|
||||
// set up layout
|
||||
nsRefPtr<IDWriteTextLayout> fallbackLayout;
|
||||
|
||||
hr = dwFactory->CreateTextLayout(str, strLen, mFallbackFormat,
|
||||
200.0f, 200.0f,
|
||||
getter_AddRefs(fallbackLayout));
|
||||
if (FAILED(hr)) {
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
// call the draw method to invoke the DirectWrite layout functions
|
||||
// which determine the fallback font
|
||||
hr = fallbackLayout->Draw(NULL, mFallbackRenderer, 50.0f, 50.0f);
|
||||
if (FAILED(hr)) {
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
gfxFontEntry *fontEntry = nsnull;
|
||||
bool needsBold; // ignored in the system fallback case
|
||||
fontEntry = FindFontForFamily(mFallbackRenderer->FallbackFamilyName(),
|
||||
aMatchStyle, needsBold);
|
||||
if (fontEntry && !fontEntry->TestCharacterMap(aCh)) {
|
||||
fontEntry = nsnull;
|
||||
Telemetry::Accumulate(Telemetry::BAD_FALLBACK_FONT, true);
|
||||
}
|
||||
return fontEntry;
|
||||
}
|
||||
|
@ -204,6 +204,145 @@ protected:
|
||||
bool mForceGDIClassic;
|
||||
};
|
||||
|
||||
// custom text renderer used to determine the fallback font for a given char
|
||||
class FontFallbackRenderer : public IDWriteTextRenderer
|
||||
{
|
||||
public:
|
||||
FontFallbackRenderer(IDWriteFactory *aFactory)
|
||||
: mRefCount(0)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
hr = aFactory->GetSystemFontCollection(getter_AddRefs(mSystemFonts));
|
||||
NS_ASSERTION(SUCCEEDED(hr), "GetSystemFontCollection failed!");
|
||||
}
|
||||
|
||||
~FontFallbackRenderer()
|
||||
{}
|
||||
|
||||
// IDWriteTextRenderer methods
|
||||
IFACEMETHOD(DrawGlyphRun)(
|
||||
__maybenull void* clientDrawingContext,
|
||||
FLOAT baselineOriginX,
|
||||
FLOAT baselineOriginY,
|
||||
DWRITE_MEASURING_MODE measuringMode,
|
||||
__in DWRITE_GLYPH_RUN const* glyphRun,
|
||||
__in DWRITE_GLYPH_RUN_DESCRIPTION const* glyphRunDescription,
|
||||
__maybenull IUnknown* clientDrawingEffect
|
||||
);
|
||||
|
||||
IFACEMETHOD(DrawUnderline)(
|
||||
__maybenull void* clientDrawingContext,
|
||||
FLOAT baselineOriginX,
|
||||
FLOAT baselineOriginY,
|
||||
__in DWRITE_UNDERLINE const* underline,
|
||||
__maybenull IUnknown* clientDrawingEffect
|
||||
)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
|
||||
IFACEMETHOD(DrawStrikethrough)(
|
||||
__maybenull void* clientDrawingContext,
|
||||
FLOAT baselineOriginX,
|
||||
FLOAT baselineOriginY,
|
||||
__in DWRITE_STRIKETHROUGH const* strikethrough,
|
||||
__maybenull IUnknown* clientDrawingEffect
|
||||
)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
|
||||
IFACEMETHOD(DrawInlineObject)(
|
||||
__maybenull void* clientDrawingContext,
|
||||
FLOAT originX,
|
||||
FLOAT originY,
|
||||
IDWriteInlineObject* inlineObject,
|
||||
BOOL isSideways,
|
||||
BOOL isRightToLeft,
|
||||
__maybenull IUnknown* clientDrawingEffect
|
||||
)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
// IDWritePixelSnapping methods
|
||||
|
||||
IFACEMETHOD(IsPixelSnappingDisabled)(
|
||||
__maybenull void* clientDrawingContext,
|
||||
__out BOOL* isDisabled
|
||||
)
|
||||
{
|
||||
*isDisabled = FALSE;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
IFACEMETHOD(GetCurrentTransform)(
|
||||
__maybenull void* clientDrawingContext,
|
||||
__out DWRITE_MATRIX* transform
|
||||
)
|
||||
{
|
||||
const DWRITE_MATRIX ident = {1.0, 0.0, 0.0, 1.0, 0.0, 0.0};
|
||||
*transform = ident;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
IFACEMETHOD(GetPixelsPerDip)(
|
||||
__maybenull void* clientDrawingContext,
|
||||
__out FLOAT* pixelsPerDip
|
||||
)
|
||||
{
|
||||
*pixelsPerDip = 1.0f;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
// IUnknown methods
|
||||
|
||||
IFACEMETHOD_(unsigned long, AddRef) ()
|
||||
{
|
||||
return InterlockedIncrement(&mRefCount);
|
||||
}
|
||||
|
||||
IFACEMETHOD_(unsigned long, Release) ()
|
||||
{
|
||||
unsigned long newCount = InterlockedDecrement(&mRefCount);
|
||||
if (newCount == 0)
|
||||
{
|
||||
delete this;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return newCount;
|
||||
}
|
||||
|
||||
IFACEMETHOD(QueryInterface) (IID const& riid, void** ppvObject)
|
||||
{
|
||||
if (__uuidof(IDWriteTextRenderer) == riid) {
|
||||
*ppvObject = this;
|
||||
} else if (__uuidof(IDWritePixelSnapping) == riid) {
|
||||
*ppvObject = this;
|
||||
} else if (__uuidof(IUnknown) == riid) {
|
||||
*ppvObject = this;
|
||||
} else {
|
||||
*ppvObject = NULL;
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
this->AddRef();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
const nsString& FallbackFamilyName() { return mFamilyName; }
|
||||
|
||||
protected:
|
||||
unsigned long mRefCount;
|
||||
nsRefPtr<IDWriteFontCollection> mSystemFonts;
|
||||
nsString mFamilyName;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class gfxDWriteFontList : public gfxPlatformFontList {
|
||||
public:
|
||||
@ -248,6 +387,14 @@ private:
|
||||
|
||||
void GetDirectWriteSubstitutes();
|
||||
|
||||
// search fonts system-wide for a given character, null otherwise
|
||||
virtual gfxFontEntry* GlobalFontFallback(const PRUint32 aCh,
|
||||
PRInt32 aRunScript,
|
||||
const gfxFontStyle* aMatchStyle,
|
||||
PRUint32& aCmapCount);
|
||||
|
||||
virtual bool UsesSystemFallback() { return true; }
|
||||
|
||||
/**
|
||||
* Fonts listed in the registry as substitutes but for which no actual
|
||||
* font family is found.
|
||||
@ -270,6 +417,9 @@ private:
|
||||
// whether to use GDI font table access routines
|
||||
bool mGDIFontTableAccess;
|
||||
nsRefPtr<IDWriteGdiInterop> mGDIInterop;
|
||||
|
||||
nsRefPtr<FontFallbackRenderer> mFallbackRenderer;
|
||||
nsRefPtr<IDWriteTextFormat> mFallbackFormat;
|
||||
};
|
||||
|
||||
|
||||
|
@ -397,11 +397,12 @@ gfxFT2FontGroup::WhichPrefFontSupportsChar(PRUint32 aCh)
|
||||
}
|
||||
|
||||
already_AddRefed<gfxFont>
|
||||
gfxFT2FontGroup::WhichSystemFontSupportsChar(PRUint32 aCh)
|
||||
gfxFT2FontGroup::WhichSystemFontSupportsChar(PRUint32 aCh, PRInt32 aRunScript)
|
||||
{
|
||||
#if defined(XP_WIN) || defined(ANDROID)
|
||||
FontEntry *fe = static_cast<FontEntry*>
|
||||
(gfxPlatformFontList::PlatformFontList()->FindFontForChar(aCh, GetFontAt(0)));
|
||||
(gfxPlatformFontList::PlatformFontList()->
|
||||
SystemFindFontForChar(aCh, aRunScript, &mStyle));
|
||||
if (fe) {
|
||||
nsRefPtr<gfxFT2Font> f = gfxFT2Font::GetOrMakeFont(fe, &mStyle);
|
||||
nsRefPtr<gfxFont> font = f.get();
|
||||
|
@ -141,7 +141,8 @@ protected: // new functions
|
||||
already_AddRefed<gfxFT2Font> WhichFontSupportsChar(const nsTArray<nsRefPtr<gfxFontEntry> >& aFontEntryList,
|
||||
PRUint32 aCh);
|
||||
already_AddRefed<gfxFont> WhichPrefFontSupportsChar(PRUint32 aCh);
|
||||
already_AddRefed<gfxFont> WhichSystemFontSupportsChar(PRUint32 aCh);
|
||||
already_AddRefed<gfxFont>
|
||||
WhichSystemFontSupportsChar(PRUint32 aCh, PRInt32 aRunScript);
|
||||
|
||||
nsTArray<gfxTextRange> mRanges;
|
||||
nsString mString;
|
||||
|
@ -690,37 +690,60 @@ void gfxFontFamily::LocalizedName(nsAString& aLocalizedName)
|
||||
aLocalizedName = mName;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
gfxFontFamily::FindFontForChar(FontSearch *aMatchData)
|
||||
// metric for how close a given font matches a style
|
||||
static PRInt32
|
||||
CalcStyleMatch(gfxFontEntry *aFontEntry, const gfxFontStyle *aStyle)
|
||||
{
|
||||
if (!mHasStyles) {
|
||||
FindStyleVariations();
|
||||
PRInt32 rank = 0;
|
||||
if (aStyle) {
|
||||
// italics
|
||||
bool wantItalic =
|
||||
((aStyle->style & (FONT_STYLE_ITALIC | FONT_STYLE_OBLIQUE)) != 0);
|
||||
if (aFontEntry->IsItalic() == wantItalic) {
|
||||
rank += 10;
|
||||
}
|
||||
|
||||
// measure of closeness of weight to the desired value
|
||||
rank += 9 - abs(aFontEntry->Weight() / 100 - aStyle->ComputeWeight());
|
||||
} else {
|
||||
// if no font to match, prefer non-bold, non-italic fonts
|
||||
if (!aFontEntry->IsItalic()) {
|
||||
rank += 3;
|
||||
}
|
||||
if (!aFontEntry->IsBold()) {
|
||||
rank += 2;
|
||||
}
|
||||
}
|
||||
|
||||
if (!TestCharacterMap(aMatchData->mCh)) {
|
||||
return rank;
|
||||
}
|
||||
|
||||
#define RANK_MATCHED_CMAP 20
|
||||
|
||||
void
|
||||
gfxFontFamily::FindFontForChar(GlobalFontMatch *aMatchData)
|
||||
{
|
||||
if (mCharacterMapInitialized && !TestCharacterMap(aMatchData->mCh)) {
|
||||
// none of the faces in the family support the required char,
|
||||
// so bail out immediately
|
||||
return;
|
||||
}
|
||||
|
||||
// iterate over fonts
|
||||
PRUint32 numFonts = mAvailableFonts.Length();
|
||||
for (PRUint32 i = 0; i < numFonts; i++) {
|
||||
gfxFontEntry *fe = mAvailableFonts[i];
|
||||
|
||||
// skip certain fonts during system fallback
|
||||
if (!fe || fe->SkipDuringSystemFallback())
|
||||
continue;
|
||||
bool needsBold;
|
||||
gfxFontStyle normal;
|
||||
gfxFontEntry *fe = FindFontForStyle(
|
||||
(aMatchData->mStyle == nsnull) ? *aMatchData->mStyle : normal,
|
||||
needsBold);
|
||||
|
||||
if (fe && !fe->SkipDuringSystemFallback()) {
|
||||
PRInt32 rank = 0;
|
||||
|
||||
if (fe->TestCharacterMap(aMatchData->mCh)) {
|
||||
rank += 20;
|
||||
rank += RANK_MATCHED_CMAP;
|
||||
aMatchData->mCount++;
|
||||
#ifdef PR_LOGGING
|
||||
PRLogModuleInfo *log = gfxPlatform::GetLog(eGfxLog_textrun);
|
||||
|
||||
|
||||
if (NS_UNLIKELY(log)) {
|
||||
PRUint32 charRange = gfxFontUtils::CharRangeBit(aMatchData->mCh);
|
||||
PRUint32 unicodeRange = FindCharUnicodeRange(aMatchData->mCh);
|
||||
@ -735,40 +758,20 @@ gfxFontFamily::FindFontForChar(FontSearch *aMatchData)
|
||||
#endif
|
||||
}
|
||||
|
||||
// if we didn't match any characters don't bother wasting more time with this face.
|
||||
if (rank == 0)
|
||||
continue;
|
||||
|
||||
// omitting from original windows code -- family name, lang group, pitch
|
||||
// not available in current FontEntry implementation
|
||||
|
||||
if (aMatchData->mFontToMatch) {
|
||||
const gfxFontStyle *style = aMatchData->mFontToMatch->GetStyle();
|
||||
|
||||
// matching italics takes precedence over weight
|
||||
bool wantItalic =
|
||||
((style->style & (FONT_STYLE_ITALIC | FONT_STYLE_OBLIQUE)) != 0);
|
||||
if (fe->IsItalic() == wantItalic) {
|
||||
rank += 10;
|
||||
}
|
||||
|
||||
// measure of closeness of weight to the desired value
|
||||
rank += 9 - abs(fe->Weight() / 100 - style->ComputeWeight());
|
||||
} else {
|
||||
// if no font to match, prefer non-bold, non-italic fonts
|
||||
if (!fe->IsItalic()) {
|
||||
rank += 3;
|
||||
}
|
||||
if (!fe->IsBold()) {
|
||||
rank += 2;
|
||||
}
|
||||
aMatchData->mCmapsTested++;
|
||||
if (rank == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// omitting from original windows code -- family name, lang group, pitch
|
||||
// not available in current FontEntry implementation
|
||||
rank += CalcStyleMatch(fe, aMatchData->mStyle);
|
||||
|
||||
// xxx - add whether AAT font with morphing info for specific lang groups
|
||||
|
||||
|
||||
if (rank > aMatchData->mMatchRank
|
||||
|| (rank == aMatchData->mMatchRank &&
|
||||
Compare(fe->Name(), aMatchData->mBestMatch->Name()) > 0))
|
||||
Compare(fe->Name(), aMatchData->mBestMatch->Name()) > 0))
|
||||
{
|
||||
aMatchData->mBestMatch = fe;
|
||||
aMatchData->mMatchRank = rank;
|
||||
@ -776,6 +779,26 @@ gfxFontFamily::FindFontForChar(FontSearch *aMatchData)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gfxFontFamily::SearchAllFontsForChar(GlobalFontMatch *aMatchData)
|
||||
{
|
||||
PRUint32 i, numFonts = mAvailableFonts.Length();
|
||||
for (i = 0; i < numFonts; i++) {
|
||||
gfxFontEntry *fe = mAvailableFonts[i];
|
||||
if (fe && fe->TestCharacterMap(aMatchData->mCh)) {
|
||||
PRInt32 rank = RANK_MATCHED_CMAP;
|
||||
rank += CalcStyleMatch(fe, aMatchData->mStyle);
|
||||
if (rank > aMatchData->mMatchRank
|
||||
|| (rank == aMatchData->mMatchRank &&
|
||||
Compare(fe->Name(), aMatchData->mBestMatch->Name()) > 0))
|
||||
{
|
||||
aMatchData->mBestMatch = fe;
|
||||
aMatchData->mMatchRank = rank;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// returns true if other names were found, false otherwise
|
||||
bool
|
||||
gfxFontFamily::ReadOtherFamilyNamesForFace(gfxPlatformFontList *aPlatformFontList,
|
||||
@ -3153,7 +3176,7 @@ gfxFontGroup::InitTextRun(gfxContext *aContext,
|
||||
nsCAutoString lang;
|
||||
mStyle.language->ToUTF8String(lang);
|
||||
PRUint32 runLen = runLimit - runStart;
|
||||
PR_LOG(log, PR_LOG_DEBUG,\
|
||||
PR_LOG(log, PR_LOG_WARNING,\
|
||||
("(%s) fontgroup: [%s] lang: %s script: %d len %d "
|
||||
"weight: %d width: %d style: %s "
|
||||
"TEXTRUN [%s] ENDTEXTRUN\n",
|
||||
@ -3359,11 +3382,12 @@ gfxFontGroup::FindFontForChar(PRUint32 aCh, PRUint32 aPrevCh,
|
||||
*aMatchType = gfxTextRange::kFontGroup;
|
||||
return font.forget();
|
||||
}
|
||||
|
||||
// check other faces of the family
|
||||
gfxFontFamily *family = font->GetFontEntry()->Family();
|
||||
if (family && family->TestCharacterMap(aCh)) {
|
||||
FontSearch matchData(aCh, font);
|
||||
family->FindFontForChar(&matchData);
|
||||
GlobalFontMatch matchData(aCh, aRunScript, &mStyle);
|
||||
family->SearchAllFontsForChar(&matchData);
|
||||
gfxFontEntry *fe = matchData.mBestMatch;
|
||||
if (fe) {
|
||||
bool needsBold =
|
||||
@ -3395,6 +3419,11 @@ gfxFontGroup::FindFontForChar(PRUint32 aCh, PRUint32 aPrevCh,
|
||||
return selectedFont.forget();
|
||||
}
|
||||
|
||||
// never fall back for characters from unknown scripts
|
||||
if (aRunScript == HB_SCRIPT_UNKNOWN) {
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
// for known "space" characters, don't do a full system-fallback search;
|
||||
// we'll synthesize appropriate-width spaces instead of missing-glyph boxes
|
||||
if (GetGeneralCategory(aCh) ==
|
||||
@ -3407,7 +3436,7 @@ gfxFontGroup::FindFontForChar(PRUint32 aCh, PRUint32 aPrevCh,
|
||||
// -- otherwise look for other stuff
|
||||
if (!selectedFont) {
|
||||
*aMatchType = gfxTextRange::kSystemFallback;
|
||||
selectedFont = WhichSystemFontSupportsChar(aCh);
|
||||
selectedFont = WhichSystemFontSupportsChar(aCh, aRunScript);
|
||||
return selectedFont.forget();
|
||||
}
|
||||
|
||||
@ -3552,10 +3581,6 @@ gfxFontGroup::WhichPrefFontSupportsChar(PRUint32 aCh)
|
||||
{
|
||||
gfxFont *font;
|
||||
|
||||
// FindCharUnicodeRange only supports BMP character points and there are no non-BMP fonts in prefs
|
||||
if (aCh > 0xFFFF)
|
||||
return nsnull;
|
||||
|
||||
// get the pref font list if it hasn't been set up already
|
||||
PRUint32 unicodeRange = FindCharUnicodeRange(aCh);
|
||||
eFontPrefLang charLang = gfxPlatform::GetPlatform()->GetFontPrefLangFor(unicodeRange);
|
||||
@ -3627,12 +3652,14 @@ gfxFontGroup::WhichPrefFontSupportsChar(PRUint32 aCh)
|
||||
}
|
||||
|
||||
already_AddRefed<gfxFont>
|
||||
gfxFontGroup::WhichSystemFontSupportsChar(PRUint32 aCh)
|
||||
gfxFontGroup::WhichSystemFontSupportsChar(PRUint32 aCh, PRInt32 aRunScript)
|
||||
{
|
||||
gfxFontEntry *fe =
|
||||
gfxPlatformFontList::PlatformFontList()->FindFontForChar(aCh, GetFontAt(0));
|
||||
gfxPlatformFontList::PlatformFontList()->
|
||||
SystemFindFontForChar(aCh, aRunScript, &mStyle);
|
||||
if (fe) {
|
||||
nsRefPtr<gfxFont> font = fe->FindOrMakeFont(&mStyle, false); // ignore bolder considerations in system fallback case...
|
||||
// ignore bolder considerations in system fallback case...
|
||||
nsRefPtr<gfxFont> font = fe->FindOrMakeFont(&mStyle, false);
|
||||
return font.forget();
|
||||
}
|
||||
|
||||
|
@ -487,16 +487,24 @@ private:
|
||||
};
|
||||
|
||||
|
||||
// used when picking fallback font
|
||||
struct FontSearch {
|
||||
FontSearch(const PRUint32 aCharacter, gfxFont *aFont) :
|
||||
mCh(aCharacter), mFontToMatch(aFont), mMatchRank(0), mCount(0) {
|
||||
}
|
||||
const PRUint32 mCh;
|
||||
gfxFont* mFontToMatch;
|
||||
PRInt32 mMatchRank;
|
||||
nsRefPtr<gfxFontEntry> mBestMatch;
|
||||
PRUint32 mCount;
|
||||
// used when iterating over all fonts looking for a match for a given character
|
||||
struct GlobalFontMatch {
|
||||
GlobalFontMatch(const PRUint32 aCharacter,
|
||||
PRInt32 aRunScript,
|
||||
const gfxFontStyle *aStyle) :
|
||||
mCh(aCharacter), mRunScript(aRunScript), mStyle(aStyle),
|
||||
mMatchRank(0), mCount(0), mCmapsTested(0)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
const PRUint32 mCh; // codepoint to be matched
|
||||
PRInt32 mRunScript; // Unicode script for the codepoint
|
||||
const gfxFontStyle* mStyle; // style to match
|
||||
PRInt32 mMatchRank; // metric indicating closest match
|
||||
nsRefPtr<gfxFontEntry> mBestMatch; // current best match
|
||||
PRUint32 mCount; // number of fonts matched
|
||||
PRUint32 mCmapsTested; // number of cmaps tested
|
||||
};
|
||||
|
||||
class gfxFontFamily {
|
||||
@ -557,9 +565,12 @@ public:
|
||||
gfxFontEntry *FindFontForStyle(const gfxFontStyle& aFontStyle,
|
||||
bool& aNeedsSyntheticBold);
|
||||
|
||||
// iterates over faces looking for a match with a given characters
|
||||
// checks for a matching font within the family
|
||||
// used as part of the font fallback process
|
||||
void FindFontForChar(FontSearch *aMatchData);
|
||||
void FindFontForChar(GlobalFontMatch *aMatchData);
|
||||
|
||||
// checks all fonts for a matching font within the family
|
||||
void SearchAllFontsForChar(GlobalFontMatch *aMatchData);
|
||||
|
||||
// read in other family names, if any, and use functor to add each into cache
|
||||
virtual void ReadOtherFamilyNames(gfxPlatformFontList *aPlatformFontList);
|
||||
@ -582,7 +593,7 @@ public:
|
||||
gfxFontEntry* FindFont(const nsAString& aPostscriptName);
|
||||
|
||||
// read in cmaps for all the faces
|
||||
void ReadCMAP() {
|
||||
void ReadAllCMAPs() {
|
||||
PRUint32 i, numFonts = mAvailableFonts.Length();
|
||||
for (i = 0; i < numFonts; i++) {
|
||||
gfxFontEntry *fe = mAvailableFonts[i];
|
||||
@ -598,7 +609,7 @@ public:
|
||||
|
||||
bool TestCharacterMap(PRUint32 aCh) {
|
||||
if (!mCharacterMapInitialized) {
|
||||
ReadCMAP();
|
||||
ReadAllCMAPs();
|
||||
}
|
||||
return mCharacterMap.test(aCh);
|
||||
}
|
||||
@ -2975,7 +2986,8 @@ public:
|
||||
// search through pref fonts for a character, return nsnull if no matching pref font
|
||||
virtual already_AddRefed<gfxFont> WhichPrefFontSupportsChar(PRUint32 aCh);
|
||||
|
||||
virtual already_AddRefed<gfxFont> WhichSystemFontSupportsChar(PRUint32 aCh);
|
||||
virtual already_AddRefed<gfxFont>
|
||||
WhichSystemFontSupportsChar(PRUint32 aCh, PRInt32 aRunScript);
|
||||
|
||||
template<typename T>
|
||||
void ComputeRanges(nsTArray<gfxTextRange>& mRanges,
|
||||
|
@ -37,6 +37,11 @@
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifdef MOZ_LOGGING
|
||||
#define FORCE_PR_LOG /* Allow logging in the release build */
|
||||
#endif
|
||||
#include "prlog.h"
|
||||
|
||||
#include "mozilla/Util.h"
|
||||
|
||||
#include "gfxFontUtils.h"
|
||||
@ -51,6 +56,7 @@
|
||||
#include "nsICharsetConverterManager.h"
|
||||
|
||||
#include "plbase64.h"
|
||||
#include "prlog.h"
|
||||
|
||||
#include "woff.h"
|
||||
|
||||
@ -58,6 +64,13 @@
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#endif
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
|
||||
#define LOG(log, args) PR_LOG(gfxPlatform::GetLog(log), \
|
||||
PR_LOG_DEBUG, args)
|
||||
|
||||
#endif // PR_LOGGING
|
||||
|
||||
#define NO_RANGE_FOUND 126 // bit 126 in the font unicode ranges is required to be 0
|
||||
|
||||
#define UNICODE_BMP_LIMIT 0x10000
|
||||
@ -269,6 +282,37 @@ typedef struct {
|
||||
|
||||
#pragma pack()
|
||||
|
||||
#if PR_LOGGING
|
||||
void
|
||||
gfxSparseBitSet::Dump(const char* aPrefix, eGfxLog aWhichLog) const
|
||||
{
|
||||
NS_ASSERTION(mBlocks.DebugGetHeader(), "mHdr is null, this is bad");
|
||||
PRUint32 b, numBlocks = mBlocks.Length();
|
||||
|
||||
for (b = 0; b < numBlocks; b++) {
|
||||
Block *block = mBlocks[b];
|
||||
if (!block) continue;
|
||||
char outStr[256];
|
||||
int index = 0;
|
||||
index += sprintf(&outStr[index], "%s u+%6.6x [", aPrefix, (b << BLOCK_INDEX_SHIFT));
|
||||
for (int i = 0; i < 32; i += 4) {
|
||||
for (int j = i; j < i + 4; j++) {
|
||||
PRUint8 bits = block->mBits[j];
|
||||
PRUint8 flip1 = ((bits & 0xaa) >> 1) | ((bits & 0x55) << 1);
|
||||
PRUint8 flip2 = ((flip1 & 0xcc) >> 2) | ((flip1 & 0x33) << 2);
|
||||
PRUint8 flipped = ((flip2 & 0xf0) >> 4) | ((flip2 & 0x0f) << 4);
|
||||
|
||||
index += sprintf(&outStr[index], "%2.2x", flipped);
|
||||
}
|
||||
if (i + 4 != 32) index += sprintf(&outStr[index], " ");
|
||||
}
|
||||
index += sprintf(&outStr[index], "]");
|
||||
LOG(aWhichLog, ("%s", outStr));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
nsresult
|
||||
gfxFontUtils::ReadCMAPTableFormat12(const PRUint8 *aBuf, PRUint32 aLength,
|
||||
gfxSparseBitSet& aCharacterMap)
|
||||
|
@ -41,6 +41,7 @@
|
||||
#define GFX_FONT_UTILS_H
|
||||
|
||||
#include "gfxTypes.h"
|
||||
#include "gfxPlatform.h"
|
||||
|
||||
#include "prtypes.h"
|
||||
#include "nsAlgorithm.h"
|
||||
@ -97,6 +98,11 @@ public:
|
||||
return ((block->mBits[(aIndex>>3) & (BLOCK_SIZE - 1)]) & (1 << (aIndex & 0x7))) != 0;
|
||||
}
|
||||
|
||||
#if PR_LOGGING
|
||||
// dump out contents of bitmap
|
||||
void Dump(const char* aPrefix, eGfxLog aWhichLog) const;
|
||||
#endif
|
||||
|
||||
bool TestRange(PRUint32 aStart, PRUint32 aEnd) {
|
||||
PRUint32 startBlock, endBlock, blockLen;
|
||||
|
||||
|
@ -83,6 +83,10 @@ using namespace mozilla;
|
||||
gfxPlatform::GetLog(eGfxLog_fontlist), \
|
||||
PR_LOG_DEBUG)
|
||||
|
||||
#define LOG_CMAPDATA_ENABLED() PR_LOG_TEST( \
|
||||
gfxPlatform::GetLog(eGfxLog_cmapdata), \
|
||||
PR_LOG_DEBUG)
|
||||
|
||||
#endif // PR_LOGGING
|
||||
|
||||
// font info loader constants
|
||||
@ -227,6 +231,12 @@ GDIFontEntry::ReadCMAP()
|
||||
#ifdef PR_LOGGING
|
||||
LOG_FONTLIST(("(fontlist-cmap) name: %s, size: %d\n",
|
||||
NS_ConvertUTF16toUTF8(mName).get(), mCharacterMap.GetSize()));
|
||||
if (LOG_CMAPDATA_ENABLED()) {
|
||||
char prefix[256];
|
||||
sprintf(prefix, "(cmapdata) name: %.220s",
|
||||
NS_ConvertUTF16toUTF8(mName).get());
|
||||
mCharacterMap.Dump(prefix, eGfxLog_cmapdata);
|
||||
}
|
||||
#endif
|
||||
return rv;
|
||||
}
|
||||
|
@ -166,6 +166,7 @@ private:
|
||||
friend class gfxPlatformMac;
|
||||
|
||||
gfxMacPlatformFontList();
|
||||
virtual ~gfxMacPlatformFontList();
|
||||
|
||||
// initialize font lists
|
||||
virtual nsresult InitFontList();
|
||||
@ -181,12 +182,23 @@ private:
|
||||
|
||||
static void ATSNotification(ATSFontNotificationInfoRef aInfo, void* aUserArg);
|
||||
|
||||
// search fonts system-wide for a given character, null otherwise
|
||||
virtual gfxFontEntry* GlobalFontFallback(const PRUint32 aCh,
|
||||
PRInt32 aRunScript,
|
||||
const gfxFontStyle* aMatchStyle,
|
||||
PRUint32& aCmapCount);
|
||||
|
||||
virtual bool UsesSystemFallback() { return true; }
|
||||
|
||||
// keep track of ATS generation to prevent unneeded updates when loading downloaded fonts
|
||||
PRUint32 mATSGeneration;
|
||||
|
||||
enum {
|
||||
kATSGenerationInitial = -1
|
||||
};
|
||||
|
||||
// default font for use with system-wide font fallback
|
||||
CTFontRef mDefaultFont;
|
||||
};
|
||||
|
||||
#endif /* gfxMacPlatformFontList_H_ */
|
||||
|
@ -58,6 +58,7 @@
|
||||
#include "nsDirectoryServiceUtils.h"
|
||||
#include "nsDirectoryServiceDefs.h"
|
||||
#include "nsISimpleEnumerator.h"
|
||||
#include "nsCharTraits.h"
|
||||
|
||||
#include "mozilla/Telemetry.h"
|
||||
|
||||
@ -136,6 +137,9 @@ static NSString* GetNSStringForString(const nsAString& aSrc)
|
||||
#define LOG_FONTLIST_ENABLED() PR_LOG_TEST( \
|
||||
gfxPlatform::GetLog(eGfxLog_fontlist), \
|
||||
PR_LOG_DEBUG)
|
||||
#define LOG_CMAPDATA_ENABLED() PR_LOG_TEST( \
|
||||
gfxPlatform::GetLog(eGfxLog_cmapdata), \
|
||||
PR_LOG_DEBUG)
|
||||
|
||||
#endif // PR_LOGGING
|
||||
|
||||
@ -267,6 +271,12 @@ MacOSFontEntry::ReadCMAP()
|
||||
LOG_FONTLIST(("(fontlist-cmap) name: %s, size: %d\n",
|
||||
NS_ConvertUTF16toUTF8(mName).get(),
|
||||
mCharacterMap.GetSize()));
|
||||
if (LOG_CMAPDATA_ENABLED()) {
|
||||
char prefix[256];
|
||||
sprintf(prefix, "(cmapdata) name: %.220s",
|
||||
NS_ConvertUTF16toUTF8(mName).get());
|
||||
mCharacterMap.Dump(prefix, eGfxLog_cmapdata);
|
||||
}
|
||||
#endif
|
||||
|
||||
return rv;
|
||||
@ -695,7 +705,8 @@ gfxSingleFaceMacFontFamily::ReadOtherFamilyNames(gfxPlatformFontList *aPlatformF
|
||||
#pragma mark-
|
||||
|
||||
gfxMacPlatformFontList::gfxMacPlatformFontList() :
|
||||
gfxPlatformFontList(false), mATSGeneration(PRUint32(kATSGenerationInitial))
|
||||
gfxPlatformFontList(false), mATSGeneration(PRUint32(kATSGenerationInitial)),
|
||||
mDefaultFont(nsnull)
|
||||
{
|
||||
::ATSFontNotificationSubscribe(ATSNotification,
|
||||
kATSFontNotifyOptionDefault,
|
||||
@ -710,6 +721,13 @@ gfxMacPlatformFontList::gfxMacPlatformFontList() :
|
||||
sFontManager = [NSFontManager sharedFontManager];
|
||||
}
|
||||
|
||||
gfxMacPlatformFontList::~gfxMacPlatformFontList()
|
||||
{
|
||||
if (mDefaultFont) {
|
||||
::CFRelease(mDefaultFont);
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
gfxMacPlatformFontList::InitFontList()
|
||||
{
|
||||
@ -866,6 +884,93 @@ gfxMacPlatformFontList::ATSNotification(ATSFontNotificationInfoRef aInfo,
|
||||
qfc->UpdateFontList();
|
||||
}
|
||||
|
||||
gfxFontEntry*
|
||||
gfxMacPlatformFontList::GlobalFontFallback(const PRUint32 aCh,
|
||||
PRInt32 aRunScript,
|
||||
const gfxFontStyle* aMatchStyle,
|
||||
PRUint32& aCmapCount)
|
||||
{
|
||||
bool useCmaps = gfxPlatform::GetPlatform()->UseCmapsDuringSystemFallback();
|
||||
|
||||
if (useCmaps) {
|
||||
return gfxPlatformFontList::GlobalFontFallback(aCh,
|
||||
aRunScript,
|
||||
aMatchStyle,
|
||||
aCmapCount);
|
||||
}
|
||||
|
||||
CFStringRef str;
|
||||
UniChar ch[2];
|
||||
CFIndex len = 1;
|
||||
|
||||
if (IS_IN_BMP(aCh)) {
|
||||
ch[0] = aCh;
|
||||
str = ::CFStringCreateWithCharactersNoCopy(kCFAllocatorDefault, ch, 1,
|
||||
kCFAllocatorNull);
|
||||
} else {
|
||||
ch[0] = H_SURROGATE(aCh);
|
||||
ch[1] = L_SURROGATE(aCh);
|
||||
str = ::CFStringCreateWithCharactersNoCopy(kCFAllocatorDefault, ch, 2,
|
||||
kCFAllocatorNull);
|
||||
if (!str) {
|
||||
return nsnull;
|
||||
}
|
||||
len = 2;
|
||||
}
|
||||
|
||||
// use CoreText to find the fallback family
|
||||
|
||||
gfxFontEntry *fontEntry = nsnull;
|
||||
CTFontRef fallback;
|
||||
bool cantUseFallbackFont = false;
|
||||
|
||||
if (!mDefaultFont) {
|
||||
mDefaultFont = ::CTFontCreateWithName(CFSTR("Lucida Grande"), 12.f,
|
||||
NULL);
|
||||
}
|
||||
|
||||
fallback = ::CTFontCreateForString(mDefaultFont, str,
|
||||
::CFRangeMake(0, len));
|
||||
|
||||
if (fallback) {
|
||||
CFStringRef familyName = ::CTFontCopyFamilyName(fallback);
|
||||
::CFRelease(fallback);
|
||||
|
||||
if (familyName &&
|
||||
::CFStringCompare(familyName, CFSTR("LastResort"),
|
||||
kCFCompareCaseInsensitive) != kCFCompareEqualTo)
|
||||
{
|
||||
nsAutoTArray<UniChar, 1024> buffer;
|
||||
CFIndex len = ::CFStringGetLength(familyName);
|
||||
buffer.SetLength(len+1);
|
||||
::CFStringGetCharacters(familyName, ::CFRangeMake(0, len),
|
||||
buffer.Elements());
|
||||
buffer[len] = 0;
|
||||
nsDependentString family(buffer.Elements(), len);
|
||||
|
||||
bool needsBold; // ignored in the system fallback case
|
||||
|
||||
fontEntry = FindFontForFamily(family, aMatchStyle, needsBold);
|
||||
if (fontEntry && !fontEntry->TestCharacterMap(aCh)) {
|
||||
fontEntry = nsnull;
|
||||
cantUseFallbackFont = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (familyName) {
|
||||
::CFRelease(familyName);
|
||||
}
|
||||
}
|
||||
|
||||
if (cantUseFallbackFont) {
|
||||
Telemetry::Accumulate(Telemetry::BAD_FALLBACK_FONT, cantUseFallbackFont);
|
||||
}
|
||||
|
||||
::CFRelease(str);
|
||||
|
||||
return fontEntry;
|
||||
}
|
||||
|
||||
gfxFontEntry*
|
||||
gfxMacPlatformFontList::GetDefaultFont(const gfxFontStyle* aStyle, bool& aNeedsBold)
|
||||
{
|
||||
|
@ -118,6 +118,7 @@ static PRLogModuleInfo *sFontlistLog = nsnull;
|
||||
static PRLogModuleInfo *sFontInitLog = nsnull;
|
||||
static PRLogModuleInfo *sTextrunLog = nsnull;
|
||||
static PRLogModuleInfo *sTextrunuiLog = nsnull;
|
||||
static PRLogModuleInfo *sCmapDataLog = nsnull;
|
||||
#endif
|
||||
|
||||
/* Class to listen for pref changes so that chrome code can dynamically
|
||||
@ -149,6 +150,7 @@ SRGBOverrideObserver::Observe(nsISupports *aSubject,
|
||||
|
||||
#define GFX_PREF_HARFBUZZ_SCRIPTS "gfx.font_rendering.harfbuzz.scripts"
|
||||
#define HARFBUZZ_SCRIPTS_DEFAULT mozilla::unicode::SHAPING_DEFAULT
|
||||
#define GFX_PREF_FALLBACK_USE_CMAPS "gfx.font_rendering.fallback.always_use_cmaps"
|
||||
|
||||
#ifdef MOZ_GRAPHITE
|
||||
#define GFX_PREF_GRAPHITE_SHAPING "gfx.font_rendering.graphite.enabled"
|
||||
@ -232,6 +234,8 @@ gfxPlatform::gfxPlatform()
|
||||
mUseHarfBuzzScripts = UNINITIALIZED_VALUE;
|
||||
mAllowDownloadableFonts = UNINITIALIZED_VALUE;
|
||||
mDownloadableFontsSanitize = UNINITIALIZED_VALUE;
|
||||
mFallbackUsesCmaps = UNINITIALIZED_VALUE;
|
||||
|
||||
#ifdef MOZ_GRAPHITE
|
||||
mGraphiteShapingEnabled = UNINITIALIZED_VALUE;
|
||||
#endif
|
||||
@ -268,6 +272,7 @@ gfxPlatform::Init()
|
||||
sFontInitLog = PR_NewLogModule("fontinit");;
|
||||
sTextrunLog = PR_NewLogModule("textrun");;
|
||||
sTextrunuiLog = PR_NewLogModule("textrunui");;
|
||||
sCmapDataLog = PR_NewLogModule("cmapdata");;
|
||||
#endif
|
||||
|
||||
|
||||
@ -680,6 +685,17 @@ gfxPlatform::SanitizeDownloadedFonts()
|
||||
return mDownloadableFontsSanitize;
|
||||
}
|
||||
|
||||
bool
|
||||
gfxPlatform::UseCmapsDuringSystemFallback()
|
||||
{
|
||||
if (mFallbackUsesCmaps == UNINITIALIZED_VALUE) {
|
||||
mFallbackUsesCmaps =
|
||||
Preferences::GetBool(GFX_PREF_FALLBACK_USE_CMAPS, false);
|
||||
}
|
||||
|
||||
return mFallbackUsesCmaps;
|
||||
}
|
||||
|
||||
#ifdef MOZ_GRAPHITE
|
||||
bool
|
||||
gfxPlatform::UseGraphiteShaping()
|
||||
@ -1358,6 +1374,8 @@ gfxPlatform::FontsPrefsChanged(const char *aPref)
|
||||
mAllowDownloadableFonts = UNINITIALIZED_VALUE;
|
||||
} else if (!strcmp(GFX_DOWNLOADABLE_FONTS_SANITIZE, aPref)) {
|
||||
mDownloadableFontsSanitize = UNINITIALIZED_VALUE;
|
||||
} else if (!strcmp(GFX_PREF_FALLBACK_USE_CMAPS, aPref)) {
|
||||
mFallbackUsesCmaps = UNINITIALIZED_VALUE;
|
||||
#ifdef MOZ_GRAPHITE
|
||||
} else if (!strcmp(GFX_PREF_GRAPHITE_SHAPING, aPref)) {
|
||||
mGraphiteShapingEnabled = UNINITIALIZED_VALUE;
|
||||
@ -1397,6 +1415,9 @@ gfxPlatform::GetLog(eGfxLog aWhichLog)
|
||||
case eGfxLog_textrunui:
|
||||
return sTextrunuiLog;
|
||||
break;
|
||||
case eGfxLog_cmapdata:
|
||||
return sCmapDataLog;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -136,7 +136,9 @@ enum eGfxLog {
|
||||
// dump text runs, font matching, system fallback for content
|
||||
eGfxLog_textrun = 2,
|
||||
// dump text runs, font matching, system fallback for chrome
|
||||
eGfxLog_textrunui = 3
|
||||
eGfxLog_textrunui = 3,
|
||||
// dump cmap coverage data as they are loaded
|
||||
eGfxLog_cmapdata = 4
|
||||
};
|
||||
|
||||
// when searching through pref langs, max number of pref langs
|
||||
@ -317,6 +319,11 @@ public:
|
||||
*/
|
||||
virtual bool FontHintingEnabled() { return true; }
|
||||
|
||||
/**
|
||||
* Whether to check all font cmaps during system font fallback
|
||||
*/
|
||||
bool UseCmapsDuringSystemFallback();
|
||||
|
||||
#ifdef MOZ_GRAPHITE
|
||||
/**
|
||||
* Whether to use the SIL Graphite rendering engine
|
||||
@ -369,6 +376,15 @@ public:
|
||||
// helper method to add a pref lang to an array, if not already in array
|
||||
static void AppendPrefLang(eFontPrefLang aPrefLangs[], PRUint32& aLen, eFontPrefLang aAddLang);
|
||||
|
||||
// returns a list of commonly used fonts for a given character
|
||||
// these are *possible* matches, no cmap-checking is done at this level
|
||||
virtual void GetCommonFallbackFonts(const PRUint32 /*aCh*/,
|
||||
PRInt32 /*aRunScript*/,
|
||||
nsTArray<const char*>& /*aFontList*/)
|
||||
{
|
||||
// platform-specific override, by default do nothing
|
||||
}
|
||||
|
||||
// helper method to indicate if we want to use Azure content drawing
|
||||
static bool UseAzureContentDrawing();
|
||||
|
||||
@ -454,6 +470,10 @@ protected:
|
||||
|
||||
PRInt8 mBidiNumeralOption;
|
||||
|
||||
// whether to always search font cmaps globally
|
||||
// when doing system font fallback
|
||||
PRInt8 mFallbackUsesCmaps;
|
||||
|
||||
// which scripts should be shaped with harfbuzz
|
||||
PRInt32 mUseHarfBuzzScripts;
|
||||
|
||||
|
@ -20,6 +20,7 @@
|
||||
*
|
||||
* Contributor(s):
|
||||
* Jonathan Kew <jfkthame@gmail.com>
|
||||
* John Daggett <jdaggett@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
@ -376,44 +377,45 @@ gfxPlatformFontList::GetFontFamilyList(nsTArray<nsRefPtr<gfxFontFamily> >& aFami
|
||||
mFontFamilies.Enumerate(FontFamilyListData::AppendFamily, &data);
|
||||
}
|
||||
|
||||
gfxFontEntry*
|
||||
gfxPlatformFontList::FindFontForChar(const PRUint32 aCh, gfxFont *aPrevFont)
|
||||
{
|
||||
gfxFontEntry*
|
||||
gfxPlatformFontList::SystemFindFontForChar(const PRUint32 aCh,
|
||||
PRInt32 aRunScript,
|
||||
const gfxFontStyle* aStyle)
|
||||
{
|
||||
gfxFontEntry* fontEntry = nsnull;
|
||||
|
||||
// is codepoint with no matching font? return null immediately
|
||||
if (mCodepointsWithNoFonts.test(aCh)) {
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
// TODO: optimize fallback e.g. by caching lists of fonts to try for a given
|
||||
// unicode range or script
|
||||
|
||||
// try to short-circuit font fallback for U+FFFD, used to represent encoding errors:
|
||||
// just use a platform-specific fallback system font that is guaranteed (or at least
|
||||
// highly likely) to be around, or a cached family from last time U+FFFD was seen.
|
||||
// this helps speed up pages with lots of encoding errors, binary-as-text, etc.
|
||||
// try to short-circuit font fallback for U+FFFD, used to represent
|
||||
// encoding errors: just use a platform-specific fallback system
|
||||
// font that is guaranteed (or at least highly likely) to be around,
|
||||
// or a cached family from last time U+FFFD was seen. this helps
|
||||
// speed up pages with lots of encoding errors, binary-as-text, etc.
|
||||
if (aCh == 0xFFFD && mReplacementCharFallbackFamily.Length() > 0) {
|
||||
gfxFontEntry* fontEntry = nsnull;
|
||||
bool needsBold; // ignored in the system fallback case
|
||||
|
||||
if (aPrevFont) {
|
||||
fontEntry = FindFontForFamily(mReplacementCharFallbackFamily, aPrevFont->GetStyle(), needsBold);
|
||||
} else {
|
||||
gfxFontStyle normalStyle;
|
||||
fontEntry = FindFontForFamily(mReplacementCharFallbackFamily, &normalStyle, needsBold);
|
||||
}
|
||||
fontEntry = FindFontForFamily(mReplacementCharFallbackFamily,
|
||||
aStyle, needsBold);
|
||||
|
||||
if (fontEntry && fontEntry->TestCharacterMap(aCh))
|
||||
return fontEntry;
|
||||
}
|
||||
|
||||
static bool first = true;
|
||||
TimeStamp start = TimeStamp::Now();
|
||||
|
||||
FontSearch data(aCh, aPrevFont);
|
||||
|
||||
// iterate over all font families to find a font that support the character
|
||||
mFontFamilies.Enumerate(gfxPlatformFontList::FindFontForCharProc, &data);
|
||||
|
||||
// search commonly available fonts
|
||||
bool common = true;
|
||||
fontEntry = CommonFontFallback(aCh, aRunScript, aStyle);
|
||||
|
||||
// if didn't find a font, do system-wide fallback (except for specials)
|
||||
PRUint32 cmapCount = 0;
|
||||
if (!fontEntry) {
|
||||
common = false;
|
||||
fontEntry = GlobalFontFallback(aCh, aRunScript, aStyle, cmapCount);
|
||||
}
|
||||
TimeDuration elapsed = TimeStamp::Now() - start;
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
@ -423,27 +425,28 @@ gfxPlatformFontList::FindFontForChar(const PRUint32 aCh, gfxFont *aPrevFont)
|
||||
PRUint32 charRange = gfxFontUtils::CharRangeBit(aCh);
|
||||
PRUint32 unicodeRange = FindCharUnicodeRange(aCh);
|
||||
PRInt32 script = mozilla::unicode::GetScriptCode(aCh);
|
||||
PR_LOG(log, PR_LOG_DEBUG,\
|
||||
("(textrun-systemfallback) char: u+%6.6x "
|
||||
"char-range: %d unicode-range: %d script: %d match: [%s]"
|
||||
" count: %d time: %dus\n",
|
||||
aCh,
|
||||
charRange, unicodeRange, script,
|
||||
(data.mBestMatch ?
|
||||
NS_ConvertUTF16toUTF8(data.mBestMatch->Name()).get() :
|
||||
"<none>"),
|
||||
data.mCount,
|
||||
PRInt32(elapsed.ToMicroseconds())));
|
||||
PR_LOG(log, PR_LOG_WARNING,\
|
||||
("(textrun-systemfallback-%s) char: u+%6.6x "
|
||||
"char-range: %d unicode-range: %d script: %d match: [%s]"
|
||||
" time: %dus cmaps: %d\n",
|
||||
(common ? "common" : "global"), aCh,
|
||||
charRange, unicodeRange, script,
|
||||
(fontEntry ? NS_ConvertUTF16toUTF8(fontEntry->Name()).get() :
|
||||
"<none>"),
|
||||
PRInt32(elapsed.ToMicroseconds()),
|
||||
cmapCount));
|
||||
}
|
||||
#endif
|
||||
|
||||
// no match? add to set of non-matching codepoints
|
||||
if (!data.mBestMatch) {
|
||||
mCodepointsWithNoFonts.set(aCh);
|
||||
} else if (aCh == 0xFFFD) {
|
||||
mReplacementCharFallbackFamily = data.mBestMatch->FamilyName();
|
||||
}
|
||||
|
||||
if (!fontEntry) {
|
||||
mCodepointsWithNoFonts.set(aCh);
|
||||
} else if (aCh == 0xFFFD && fontEntry) {
|
||||
mReplacementCharFallbackFamily = fontEntry->FamilyName();
|
||||
}
|
||||
|
||||
// track system fallback time
|
||||
static bool first = true;
|
||||
PRInt32 intElapsed = PRInt32(first ? elapsed.ToMilliseconds() :
|
||||
elapsed.ToMicroseconds());
|
||||
Telemetry::Accumulate((first ? Telemetry::SYSTEM_FONT_FALLBACK_FIRST :
|
||||
@ -451,18 +454,76 @@ gfxPlatformFontList::FindFontForChar(const PRUint32 aCh, gfxFont *aPrevFont)
|
||||
intElapsed);
|
||||
first = false;
|
||||
|
||||
return data.mBestMatch;
|
||||
// track the script for which fallback occurred (incremented one make it
|
||||
// 1-based)
|
||||
Telemetry::Accumulate(Telemetry::SYSTEM_FONT_FALLBACK_SCRIPT, aRunScript + 1);
|
||||
|
||||
return fontEntry;
|
||||
}
|
||||
|
||||
PLDHashOperator PR_CALLBACK
|
||||
gfxPlatformFontList::FindFontForCharProc(nsStringHashKey::KeyType aKey, nsRefPtr<gfxFontFamily>& aFamilyEntry,
|
||||
void *userArg)
|
||||
{
|
||||
FontSearch *data = static_cast<FontSearch*>(userArg);
|
||||
GlobalFontMatch *data = static_cast<GlobalFontMatch*>(userArg);
|
||||
|
||||
// evaluate all fonts in this family for a match
|
||||
aFamilyEntry->FindFontForChar(data);
|
||||
|
||||
// evaluate all fonts in this family for a match
|
||||
aFamilyEntry->FindFontForChar(data);
|
||||
return PL_DHASH_NEXT;
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
#define NUM_FALLBACK_FONTS 8
|
||||
|
||||
gfxFontEntry*
|
||||
gfxPlatformFontList::CommonFontFallback(const PRUint32 aCh,
|
||||
PRInt32 aRunScript,
|
||||
const gfxFontStyle* aMatchStyle)
|
||||
{
|
||||
nsAutoTArray<const char*,NUM_FALLBACK_FONTS> defaultFallbacks;
|
||||
PRUint32 i, numFallbacks;
|
||||
|
||||
gfxPlatform::GetPlatform()->GetCommonFallbackFonts(aCh, aRunScript,
|
||||
defaultFallbacks);
|
||||
numFallbacks = defaultFallbacks.Length();
|
||||
for (i = 0; i < numFallbacks; i++) {
|
||||
nsAutoString familyName;
|
||||
const char *fallbackFamily = defaultFallbacks[i];
|
||||
|
||||
familyName.AppendASCII(fallbackFamily);
|
||||
gfxFontFamily *fallback =
|
||||
gfxPlatformFontList::PlatformFontList()->FindFamily(familyName);
|
||||
if (!fallback)
|
||||
continue;
|
||||
|
||||
gfxFontEntry *fontEntry;
|
||||
bool needsBold; // ignored in the system fallback case
|
||||
|
||||
// use first font in list that supports a given character
|
||||
fontEntry = fallback->FindFontForStyle(*aMatchStyle, needsBold);
|
||||
if (fontEntry && fontEntry->TestCharacterMap(aCh)) {
|
||||
return fontEntry;
|
||||
}
|
||||
}
|
||||
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
gfxFontEntry*
|
||||
gfxPlatformFontList::GlobalFontFallback(const PRUint32 aCh,
|
||||
PRInt32 aRunScript,
|
||||
const gfxFontStyle* aMatchStyle,
|
||||
PRUint32& aCmapCount)
|
||||
{
|
||||
// otherwise, try to find it among local fonts
|
||||
GlobalFontMatch data(aCh, aRunScript, aMatchStyle);
|
||||
|
||||
// iterate over all font families to find a font that support the character
|
||||
mFontFamilies.Enumerate(gfxPlatformFontList::FindFontForCharProc, &data);
|
||||
|
||||
aCmapCount = data.mCmapsTested;
|
||||
|
||||
return data.mBestMatch;
|
||||
}
|
||||
|
||||
#ifdef XP_WIN
|
||||
@ -609,10 +670,12 @@ gfxPlatformFontList::InitLoader()
|
||||
mNumFamilies = mFontFamiliesToLoad.Length();
|
||||
}
|
||||
|
||||
bool
|
||||
bool
|
||||
gfxPlatformFontList::RunLoader()
|
||||
{
|
||||
PRUint32 i, endIndex = (mStartIndex + mIncrement < mNumFamilies ? mStartIndex + mIncrement : mNumFamilies);
|
||||
bool loadCmaps = !UsesSystemFallback() ||
|
||||
gfxPlatform::GetPlatform()->UseCmapsDuringSystemFallback();
|
||||
|
||||
// for each font family, load in various font info
|
||||
for (i = mStartIndex; i < endIndex; i++) {
|
||||
@ -628,8 +691,10 @@ gfxPlatformFontList::RunLoader()
|
||||
continue;
|
||||
}
|
||||
|
||||
// load the cmaps
|
||||
familyEntry->ReadCMAP();
|
||||
// load the cmaps if needed
|
||||
if (loadCmaps) {
|
||||
familyEntry->ReadAllCMAPs();
|
||||
}
|
||||
|
||||
// read in face names
|
||||
familyEntry->ReadFaceNames(this, mNeedFullnamePostscriptNames);
|
||||
|
@ -20,6 +20,7 @@
|
||||
*
|
||||
* Contributor(s):
|
||||
* Jonathan Kew <jfkthame@gmail.com>
|
||||
* John Daggett <jdaggett@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
@ -97,7 +98,10 @@ public:
|
||||
|
||||
virtual void GetFontFamilyList(nsTArray<nsRefPtr<gfxFontFamily> >& aFamilyArray);
|
||||
|
||||
gfxFontEntry* FindFontForChar(const PRUint32 aCh, gfxFont *aPrevFont);
|
||||
virtual gfxFontEntry*
|
||||
SystemFindFontForChar(const PRUint32 aCh,
|
||||
PRInt32 aRunScript,
|
||||
const gfxFontStyle* aStyle);
|
||||
|
||||
// TODO: make this virtual, for lazily adding to the font list
|
||||
virtual gfxFontFamily* FindFamily(const nsAString& aFamily);
|
||||
@ -146,6 +150,21 @@ protected:
|
||||
nsRefPtr<gfxFontFamily>& aFamilyEntry,
|
||||
void* userArg);
|
||||
|
||||
// returns default font for a given character, null otherwise
|
||||
virtual gfxFontEntry* CommonFontFallback(const PRUint32 aCh,
|
||||
PRInt32 aRunScript,
|
||||
const gfxFontStyle* aMatchStyle);
|
||||
|
||||
// search fonts system-wide for a given character, null otherwise
|
||||
virtual gfxFontEntry* GlobalFontFallback(const PRUint32 aCh,
|
||||
PRInt32 aRunScript,
|
||||
const gfxFontStyle* aMatchStyle,
|
||||
PRUint32& aCmapCount);
|
||||
|
||||
// whether system-based font fallback is used or not
|
||||
// if system fallback is used, no need to load all cmaps
|
||||
virtual bool UsesSystemFallback() { return false; }
|
||||
|
||||
// separate initialization for reading in name tables, since this is expensive
|
||||
void InitOtherFamilyNames();
|
||||
|
||||
|
@ -45,6 +45,7 @@
|
||||
#include "gfxPlatformGtk.h"
|
||||
|
||||
#include "nsUnicharUtils.h"
|
||||
#include "nsUnicodeProperties.h"
|
||||
#include "gfxFontconfigUtils.h"
|
||||
#ifdef MOZ_PANGO
|
||||
#include "gfxPangoFonts.h"
|
||||
@ -82,6 +83,7 @@
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::gfx;
|
||||
using namespace mozilla::unicode;
|
||||
|
||||
gfxFontconfigUtils *gfxPlatformGtk::sFontconfigUtils = nsnull;
|
||||
|
||||
@ -668,7 +670,7 @@ FindFontForCharProc(nsStringHashKey::KeyType aKey,
|
||||
nsRefPtr<FontFamily>& aFontFamily,
|
||||
void* aUserArg)
|
||||
{
|
||||
FontSearch *data = (FontSearch*)aUserArg;
|
||||
GlobalFontMatch *data = (GlobalFontMatch*)aUserArg;
|
||||
aFontFamily->FindFontForChar(data);
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
@ -684,7 +686,8 @@ gfxPlatformGtk::FindFontForChar(PRUint32 aCh, gfxFont *aFont)
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
FontSearch data(aCh, aFont);
|
||||
GlobalFontMatch data(aCh, GetScriptCode(aCh),
|
||||
(aFont ? aFont->GetStyle() : nsnull));
|
||||
|
||||
// find fonts that support the character
|
||||
gPlatformFonts->Enumerate(FindFontForCharProc, &data);
|
||||
|
@ -263,6 +263,108 @@ gfxPlatformMac::UpdateFontList()
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static const char kFontArialUnicodeMS[] = "Arial Unicode MS";
|
||||
static const char kFontAppleBraille[] = "Apple Braille";
|
||||
static const char kFontAppleSymbols[] = "Apple Symbols";
|
||||
static const char kFontAppleMyungjo[] = "AppleMyungjo";
|
||||
static const char kFontGeneva[] = "Geneva";
|
||||
static const char kFontGeezaPro[] = "Geeza Pro";
|
||||
static const char kFontHiraginoKakuGothic[] = "Hiragino Kaku Gothic ProN";
|
||||
static const char kFontLucidaGrande[] = "Lucida Grande";
|
||||
static const char kFontMenlo[] = "Menlo";
|
||||
static const char kFontPlantagenetCherokee[] = "Plantagenet Cherokee";
|
||||
static const char kFontSTHeiti[] = "STHeiti";
|
||||
|
||||
void
|
||||
gfxPlatformMac::GetCommonFallbackFonts(const PRUint32 aCh,
|
||||
PRInt32 aRunScript,
|
||||
nsTArray<const char*>& aFontList)
|
||||
{
|
||||
aFontList.AppendElement(kFontLucidaGrande);
|
||||
|
||||
if (!IS_IN_BMP(aCh)) {
|
||||
PRUint32 p = aCh >> 16;
|
||||
if (p == 1) {
|
||||
aFontList.AppendElement(kFontAppleSymbols);
|
||||
aFontList.AppendElement(kFontGeneva);
|
||||
}
|
||||
} else {
|
||||
PRUint32 b = (aCh >> 8) & 0xff;
|
||||
|
||||
switch (b) {
|
||||
case 0x03:
|
||||
case 0x05:
|
||||
aFontList.AppendElement(kFontGeneva);
|
||||
break;
|
||||
case 0x07:
|
||||
aFontList.AppendElement(kFontGeezaPro);
|
||||
break;
|
||||
case 0x10:
|
||||
aFontList.AppendElement(kFontMenlo);
|
||||
break;
|
||||
case 0x13: // Cherokee
|
||||
aFontList.AppendElement(kFontPlantagenetCherokee);
|
||||
break;
|
||||
case 0x18: // Mongolian
|
||||
aFontList.AppendElement(kFontSTHeiti);
|
||||
break;
|
||||
case 0x1d:
|
||||
case 0x1e:
|
||||
aFontList.AppendElement(kFontGeneva);
|
||||
break;
|
||||
case 0x20: // Symbol ranges
|
||||
case 0x21:
|
||||
case 0x22:
|
||||
case 0x23:
|
||||
case 0x24:
|
||||
case 0x25:
|
||||
case 0x26:
|
||||
case 0x27:
|
||||
case 0x29:
|
||||
case 0x2a:
|
||||
case 0x2b:
|
||||
case 0x2e:
|
||||
aFontList.AppendElement(kFontAppleSymbols);
|
||||
aFontList.AppendElement(kFontMenlo);
|
||||
aFontList.AppendElement(kFontGeneva);
|
||||
aFontList.AppendElement(kFontHiraginoKakuGothic);
|
||||
break;
|
||||
case 0x2c:
|
||||
case 0x2d:
|
||||
aFontList.AppendElement(kFontGeneva);
|
||||
break;
|
||||
case 0x28: // Braille
|
||||
aFontList.AppendElement(kFontAppleBraille);
|
||||
break;
|
||||
case 0x4d:
|
||||
aFontList.AppendElement(kFontAppleSymbols);
|
||||
break;
|
||||
case 0xa0: // Yi
|
||||
case 0xa1:
|
||||
case 0xa2:
|
||||
case 0xa3:
|
||||
case 0xa4:
|
||||
aFontList.AppendElement(kFontSTHeiti);
|
||||
break;
|
||||
case 0xa6:
|
||||
case 0xa7:
|
||||
aFontList.AppendElement(kFontGeneva);
|
||||
aFontList.AppendElement(kFontAppleSymbols);
|
||||
break;
|
||||
case 0xfc:
|
||||
case 0xff:
|
||||
aFontList.AppendElement(kFontAppleSymbols);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Arial Unicode MS has lots of glyphs for obscure, use it as a last resort
|
||||
aFontList.AppendElement(kFontArialUnicodeMS);
|
||||
}
|
||||
|
||||
|
||||
PRInt32
|
||||
gfxPlatformMac::OSXVersion()
|
||||
{
|
||||
|
@ -50,6 +50,7 @@
|
||||
#define MAC_OS_X_MAJOR_VERSION_MASK 0xFFFFFFF0U
|
||||
|
||||
class gfxTextRun;
|
||||
class gfxFontFamily;
|
||||
class mozilla::gfx::DrawTarget;
|
||||
|
||||
class THEBES_API gfxPlatformMac : public gfxPlatform {
|
||||
@ -98,6 +99,10 @@ public:
|
||||
nsTArray<nsString>& aListOfFonts);
|
||||
nsresult UpdateFontList();
|
||||
|
||||
virtual void GetCommonFallbackFonts(const PRUint32 aCh,
|
||||
PRInt32 aRunScript,
|
||||
nsTArray<const char*>& aFontList);
|
||||
|
||||
// Returns the OS X version as returned from Gestalt(gestaltSystemVersion, ...)
|
||||
// Ex: Mac OS X 10.4.x ==> 0x104x
|
||||
PRInt32 OSXVersion();
|
||||
|
@ -50,6 +50,7 @@
|
||||
|
||||
#include "gfxImageSurface.h"
|
||||
#include "gfxQPainterSurface.h"
|
||||
#include "nsUnicodeProperties.h"
|
||||
|
||||
#ifdef MOZ_PANGO
|
||||
#include "gfxPangoFonts.h"
|
||||
@ -79,6 +80,7 @@
|
||||
#include "mozilla/Preferences.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::unicode;
|
||||
|
||||
#define DEFAULT_RENDER_MODE RENDER_DIRECT
|
||||
|
||||
@ -526,7 +528,7 @@ FindFontForCharProc(nsStringHashKey::KeyType aKey,
|
||||
nsRefPtr<FontFamily>& aFontFamily,
|
||||
void* aUserArg)
|
||||
{
|
||||
FontSearch *data = (FontSearch*)aUserArg;
|
||||
GlobalFontMatch *data = (GlobalFontMatch*)aUserArg;
|
||||
aFontFamily->FindFontForChar(data);
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
@ -542,7 +544,8 @@ gfxQtPlatform::FindFontForChar(PRUint32 aCh, gfxFont *aFont)
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
FontSearch data(aCh, aFont);
|
||||
GlobalFontMatch data(aCh, GetScriptCode(aCh),
|
||||
(aFont ? aFont->GetStyle() : nsnull));
|
||||
|
||||
// find fonts that support the character
|
||||
gPlatformFonts->Enumerate(FindFontForCharProc, &data);
|
||||
|
@ -402,6 +402,22 @@ StoreUserFontData(gfxFontEntry* aFontEntry, gfxProxyFontEntry* aProxy,
|
||||
}
|
||||
}
|
||||
|
||||
struct WOFFHeader {
|
||||
AutoSwap_PRUint32 signature;
|
||||
AutoSwap_PRUint32 flavor;
|
||||
AutoSwap_PRUint32 length;
|
||||
AutoSwap_PRUint16 numTables;
|
||||
AutoSwap_PRUint16 reserved;
|
||||
AutoSwap_PRUint32 totalSfntSize;
|
||||
AutoSwap_PRUint16 majorVersion;
|
||||
AutoSwap_PRUint16 minorVersion;
|
||||
AutoSwap_PRUint32 metaOffset;
|
||||
AutoSwap_PRUint32 metaCompLen;
|
||||
AutoSwap_PRUint32 metaOrigLen;
|
||||
AutoSwap_PRUint32 privOffset;
|
||||
AutoSwap_PRUint32 privLen;
|
||||
};
|
||||
|
||||
void
|
||||
gfxUserFontSet::CopyWOFFMetadata(const PRUint8* aFontData,
|
||||
PRUint32 aLength,
|
||||
@ -414,21 +430,6 @@ gfxUserFontSet::CopyWOFFMetadata(const PRUint8* aFontData,
|
||||
// This just saves a copy of the compressed data block; it does NOT check
|
||||
// that the block can be successfully decompressed, or that it contains
|
||||
// well-formed/valid XML metadata.
|
||||
struct WOFFHeader {
|
||||
AutoSwap_PRUint32 signature;
|
||||
AutoSwap_PRUint32 flavor;
|
||||
AutoSwap_PRUint32 length;
|
||||
AutoSwap_PRUint16 numTables;
|
||||
AutoSwap_PRUint16 reserved;
|
||||
AutoSwap_PRUint32 totalSfntSize;
|
||||
AutoSwap_PRUint16 majorVersion;
|
||||
AutoSwap_PRUint16 minorVersion;
|
||||
AutoSwap_PRUint32 metaOffset;
|
||||
AutoSwap_PRUint32 metaCompLen;
|
||||
AutoSwap_PRUint32 metaOrigLen;
|
||||
AutoSwap_PRUint32 privOffset;
|
||||
AutoSwap_PRUint32 privLen;
|
||||
};
|
||||
if (aLength < sizeof(WOFFHeader)) {
|
||||
return;
|
||||
}
|
||||
|
@ -828,6 +828,175 @@ gfxWindowsPlatform::UpdateFontList()
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static const char kFontArabicTypesetting[] = "Arabic Typesetting";
|
||||
static const char kFontArial[] = "Arial";
|
||||
static const char kFontArialUnicodeMS[] = "Arial Unicode MS";
|
||||
static const char kFontCambria[] = "Cambria";
|
||||
static const char kFontCambriaMath[] = "Cambria Math";
|
||||
static const char kFontEbrima[] = "Ebrima";
|
||||
static const char kFontEstrangeloEdessa[] = "Estrangelo Edessa";
|
||||
static const char kFontEuphemia[] = "Euphemia";
|
||||
static const char kFontGabriola[] = "Gabriola";
|
||||
static const char kFontKhmerUI[] = "Khmer UI";
|
||||
static const char kFontLaoUI[] = "Lao UI";
|
||||
static const char kFontMVBoli[] = "MV Boli";
|
||||
static const char kFontMalgunGothic[] = "Malgun Gothic";
|
||||
static const char kFontMicrosoftJhengHei[] = "Microsoft JhengHei";
|
||||
static const char kFontMicrosoftNewTaiLue[] = "Microsoft New Tai Lue";
|
||||
static const char kFontMicrosoftPhagsPa[] = "Microsoft PhagsPa";
|
||||
static const char kFontMicrosoftTaiLe[] = "Microsoft Tai Le";
|
||||
static const char kFontMicrosoftUighur[] = "Microsoft Uighur";
|
||||
static const char kFontMicrosoftYaHei[] = "Microsoft YaHei";
|
||||
static const char kFontMicrosoftYiBaiti[] = "Microsoft Yi Baiti";
|
||||
static const char kFontMeiryo[] = "Meiryo";
|
||||
static const char kFontMongolianBaiti[] = "Mongolian Baiti";
|
||||
static const char kFontNyala[] = "Nyala";
|
||||
static const char kFontPlantagenetCherokee[] = "Plantagenet Cherokee";
|
||||
static const char kFontSegoeUI[] = "Segoe UI";
|
||||
static const char kFontSegoeUISymbol[] = "Segoe UI Symbol";
|
||||
static const char kFontSylfaen[] = "Sylfaen";
|
||||
static const char kFontTraditionalArabic[] = "Traditional Arabic";
|
||||
|
||||
void
|
||||
gfxWindowsPlatform::GetCommonFallbackFonts(const PRUint32 aCh,
|
||||
PRInt32 aRunScript,
|
||||
nsTArray<const char*>& aFontList)
|
||||
{
|
||||
// Arial is used as the default fallback for system fallback
|
||||
aFontList.AppendElement(kFontArial);
|
||||
|
||||
if (!IS_IN_BMP(aCh)) {
|
||||
PRUint32 p = aCh >> 16;
|
||||
if (p == 1) { // SMP plane
|
||||
aFontList.AppendElement(kFontCambriaMath);
|
||||
aFontList.AppendElement(kFontSegoeUISymbol);
|
||||
aFontList.AppendElement(kFontEbrima);
|
||||
}
|
||||
} else {
|
||||
PRUint32 b = (aCh >> 8) & 0xff;
|
||||
|
||||
switch (b) {
|
||||
case 0x05:
|
||||
aFontList.AppendElement(kFontEstrangeloEdessa);
|
||||
aFontList.AppendElement(kFontCambria);
|
||||
break;
|
||||
case 0x06:
|
||||
aFontList.AppendElement(kFontMicrosoftUighur);
|
||||
break;
|
||||
case 0x07:
|
||||
aFontList.AppendElement(kFontEstrangeloEdessa);
|
||||
aFontList.AppendElement(kFontMVBoli);
|
||||
aFontList.AppendElement(kFontEbrima);
|
||||
break;
|
||||
case 0x0e:
|
||||
aFontList.AppendElement(kFontLaoUI);
|
||||
break;
|
||||
case 0x12:
|
||||
case 0x13:
|
||||
aFontList.AppendElement(kFontNyala);
|
||||
aFontList.AppendElement(kFontPlantagenetCherokee);
|
||||
break;
|
||||
case 0x14:
|
||||
case 0x15:
|
||||
case 0x16:
|
||||
aFontList.AppendElement(kFontEuphemia);
|
||||
aFontList.AppendElement(kFontSegoeUISymbol);
|
||||
break;
|
||||
case 0x17:
|
||||
aFontList.AppendElement(kFontKhmerUI);
|
||||
break;
|
||||
case 0x18: // Mongolian
|
||||
aFontList.AppendElement(kFontMongolianBaiti);
|
||||
break;
|
||||
case 0x19:
|
||||
aFontList.AppendElement(kFontMicrosoftTaiLe);
|
||||
aFontList.AppendElement(kFontMicrosoftNewTaiLue);
|
||||
aFontList.AppendElement(kFontKhmerUI);
|
||||
break;
|
||||
break;
|
||||
case 0x20: // Symbol ranges
|
||||
case 0x21:
|
||||
case 0x22:
|
||||
case 0x23:
|
||||
case 0x24:
|
||||
case 0x25:
|
||||
case 0x26:
|
||||
case 0x27:
|
||||
case 0x29:
|
||||
case 0x2a:
|
||||
case 0x2b:
|
||||
case 0x2c:
|
||||
aFontList.AppendElement(kFontSegoeUI);
|
||||
aFontList.AppendElement(kFontSegoeUISymbol);
|
||||
aFontList.AppendElement(kFontCambria);
|
||||
aFontList.AppendElement(kFontCambriaMath);
|
||||
aFontList.AppendElement(kFontMeiryo);
|
||||
aFontList.AppendElement(kFontArial);
|
||||
aFontList.AppendElement(kFontEbrima);
|
||||
break;
|
||||
case 0x2d:
|
||||
case 0x2e:
|
||||
case 0x2f:
|
||||
aFontList.AppendElement(kFontEbrima);
|
||||
aFontList.AppendElement(kFontNyala);
|
||||
aFontList.AppendElement(kFontMeiryo);
|
||||
break;
|
||||
case 0x28: // Braille
|
||||
aFontList.AppendElement(kFontSegoeUISymbol);
|
||||
break;
|
||||
case 0x30:
|
||||
case 0x31:
|
||||
aFontList.AppendElement(kFontMicrosoftYaHei);
|
||||
break;
|
||||
case 0x32:
|
||||
aFontList.AppendElement(kFontMalgunGothic);
|
||||
break;
|
||||
case 0x4d:
|
||||
aFontList.AppendElement(kFontSegoeUISymbol);
|
||||
break;
|
||||
case 0xa0: // Yi
|
||||
case 0xa1:
|
||||
case 0xa2:
|
||||
case 0xa3:
|
||||
case 0xa4:
|
||||
aFontList.AppendElement(kFontMicrosoftYiBaiti);
|
||||
break;
|
||||
case 0xa5:
|
||||
case 0xa6:
|
||||
case 0xa7:
|
||||
aFontList.AppendElement(kFontEbrima);
|
||||
aFontList.AppendElement(kFontCambriaMath);
|
||||
break;
|
||||
case 0xa8:
|
||||
aFontList.AppendElement(kFontMicrosoftPhagsPa);
|
||||
break;
|
||||
case 0xfb:
|
||||
aFontList.AppendElement(kFontMicrosoftUighur);
|
||||
aFontList.AppendElement(kFontGabriola);
|
||||
aFontList.AppendElement(kFontSylfaen);
|
||||
break;
|
||||
case 0xfc:
|
||||
case 0xfd:
|
||||
aFontList.AppendElement(kFontTraditionalArabic);
|
||||
aFontList.AppendElement(kFontArabicTypesetting);
|
||||
break;
|
||||
case 0xfe:
|
||||
aFontList.AppendElement(kFontTraditionalArabic);
|
||||
aFontList.AppendElement(kFontMicrosoftJhengHei);
|
||||
break;
|
||||
case 0xff:
|
||||
aFontList.AppendElement(kFontMicrosoftJhengHei);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Arial Unicode MS has lots of glyphs for obscure characters,
|
||||
// use it as a last resort
|
||||
aFontList.AppendElement(kFontArialUnicodeMS);
|
||||
}
|
||||
|
||||
struct ResolveData {
|
||||
ResolveData(gfxPlatform::FontResolverCallback aCallback,
|
||||
gfxWindowsPlatform *aCaller, const nsAString *aFontName,
|
||||
|
@ -179,6 +179,10 @@ public:
|
||||
|
||||
nsresult UpdateFontList();
|
||||
|
||||
virtual void GetCommonFallbackFonts(const PRUint32 aCh,
|
||||
PRInt32 aRunScript,
|
||||
nsTArray<const char*>& aFontList);
|
||||
|
||||
nsresult ResolveFontName(const nsAString& aFontName,
|
||||
FontResolverCallback aCallback,
|
||||
void *aClosure, bool& aAborted);
|
||||
|
@ -213,7 +213,7 @@ static nsIAtom **gUnicodeRangeToLangGroupAtomTable[] =
|
||||
|
||||
|
||||
|
||||
#define NUM_OF_SUBTABLES 9
|
||||
#define NUM_OF_SUBTABLES 10
|
||||
#define SUBTABLE_SIZE 16
|
||||
|
||||
static const PRUint8 gUnicodeSubrangeTable[NUM_OF_SUBTABLES][SUBTABLE_SIZE] =
|
||||
@ -252,7 +252,7 @@ static const PRUint8 gUnicodeSubrangeTable[NUM_OF_SUBTABLES][SUBTABLE_SIZE] =
|
||||
kRangeTertiaryTable, //u0cxx
|
||||
kRangeTertiaryTable, //u0dxx
|
||||
kRangeTertiaryTable, //u0exx
|
||||
kRangeTibetan, //u0fxx
|
||||
kRangeTibetan //u0fxx
|
||||
},
|
||||
{ //table for 1x--
|
||||
kRangeTertiaryTable, //u10xx
|
||||
@ -270,7 +270,7 @@ static const PRUint8 gUnicodeSubrangeTable[NUM_OF_SUBTABLES][SUBTABLE_SIZE] =
|
||||
kRangeUnassigned, //u1cxx
|
||||
kRangeUnassigned, //u1dxx
|
||||
kRangeSetLatin, //u1exx
|
||||
kRangeGreek, //u1fxx
|
||||
kRangeGreek //u1fxx
|
||||
},
|
||||
{ //table for 2x--
|
||||
kRangeSetLatin, //u20xx
|
||||
@ -288,7 +288,7 @@ static const PRUint8 gUnicodeSubrangeTable[NUM_OF_SUBTABLES][SUBTABLE_SIZE] =
|
||||
kRangeUnassigned, //u2cxx
|
||||
kRangeUnassigned, //u2dxx
|
||||
kRangeSetCJK, //u2exx
|
||||
kRangeSetCJK, //u2fxx
|
||||
kRangeSetCJK //u2fxx
|
||||
},
|
||||
{ //table for ax--
|
||||
kRangeYi, //ua0xx
|
||||
@ -306,7 +306,7 @@ static const PRUint8 gUnicodeSubrangeTable[NUM_OF_SUBTABLES][SUBTABLE_SIZE] =
|
||||
kRangeKorean, //uacxx
|
||||
kRangeKorean, //uadxx
|
||||
kRangeKorean, //uaexx
|
||||
kRangeKorean, //uafxx
|
||||
kRangeKorean //uafxx
|
||||
},
|
||||
{ //table for dx--
|
||||
kRangeKorean, //ud0xx
|
||||
@ -324,7 +324,7 @@ static const PRUint8 gUnicodeSubrangeTable[NUM_OF_SUBTABLES][SUBTABLE_SIZE] =
|
||||
kRangeSurrogate, //udcxx
|
||||
kRangeSurrogate, //uddxx
|
||||
kRangeSurrogate, //udexx
|
||||
kRangeSurrogate, //udfxx
|
||||
kRangeSurrogate //udfxx
|
||||
},
|
||||
{ // table for fx--
|
||||
kRangePrivate, //uf0xx
|
||||
@ -341,11 +341,8 @@ static const PRUint8 gUnicodeSubrangeTable[NUM_OF_SUBTABLES][SUBTABLE_SIZE] =
|
||||
kRangeArabic, //ufbxx, includes alphabic presentation form
|
||||
kRangeArabic, //ufcxx
|
||||
kRangeArabic, //ufdxx
|
||||
kRangeArabic, //ufexx, includes Combining half marks,
|
||||
// CJK compatibility forms,
|
||||
// CJK compatibility forms,
|
||||
// small form variants
|
||||
kRangeTableBase+8, //uffxx, halfwidth and fullwidth forms, includes Specials
|
||||
kRangeTableBase+8, //ufexx
|
||||
kRangeTableBase+9 //uffxx, halfwidth and fullwidth forms, includes Specials
|
||||
},
|
||||
{ //table for 0x0500 - 0x05ff
|
||||
kRangeCyrillic, //u050x
|
||||
@ -363,7 +360,25 @@ static const PRUint8 gUnicodeSubrangeTable[NUM_OF_SUBTABLES][SUBTABLE_SIZE] =
|
||||
kRangeHebrew, //u05cx
|
||||
kRangeHebrew, //u05dx
|
||||
kRangeHebrew, //u05ex
|
||||
kRangeHebrew, //u05fx
|
||||
kRangeHebrew //u05fx
|
||||
},
|
||||
{ //table for 0xfe00 - 0xfeff
|
||||
kRangeSetCJK, //ufe0x
|
||||
kRangeSetCJK, //ufe1x
|
||||
kRangeSetCJK, //ufe2x
|
||||
kRangeSetCJK, //ufe3x
|
||||
kRangeSetCJK, //ufe4x
|
||||
kRangeSetCJK, //ufe5x
|
||||
kRangeSetCJK, //ufe6x
|
||||
kRangeArabic, //ufe7x
|
||||
kRangeArabic, //ufe8x
|
||||
kRangeArabic, //ufe9x
|
||||
kRangeArabic, //ufeax
|
||||
kRangeArabic, //ufebx
|
||||
kRangeArabic, //ufecx
|
||||
kRangeArabic, //ufedx
|
||||
kRangeArabic, //ufeex
|
||||
kRangeArabic //ufefx
|
||||
},
|
||||
{ //table for 0xff00 - 0xffff
|
||||
kRangeSetCJK, //uff0x, fullwidth latin
|
||||
@ -425,7 +440,7 @@ static const PRUint8 gUnicodeTertiaryRangeTable[TERTIARY_TABLE_SIZE] =
|
||||
kRangeCanadian, //u150x place holder(resolved in the 2ndary tab.)
|
||||
kRangeCanadian, //u158x place holder(resolved in the 2ndary tab.)
|
||||
kRangeCanadian, //u160x
|
||||
kRangeOghamRunic, //u168x this contains two scripts, Ogham & Runic
|
||||
kRangeOghamRunic //u168x this contains two scripts, Ogham & Runic
|
||||
};
|
||||
|
||||
// A two level index is almost enough for locating a range, with the
|
||||
@ -436,18 +451,31 @@ static const PRUint8 gUnicodeTertiaryRangeTable[TERTIARY_TABLE_SIZE] =
|
||||
// there is such a need.
|
||||
// For Indic, Southeast Asian scripts and some other scripts between
|
||||
// U+0700 and U+16FF, it's extended to the third level.
|
||||
PRUint32 FindCharUnicodeRange(PRUnichar ch)
|
||||
PRUint32 FindCharUnicodeRange(PRUint32 ch)
|
||||
{
|
||||
PRUint32 range;
|
||||
|
||||
// aggregate ranges for non-BMP codepoints
|
||||
if (ch > 0xFFFF) {
|
||||
PRUint32 p = (ch >> 16);
|
||||
if (p == 1) {
|
||||
return kRangeSMP;
|
||||
} else if (p == 2) {
|
||||
return kRangeSetCJK;
|
||||
}
|
||||
return kRangeHigherPlanes;
|
||||
}
|
||||
|
||||
//search the first table
|
||||
// lookup explicit range for BMP codepoints
|
||||
// first general range
|
||||
range = gUnicodeSubrangeTable[0][ch >> 12];
|
||||
|
||||
// if general range is good enough, return that
|
||||
if (range < kRangeTableBase)
|
||||
// we try to get a specific range
|
||||
return range;
|
||||
|
||||
// otherwise, we have one more table to look at
|
||||
// otherwise, use subrange tables
|
||||
range = gUnicodeSubrangeTable[range - kRangeTableBase][(ch & 0x0f00) >> 8];
|
||||
if (range < kRangeTableBase)
|
||||
return range;
|
||||
|
@ -108,6 +108,10 @@ const PRUint8 kRangeYi = 50;
|
||||
const PRUint8 kRangeCombiningDiacriticalMarks = 51;
|
||||
const PRUint8 kRangeSpecials = 52;
|
||||
|
||||
// aggregate ranges for non-BMP codepoints (u+2xxxx are all CJK)
|
||||
const PRUint8 kRangeSMP = 53; // u+1xxxx
|
||||
const PRUint8 kRangeHigherPlanes = 54; // u+3xxxx and above
|
||||
|
||||
const PRUint8 kRangeTableBase = 128; //values over 127 are reserved for internal use only
|
||||
const PRUint8 kRangeTertiaryTable = 145; // leave room for 16 subtable
|
||||
// indices (kRangeTableBase + 1 ..
|
||||
@ -115,5 +119,5 @@ const PRUint8 kRangeTertiaryTable = 145; // leave room for 16 subtable
|
||||
|
||||
|
||||
|
||||
PRUint32 FindCharUnicodeRange(PRUnichar ch);
|
||||
PRUint32 FindCharUnicodeRange(PRUint32 ch);
|
||||
nsIAtom* LangGroupFromUnicodeRange(PRUint8 unicodeRange);
|
||||
|
@ -2581,6 +2581,16 @@ RasterImage::Draw(gfxContext *aContext,
|
||||
mFrameDecodeFlags = DECODE_FLAGS_DEFAULT;
|
||||
}
|
||||
|
||||
// If this image is a candidate for discarding, reset its position in the
|
||||
// discard tracker so we're less likely to discard it right away.
|
||||
//
|
||||
// (We don't normally draw unlocked images, so this conditition will usually
|
||||
// be false. But we will draw unlocked images if image locking is globally
|
||||
// disabled via the content.image.allow_locking pref.)
|
||||
if (DiscardingActive()) {
|
||||
DiscardTracker::Reset(&mDiscardTrackerNode);
|
||||
}
|
||||
|
||||
// We use !mDecoded && mHasSourceData to mean discarded.
|
||||
if (!mDecoded && mHasSourceData) {
|
||||
mDrawStartTime = TimeStamp::Now();
|
||||
|
@ -1,5 +1,5 @@
|
||||
# Check for 24-bit color mode (test for bug 414720)
|
||||
== colordepth.html about:blank
|
||||
skip-if(Android) == colordepth.html about:blank
|
||||
|
||||
# "PngSuite, the official set of PNG test images"
|
||||
# Images by Willem van Schaik
|
||||
|
1
js/src/aclocal.m4
vendored
@ -15,5 +15,6 @@ builtin(include, build/autoconf/lto.m4)dnl
|
||||
builtin(include, build/autoconf/gcc-pr49911.m4)dnl
|
||||
builtin(include, build/autoconf/frameptr.m4)dnl
|
||||
builtin(include, build/autoconf/compiler-opts.m4)dnl
|
||||
builtin(include, build/autoconf/expandlibs.m4)dnl
|
||||
|
||||
MOZ_PROG_CHECKMSYS()
|
||||
|
93
js/src/build/autoconf/check_debug_ranges.py
Normal file
@ -0,0 +1,93 @@
|
||||
# ***** BEGIN LICENSE BLOCK *****
|
||||
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public License Version
|
||||
# 1.1 (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
# http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS" basis,
|
||||
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
# for the specific language governing rights and limitations under the
|
||||
# License.
|
||||
#
|
||||
# The Original Code is mozilla.org
|
||||
#
|
||||
# The Initial Developer of the Original Code is
|
||||
# the Mozilla Foundation
|
||||
# Portions created by the Initial Developer are Copyright (C) 2011
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Mike Hommey <mh@glandium.org>
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the terms of
|
||||
# either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
# in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
# of those above. If you wish to allow use of your version of this file only
|
||||
# under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
# use your version of this file under the terms of the MPL, indicate your
|
||||
# decision by deleting the provisions above and replace them with the notice
|
||||
# and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
# the provisions above, a recipient may use your version of this file under
|
||||
# the terms of any one of the MPL, the GPL or the LGPL.
|
||||
#
|
||||
# ***** END LICENSE BLOCK *****
|
||||
|
||||
# This script returns the number of items for the DW_AT_ranges corresponding
|
||||
# to a given compilation unit. This is used as a helper to find a bug in some
|
||||
# versions of GNU ld.
|
||||
|
||||
import subprocess
|
||||
import sys
|
||||
import re
|
||||
|
||||
def get_range_for(compilation_unit, debug_info):
|
||||
'''Returns the range offset for a given compilation unit
|
||||
in a given debug_info.'''
|
||||
name = ranges = ''
|
||||
search_cu = False
|
||||
for nfo in debug_info.splitlines():
|
||||
if 'DW_TAG_compile_unit' in nfo:
|
||||
search_cu = True
|
||||
elif 'DW_TAG_' in nfo or not nfo.strip():
|
||||
if name == compilation_unit:
|
||||
return int(ranges, 16)
|
||||
name = ranges = ''
|
||||
search_cu = False
|
||||
if search_cu:
|
||||
if 'DW_AT_name' in nfo:
|
||||
name = nfo.rsplit(None, 1)[1]
|
||||
elif 'DW_AT_ranges' in nfo:
|
||||
ranges = nfo.rsplit(None, 1)[1]
|
||||
return None
|
||||
|
||||
def get_range_length(range, debug_ranges):
|
||||
'''Returns the number of items in the range starting at the
|
||||
given offset.'''
|
||||
length = 0
|
||||
for line in debug_ranges.splitlines():
|
||||
m = re.match('\s*([0-9a-fA-F]+)\s+([0-9a-fA-F]+)\s+([0-9a-fA-F]+)', line)
|
||||
if m and int(m.group(1), 16) == range:
|
||||
length += 1
|
||||
return length
|
||||
|
||||
def main(bin, compilation_unit):
|
||||
p = subprocess.Popen(['objdump', '-W', bin], stdout = subprocess.PIPE, stderr = subprocess.PIPE)
|
||||
(out, err) = p.communicate()
|
||||
sections = re.split('\n(Contents of the|The section) ', out)
|
||||
debug_info = [s for s in sections if s.startswith('.debug_info')]
|
||||
debug_ranges = [s for s in sections if s.startswith('.debug_ranges')]
|
||||
if not debug_ranges or not debug_info:
|
||||
return 0
|
||||
|
||||
range = get_range_for(compilation_unit, debug_info[0])
|
||||
if range is not None:
|
||||
return get_range_length(range, debug_ranges[0])
|
||||
|
||||
return -1
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
print main(*sys.argv[1:])
|
@ -9,5 +9,76 @@ if test "$CLANG_CXX"; then
|
||||
## from C.
|
||||
_WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wno-unknown-warning-option -Wno-return-type-c-linkage"
|
||||
fi
|
||||
])
|
||||
|
||||
if test "$GNU_CC"; then
|
||||
CFLAGS="$CFLAGS -ffunction-sections -fdata-sections"
|
||||
CXXFLAGS="$CXXFLAGS -ffunction-sections -fdata-sections"
|
||||
fi
|
||||
|
||||
dnl ========================================================
|
||||
dnl = Identical Code Folding
|
||||
dnl ========================================================
|
||||
|
||||
MOZ_ARG_DISABLE_BOOL(icf,
|
||||
[ --disable-icf Disable Identical Code Folding],
|
||||
MOZ_DISABLE_ICF=1,
|
||||
MOZ_DISABLE_ICF= )
|
||||
|
||||
if test "$GNU_CC" -a "$GCC_USE_GNU_LD" -a -z "$MOZ_DISABLE_ICF"; then
|
||||
AC_CACHE_CHECK([whether the linker supports Identical Code Folding],
|
||||
LD_SUPPORTS_ICF,
|
||||
[echo 'int foo() {return 42;}' \
|
||||
'int bar() {return 42;}' \
|
||||
'int main() {return foo() - bar();}' > conftest.${ac_ext}
|
||||
# If the linker supports ICF, foo and bar symbols will have
|
||||
# the same address
|
||||
if AC_TRY_COMMAND([${CC-cc} -o conftest${ac_exeext} $LDFLAGS -Wl,--icf=safe -ffunction-sections conftest.${ac_ext} $LIBS 1>&2]) &&
|
||||
test -s conftest${ac_exeext} &&
|
||||
objdump -t conftest${ac_exeext} | awk changequote(<<, >>)'{a[<<$>>6] = <<$>>1} END {if (a["foo"] && (a["foo"] != a["bar"])) { exit 1 }}'changequote([, ]); then
|
||||
LD_SUPPORTS_ICF=yes
|
||||
else
|
||||
LD_SUPPORTS_ICF=no
|
||||
fi
|
||||
rm -rf conftest*])
|
||||
if test "$LD_SUPPORTS_ICF" = yes; then
|
||||
_SAVE_LDFLAGS="$LDFLAGS -Wl,--icf=safe"
|
||||
LDFLAGS="$LDFLAGS -Wl,--icf=safe -Wl,--print-icf-sections"
|
||||
AC_TRY_LINK([], [],
|
||||
[LD_PRINT_ICF_SECTIONS=-Wl,--print-icf-sections],
|
||||
[LD_PRINT_ICF_SECTIONS=])
|
||||
AC_SUBST([LD_PRINT_ICF_SECTIONS])
|
||||
LDFLAGS="$_SAVE_LDFLAGS"
|
||||
fi
|
||||
fi
|
||||
|
||||
dnl ========================================================
|
||||
dnl = Automatically remove dead symbols
|
||||
dnl ========================================================
|
||||
|
||||
if test "$GNU_CC" -a "$GCC_USE_GNU_LD" -a -n "$MOZ_DEBUG_FLAGS"; then
|
||||
dnl See bug 670659
|
||||
AC_CACHE_CHECK([whether removing dead symbols breaks debugging],
|
||||
GC_SECTIONS_BREAKS_DEBUG_RANGES,
|
||||
[echo 'int foo() {return 42;}' \
|
||||
'int bar() {return 1;}' \
|
||||
'int main() {return foo();}' > conftest.${ac_ext}
|
||||
if AC_TRY_COMMAND([${CC-cc} -o conftest.${ac_objext} $CFLAGS $MOZ_DEBUG_FLAGS -c conftest.${ac_ext} 1>&2]) &&
|
||||
AC_TRY_COMMAND([${CC-cc} -o conftest${ac_exeext} $LDFLAGS $MOZ_DEBUG_FLAGS -Wl,--gc-sections conftest.${ac_objext} $LIBS 1>&2]) &&
|
||||
test -s conftest${ac_exeext} -a -s conftest.${ac_objext}; then
|
||||
if test "`$PYTHON "$_topsrcdir"/build/autoconf/check_debug_ranges.py conftest.${ac_objext} conftest.${ac_ext}`" = \
|
||||
"`$PYTHON "$_topsrcdir"/build/autoconf/check_debug_ranges.py conftest${ac_exeext} conftest.${ac_ext}`"; then
|
||||
GC_SECTIONS_BREAKS_DEBUG_RANGES=no
|
||||
else
|
||||
GC_SECTIONS_BREAKS_DEBUG_RANGES=yes
|
||||
fi
|
||||
else
|
||||
dnl We really don't expect to get here, but just in case
|
||||
GC_SECTIONS_BREAKS_DEBUG_RANGES="no, but it's broken in some other way"
|
||||
fi
|
||||
rm -rf conftest*])
|
||||
if test "$GC_SECTIONS_BREAKS_DEBUG_RANGES" = no; then
|
||||
DSO_LDOPTS="$DSO_LDOPTS -Wl,--gc-sections"
|
||||
fi
|
||||
fi
|
||||
|
||||
])
|
||||
|
56
js/src/build/autoconf/expandlibs.m4
Normal file
@ -0,0 +1,56 @@
|
||||
AC_DEFUN([MOZ_EXPAND_LIBS],
|
||||
[
|
||||
dnl ========================================================
|
||||
dnl =
|
||||
dnl = Check what kind of list files are supported by the
|
||||
dnl = linker
|
||||
dnl =
|
||||
dnl ========================================================
|
||||
|
||||
AC_CACHE_CHECK(what kind of list files are supported by the linker,
|
||||
EXPAND_LIBS_LIST_STYLE,
|
||||
[echo "int main() {return 0;}" > conftest.${ac_ext}
|
||||
if AC_TRY_COMMAND(${CC-cc} -o conftest.${OBJ_SUFFIX} -c $CFLAGS $CPPFLAGS conftest.${ac_ext} 1>&5) && test -s conftest.${OBJ_SUFFIX}; then
|
||||
echo "INPUT(conftest.${OBJ_SUFFIX})" > conftest.list
|
||||
if AC_TRY_COMMAND(${CC-cc} -o conftest${ac_exeext} $LDFLAGS conftest.list $LIBS 1>&5) && test -s conftest${ac_exeext}; then
|
||||
EXPAND_LIBS_LIST_STYLE=linkerscript
|
||||
else
|
||||
echo "conftest.${OBJ_SUFFIX}" > conftest.list
|
||||
if AC_TRY_COMMAND(${CC-cc} -o conftest${ac_exeext} $LDFLAGS @conftest.list $LIBS 1>&5) && test -s conftest${ac_exeext}; then
|
||||
EXPAND_LIBS_LIST_STYLE=list
|
||||
else
|
||||
EXPAND_LIBS_LIST_STYLE=none
|
||||
fi
|
||||
fi
|
||||
else
|
||||
dnl We really don't expect to get here, but just in case
|
||||
AC_ERROR([couldn't compile a simple C file])
|
||||
fi
|
||||
rm -rf conftest*])
|
||||
|
||||
LIBS_DESC_SUFFIX=desc
|
||||
AC_SUBST(LIBS_DESC_SUFFIX)
|
||||
AC_SUBST(EXPAND_LIBS_LIST_STYLE)
|
||||
|
||||
if test "$GCC_USE_GNU_LD"; then
|
||||
AC_CACHE_CHECK(what kind of ordering can be done with the linker,
|
||||
EXPAND_LIBS_ORDER_STYLE,
|
||||
[> conftest.order
|
||||
_SAVE_LDFLAGS="$LDFLAGS"
|
||||
LDFLAGS="${LDFLAGS} -Wl,--section-ordering-file,conftest.order"
|
||||
AC_TRY_LINK([], [],
|
||||
EXPAND_LIBS_ORDER_STYLE=section-ordering-file,
|
||||
EXPAND_LIBS_ORDER_STYLE=)
|
||||
LDFLAGS="$_SAVE_LDFLAGS"
|
||||
if test -z "$EXPAND_LIBS_ORDER_STYLE"; then
|
||||
if AC_TRY_COMMAND(${CC-cc} ${DSO_LDOPTS} ${LDFLAGS} -o ${DLL_PREFIX}conftest${DLL_SUFFIX} -Wl,--verbose 2> /dev/null | sed -n '/^===/,/^===/p' | grep '\.text'); then
|
||||
EXPAND_LIBS_ORDER_STYLE=linkerscript
|
||||
else
|
||||
EXPAND_LIBS_ORDER_STYLE=none
|
||||
fi
|
||||
rm -f ${DLL_PREFIX}conftest${DLL_SUFFIX}
|
||||
fi])
|
||||
fi
|
||||
AC_SUBST(EXPAND_LIBS_ORDER_STYLE)
|
||||
|
||||
])
|
@ -789,8 +789,12 @@ EXPAND_LIBS_GEN = $(PYTHON) $(topsrcdir)/config/pythonpath.py -I$(DEPTH)/config
|
||||
EXPAND_AR = $(EXPAND_LIBS_EXEC) --extract -- $(AR)
|
||||
EXPAND_CC = $(EXPAND_LIBS_EXEC) --uselist -- $(CC)
|
||||
EXPAND_CCC = $(EXPAND_LIBS_EXEC) --uselist -- $(CCC)
|
||||
EXPAND_LD = $(EXPAND_LIBS_EXEC) --uselist $(if $(REORDER),--reorder $(REORDER))-- $(LD)
|
||||
EXPAND_MKSHLIB = $(EXPAND_LIBS_EXEC) --uselist $(if $(REORDER),--reorder $(REORDER))-- $(MKSHLIB)
|
||||
EXPAND_LD = $(EXPAND_LIBS_EXEC) --uselist -- $(LD)
|
||||
EXPAND_MKSHLIB_ARGS = --uselist
|
||||
ifdef SYMBOL_ORDER
|
||||
EXPAND_MKSHLIB_ARGS += --symbol-order $(SYMBOL_ORDER)
|
||||
endif
|
||||
EXPAND_MKSHLIB = $(EXPAND_LIBS_EXEC) $(EXPAND_MKSHLIB_ARGS) -- $(MKSHLIB)
|
||||
|
||||
ifdef STDCXX_COMPAT
|
||||
ifneq ($(OS_ARCH),Darwin)
|
||||
|
@ -54,3 +54,5 @@ DLL_SUFFIX = normalize_suffix("@DLL_SUFFIX@")
|
||||
IMPORT_LIB_SUFFIX = normalize_suffix("@IMPORT_LIB_SUFFIX@")
|
||||
LIBS_DESC_SUFFIX = normalize_suffix("@LIBS_DESC_SUFFIX@")
|
||||
EXPAND_LIBS_LIST_STYLE = "@EXPAND_LIBS_LIST_STYLE@"
|
||||
EXPAND_LIBS_ORDER_STYLE = "@EXPAND_LIBS_ORDER_STYLE@"
|
||||
LD_PRINT_ICF_SECTIONS = "@LD_PRINT_ICF_SECTIONS@"
|
||||
|
@ -49,9 +49,9 @@ EXPAND_LIBS_LIST_STYLE variable: 'list' for MSVC style lists (@file.list)
|
||||
or 'linkerscript' for GNU ld linker scripts.
|
||||
See https://bugzilla.mozilla.org/show_bug.cgi?id=584474#c59 for more details.
|
||||
|
||||
With the --reorder argument, followed by a file name, it will reorder the
|
||||
object files from the command line according to the order given in the file.
|
||||
Implies --extract.
|
||||
With the --symbol-order argument, followed by a file name, it will add the
|
||||
relevant linker options to change the order in which the linker puts the
|
||||
symbols appear in the resulting binary. Only works for ELF targets.
|
||||
'''
|
||||
from __future__ import with_statement
|
||||
import sys
|
||||
@ -62,6 +62,18 @@ from optparse import OptionParser
|
||||
import subprocess
|
||||
import tempfile
|
||||
import shutil
|
||||
import subprocess
|
||||
import re
|
||||
|
||||
# The are the insert points for a GNU ld linker script, assuming a more
|
||||
# or less "standard" default linker script. This is not a dict because
|
||||
# order is important.
|
||||
SECTION_INSERT_BEFORE = [
|
||||
('.text', '.fini'),
|
||||
('.rodata', '.rodata1'),
|
||||
('.data.rel.ro', '.dynamic'),
|
||||
('.data', '.data1'),
|
||||
]
|
||||
|
||||
class ExpandArgsMore(ExpandArgs):
|
||||
''' Meant to be used as 'with ExpandArgsMore(args) as ...: '''
|
||||
@ -119,6 +131,7 @@ class ExpandArgsMore(ExpandArgs):
|
||||
content = ["%s\n" % obj for obj in objs]
|
||||
ref = "@" + tmp
|
||||
else:
|
||||
os.close(fd)
|
||||
os.remove(tmp)
|
||||
return
|
||||
self.tmp.append(tmp)
|
||||
@ -129,21 +142,163 @@ class ExpandArgsMore(ExpandArgs):
|
||||
newlist = self[0:idx] + [ref] + [item for item in self[idx:] if item not in objs]
|
||||
self[0:] = newlist
|
||||
|
||||
def reorder(self, order_list):
|
||||
'''Given a list of file names without OBJ_SUFFIX, rearrange self
|
||||
so that the object file names it contains are ordered according to
|
||||
that list.
|
||||
'''
|
||||
objs = [o for o in self if isObject(o)]
|
||||
if not objs: return
|
||||
idx = self.index(objs[0])
|
||||
# Keep everything before the first object, then the ordered objects,
|
||||
# then any other objects, then any non-objects after the first object
|
||||
objnames = dict([(os.path.splitext(os.path.basename(o))[0], o) for o in objs])
|
||||
self[0:] = self[0:idx] + [objnames[o] for o in order_list if o in objnames] + \
|
||||
[o for o in objs if os.path.splitext(os.path.basename(o))[0] not in order_list] + \
|
||||
[x for x in self[idx:] if not isObject(x)]
|
||||
def _getFoldedSections(self):
|
||||
'''Returns a dict about folded sections.
|
||||
When section A and B are folded into section C, the dict contains:
|
||||
{ 'A': 'C',
|
||||
'B': 'C',
|
||||
'C': ['A', 'B'] }'''
|
||||
if not conf.LD_PRINT_ICF_SECTIONS:
|
||||
return {}
|
||||
|
||||
proc = subprocess.Popen(self + [conf.LD_PRINT_ICF_SECTIONS], stdout = subprocess.PIPE, stderr = subprocess.PIPE)
|
||||
(stdout, stderr) = proc.communicate()
|
||||
result = {}
|
||||
# gold's --print-icf-sections output looks like the following:
|
||||
# ld: ICF folding section '.section' in file 'file.o'into '.section' in file 'file.o'
|
||||
# In terms of words, chances are this will change in the future,
|
||||
# especially considering "into" is misplaced. Splitting on quotes
|
||||
# seems safer.
|
||||
for l in stderr.split('\n'):
|
||||
quoted = l.split("'")
|
||||
if len(quoted) > 5 and quoted[1] != quoted[5]:
|
||||
result[quoted[1]] = quoted[5]
|
||||
if quoted[5] in result:
|
||||
result[quoted[5]].append(quoted[1])
|
||||
else:
|
||||
result[quoted[5]] = [quoted[1]]
|
||||
return result
|
||||
|
||||
def _getOrderedSections(self, ordered_symbols):
|
||||
'''Given an ordered list of symbols, returns the corresponding list
|
||||
of sections following the order.'''
|
||||
if not conf.EXPAND_LIBS_ORDER_STYLE in ['linkerscript', 'section-ordering-file']:
|
||||
raise Exception('EXPAND_LIBS_ORDER_STYLE "%s" is not supported' % conf.EXPAND_LIBS_ORDER_STYLE)
|
||||
finder = SectionFinder([arg for arg in self if isObject(arg) or os.path.splitext(arg)[1] == conf.LIB_SUFFIX])
|
||||
folded = self._getFoldedSections()
|
||||
sections = set()
|
||||
ordered_sections = []
|
||||
for symbol in ordered_symbols:
|
||||
symbol_sections = finder.getSections(symbol)
|
||||
all_symbol_sections = []
|
||||
for section in symbol_sections:
|
||||
if section in folded:
|
||||
if isinstance(folded[section], str):
|
||||
section = folded[section]
|
||||
all_symbol_sections.append(section)
|
||||
all_symbol_sections.extend(folded[section])
|
||||
else:
|
||||
all_symbol_sections.append(section)
|
||||
for section in all_symbol_sections:
|
||||
if not section in sections:
|
||||
ordered_sections.append(section)
|
||||
sections.add(section)
|
||||
return ordered_sections
|
||||
|
||||
def orderSymbols(self, order):
|
||||
'''Given a file containing a list of symbols, adds the appropriate
|
||||
argument to make the linker put the symbols in that order.'''
|
||||
with open(order) as file:
|
||||
sections = self._getOrderedSections([l.strip() for l in file.readlines() if l.strip()])
|
||||
split_sections = {}
|
||||
linked_sections = [s[0] for s in SECTION_INSERT_BEFORE]
|
||||
for s in sections:
|
||||
for linked_section in linked_sections:
|
||||
if s.startswith(linked_section):
|
||||
if linked_section in split_sections:
|
||||
split_sections[linked_section].append(s)
|
||||
else:
|
||||
split_sections[linked_section] = [s]
|
||||
break
|
||||
content = []
|
||||
# Order is important
|
||||
linked_sections = [s for s in linked_sections if s in split_sections]
|
||||
|
||||
if conf.EXPAND_LIBS_ORDER_STYLE == 'section-ordering-file':
|
||||
option = '-Wl,--section-ordering-file,%s'
|
||||
content = sections
|
||||
for linked_section in linked_sections:
|
||||
content.extend(split_sections[linked_section])
|
||||
content.append('%s.*' % linked_section)
|
||||
content.append(linked_section)
|
||||
|
||||
elif conf.EXPAND_LIBS_ORDER_STYLE == 'linkerscript':
|
||||
option = '-Wl,-T,%s'
|
||||
section_insert_before = dict(SECTION_INSERT_BEFORE)
|
||||
for linked_section in linked_sections:
|
||||
content.append('SECTIONS {')
|
||||
content.append(' %s : {' % linked_section)
|
||||
content.extend(' *(%s)' % s for s in split_sections[linked_section])
|
||||
content.append(' }')
|
||||
content.append('}')
|
||||
content.append('INSERT BEFORE %s' % section_insert_before[linked_section])
|
||||
else:
|
||||
raise Exception('EXPAND_LIBS_ORDER_STYLE "%s" is not supported' % conf.EXPAND_LIBS_ORDER_STYLE)
|
||||
|
||||
fd, tmp = tempfile.mkstemp(dir=os.curdir)
|
||||
f = os.fdopen(fd, "w")
|
||||
f.write('\n'.join(content)+'\n')
|
||||
f.close()
|
||||
self.tmp.append(tmp)
|
||||
self.append(option % tmp)
|
||||
|
||||
class SectionFinder(object):
|
||||
'''Instances of this class allow to map symbol names to sections in
|
||||
object files.'''
|
||||
|
||||
def __init__(self, objs):
|
||||
'''Creates an instance, given a list of object files.'''
|
||||
if not conf.EXPAND_LIBS_ORDER_STYLE in ['linkerscript', 'section-ordering-file']:
|
||||
raise Exception('EXPAND_LIBS_ORDER_STYLE "%s" is not supported' % conf.EXPAND_LIBS_ORDER_STYLE)
|
||||
self.mapping = {}
|
||||
for obj in objs:
|
||||
if not isObject(obj) and os.path.splitext(obj)[1] != conf.LIB_SUFFIX:
|
||||
raise Exception('%s is not an object nor a static library' % obj)
|
||||
for symbol, section in SectionFinder._getSymbols(obj):
|
||||
sym = SectionFinder._normalize(symbol)
|
||||
if sym in self.mapping:
|
||||
if not section in self.mapping[sym]:
|
||||
self.mapping[sym].append(section)
|
||||
else:
|
||||
self.mapping[sym] = [section]
|
||||
|
||||
def getSections(self, symbol):
|
||||
'''Given a symbol, returns a list of sections containing it or the
|
||||
corresponding thunks. When the given symbol is a thunk, returns the
|
||||
list of sections containing its corresponding normal symbol and the
|
||||
other thunks for that symbol.'''
|
||||
sym = SectionFinder._normalize(symbol)
|
||||
if sym in self.mapping:
|
||||
return self.mapping[sym]
|
||||
return []
|
||||
|
||||
@staticmethod
|
||||
def _normalize(symbol):
|
||||
'''For normal symbols, return the given symbol. For thunks, return
|
||||
the corresponding normal symbol.'''
|
||||
if re.match('^_ZThn[0-9]+_', symbol):
|
||||
return re.sub('^_ZThn[0-9]+_', '_Z', symbol)
|
||||
return symbol
|
||||
|
||||
@staticmethod
|
||||
def _getSymbols(obj):
|
||||
'''Returns a list of (symbol, section) contained in the given object
|
||||
file.'''
|
||||
proc = subprocess.Popen(['objdump', '-t', obj], stdout = subprocess.PIPE, stderr = subprocess.PIPE)
|
||||
(stdout, stderr) = proc.communicate()
|
||||
syms = []
|
||||
for line in stdout.splitlines():
|
||||
# Each line has the following format:
|
||||
# <addr> [lgu!][w ][C ][W ][Ii ][dD ][FfO ] <section>\t<length> <symbol>
|
||||
tmp = line.split(' ',1)
|
||||
# This gives us ["<addr>", "[lgu!][w ][C ][W ][Ii ][dD ][FfO ] <section>\t<length> <symbol>"]
|
||||
# We only need to consider cases where "<section>\t<length> <symbol>" is present,
|
||||
# and where the [FfO] flag is either F (function) or O (object).
|
||||
if len(tmp) > 1 and len(tmp[1]) > 6 and tmp[1][6] in ['O', 'F']:
|
||||
tmp = tmp[1][8:].split()
|
||||
# That gives us ["<section>","<length>", "<symbol>"]
|
||||
syms.append((tmp[-1], tmp[0]))
|
||||
return syms
|
||||
|
||||
def main():
|
||||
parser = OptionParser()
|
||||
@ -153,17 +308,16 @@ def main():
|
||||
help="use a list file for objects when executing a command")
|
||||
parser.add_option("--verbose", action="store_true", dest="verbose",
|
||||
help="display executed command and temporary files content")
|
||||
parser.add_option("--reorder", dest="reorder",
|
||||
help="reorder the objects according to the given list", metavar="FILE")
|
||||
parser.add_option("--symbol-order", dest="symbol_order", metavar="FILE",
|
||||
help="use the given list of symbols to order symbols in the resulting binary when using with a linker")
|
||||
|
||||
(options, args) = parser.parse_args()
|
||||
|
||||
with ExpandArgsMore(args) as args:
|
||||
if options.extract or options.reorder:
|
||||
if options.extract:
|
||||
args.extract()
|
||||
if options.reorder:
|
||||
with open(options.reorder) as file:
|
||||
args.reorder([l.strip() for l in file.readlines()])
|
||||
if options.symbol_order:
|
||||
args.orderSymbols(options.symbol_order)
|
||||
if options.uselist:
|
||||
args.makelist()
|
||||
|
||||
|
@ -4829,37 +4829,7 @@ AC_SUBST(_MOZ_RTTI_FLAGS_ON)
|
||||
AC_DEFINE(CPP_THROW_NEW, [throw()])
|
||||
AC_LANG_C
|
||||
|
||||
dnl ========================================================
|
||||
dnl =
|
||||
dnl = Check what kind of list files are supported by the
|
||||
dnl = linker
|
||||
dnl =
|
||||
dnl ========================================================
|
||||
|
||||
AC_CACHE_CHECK(what kind of list files are supported by the linker,
|
||||
EXPAND_LIBS_LIST_STYLE,
|
||||
[echo "int main() {return 0;}" > conftest.${ac_ext}
|
||||
if AC_TRY_COMMAND(${CC-cc} -o conftest.${OBJ_SUFFIX} -c $CFLAGS $CPPFLAGS conftest.${ac_ext} 1>&2) && test -s conftest.${OBJ_SUFFIX}; then
|
||||
echo "INPUT(conftest.${OBJ_SUFFIX})" > conftest.list
|
||||
if AC_TRY_COMMAND(${CC-cc} -o conftest${ac_exeext} $LDFLAGS conftest.list $LIBS 1>&2) && test -s conftest${ac_exeext}; then
|
||||
EXPAND_LIBS_LIST_STYLE=linkerscript
|
||||
else
|
||||
echo "conftest.${OBJ_SUFFIX}" > conftest.list
|
||||
if AC_TRY_COMMAND(${CC-cc} -o conftest${ac_exeext} $LDFLAGS @conftest.list $LIBS 1>&2) && test -s conftest${ac_exeext}; then
|
||||
EXPAND_LIBS_LIST_STYLE=list
|
||||
else
|
||||
EXPAND_LIBS_LIST_STYLE=none
|
||||
fi
|
||||
fi
|
||||
else
|
||||
dnl We really don't expect to get here, but just in case
|
||||
AC_ERROR([couldn't compile a simple C file])
|
||||
fi
|
||||
rm -rf conftest*])
|
||||
|
||||
LIBS_DESC_SUFFIX=desc
|
||||
AC_SUBST(LIBS_DESC_SUFFIX)
|
||||
AC_SUBST(EXPAND_LIBS_LIST_STYLE)
|
||||
MOZ_EXPAND_LIBS
|
||||
|
||||
dnl ========================================================
|
||||
dnl =
|
||||
|