Merge mozilla-central to tracemonkey.
Before Width: | Height: | Size: 7.7 KiB After Width: | Height: | Size: 7.7 KiB |
@ -105,20 +105,7 @@
|
||||
var s = new Sanitizer();
|
||||
s.ignoreTimespan = false;
|
||||
s.prefDomain = "privacy.cpd.";
|
||||
var sanitizePreferences = document.getElementById("sanitizePreferences");
|
||||
var preference, name;
|
||||
for (var i = 0; i < sanitizePreferences.childNodes.length; ++i) {
|
||||
preference = sanitizePreferences.childNodes[i];
|
||||
if (preference.value) {
|
||||
name = s.getNameFromPreference(preference.name);
|
||||
try {
|
||||
s.clearItem(name);
|
||||
} catch(er) {
|
||||
dump(er + " sanitizing " + name);
|
||||
// TODO: give user feedback about partially failed sanitization
|
||||
}
|
||||
}
|
||||
}
|
||||
s.sanitize();
|
||||
},
|
||||
|
||||
onReadGeneric: function ()
|
||||
|
@ -53,6 +53,22 @@
|
||||
<link rel="stylesheet" href="chrome://global/skin/netError.css" type="text/css" media="all"/>
|
||||
<link rel="stylesheet" href="chrome://browser/skin/aboutPrivateBrowsing.css" type="text/css" media="all"/>
|
||||
<link rel="icon" type="image/png" href="chrome://browser/skin/Privacy-16.png"/>
|
||||
<script type="application/x-javascript;version=1.7"><![CDATA[
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
|
||||
function openSanitizeDialog() {
|
||||
let mainWindow = window.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIWebNavigation)
|
||||
.QueryInterface(Ci.nsIDocShellTreeItem)
|
||||
.rootTreeItem
|
||||
.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDOMWindow);
|
||||
let browserGlue = Cc["@mozilla.org/browser/browserglue;1"].
|
||||
getService(Ci.nsIBrowserGlue);
|
||||
browserGlue.sanitize(mainWindow || null);
|
||||
}
|
||||
]]></script>
|
||||
</head>
|
||||
|
||||
<body dir="&locale.dir;">
|
||||
@ -78,17 +94,14 @@
|
||||
<p>&privatebrowsingpage.longDesc;</p>
|
||||
</div>
|
||||
|
||||
# XXX do not show the clear recent history section until bug 453440 is fixed
|
||||
#if 0
|
||||
<!-- Clear Recent History -->
|
||||
<div id="clearRecentHistoryDesc">
|
||||
<p>&privatebrowsingpage.clearRecentHistoryDesc;</p>
|
||||
<button xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
id="showClearRecentHistory" label="&privatebrowsingpage.recentHistory.label;"
|
||||
accesskey="&privatebrowsingpage.recentHistory.accesskey;"
|
||||
disabled="true"/>
|
||||
oncommand="openSanitizeDialog();"/>
|
||||
</div>
|
||||
#endif
|
||||
|
||||
<!-- Footer -->
|
||||
<div id="footerDesc">
|
||||
|
@ -44,8 +44,6 @@ function run_test() {
|
||||
getService(Ci.nsIObserverService);
|
||||
var pb = Cc["@mozilla.org/privatebrowsing;1"].
|
||||
getService(Ci.nsIPrivateBrowsingService);
|
||||
var appStartup = Cc["@mozilla.org/toolkit/app-startup;1"].
|
||||
getService(Ci.nsIAppStartup);
|
||||
var prefBranch = Cc["@mozilla.org/preferences-service;1"].
|
||||
getService(Ci.nsIPrefBranch);
|
||||
prefBranch.setBoolPref("browser.privatebrowsing.keep_current_session", true);
|
||||
@ -92,8 +90,8 @@ function run_test() {
|
||||
// enter the private browsing mode
|
||||
pb.privateBrowsingEnabled = true;
|
||||
|
||||
// exit and leave the test pending
|
||||
// Simulate an exit
|
||||
expectedQuitting = true;
|
||||
do_test_pending();
|
||||
appStartup.quit(Ci.nsIAppStartup.eForceQuit);
|
||||
os.notifyObservers(null, "quit-application-granted", null);
|
||||
}
|
||||
|
@ -344,6 +344,9 @@ SessionStoreService.prototype = {
|
||||
win.setTimeout(function() { _this.saveState(true); }, 0);
|
||||
else if (this._loadState == STATE_RUNNING)
|
||||
this.saveState(true);
|
||||
// Delete the private browsing backed up state, if any
|
||||
if ("_stateBackup" in this)
|
||||
delete this._stateBackup;
|
||||
break;
|
||||
case "nsPref:changed": // catch pref changes
|
||||
switch (aData) {
|
||||
@ -398,6 +401,8 @@ SessionStoreService.prototype = {
|
||||
|
||||
this._saveStateObject(oState);
|
||||
}
|
||||
// make sure to restore the non-private session upon resuming
|
||||
this._prefBranch.setBoolPref("sessionstore.resume_session_once", true);
|
||||
}
|
||||
else
|
||||
this._inPrivateBrowsing = false;
|
||||
@ -485,19 +490,16 @@ SessionStoreService.prototype = {
|
||||
this._restoreCount = this._initialState.windows ? this._initialState.windows.length : 0;
|
||||
this.restoreWindow(aWindow, this._initialState, this._isCmdLineEmpty(aWindow));
|
||||
delete this._initialState;
|
||||
|
||||
// mark ourselves as running
|
||||
this.saveState(true);
|
||||
}
|
||||
else {
|
||||
// Nothing to restore, notify observers things are complete.
|
||||
var observerService = Cc["@mozilla.org/observer-service;1"].
|
||||
getService(Ci.nsIObserverService);
|
||||
observerService.notifyObservers(null, NOTIFY_WINDOWS_RESTORED, "");
|
||||
|
||||
// the next delayed save request should execute immediately
|
||||
this._lastSaveTime -= this._interval;
|
||||
}
|
||||
|
||||
// mark ourselves as running
|
||||
this.saveState(true);
|
||||
}
|
||||
// this window was opened by _openWindowWithState
|
||||
else if (!this._isWindowLoaded(aWindow)) {
|
||||
|
@ -81,17 +81,26 @@ function test() {
|
||||
tab_A.linkedBrowser.addEventListener("load", function (aEvent) {
|
||||
this.removeEventListener("load", arguments.callee, true);
|
||||
|
||||
let prePBModeTimeStamp = getSessionstorejsModificationTime();
|
||||
// remove sessionstore.js to make sure it's created again when entering
|
||||
// the private browsing mode.
|
||||
let profilePath = Cc["@mozilla.org/file/directory_service;1"].
|
||||
getService(Ci.nsIProperties).
|
||||
get("ProfD", Ci.nsIFile);
|
||||
let sessionStoreJS = profilePath.clone();
|
||||
sessionStoreJS.append("sessionstore.js");
|
||||
ok(sessionStoreJS.exists(),
|
||||
"sessionstore.js should exist prior to entering the private browsing mode");
|
||||
sessionStoreJS.remove(false);
|
||||
|
||||
// enter private browsing mode
|
||||
pb.privateBrowsingEnabled = true;
|
||||
ok(pb.privateBrowsingEnabled, "private browsing enabled");
|
||||
|
||||
// sessionstore.js should be modified at this point
|
||||
/* XXX this strangely fails!
|
||||
TODO filed bug 462986
|
||||
isnot(prePBModeTimeStamp, getSessionstorejsModificationTime(),
|
||||
"sessionstore.js should be modified when entering the private browsing mode");
|
||||
*/
|
||||
// sessionstore.js should be re-created at this point
|
||||
sessionStoreJS = profilePath.clone();
|
||||
sessionStoreJS.append("sessionstore.js");
|
||||
ok(sessionStoreJS.exists(),
|
||||
"sessionstore.js should be re-created after entering the private browsing mode");
|
||||
|
||||
// record the time stamp of sessionstore.js in the private session
|
||||
let startPBModeTimeStamp = getSessionstorejsModificationTime();
|
||||
|
@ -1,6 +1,65 @@
|
||||
const Ci = Components.interfaces;
|
||||
const Cc = Components.classes;
|
||||
|
||||
// This listens for the next opened window and checks it is of the right url.
|
||||
// opencallback is called when the new window is fully loaded
|
||||
// closecallback is called when the window is closed
|
||||
function WindowOpenListener(url, opencallback, closecallback) {
|
||||
this.url = url;
|
||||
this.opencallback = opencallback;
|
||||
this.closecallback = closecallback;
|
||||
|
||||
var wm = Cc["@mozilla.org/appshell/window-mediator;1"].
|
||||
getService(Ci.nsIWindowMediator);
|
||||
wm.addListener(this);
|
||||
}
|
||||
|
||||
WindowOpenListener.prototype = {
|
||||
url: null,
|
||||
opencallback: null,
|
||||
closecallback: null,
|
||||
window: null,
|
||||
domwindow: null,
|
||||
|
||||
handleEvent: function(event) {
|
||||
is(this.domwindow.document.location.href, this.url, "Should have opened the correct window");
|
||||
|
||||
this.domwindow.removeEventListener("load", this, false);
|
||||
// Allow any other load handlers to execute
|
||||
var self = this;
|
||||
executeSoon(function() { self.opencallback(self.domwindow); } );
|
||||
},
|
||||
|
||||
onWindowTitleChange: function(window, title) {
|
||||
},
|
||||
|
||||
onOpenWindow: function(window) {
|
||||
if (this.window)
|
||||
return;
|
||||
|
||||
this.window = window;
|
||||
this.domwindow = window.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDOMWindowInternal);
|
||||
this.domwindow.addEventListener("load", this, false);
|
||||
},
|
||||
|
||||
onCloseWindow: function(window) {
|
||||
if (this.window != window)
|
||||
return;
|
||||
|
||||
var wm = Cc["@mozilla.org/appshell/window-mediator;1"].
|
||||
getService(Ci.nsIWindowMediator);
|
||||
wm.removeListener(this);
|
||||
this.opencallback = null;
|
||||
this.window = null;
|
||||
this.domwindow = null;
|
||||
|
||||
// Let the window close complete
|
||||
executeSoon(this.closecallback);
|
||||
this.closecallback = null;
|
||||
}
|
||||
};
|
||||
|
||||
function test() {
|
||||
ok(Application, "Check global access to Application");
|
||||
|
||||
@ -12,17 +71,16 @@ function test() {
|
||||
var wMediator = Cc["@mozilla.org/appshell/window-mediator;1"].getService(Ci.nsIWindowMediator);
|
||||
var console = wMediator.getMostRecentWindow("global:console");
|
||||
waitForExplicitFinish();
|
||||
if (!console) {
|
||||
Application.console.open();
|
||||
}
|
||||
setTimeout(checkConsole, 500);
|
||||
ok(!console, "Console should not already be open");
|
||||
|
||||
new WindowOpenListener("chrome://global/content/console.xul", consoleOpened, consoleClosed);
|
||||
Application.console.open();
|
||||
}
|
||||
|
||||
function checkConsole() {
|
||||
var wMediator = Cc["@mozilla.org/appshell/window-mediator;1"].getService(Ci.nsIWindowMediator);
|
||||
var console = wMediator.getMostRecentWindow("global:console");
|
||||
ok(console, "Check to see if the console window opened");
|
||||
if (console)
|
||||
console.close();
|
||||
function consoleOpened(win) {
|
||||
win.close();
|
||||
}
|
||||
|
||||
function consoleClosed() {
|
||||
finish();
|
||||
}
|
||||
|
@ -35,7 +35,9 @@ function test() {
|
||||
gPageA.events.removeListener("load", onPageAFirstLoad);
|
||||
|
||||
gPageB = activeWin.open(url("chrome://mochikit/content/browser/browser/fuel/test/ContentB.html"));
|
||||
gPageB.events.addListener("load", afterOpen);
|
||||
gPageB.events.addListener("load", function() {
|
||||
executeSoon(afterOpen);
|
||||
});
|
||||
gPageB.focus();
|
||||
|
||||
is(activeWin.tabs.length, 3, "Checking length of 'Browser.tabs' after opening a second additional tab");
|
||||
@ -64,10 +66,27 @@ function test() {
|
||||
// check event
|
||||
is(gTabMoveCount, 1, "Checking event handler for tab move");
|
||||
|
||||
// test loading new content into a tab
|
||||
// the event will be checked in onPageLoad
|
||||
gPageA.events.addListener("load", onPageASecondLoad);
|
||||
gPageA.load(gPageB.uri);
|
||||
let browser = gBrowser.getBrowserAtIndex(gPageB.index);
|
||||
browser.addProgressListener({
|
||||
onStateChange: function(webProgress, request, stateFlags, status) {
|
||||
const complete = Ci.nsIWebProgressListener.STATE_IS_WINDOW +
|
||||
Ci.nsIWebProgressListener.STATE_IS_NETWORK +
|
||||
Ci.nsIWebProgressListener.STATE_STOP;
|
||||
if ((stateFlags & complete) == complete) {
|
||||
browser.removeProgressListener(this);
|
||||
onPageBLoadComplete();
|
||||
}
|
||||
},
|
||||
|
||||
QueryInterface: function(iid) {
|
||||
if (iid.equals(Ci.nsISupportsWeakReference) ||
|
||||
iid.equals(Ci.nsIWebProgressListener) ||
|
||||
iid.equals(Ci.nsISupports))
|
||||
return this;
|
||||
|
||||
throw Components.results.NS_ERROR_NO_INTERFACE;
|
||||
}
|
||||
});
|
||||
|
||||
// test loading new content with a frame into a tab
|
||||
// the event will be checked in afterClose
|
||||
@ -75,33 +94,34 @@ function test() {
|
||||
gPageB.load(url("chrome://mochikit/content/browser/browser/fuel/test/ContentWithFrames.html"));
|
||||
}
|
||||
|
||||
function onPageBLoadWithFrames(event) {
|
||||
gPageLoadCount++;
|
||||
}
|
||||
|
||||
function onPageBLoadComplete() {
|
||||
gPageB.events.removeListener("load", onPageBLoadWithFrames);
|
||||
// check page load with frame event
|
||||
is(gPageLoadCount, 1, "Checking load count after loading new content with a frame");
|
||||
|
||||
// test loading new content into a tab
|
||||
// the event will be checked in onPageLoad
|
||||
gPageA.events.addListener("load", onPageASecondLoad);
|
||||
gPageA.load(url("chrome://mochikit/content/browser/browser/fuel/test/ContentB.html"));
|
||||
}
|
||||
|
||||
function onPageASecondLoad(event) {
|
||||
gPageA.events.removeListener("load", onPageASecondLoad);
|
||||
is(gPageA.uri.spec, "chrome://mochikit/content/browser/browser/fuel/test/ContentB.html", "Checking 'BrowserTab.uri' after loading new content");
|
||||
|
||||
// start testing closing tabs
|
||||
// the event will be checked in afterClose
|
||||
// use executeSoon so the onPageASecondLoad
|
||||
// has a chance to finish first
|
||||
executeSoon(function() {
|
||||
gPageA.close();
|
||||
gPageB.close();
|
||||
executeSoon(afterClose);
|
||||
});
|
||||
}
|
||||
|
||||
function onPageBLoadWithFrames(event) {
|
||||
gPageLoadCount++;
|
||||
}
|
||||
|
||||
function afterClose() {
|
||||
// check close event
|
||||
is(gTabCloseCount, 2, "Checking event handler for tab close");
|
||||
|
||||
// check page load with frame event
|
||||
is(gPageLoadCount, 1, "Checking 'BrowserTab.uri' after loading new content with a frame");
|
||||
gPageA.close();
|
||||
gPageB.close();
|
||||
|
||||
is(gTabCloseCount, 2, "Checking that tabs closed");
|
||||
is(activeWin.tabs.length, 1, "Checking length of 'Browser.tabs' after closing 2 tabs");
|
||||
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 773 B After Width: | Height: | Size: 840 B |
Before Width: | Height: | Size: 5.1 KiB After Width: | Height: | Size: 5.6 KiB |
Before Width: | Height: | Size: 8.2 KiB After Width: | Height: | Size: 8.5 KiB |
Before Width: | Height: | Size: 9.5 KiB After Width: | Height: | Size: 9.5 KiB |
Before Width: | Height: | Size: 8.7 KiB After Width: | Height: | Size: 8.7 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 9.8 KiB After Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 807 B After Width: | Height: | Size: 804 B |
Before Width: | Height: | Size: 356 B After Width: | Height: | Size: 395 B |
Before Width: | Height: | Size: 356 B After Width: | Height: | Size: 395 B |
Before Width: | Height: | Size: 379 B After Width: | Height: | Size: 413 B |
@ -64,7 +64,7 @@ nsXBLProtoImpl::InstallImplementation(nsXBLPrototypeBinding* aBinding, nsIConten
|
||||
nsIDocument* document = aBoundElement->GetOwnerDoc();
|
||||
if (!document) return NS_OK;
|
||||
|
||||
nsIScriptGlobalObject *global = document->GetScriptGlobalObject();
|
||||
nsIScriptGlobalObject *global = document->GetScopeObject();
|
||||
if (!global) return NS_OK;
|
||||
|
||||
nsCOMPtr<nsIScriptContext> context = global->GetContext();
|
||||
@ -122,9 +122,7 @@ nsXBLProtoImpl::InitTargetObjects(nsXBLPrototypeBinding* aBinding,
|
||||
nsIDocument *ownerDoc = aBoundElement->GetOwnerDoc();
|
||||
nsIScriptGlobalObject *sgo;
|
||||
|
||||
if (!ownerDoc || !(sgo = ownerDoc->GetScriptGlobalObject())) {
|
||||
NS_ERROR("Can't find global object for bound content!");
|
||||
|
||||
if (!ownerDoc || !(sgo = ownerDoc->GetScopeObject())) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
|
@ -132,9 +132,7 @@ nsXBLProtoImplMethod::InstallMember(nsIScriptContext* aContext,
|
||||
nsIDocument *ownerDoc = aBoundElement->GetOwnerDoc();
|
||||
nsIScriptGlobalObject *sgo;
|
||||
|
||||
if (!ownerDoc || !(sgo = ownerDoc->GetScriptGlobalObject())) {
|
||||
NS_ERROR("Can't find global object for bound content!");
|
||||
|
||||
if (!ownerDoc || !(sgo = ownerDoc->GetScopeObject())) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
|
@ -160,9 +160,7 @@ nsXBLProtoImplProperty::InstallMember(nsIScriptContext* aContext,
|
||||
nsIDocument *ownerDoc = aBoundElement->GetOwnerDoc();
|
||||
nsIScriptGlobalObject *sgo;
|
||||
|
||||
if (!ownerDoc || !(sgo = ownerDoc->GetScriptGlobalObject())) {
|
||||
NS_ERROR("Can't find global object for bound content!");
|
||||
|
||||
if (!ownerDoc || !(sgo = ownerDoc->GetScopeObject())) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
|
@ -302,11 +302,9 @@ nsXBLPrototypeHandler::ExecuteHandler(nsPIDOMEventTarget* aTarget,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
boundGlobal = boundDocument->GetScriptGlobalObject();
|
||||
boundGlobal = boundDocument->GetScopeObject();
|
||||
}
|
||||
|
||||
// If we still don't have a 'boundGlobal', we're doomed. bug 95465.
|
||||
NS_ASSERTION(boundGlobal, "failed to get the nsIScriptGlobalObject. bug 95465?");
|
||||
if (!boundGlobal)
|
||||
return NS_OK;
|
||||
|
||||
|
@ -82,7 +82,7 @@ nsMimeTypeArray::GetLength(PRUint32* aLength)
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_ASSERTION(mPluginMimeTypeCount <= mMimeTypeArray.Count(),
|
||||
NS_ASSERTION(mPluginMimeTypeCount <= (PRUint32)mMimeTypeArray.Count(),
|
||||
"The number of total mimetypes should be equal to or higher "
|
||||
"than the number of plugin mimetypes.");
|
||||
|
||||
@ -99,7 +99,7 @@ nsMimeTypeArray::GetItemAt(PRUint32 aIndex, nsresult *aResult)
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
NS_ASSERTION(mPluginMimeTypeCount <= mMimeTypeArray.Count(),
|
||||
NS_ASSERTION(mPluginMimeTypeCount <= (PRUint32)mMimeTypeArray.Count(),
|
||||
"The number of total mimetypes should be equal to or higher "
|
||||
"than the number of plugin mimetypes.");
|
||||
|
||||
@ -133,7 +133,7 @@ nsMimeTypeArray::GetNamedItem(const nsAString& aName, nsresult* aResult)
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
NS_ASSERTION(mPluginMimeTypeCount <= mMimeTypeArray.Count(),
|
||||
NS_ASSERTION(mPluginMimeTypeCount <= (PRUint32)mMimeTypeArray.Count(),
|
||||
"The number of total mimetypes should be equal to or higher "
|
||||
"than the number of plugin mimetypes.");
|
||||
|
||||
|
205
dom/src/json/test/unit/test_wrappers.js
Normal file
@ -0,0 +1,205 @@
|
||||
|
||||
// returns a list of [string, object] pairs to test encoding
|
||||
function getTestPairs() {
|
||||
var testPairs = [
|
||||
["{}", {}],
|
||||
["[]", []],
|
||||
['{"foo":"bar"}', {"foo":"bar"}],
|
||||
['{"null":null}', {"null":null}],
|
||||
['{"five":5}', {"five":5}],
|
||||
['{"five":5,"six":6}', {"five":5, "six":6}],
|
||||
['{"x":{"y":"z"}}', {"x":{"y":"z"}}],
|
||||
['{"w":{"x":{"y":"z"}}}', {"w":{"x":{"y":"z"}}}],
|
||||
['[1,2,3]', [1,2,3]],
|
||||
['{"w":{"x":{"y":[1,2,3]}}}', {"w":{"x":{"y":[1,2,3]}}}],
|
||||
['{"false":false}', {"false":false}],
|
||||
['{"true":true}', {"true":true}],
|
||||
['{"child has two members":{"this":"one","2":"and this one"}}',
|
||||
{"child has two members": {"this":"one", 2:"and this one"}}],
|
||||
['{"x":{"a":"b","c":{"y":"z"},"f":"g"}}',
|
||||
{"x":{"a":"b","c":{"y":"z"},"f":"g"}}],
|
||||
['{"x":[1,{"y":"z"},3]}', {"x":[1,{"y":"z"},3]}],
|
||||
['["hmm"]', [new String("hmm")]],
|
||||
['[true]', [new Boolean(true)]],
|
||||
['[42]', [new Number(42)]],
|
||||
['["1978-09-13T12:24:34.023Z"]', [new Date(Date.UTC(1978, 8, 13, 12, 24, 34, 23))]],
|
||||
['[1,null,3]',[1,,3]],
|
||||
['{"mm\\\"mm":"hmm"}',{"mm\"mm":"hmm"}],
|
||||
['{"mm\\\"mm\\\"mm":"hmm"}',{"mm\"mm\"mm":"hmm"}],
|
||||
['{"\\\"":"hmm"}',{'"':"hmm"}],
|
||||
['{"\\\\":"hmm"}',{'\\':"hmm"}],
|
||||
['{"mmm\\\\mmm":"hmm"}',{'mmm\\mmm':"hmm"}],
|
||||
['{"mmm\\\\mmm\\\\mmm":"hmm"}',{'mmm\\mmm\\mmm':"hmm"}],
|
||||
['{"mm\\u000bmm":"hmm"}',{"mm\u000bmm":"hmm"}],
|
||||
['{"mm\\u0000mm":"hmm"}',{"mm\u0000mm":"hmm"}]
|
||||
];
|
||||
|
||||
var x = {"free":"variable"}
|
||||
testPairs.push(['{"free":"variable"}', x]);
|
||||
testPairs.push(['{"y":{"free":"variable"}}', {"y":x}]);
|
||||
|
||||
// array prop
|
||||
var x = {
|
||||
a: [1,2,3]
|
||||
}
|
||||
testPairs.push(['{"a":[1,2,3]}', x])
|
||||
|
||||
var y = {
|
||||
foo: function(hmm) { return hmm; }
|
||||
}
|
||||
testPairs.push(['{"y":{}}',{"y":y}]);
|
||||
|
||||
// test toJSON
|
||||
var hmm = {
|
||||
toJSON: function() { return {"foo":"bar"}}
|
||||
}
|
||||
testPairs.push(['{"hmm":{"foo":"bar"}}', {"hmm":hmm}]);
|
||||
testPairs.push(['{"foo":"bar"}', hmm]); // on the root
|
||||
|
||||
// toJSON on prototype
|
||||
var Y = function() {
|
||||
this.d = "e";
|
||||
}
|
||||
Y.prototype = {
|
||||
not:"there?",
|
||||
toJSON: function() { return {"foo":"bar"}}
|
||||
};
|
||||
var y = new Y();
|
||||
testPairs.push(['{"foo":"bar"}', y.toJSON()]);
|
||||
testPairs.push(['{"foo":"bar"}', y]);
|
||||
|
||||
// return undefined from toJSON
|
||||
var hmm = {
|
||||
toJSON: function() { return; }
|
||||
}
|
||||
testPairs.push(['{}', {"hmm":hmm}]);
|
||||
|
||||
// array with named prop
|
||||
var x= new Array();
|
||||
x[0] = 1;
|
||||
x.foo = "bar";
|
||||
testPairs.push(['[1]', x]);
|
||||
|
||||
// prototype
|
||||
var X = function() { this.a = "b" }
|
||||
X.prototype = {c:"d"}
|
||||
var y = new X();
|
||||
testPairs.push(['{"a":"b","c":"d"}', y]);
|
||||
|
||||
// custom iterator: JS 1.7+
|
||||
var x = {
|
||||
"a": "foo",
|
||||
b: "not included",
|
||||
c: "bar",
|
||||
"4": "qux",
|
||||
__iterator__: function() { return (function() { yield "a"; yield "c"; yield 4; })() }
|
||||
}
|
||||
do_check_eq('{"a":"foo","c":"bar","4":"qux"}', JSON.stringify(x));
|
||||
|
||||
return testPairs;
|
||||
}
|
||||
|
||||
function testStringEncode() {
|
||||
var pairs = getTestPairs();
|
||||
for each(pair in pairs) {
|
||||
print(pair)
|
||||
var nativeResult = JSON.stringify(pair[1]);
|
||||
var crockfordResult = crockfordJSON.stringify(pair[1]);
|
||||
do_check_eq(pair[0], nativeResult);
|
||||
|
||||
// Don't follow json2.js handling of non-objects
|
||||
if (pair[1] && (typeof pair[1] == "object")) {
|
||||
do_check_eq(crockfordResult, nativeResult);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function decode_strings() {
|
||||
// empty object
|
||||
var x = JSON.parse("{}");
|
||||
do_check_eq(typeof x, "object");
|
||||
|
||||
// empty array
|
||||
x = JSON.parse("[]");
|
||||
do_check_eq(typeof x, "object");
|
||||
do_check_eq(x.length, 0);
|
||||
do_check_eq(x.constructor, Array);
|
||||
|
||||
// one element array
|
||||
x = JSON.parse("[[]]");
|
||||
do_check_eq(typeof x, "object");
|
||||
do_check_eq(x.length, 1);
|
||||
do_check_eq(x.constructor, Array);
|
||||
do_check_eq(x[0].constructor, Array);
|
||||
|
||||
// multiple arrays
|
||||
x = JSON.parse("[[],[],[]]");
|
||||
do_check_eq(typeof x, "object");
|
||||
do_check_eq(x.length, 3);
|
||||
do_check_eq(x.constructor, Array);
|
||||
do_check_eq(x[0].constructor, Array);
|
||||
do_check_eq(x[1].constructor, Array);
|
||||
do_check_eq(x[2].constructor, Array);
|
||||
|
||||
// array key/value
|
||||
x = JSON.parse('{"foo":[]}');
|
||||
do_check_eq(typeof x, "object");
|
||||
do_check_eq(typeof x.foo, "object");
|
||||
do_check_eq(x.foo.constructor, Array);
|
||||
x = JSON.parse('{"foo":[], "bar":[]}');
|
||||
do_check_eq(typeof x, "object");
|
||||
do_check_eq(typeof x.foo, "object");
|
||||
do_check_eq(x.foo.constructor, Array);
|
||||
do_check_eq(typeof x.bar, "object");
|
||||
do_check_eq(x.bar.constructor, Array);
|
||||
|
||||
// nesting
|
||||
x = JSON.parse('{"foo":[{}]}');
|
||||
do_check_eq(x.foo.constructor, Array);
|
||||
do_check_eq(x.foo.length, 1);
|
||||
do_check_eq(typeof x.foo[0], "object");
|
||||
x = JSON.parse('{"foo":[{"foo":[{"foo":{}}]}]}');
|
||||
do_check_eq(x.foo[0].foo[0].foo.constructor, Object);
|
||||
x = JSON.parse('{"foo":[{"foo":[{"foo":[]}]}]}');
|
||||
do_check_eq(x.foo[0].foo[0].foo.constructor, Array);
|
||||
|
||||
// strings
|
||||
x = JSON.parse('{"foo":"bar"}');
|
||||
do_check_eq(x.foo, "bar");
|
||||
x = JSON.parse('["foo", "bar", "baz"]');
|
||||
do_check_eq(x[0], "foo");
|
||||
do_check_eq(x[1], "bar");
|
||||
do_check_eq(x[2], "baz");
|
||||
|
||||
// numbers
|
||||
x = JSON.parse('{"foo":5.5, "bar":5}');
|
||||
do_check_eq(x.foo, 5.5);
|
||||
do_check_eq(x.bar, 5);
|
||||
|
||||
// keywords
|
||||
x = JSON.parse('{"foo": true, "bar":false, "baz":null}');
|
||||
do_check_eq(x.foo, true);
|
||||
do_check_eq(x.bar, false);
|
||||
do_check_eq(x.baz, null);
|
||||
|
||||
// short escapes
|
||||
x = JSON.parse('{"foo": "\\"", "bar":"\\\\", "baz":"\\b","qux":"\\f", "quux":"\\n", "quuux":"\\r","quuuux":"\\t"}');
|
||||
do_check_eq(x.foo, '"');
|
||||
do_check_eq(x.bar, '\\');
|
||||
do_check_eq(x.baz, '\b');
|
||||
do_check_eq(x.qux, '\f');
|
||||
do_check_eq(x.quux, "\n");
|
||||
do_check_eq(x.quuux, "\r");
|
||||
do_check_eq(x.quuuux, "\t");
|
||||
|
||||
// unicode escape
|
||||
x = JSON.parse('{"foo":"hmm\\u006dmm"}');
|
||||
do_check_eq("hmm\u006dmm", x.foo);
|
||||
|
||||
x = JSON.parse('{"JSON Test Pattern pass3": {"The outermost value": "must be an object or array.","In this test": "It is an object." }}');
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
testStringEncode();
|
||||
decode_strings();
|
||||
}
|
@ -495,7 +495,7 @@ nsThebesImage::Draw(gfxContext* aContext,
|
||||
format = mFormat;
|
||||
subimage = subimage.Intersect(available) - gfxPoint(aPadding.left, aPadding.top);
|
||||
userSpaceToImageSpace.Multiply(
|
||||
gfxMatrix().Translate(gfxPoint(aPadding.left, aPadding.top)));
|
||||
gfxMatrix().Translate(-gfxPoint(aPadding.left, aPadding.top)));
|
||||
sourceRect = sourceRect - gfxPoint(aPadding.left, aPadding.top);
|
||||
imageRect = gfxRect(0, 0, mWidth, mHeight);
|
||||
} else {
|
||||
|
@ -43,7 +43,10 @@
|
||||
#include "gfxTypes.h"
|
||||
#include "gfxFont.h"
|
||||
|
||||
#include "nsAutoRef.h"
|
||||
|
||||
#include <pango/pango.h>
|
||||
#include <fontconfig/fontconfig.h>
|
||||
|
||||
// Control when we bypass Pango
|
||||
// Enable this to use FreeType to glyph-convert 8bit-only textruns, but use Pango
|
||||
@ -54,21 +57,7 @@
|
||||
// anything other than simple Latin work though!
|
||||
//#define ENABLE_FAST_PATH_ALWAYS
|
||||
|
||||
#include "nsDataHashtable.h"
|
||||
#include "nsClassHashtable.h"
|
||||
|
||||
class gfxPangoTextRun;
|
||||
|
||||
// stub class until fuller implementation is flushed out
|
||||
class gfxPangoFontEntry : public gfxFontEntry {
|
||||
public:
|
||||
gfxPangoFontEntry(const nsAString& aName)
|
||||
: gfxFontEntry(aName)
|
||||
{ }
|
||||
|
||||
~gfxPangoFontEntry() {}
|
||||
|
||||
};
|
||||
class gfxFcPangoFontSet;
|
||||
|
||||
class THEBES_API gfxPangoFontGroup : public gfxFontGroup {
|
||||
public:
|
||||
@ -89,9 +78,33 @@ public:
|
||||
|
||||
static void Shutdown();
|
||||
|
||||
// Interfaces used internally
|
||||
// (but public so that they can be accessed from non-member functions):
|
||||
|
||||
// The FontGroup holds the reference to the PangoFont (through the FontSet).
|
||||
PangoFont *GetBasePangoFont();
|
||||
|
||||
// A language guessed from the gfxFontStyle
|
||||
PangoLanguage *GetPangoLanguage() { return mPangoLanguage; }
|
||||
|
||||
// @param aLang [in] language to use for pref fonts and system default font
|
||||
// selection, or NULL for the language guessed from the gfxFontStyle.
|
||||
// The FontGroup holds a reference to this set.
|
||||
gfxFcPangoFontSet *GetFontSet(PangoLanguage *aLang = NULL);
|
||||
|
||||
protected:
|
||||
PangoFont *mBasePangoFont;
|
||||
gfxFloat mAdjustedSize;
|
||||
class FontSetByLangEntry {
|
||||
public:
|
||||
FontSetByLangEntry(PangoLanguage *aLang, gfxFcPangoFontSet *aFontSet);
|
||||
PangoLanguage *mLang;
|
||||
nsRefPtr<gfxFcPangoFontSet> mFontSet;
|
||||
};
|
||||
// There is only one of entry in this array unless characters from scripts
|
||||
// of other languages are measured.
|
||||
nsAutoTArray<FontSetByLangEntry,1> mFontSets;
|
||||
|
||||
gfxFloat mSizeAdjustFactor;
|
||||
PangoLanguage *mPangoLanguage;
|
||||
|
||||
// ****** Textrun glyph conversion helpers ******
|
||||
|
||||
@ -123,55 +136,24 @@ protected:
|
||||
const gchar *aUTF8, PRUint32 aUTF8Length);
|
||||
#endif
|
||||
|
||||
void GetFcFamilies(nsAString &aFcFamilies);
|
||||
PangoFont *GetBasePangoFont();
|
||||
void GetFcFamilies(nsStringArray *aFcFamilyList,
|
||||
const nsACString& aLangGroup);
|
||||
|
||||
// Check GetStyle()->sizeAdjust != 0.0 before calling this
|
||||
gfxFloat GetAdjustedSize()
|
||||
// @param aLang [in] language to use for pref fonts and system font
|
||||
// resolution, or NULL to guess a language from the gfxFontStyle.
|
||||
// @param aMatchPattern [out] if non-NULL, will return the pattern used.
|
||||
already_AddRefed<gfxFcPangoFontSet>
|
||||
MakeFontSet(PangoLanguage *aLang, gfxFloat aSizeAdjustFactor,
|
||||
nsAutoRef<FcPattern> *aMatchPattern = NULL);
|
||||
|
||||
gfxFcPangoFontSet *GetBaseFontSet();
|
||||
|
||||
gfxFloat GetSizeAdjustFactor()
|
||||
{
|
||||
if (!mBasePangoFont)
|
||||
GetBasePangoFont();
|
||||
return mAdjustedSize;
|
||||
if (mFontSets.Length() == 0)
|
||||
GetBaseFontSet();
|
||||
return mSizeAdjustFactor;
|
||||
}
|
||||
};
|
||||
|
||||
class gfxPangoFontWrapper {
|
||||
public:
|
||||
gfxPangoFontWrapper(PangoFont *aFont) {
|
||||
mFont = aFont;
|
||||
g_object_ref(mFont);
|
||||
}
|
||||
~gfxPangoFontWrapper() {
|
||||
if (mFont)
|
||||
g_object_unref(mFont);
|
||||
}
|
||||
PangoFont* Get() { return mFont; }
|
||||
private:
|
||||
PangoFont *mFont;
|
||||
};
|
||||
|
||||
class gfxPangoFontCache
|
||||
{
|
||||
public:
|
||||
gfxPangoFontCache();
|
||||
~gfxPangoFontCache();
|
||||
|
||||
static gfxPangoFontCache* GetPangoFontCache() {
|
||||
if (!sPangoFontCache)
|
||||
sPangoFontCache = new gfxPangoFontCache();
|
||||
return sPangoFontCache;
|
||||
}
|
||||
static void Shutdown() {
|
||||
if (sPangoFontCache)
|
||||
delete sPangoFontCache;
|
||||
sPangoFontCache = nsnull;
|
||||
}
|
||||
|
||||
void Put(const PangoFontDescription *aFontDesc, PangoFont *aPangoFont);
|
||||
PangoFont* Get(const PangoFontDescription *aFontDesc);
|
||||
private:
|
||||
static gfxPangoFontCache *sPangoFontCache;
|
||||
nsClassHashtable<nsUint32HashKey, gfxPangoFontWrapper> mPangoFonts;
|
||||
};
|
||||
|
||||
#endif /* GFX_PANGOFONTS_H */
|
||||
|
@ -40,6 +40,7 @@
|
||||
#define GFX_PLATFORM_GTK_H
|
||||
|
||||
#include "gfxPlatform.h"
|
||||
#include "nsAutoRef.h"
|
||||
|
||||
extern "C" {
|
||||
typedef struct _GdkDrawable GdkDrawable;
|
||||
@ -52,7 +53,12 @@ class FontEntry;
|
||||
typedef struct FT_LibraryRec_ *FT_Library;
|
||||
#endif
|
||||
|
||||
|
||||
template <class T>
|
||||
class gfxGObjectRefTraits : public nsPointerRefTraits<T> {
|
||||
public:
|
||||
static void Release(T *aPtr) { g_object_unref(aPtr); }
|
||||
static void AddRef(T *aPtr) { g_object_ref(aPtr); }
|
||||
};
|
||||
|
||||
class THEBES_API gfxPlatformGtk : public gfxPlatform {
|
||||
public:
|
||||
|
@ -77,6 +77,17 @@ gfxFontconfigUtils::GetThebesStyle(FcPattern *aPattern)
|
||||
return FONT_STYLE_NORMAL;
|
||||
}
|
||||
|
||||
/* static */ int
|
||||
gfxFontconfigUtils::GetFcSlant(const gfxFontStyle& aFontStyle)
|
||||
{
|
||||
if (aFontStyle.style == FONT_STYLE_ITALIC)
|
||||
return FC_SLANT_ITALIC;
|
||||
if (aFontStyle.style == FONT_STYLE_OBLIQUE)
|
||||
return FC_SLANT_OBLIQUE;
|
||||
|
||||
return FC_SLANT_ROMAN;
|
||||
}
|
||||
|
||||
// OS/2 weight classes were introduced in fontconfig-2.1.93 (2003).
|
||||
#ifndef FC_WEIGHT_THIN
|
||||
#define FC_WEIGHT_THIN 0 // 2.1.93
|
||||
@ -88,6 +99,10 @@ gfxFontconfigUtils::GetThebesStyle(FcPattern *aPattern)
|
||||
#ifndef FC_WEIGHT_BOOK
|
||||
#define FC_WEIGHT_BOOK 75
|
||||
#endif
|
||||
// extra black was introduced in fontconfig-2.4.91 (2007)
|
||||
#ifndef FC_WEIGHT_EXTRABLACK
|
||||
#define FC_WEIGHT_EXTRABLACK 215
|
||||
#endif
|
||||
|
||||
/* static */ PRUint16
|
||||
gfxFontconfigUtils::GetThebesWeight(FcPattern *aPattern)
|
||||
@ -116,14 +131,134 @@ gfxFontconfigUtils::GetThebesWeight(FcPattern *aPattern)
|
||||
if (weight <= FC_WEIGHT_BLACK)
|
||||
return 900;
|
||||
|
||||
// FC_WEIGHT_EXTRABLACK was introduced in fontconfig-2.4.91 (2007)
|
||||
// including FC_WEIGHT_EXTRABLACK
|
||||
return 901;
|
||||
}
|
||||
|
||||
/* static */ int
|
||||
gfxFontconfigUtils::FcWeightForBaseWeight(PRInt8 aBaseWeight)
|
||||
{
|
||||
switch (aBaseWeight) {
|
||||
case 2:
|
||||
return FC_WEIGHT_EXTRALIGHT;
|
||||
case 3:
|
||||
return FC_WEIGHT_LIGHT;
|
||||
case 4:
|
||||
return FC_WEIGHT_REGULAR;
|
||||
case 5:
|
||||
return FC_WEIGHT_MEDIUM;
|
||||
case 6:
|
||||
return FC_WEIGHT_DEMIBOLD;
|
||||
case 7:
|
||||
return FC_WEIGHT_BOLD;
|
||||
case 8:
|
||||
return FC_WEIGHT_EXTRABOLD;
|
||||
case 9:
|
||||
return FC_WEIGHT_BLACK;
|
||||
}
|
||||
|
||||
// extremes
|
||||
return aBaseWeight < 2 ? FC_WEIGHT_THIN : FC_WEIGHT_EXTRABLACK;
|
||||
}
|
||||
|
||||
// This makes a guess at an FC_WEIGHT corresponding to a base weight and
|
||||
// offset (without any knowledge of which weights are available).
|
||||
|
||||
/* static */ int
|
||||
GuessFcWeight(const gfxFontStyle& aFontStyle)
|
||||
{
|
||||
/*
|
||||
* weights come in two parts crammed into one
|
||||
* integer -- the "base" weight is weight / 100,
|
||||
* the rest of the value is the "offset" from that
|
||||
* weight -- the number of steps to move to adjust
|
||||
* the weight in the list of supported font weights,
|
||||
* this value can be negative or positive.
|
||||
*/
|
||||
PRInt8 weight;
|
||||
PRInt8 offset;
|
||||
aFontStyle.ComputeWeightAndOffset(&weight, &offset);
|
||||
|
||||
// ComputeWeightAndOffset trimmed the range of weights for us
|
||||
NS_ASSERTION(weight >= 0 && weight <= 10,
|
||||
"base weight out of range");
|
||||
|
||||
// Most font families do not support every weight. The tables here are
|
||||
// chosen such that a normal (4) base weight and an offset of +1 will
|
||||
// guess bold.
|
||||
|
||||
// Mapping from weight to a guess of the nearest available lighter weight
|
||||
static const int lighterGuess[11] =
|
||||
{ 0, 0, 1, 1, 2, 3, 4, 4, 6, 7, 8 };
|
||||
// Mapping from weight to a guess of the nearest available bolder weight
|
||||
static const int bolderGuess[11] =
|
||||
{ 2, 3, 4, 6, 7, 7, 8, 9, 10, 10, 10 };
|
||||
|
||||
while (offset < 0) {
|
||||
weight = lighterGuess[weight];
|
||||
offset++;
|
||||
}
|
||||
while (offset > 0) {
|
||||
weight = bolderGuess[weight];
|
||||
offset--;
|
||||
}
|
||||
|
||||
return gfxFontconfigUtils::FcWeightForBaseWeight(weight);
|
||||
}
|
||||
|
||||
static void
|
||||
AddString(FcPattern *aPattern, const char *object, const char *aString)
|
||||
{
|
||||
// Cast from signed chars used in nsString to unsigned in fontconfig
|
||||
const FcChar8 *fcString = gfxFontconfigUtils::ToFcChar8(aString);
|
||||
// and cast away the const for fontconfig, that will merely make a copy.
|
||||
FcPatternAddString(aPattern, object, const_cast<FcChar8*>(fcString));
|
||||
}
|
||||
|
||||
static void
|
||||
AddLangGroup(FcPattern *aPattern, const nsACString& aLangGroup)
|
||||
{
|
||||
// Translate from mozilla's internal mapping into fontconfig's
|
||||
nsCAutoString lang;
|
||||
gfxFontconfigUtils::GetSampleLangForGroup(aLangGroup, &lang);
|
||||
|
||||
if (!lang.IsEmpty()) {
|
||||
AddString(aPattern, FC_LANG, lang.get());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
nsReturnRef<FcPattern>
|
||||
gfxFontconfigUtils::NewPattern(const nsStringArray& aFamilies,
|
||||
const gfxFontStyle& aFontStyle,
|
||||
const char *aLang)
|
||||
{
|
||||
nsAutoRef<FcPattern> pattern(FcPatternCreate());
|
||||
if (!pattern)
|
||||
return nsReturnRef<FcPattern>();
|
||||
|
||||
FcPatternAddDouble(pattern, FC_PIXEL_SIZE, aFontStyle.size);
|
||||
FcPatternAddInteger(pattern, FC_SLANT, GetFcSlant(aFontStyle));
|
||||
FcPatternAddInteger(pattern, FC_WEIGHT, GuessFcWeight(aFontStyle));
|
||||
|
||||
if (aLang) {
|
||||
AddString(pattern, FC_LANG, aLang);
|
||||
}
|
||||
|
||||
for (PRInt32 i = 0; i < aFamilies.Count(); ++i) {
|
||||
NS_ConvertUTF16toUTF8 family(*aFamilies[i]);
|
||||
AddString(pattern, FC_FAMILY, family.get());
|
||||
}
|
||||
|
||||
return pattern.out();
|
||||
}
|
||||
|
||||
gfxFontconfigUtils::gfxFontconfigUtils()
|
||||
: mLastConfig(NULL)
|
||||
{
|
||||
mAliasTable.Init(50);
|
||||
mFontsByFamily.Init(50);
|
||||
mLangSupportTable.Init(20);
|
||||
UpdateFontListInternal();
|
||||
}
|
||||
|
||||
nsresult
|
||||
@ -133,22 +268,15 @@ gfxFontconfigUtils::GetFontList(const nsACString& aLangGroup,
|
||||
{
|
||||
aListOfFonts.Clear();
|
||||
|
||||
nsresult rv = UpdateFontListInternal();
|
||||
nsCStringArray fonts;
|
||||
nsresult rv = GetFontListInternal(fonts, aLangGroup);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
nsCStringArray tmpFonts;
|
||||
nsCStringArray *fonts = &mFonts;
|
||||
if (!aLangGroup.IsEmpty() || !aGenericFamily.IsEmpty()) {
|
||||
rv = GetFontListInternal(tmpFonts, &aLangGroup);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
fonts = &tmpFonts;
|
||||
for (PRInt32 i = 0; i < fonts.Count(); ++i) {
|
||||
aListOfFonts.AppendString(NS_ConvertUTF8toUTF16(*fonts.CStringAt(i)));
|
||||
}
|
||||
|
||||
for (PRInt32 i = 0; i < fonts->Count(); ++i)
|
||||
aListOfFonts.AppendString(NS_ConvertUTF8toUTF16(*fonts->CStringAt(i)));
|
||||
|
||||
aListOfFonts.Sort();
|
||||
|
||||
PRInt32 serif = 0, sansSerif = 0, monospace = 0;
|
||||
@ -254,7 +382,7 @@ gfxFontconfigUtils::GetSampleLangForGroup(const nsACString& aLangGroup,
|
||||
|
||||
const MozLangGroupData *langGroup = nsnull;
|
||||
|
||||
for (unsigned int i=0; i < NS_ARRAY_LENGTH(MozLangGroups); ++i) {
|
||||
for (unsigned int i = 0; i < NS_ARRAY_LENGTH(MozLangGroups); ++i) {
|
||||
if (aLangGroup.Equals(MozLangGroups[i].mozLangGroup,
|
||||
nsCaseInsensitiveCStringComparator())) {
|
||||
langGroup = &MozLangGroups[i];
|
||||
@ -309,25 +437,9 @@ gfxFontconfigUtils::GetSampleLangForGroup(const nsACString& aLangGroup,
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
AddLangGroup(FcPattern *aPattern, const nsACString& aLangGroup)
|
||||
{
|
||||
// Translate from mozilla's internal mapping into fontconfig's
|
||||
nsCAutoString lang;
|
||||
gfxFontconfigUtils::GetSampleLangForGroup(aLangGroup, &lang);
|
||||
|
||||
if (!lang.IsEmpty()) {
|
||||
// cast from signed chars used in nsString to unsigned in fontconfig
|
||||
const FcChar8 *fcString = reinterpret_cast<const FcChar8*>(lang.get());
|
||||
// and cast away the const for fontconfig, that will merely make a copy.
|
||||
FcPatternAddString(aPattern, FC_LANG, const_cast<FcChar8*>(fcString));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
gfxFontconfigUtils::GetFontListInternal(nsCStringArray& aListOfFonts,
|
||||
const nsACString *aLangGroup)
|
||||
const nsACString& aLangGroup)
|
||||
{
|
||||
FcPattern *pat = NULL;
|
||||
FcObjectSet *os = NULL;
|
||||
@ -345,8 +457,8 @@ gfxFontconfigUtils::GetFontListInternal(nsCStringArray& aListOfFonts,
|
||||
goto end;
|
||||
|
||||
// take the pattern and add the lang group to it
|
||||
if (aLangGroup && !aLangGroup->IsEmpty()) {
|
||||
AddLangGroup(pat, *aLangGroup);
|
||||
if (!aLangGroup.IsEmpty()) {
|
||||
AddLangGroup(pat, aLangGroup);
|
||||
}
|
||||
|
||||
fs = FcFontList(NULL, pat, os);
|
||||
@ -413,16 +525,38 @@ gfxFontconfigUtils::UpdateFontListInternal(PRBool aForce)
|
||||
if (currentConfig == mLastConfig)
|
||||
return NS_OK;
|
||||
|
||||
mFonts.Clear();
|
||||
mAliasForSingleFont.Clear();
|
||||
// This FcFontSet is owned by fontconfig
|
||||
FcFontSet *fontSet = FcConfigGetFonts(currentConfig, FcSetSystem);
|
||||
|
||||
mFontsByFamily.Clear();
|
||||
mLangSupportTable.Clear();
|
||||
mAliasForMultiFonts.Clear();
|
||||
mNonExistingFonts.Clear();
|
||||
|
||||
mAliasTable.Clear();
|
||||
// Record the existing font families
|
||||
for (int f = 0; f < fontSet->nfont; ++f) {
|
||||
FcPattern *font = fontSet->fonts[f];
|
||||
|
||||
nsresult rv = GetFontListInternal(mFonts);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
FcChar8 *family;
|
||||
for (int v = 0;
|
||||
FcPatternGetString(font, FC_FAMILY, v, &family) == FcResultMatch;
|
||||
++v) {
|
||||
FontsByFcStrEntry *entry = mFontsByFamily.PutEntry(family);
|
||||
if (entry) {
|
||||
PRBool added = entry->AddFont(font);
|
||||
|
||||
if (!entry->mKey) {
|
||||
// The reference to the font pattern keeps the pointer to
|
||||
// string for the key valid. If adding the font failed
|
||||
// then the entry must be removed.
|
||||
if (added) {
|
||||
entry->mKey = family;
|
||||
} else {
|
||||
mFontsByFamily.RawRemoveEntry(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// XXX we don't support all alias names.
|
||||
// Because if we don't check whether the given font name is alias name,
|
||||
@ -463,72 +597,10 @@ gfxFontconfigUtils::UpdateFontListInternal(PRBool aForce)
|
||||
}
|
||||
}
|
||||
|
||||
for (PRInt32 i = 0; i < mAliasForMultiFonts.Count(); i++) {
|
||||
nsRefPtr<gfxFontNameList> fonts = new gfxFontNameList;
|
||||
nsCAutoString fontname(*mAliasForMultiFonts.CStringAt(i));
|
||||
rv = GetResolvedFonts(fontname, fonts);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
nsCAutoString key;
|
||||
ToLowerCase(fontname, key);
|
||||
mAliasTable.Put(key, fonts);
|
||||
}
|
||||
|
||||
mLastConfig = currentConfig;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
gfxFontconfigUtils::GetResolvedFonts(const nsACString& aName,
|
||||
gfxFontNameList* aResult)
|
||||
{
|
||||
FcPattern *pat = NULL;
|
||||
FcFontSet *fs = NULL;
|
||||
FcResult fresult;
|
||||
aResult->Clear();
|
||||
nsresult rv = NS_ERROR_FAILURE;
|
||||
|
||||
pat = FcPatternCreate();
|
||||
if (!pat)
|
||||
goto end;
|
||||
|
||||
FcDefaultSubstitute(pat);
|
||||
FcPatternAddString(pat, FC_FAMILY,
|
||||
(FcChar8 *)nsPromiseFlatCString(aName).get());
|
||||
// Delete the lang param. We need lang independent alias list.
|
||||
FcPatternDel(pat, FC_LANG);
|
||||
FcConfigSubstitute(NULL, pat, FcMatchPattern);
|
||||
|
||||
fs = FcFontSort(NULL, pat, FcTrue, NULL, &fresult);
|
||||
if (!fs)
|
||||
goto end;
|
||||
|
||||
rv = NS_OK;
|
||||
for (int i = 0; i < fs->nfont; i++) {
|
||||
char *family;
|
||||
|
||||
if (FcPatternGetString(fs->fonts[i], FC_FAMILY, 0,
|
||||
(FcChar8 **) &family) != FcResultMatch ||
|
||||
mAliasForMultiFonts.IndexOfIgnoreCase(nsDependentCString(family)) >= 0 ||
|
||||
IsExistingFont(nsDependentCString(family)) == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
NS_ConvertUTF8toUTF16 actualName(family);
|
||||
if (aResult->Exists(actualName))
|
||||
continue;
|
||||
aResult->AppendElement(actualName);
|
||||
}
|
||||
|
||||
end:
|
||||
if (pat)
|
||||
FcPatternDestroy(pat);
|
||||
if (fs)
|
||||
FcFontSetDestroy(fs);
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
gfxFontconfigUtils::GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName)
|
||||
{
|
||||
@ -548,12 +620,8 @@ gfxFontconfigUtils::GetStandardFamilyName(const nsAString& aFontName, nsAString&
|
||||
|
||||
NS_ConvertUTF16toUTF8 fontname(aFontName);
|
||||
|
||||
if (mFonts.IndexOf(fontname) >= 0) {
|
||||
aFamilyName.Assign(aFontName);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (mNonExistingFonts.IndexOf(fontname) >= 0)
|
||||
// return empty string if no such family exists
|
||||
if (!IsExistingFamily(fontname))
|
||||
return NS_OK;
|
||||
|
||||
FcPattern *pat = NULL;
|
||||
@ -655,87 +723,203 @@ gfxFontconfigUtils::ResolveFontName(const nsAString& aFontName,
|
||||
return rv;
|
||||
|
||||
NS_ConvertUTF16toUTF8 fontname(aFontName);
|
||||
if (mAliasForMultiFonts.IndexOfIgnoreCase(fontname) >= 0) {
|
||||
nsCAutoString key;
|
||||
ToLowerCase(fontname, key);
|
||||
nsRefPtr<gfxFontNameList> fonts;
|
||||
if (!mAliasTable.Get(key, &fonts))
|
||||
NS_ERROR("The mAliasTable was broken!");
|
||||
for (PRUint32 i = 0; i < fonts->Length(); i++) {
|
||||
aAborted = !(*aCallback)(fonts->ElementAt(i), aClosure);
|
||||
if (aAborted)
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
PRInt32 result = IsExistingFont(fontname);
|
||||
if (result < 0)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
if (result > 0)
|
||||
aAborted = !(*aCallback)(aFontName, aClosure);
|
||||
}
|
||||
// Sometimes, the font has two or more names (e.g., "Sazanami Gothic" has
|
||||
// Japanese localized name). We should not resolve to a single name
|
||||
// because different names sometimes have different behavior. e.g., with
|
||||
// the default settings of "Sazanami" on Fedora Core 5, the non-localized
|
||||
// name uses anti-alias, but the localized name uses it. So, we should
|
||||
// check just whether the font is existing, without resolving to regular
|
||||
// name.
|
||||
//
|
||||
// The family names in mAliasForMultiFonts are names understood by
|
||||
// fontconfig. The actual font to which they resolve depends on the
|
||||
// entire match pattern. That info is not available here, but there
|
||||
// will be a font so leave the resolving to the gfxFontGroup.
|
||||
if (IsExistingFamily(fontname) ||
|
||||
mAliasForMultiFonts.IndexOfIgnoreCase(fontname))
|
||||
aAborted = !(*aCallback)(aFontName, aClosure);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
PRInt32
|
||||
gfxFontconfigUtils::IsExistingFont(const nsACString &aFontName)
|
||||
PRBool
|
||||
gfxFontconfigUtils::IsExistingFamily(const nsCString& aFamilyName)
|
||||
{
|
||||
// Very many sites may specify the font-family only for Windows and Mac.
|
||||
// We should check negative cache at first.
|
||||
if (mNonExistingFonts.IndexOf(aFontName) >= 0)
|
||||
return 0;
|
||||
if (mAliasForSingleFont.IndexOf(aFontName) >= 0)
|
||||
return 1;
|
||||
if (mFonts.IndexOf(aFontName) >= 0)
|
||||
return 1;
|
||||
return mFontsByFamily.GetEntry(ToFcChar8(aFamilyName.get())) != nsnull;
|
||||
}
|
||||
|
||||
// XXX Sometimes, the font has two or more names (e.g., "Sazanami Gothic"
|
||||
// has Japanese localized name). The another name doesn't including the
|
||||
// cache. Therefore, we need to check the name.
|
||||
// But we don't need to resolve the name. Because both names are not same
|
||||
// behavior. E.g., the default settings of "Sazanami" on Fedora Core 5,
|
||||
// the non-localized name uses Anti-alias, but the localized name uses it.
|
||||
// So, we should check just whether the font is existing, don't resolve
|
||||
// to regular name.
|
||||
const nsTArray< nsCountedRef<FcPattern> >&
|
||||
gfxFontconfigUtils::GetFontsForFamily(const FcChar8 *aFamilyName)
|
||||
{
|
||||
FontsByFcStrEntry *entry = mFontsByFamily.GetEntry(aFamilyName);
|
||||
|
||||
FcPattern *pat = NULL;
|
||||
FcObjectSet *os = NULL;
|
||||
FcFontSet *fs = NULL;
|
||||
PRInt32 result = -1;
|
||||
if (!entry)
|
||||
return mEmptyPatternArray;
|
||||
|
||||
pat = FcPatternCreate();
|
||||
if (!pat)
|
||||
goto end;
|
||||
return entry->GetFonts();
|
||||
}
|
||||
|
||||
FcPatternAddString(pat, FC_FAMILY,
|
||||
(FcChar8 *)nsPromiseFlatCString(aFontName).get());
|
||||
static FcLangResult
|
||||
CompareLangString(const FcChar8 *aLangA, const FcChar8 *aLangB) {
|
||||
FcLangResult result = FcLangDifferentLang;
|
||||
for (PRUint32 i = 0; ; ++i) {
|
||||
FcChar8 a = FcToLower(aLangA[i]);
|
||||
FcChar8 b = FcToLower(aLangB[i]);
|
||||
|
||||
os = FcObjectSetBuild(FC_FAMILY, NULL);
|
||||
if (!os)
|
||||
goto end;
|
||||
if (a != b) {
|
||||
if ((a == '\0' && b == '-') || (a == '-' && b == '\0'))
|
||||
return FcLangDifferentCountry;
|
||||
|
||||
fs = FcFontList(NULL, pat, os);
|
||||
if (!fs)
|
||||
goto end;
|
||||
return result;
|
||||
}
|
||||
if (a == '\0')
|
||||
return FcLangEqual;
|
||||
|
||||
// There can be more than one matching set of family names: see bug 393819.
|
||||
if (fs->nfont > 0) {
|
||||
mAliasForSingleFont.AppendCString(aFontName);
|
||||
result = 1;
|
||||
} else {
|
||||
mNonExistingFonts.AppendCString(aFontName);
|
||||
result = 0;
|
||||
if (a == '-') {
|
||||
result = FcLangDifferentCountry;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* static */
|
||||
FcLangResult
|
||||
gfxFontconfigUtils::GetLangSupport(FcPattern *aFont, const FcChar8 *aLang)
|
||||
{
|
||||
// When fontconfig builds a pattern for the font, it will set a single
|
||||
// LangSet property value for the font. That value may be removed and
|
||||
// additional string values may be added through FcConfigSubsitute with
|
||||
// FcMatchScan. Values that are neither LangSet nor string are considered
|
||||
// errors in fontconfig sort and match functions.
|
||||
FcValue value;
|
||||
FcLangResult best = FcLangDifferentLang;
|
||||
int v = 0;
|
||||
while (FcPatternGet(aFont, FC_LANG, v, &value) == FcResultMatch) {
|
||||
++v;
|
||||
|
||||
FcLangResult support;
|
||||
switch (value.type) {
|
||||
case FcTypeLangSet:
|
||||
support = FcLangSetHasLang(value.u.l, aLang);
|
||||
break;
|
||||
case FcTypeString:
|
||||
support = CompareLangString(value.u.s, aLang);
|
||||
break;
|
||||
default:
|
||||
// error
|
||||
return FcLangEqual;
|
||||
}
|
||||
|
||||
if (support < best) { // lower is better
|
||||
if (support == FcLangEqual)
|
||||
return support;
|
||||
best = support;
|
||||
}
|
||||
}
|
||||
|
||||
end:
|
||||
if (pat)
|
||||
FcPatternDestroy(pat);
|
||||
if (os)
|
||||
FcObjectSetDestroy(os);
|
||||
if (fs)
|
||||
FcFontSetDestroy(fs);
|
||||
return result;
|
||||
// A missing FC_LANG property is considered a match in fontconfig sort
|
||||
// and match functions.
|
||||
if (v == 0)
|
||||
return FcLangEqual;
|
||||
|
||||
return best;
|
||||
}
|
||||
|
||||
gfxFontconfigUtils::LangSupportEntry *
|
||||
gfxFontconfigUtils::GetLangSupportEntry(const FcChar8 *aLang, PRBool aWithFonts)
|
||||
{
|
||||
// Currently any unrecognized languages from documents will be converted
|
||||
// to x-unicode by nsILanguageAtomService, so there is a limit on the
|
||||
// langugages that will be added here. Reconsider when/if document
|
||||
// languages are passed to this routine.
|
||||
|
||||
LangSupportEntry *entry = mLangSupportTable.PutEntry(aLang);
|
||||
if (!entry)
|
||||
return nsnull;
|
||||
|
||||
FcLangResult best = FcLangDifferentLang;
|
||||
|
||||
if (!entry->IsKeyInitialized()) {
|
||||
entry->InitKey(aLang);
|
||||
} else {
|
||||
// mSupport is already initialized.
|
||||
if (!aWithFonts)
|
||||
return entry;
|
||||
|
||||
best = entry->mSupport;
|
||||
// If there is support for this language, an empty font list indicates
|
||||
// that the list hasn't been initialized yet.
|
||||
if (best == FcLangDifferentLang || entry->mFonts.Length() > 0)
|
||||
return entry;
|
||||
}
|
||||
|
||||
// This FcFontSet is owned by fontconfig
|
||||
FcFontSet *fontSet = FcConfigGetFonts(NULL, FcSetSystem);
|
||||
|
||||
nsAutoTArray<FcPattern*,100> fonts;
|
||||
|
||||
for (int f = 0; f < fontSet->nfont; ++f) {
|
||||
FcPattern *font = fontSet->fonts[f];
|
||||
|
||||
FcLangResult support = GetLangSupport(font, aLang);
|
||||
|
||||
if (support < best) { // lower is better
|
||||
best = support;
|
||||
if (aWithFonts) {
|
||||
fonts.Clear();
|
||||
} else if (best == FcLangEqual) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// The font list in the LangSupportEntry is expected to be used only
|
||||
// when no default fonts support the language. There would be a large
|
||||
// number of fonts in entries for languages using Latin script but
|
||||
// these do not need to be created because default fonts already
|
||||
// support these languages.
|
||||
if (aWithFonts && support != FcLangDifferentLang && support == best) {
|
||||
fonts.AppendElement(font);
|
||||
}
|
||||
}
|
||||
|
||||
entry->mSupport = best;
|
||||
if (aWithFonts) {
|
||||
if (fonts.Length() != 0) {
|
||||
entry->mFonts.AppendElements(fonts.Elements(), fonts.Length());
|
||||
} else if (best != FcLangDifferentLang) {
|
||||
// Previously there was a font that supported this language at the
|
||||
// level of entry->mSupport, but it has now disappeared. At least
|
||||
// entry->mSupport needs to be recalculated, but this is an
|
||||
// indication that the set of installed fonts has changed, so
|
||||
// update all caches.
|
||||
mLastConfig = NULL; // invalidates caches
|
||||
UpdateFontListInternal(PR_TRUE);
|
||||
return GetLangSupportEntry(aLang, aWithFonts);
|
||||
}
|
||||
}
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
FcLangResult
|
||||
gfxFontconfigUtils::GetBestLangSupport(const FcChar8 *aLang)
|
||||
{
|
||||
UpdateFontListInternal();
|
||||
|
||||
LangSupportEntry *entry = GetLangSupportEntry(aLang, PR_FALSE);
|
||||
if (!entry)
|
||||
return FcLangEqual;
|
||||
|
||||
return entry->mSupport;
|
||||
}
|
||||
|
||||
const nsTArray< nsCountedRef<FcPattern> >&
|
||||
gfxFontconfigUtils::GetFontsForLang(const FcChar8 *aLang)
|
||||
{
|
||||
LangSupportEntry *entry = GetLangSupportEntry(aLang, PR_TRUE);
|
||||
if (!entry)
|
||||
return mEmptyPatternArray;
|
||||
|
||||
return entry->mFonts;
|
||||
}
|
||||
|
||||
PRBool
|
||||
@ -746,4 +930,3 @@ gfxFontNameList::Exists(nsAString& aName) {
|
||||
}
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
|
@ -20,6 +20,7 @@
|
||||
*
|
||||
* Contributor(s):
|
||||
* Masayuki Nakano <masayuki@d-toybox.com>
|
||||
* Karl Tomlinson <karlt+@karlt.net>, Mozilla Corporation
|
||||
*
|
||||
* 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
|
||||
@ -40,15 +41,40 @@
|
||||
|
||||
#include "gfxPlatform.h"
|
||||
|
||||
#include "nsAutoRef.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsDataHashtable.h"
|
||||
#include "nsTHashtable.h"
|
||||
|
||||
#include <fontconfig/fontconfig.h>
|
||||
|
||||
|
||||
NS_SPECIALIZE_TEMPLATE
|
||||
class nsAutoRefTraits<FcPattern> : public nsPointerRefTraits<FcPattern>
|
||||
{
|
||||
public:
|
||||
static void Release(FcPattern *ptr) { FcPatternDestroy(ptr); }
|
||||
static void AddRef(FcPattern *ptr) { FcPatternReference(ptr); }
|
||||
};
|
||||
|
||||
NS_SPECIALIZE_TEMPLATE
|
||||
class nsAutoRefTraits<FcFontSet> : public nsPointerRefTraits<FcFontSet>
|
||||
{
|
||||
public:
|
||||
static void Release(FcFontSet *ptr) { FcFontSetDestroy(ptr); }
|
||||
};
|
||||
|
||||
NS_SPECIALIZE_TEMPLATE
|
||||
class nsAutoRefTraits<FcCharSet> : public nsPointerRefTraits<FcCharSet>
|
||||
{
|
||||
public:
|
||||
static void Release(FcCharSet *ptr) { FcCharSetDestroy(ptr); }
|
||||
};
|
||||
|
||||
|
||||
class gfxFontNameList : public nsTArray<nsString>
|
||||
{
|
||||
public:
|
||||
THEBES_INLINE_DECL_REFCOUNTING(gfxFontList)
|
||||
THEBES_INLINE_DECL_REFCOUNTING(gfxFontNameList)
|
||||
PRBool Exists(nsAString& aName);
|
||||
};
|
||||
|
||||
@ -76,9 +102,42 @@ public:
|
||||
|
||||
nsresult GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName);
|
||||
|
||||
const nsTArray< nsCountedRef<FcPattern> >&
|
||||
GetFontsForFamily(const FcChar8 *aFamilyName);
|
||||
|
||||
// Returns the best support that any font offers for |aLang|.
|
||||
FcLangResult GetBestLangSupport(const FcChar8 *aLang);
|
||||
// Returns the fonts offering this best level of support.
|
||||
const nsTArray< nsCountedRef<FcPattern> >&
|
||||
GetFontsForLang(const FcChar8 *aLang);
|
||||
|
||||
// Retuns the language support for a fontconfig font pattern
|
||||
static FcLangResult GetLangSupport(FcPattern *aFont, const FcChar8 *aLang);
|
||||
|
||||
// Conversions between FcChar8*, which is unsigned char*,
|
||||
// and (signed) char*, that check the type of the argument.
|
||||
static const FcChar8 *ToFcChar8(const char *aCharPtr)
|
||||
{
|
||||
return reinterpret_cast<const FcChar8*>(aCharPtr);
|
||||
}
|
||||
static const char *ToCString(const FcChar8 *aChar8Ptr)
|
||||
{
|
||||
return reinterpret_cast<const char*>(aChar8Ptr);
|
||||
}
|
||||
|
||||
static PRUint8 GetThebesStyle(FcPattern *aPattern); // slant
|
||||
static PRUint16 GetThebesWeight(FcPattern *aPattern);
|
||||
|
||||
static int GetFcSlant(const gfxFontStyle& aFontStyle);
|
||||
// Returns a precise FC_WEIGHT from CSS weight |aBaseWeight|.
|
||||
static int FcWeightForBaseWeight(PRInt8 aBaseWeight);
|
||||
|
||||
// This doesn't consider which faces exist, and so initializes the pattern
|
||||
// using a guessed weight, and doesn't consider sizeAdjust.
|
||||
static nsReturnRef<FcPattern>
|
||||
NewPattern(const nsStringArray& aFamilies, const gfxFontStyle& aFontStyle,
|
||||
const char *aLang);
|
||||
|
||||
/**
|
||||
* @param aLangGroup [in] a Mozilla langGroup.
|
||||
* @param aFcLang [out] returns a language suitable for fontconfig
|
||||
@ -88,22 +147,133 @@ public:
|
||||
nsACString *aFcLang);
|
||||
|
||||
protected:
|
||||
// Base class for hash table entries with case-insensitive FcChar8
|
||||
// string keys.
|
||||
class FcStrEntryBase : public PLDHashEntryHdr {
|
||||
public:
|
||||
typedef const FcChar8 *KeyType;
|
||||
typedef const FcChar8 *KeyTypePointer;
|
||||
|
||||
static KeyTypePointer KeyToPointer(KeyType aKey) { return aKey; }
|
||||
// Case-insensitive hash.
|
||||
//
|
||||
// fontconfig always ignores case of ASCII characters in family
|
||||
// names and languages, but treatment of whitespace in families is
|
||||
// not consistent. FcFontSort and FcFontMatch ignore whitespace
|
||||
// except for whitespace in the first character, while FcFontList
|
||||
// and config subsitution tests require whitespace to match
|
||||
// exactly. CSS 2.1 implies that whitespace is important in the
|
||||
// font-family property. FcStrCmpIgnoreCase considers whitespace
|
||||
// important.
|
||||
static PLDHashNumber HashKey(const FcChar8 *aKey) {
|
||||
PRUint32 hash = 0;
|
||||
for (const FcChar8 *c = aKey; *c != '\0'; ++c) {
|
||||
hash = PR_ROTATE_LEFT32(hash, 3) ^ FcToLower(*c);
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
enum { ALLOW_MEMMOVE = PR_TRUE };
|
||||
};
|
||||
|
||||
public:
|
||||
// Hash entry with a dependent const FcChar8* pointer to an external
|
||||
// string for a key (and no data). The user must ensure that the string
|
||||
// associated with the pointer is not destroyed. This entry type is
|
||||
// useful for family name keys as the family name string is held in the
|
||||
// font pattern.
|
||||
class DepFcStrEntry : public FcStrEntryBase {
|
||||
public:
|
||||
// When constructing a new entry in the hashtable, the key is left
|
||||
// blank. The caller of PutEntry() must fill in mKey when NULL. This
|
||||
// provides a mechanism for the caller of PutEntry() to determine
|
||||
// whether the entry has been initialized.
|
||||
DepFcStrEntry(KeyTypePointer aName)
|
||||
: mKey(NULL) { }
|
||||
|
||||
DepFcStrEntry(const DepFcStrEntry& toCopy)
|
||||
: mKey(toCopy.mKey) { }
|
||||
|
||||
PRBool KeyEquals(KeyTypePointer aKey) const {
|
||||
return FcStrCmpIgnoreCase(aKey, mKey) == 0;
|
||||
}
|
||||
|
||||
const FcChar8 *mKey;
|
||||
};
|
||||
|
||||
// Hash entry that uses a copy of an FcChar8 string to store the key.
|
||||
// This entry type is useful for language keys, as languages are usually
|
||||
// not stored as strings in font patterns.
|
||||
class CopiedFcStrEntry : public FcStrEntryBase {
|
||||
public:
|
||||
// When constructing a new entry in the hashtable, the key is void.
|
||||
// The caller of PutEntry() must call InitKey() when IsKeyInitialized()
|
||||
// returns false. This provides a mechanism for the caller of
|
||||
// PutEntry() to determine whether the entry has been initialized.
|
||||
CopiedFcStrEntry(KeyTypePointer aName) {
|
||||
mKey.SetIsVoid(PR_TRUE);
|
||||
}
|
||||
|
||||
CopiedFcStrEntry(const CopiedFcStrEntry& toCopy)
|
||||
: mKey(toCopy.mKey) { }
|
||||
|
||||
PRBool KeyEquals(KeyTypePointer aKey) const {
|
||||
return FcStrCmpIgnoreCase(aKey, ToFcChar8(mKey.get())) == 0;
|
||||
}
|
||||
|
||||
PRBool IsKeyInitialized() { return !mKey.IsVoid(); }
|
||||
void InitKey(const FcChar8* aKey) { mKey.Assign(ToCString(aKey)); }
|
||||
|
||||
private:
|
||||
nsCString mKey;
|
||||
};
|
||||
|
||||
protected:
|
||||
class FontsByFcStrEntry : public DepFcStrEntry {
|
||||
public:
|
||||
FontsByFcStrEntry(KeyTypePointer aName)
|
||||
: DepFcStrEntry(aName) { }
|
||||
|
||||
FontsByFcStrEntry(const FontsByFcStrEntry& toCopy)
|
||||
: DepFcStrEntry(toCopy), mFonts(toCopy.mFonts) { }
|
||||
|
||||
PRBool AddFont(FcPattern *aFont) {
|
||||
return mFonts.AppendElement(aFont) != nsnull;
|
||||
}
|
||||
const nsTArray< nsCountedRef<FcPattern> >& GetFonts() {
|
||||
return mFonts;
|
||||
}
|
||||
private:
|
||||
nsTArray< nsCountedRef<FcPattern> > mFonts;
|
||||
};
|
||||
|
||||
class LangSupportEntry : public CopiedFcStrEntry {
|
||||
public:
|
||||
LangSupportEntry(KeyTypePointer aName)
|
||||
: CopiedFcStrEntry(aName) { }
|
||||
|
||||
LangSupportEntry(const LangSupportEntry& toCopy)
|
||||
: CopiedFcStrEntry(toCopy), mSupport(toCopy.mSupport) { }
|
||||
|
||||
FcLangResult mSupport;
|
||||
nsTArray< nsCountedRef<FcPattern> > mFonts;
|
||||
};
|
||||
|
||||
static gfxFontconfigUtils* sUtils;
|
||||
|
||||
PRInt32 IsExistingFont(const nsACString& aFontName);
|
||||
nsresult GetResolvedFonts(const nsACString& aName,
|
||||
gfxFontNameList* aResult);
|
||||
PRBool IsExistingFamily(const nsCString& aFamilyName);
|
||||
|
||||
nsresult GetFontListInternal(nsCStringArray& aListOfFonts,
|
||||
const nsACString *aLangGroup = nsnull);
|
||||
const nsACString& aLangGroup);
|
||||
nsresult UpdateFontListInternal(PRBool aForce = PR_FALSE);
|
||||
|
||||
nsCStringArray mFonts;
|
||||
nsCStringArray mNonExistingFonts;
|
||||
nsCStringArray mAliasForSingleFont;
|
||||
nsCStringArray mAliasForMultiFonts;
|
||||
LangSupportEntry *GetLangSupportEntry(const FcChar8 *aLang,
|
||||
PRBool aWithFonts);
|
||||
|
||||
nsDataHashtable<nsCStringHashKey, nsRefPtr<gfxFontNameList> > mAliasTable;
|
||||
nsTHashtable<FontsByFcStrEntry> mFontsByFamily;
|
||||
nsTHashtable<LangSupportEntry> mLangSupportTable;
|
||||
const nsTArray< nsCountedRef<FcPattern> > mEmptyPatternArray;
|
||||
|
||||
nsCStringArray mAliasForMultiFonts;
|
||||
|
||||
FcConfig *mLastConfig;
|
||||
};
|
||||
|
115
js/src/json.cpp
@ -83,14 +83,16 @@ js_json_parse(JSContext *cx, uintN argc, jsval *vp)
|
||||
}
|
||||
|
||||
if (!ok)
|
||||
JS_ReportError(cx, "Error parsing JSON.");
|
||||
JS_ReportError(cx, "Error parsing JSON");
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
struct StringifyClosure
|
||||
class StringifyClosure : JSAutoTempValueRooter
|
||||
{
|
||||
StringifyClosure(JSContext *aCx, jsval *str) : cx(aCx), s(str)
|
||||
public:
|
||||
StringifyClosure(JSContext *cx, size_t len, jsval *vec)
|
||||
: JSAutoTempValueRooter(cx, len, vec), cx(cx), s(vec)
|
||||
{
|
||||
}
|
||||
|
||||
@ -102,16 +104,20 @@ static JSBool
|
||||
WriteCallback(const jschar *buf, uint32 len, void *data)
|
||||
{
|
||||
StringifyClosure *sc = static_cast<StringifyClosure*>(data);
|
||||
JSString *s1 = JSVAL_TO_STRING(*sc->s);
|
||||
JSString *s1 = JSVAL_TO_STRING(sc->s[0]);
|
||||
JSString *s2 = js_NewStringCopyN(sc->cx, buf, len);
|
||||
if (!s2)
|
||||
return JS_FALSE;
|
||||
|
||||
sc->s[1] = STRING_TO_JSVAL(s2);
|
||||
|
||||
s1 = js_ConcatStrings(sc->cx, s1, s2);
|
||||
if (!s1)
|
||||
return JS_FALSE;
|
||||
|
||||
*sc->s = STRING_TO_JSVAL(s1);
|
||||
sc->s[0] = STRING_TO_JSVAL(s1);
|
||||
sc->s[1] = JSVAL_VOID;
|
||||
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
@ -126,13 +132,15 @@ js_json_stringify(JSContext *cx, uintN argc, jsval *vp)
|
||||
return JS_FALSE;
|
||||
|
||||
// Only use objects and arrays as the root for now
|
||||
jsval v = OBJECT_TO_JSVAL(obj);
|
||||
JSBool ok = js_TryJSON(cx, &v);
|
||||
*vp = OBJECT_TO_JSVAL(obj);
|
||||
|
||||
JSBool ok = js_TryJSON(cx, vp);
|
||||
JSType type;
|
||||
if (!(ok && !JSVAL_IS_PRIMITIVE(v) &&
|
||||
(type = JS_TypeOfValue(cx, v)) != JSTYPE_FUNCTION &&
|
||||
type != JSTYPE_XML)) {
|
||||
JS_ReportError(cx, "Invalid argument.");
|
||||
if (!ok ||
|
||||
JSVAL_IS_PRIMITIVE(*vp) ||
|
||||
((type = JS_TypeOfValue(cx, *vp)) == JSTYPE_FUNCTION ||
|
||||
type == JSTYPE_XML)) {
|
||||
JS_ReportError(cx, "Invalid argument");
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
@ -141,10 +149,10 @@ js_json_stringify(JSContext *cx, uintN argc, jsval *vp)
|
||||
ok = JS_FALSE;
|
||||
|
||||
if (ok) {
|
||||
jsval sv = STRING_TO_JSVAL(s);
|
||||
StringifyClosure sc(cx, &sv);
|
||||
JSAutoTempValueRooter tvr(cx, 1, sc.s);
|
||||
ok = js_Stringify(cx, &v, NULL, &WriteCallback, &sc, 0);
|
||||
jsval vec[2] = {STRING_TO_JSVAL(s), JSVAL_VOID};
|
||||
StringifyClosure sc(cx, 2, vec);
|
||||
JSAutoTempValueRooter resultTvr(cx, 1, sc.s);
|
||||
ok = js_Stringify(cx, vp, NULL, &WriteCallback, &sc, 0);
|
||||
*vp = *sc.s;
|
||||
}
|
||||
|
||||
@ -191,8 +199,11 @@ write_string(JSContext *cx, JSONWriteCallback callback, void *data, const jschar
|
||||
char ubuf[10];
|
||||
unsigned int len = JS_snprintf(ubuf, sizeof(ubuf), "%.2x", buf[i]);
|
||||
JS_ASSERT(len == 2);
|
||||
// TODO: don't allocate a JSString just to inflate (js_InflateStringToBuffer on static?)
|
||||
// FIXME: bug 463715 - don't allocate a JSString just to inflate
|
||||
// (js_InflateStringToBuffer on static?)
|
||||
JSString *us = JS_NewStringCopyN(cx, ubuf, len);
|
||||
if (!us)
|
||||
return JS_FALSE;
|
||||
if (!callback(JS_GetStringChars(us), len, data))
|
||||
return JS_FALSE;
|
||||
mark = i + 1;
|
||||
@ -246,7 +257,8 @@ js_Stringify(JSContext *cx, jsval *vp, JSObject *replacer,
|
||||
if (isArray) {
|
||||
if ((jsuint)i >= length)
|
||||
break;
|
||||
ok = JS_GetElement(cx, obj, i++, &outputValue);
|
||||
ok = OBJ_GET_PROPERTY(cx, obj, INT_TO_JSID(i), &outputValue);
|
||||
i++;
|
||||
} else {
|
||||
ok = js_CallIteratorNext(cx, iterObj, &key);
|
||||
if (!ok)
|
||||
@ -359,6 +371,11 @@ js_Stringify(JSContext *cx, jsval *vp, JSObject *replacer,
|
||||
break;
|
||||
}
|
||||
|
||||
if (!outputString) {
|
||||
ok = JS_FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
ok = callback(JS_GetStringChars(outputString), JS_GetStringLength(outputString), data);
|
||||
}
|
||||
} while (ok);
|
||||
@ -370,7 +387,7 @@ js_Stringify(JSContext *cx, jsval *vp, JSObject *replacer,
|
||||
}
|
||||
|
||||
if (!ok) {
|
||||
JS_ReportError(cx, "Error during JSON encoding.");
|
||||
JS_ReportError(cx, "Error during JSON encoding");
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
@ -410,7 +427,12 @@ js_BeginJSONParse(JSContext *cx, jsval *rootVal)
|
||||
jp->statep = jp->stateStack;
|
||||
*jp->statep = JSON_PARSE_STATE_INIT;
|
||||
jp->rootVal = rootVal;
|
||||
jp->objectKey = NULL;
|
||||
|
||||
jp->objectKey = (JSStringBuffer*) JS_malloc(cx, sizeof(JSStringBuffer));
|
||||
if (!jp->objectKey)
|
||||
goto bad;
|
||||
js_InitStringBuffer(jp->objectKey);
|
||||
|
||||
jp->buffer = (JSStringBuffer*) JS_malloc(cx, sizeof(JSStringBuffer));
|
||||
if (!jp->buffer)
|
||||
goto bad;
|
||||
@ -429,10 +451,14 @@ js_FinishJSONParse(JSContext *cx, JSONParser *jp)
|
||||
if (!jp)
|
||||
return JS_TRUE;
|
||||
|
||||
if (jp->objectKey)
|
||||
js_FinishStringBuffer(jp->objectKey);
|
||||
JS_free(cx, jp->objectKey);
|
||||
|
||||
if (jp->buffer)
|
||||
js_FinishStringBuffer(jp->buffer);
|
||||
|
||||
JS_free(cx, jp->buffer);
|
||||
|
||||
if (!js_RemoveRoot(cx->runtime, &jp->objectStack))
|
||||
return JS_FALSE;
|
||||
JSBool ok = *jp->statep == JSON_PARSE_STATE_FINISHED;
|
||||
@ -480,12 +506,16 @@ PushValue(JSContext *cx, JSONParser *jp, JSObject *parent, jsval value)
|
||||
if (OBJ_IS_ARRAY(cx, parent)) {
|
||||
jsuint len;
|
||||
ok = js_GetLengthProperty(cx, parent, &len);
|
||||
if (ok)
|
||||
ok = JS_SetElement(cx, parent, len, &value);
|
||||
if (ok) {
|
||||
ok = OBJ_DEFINE_PROPERTY(cx, parent, INT_TO_JSID(len), value,
|
||||
NULL, NULL, JSPROP_ENUMERATE, NULL);
|
||||
}
|
||||
} else {
|
||||
ok = JS_DefineUCProperty(cx, parent, JS_GetStringChars(jp->objectKey),
|
||||
JS_GetStringLength(jp->objectKey), value,
|
||||
ok = JS_DefineUCProperty(cx, parent, jp->objectKey->base,
|
||||
STRING_BUFFER_OFFSET(jp->objectKey), value,
|
||||
NULL, NULL, JSPROP_ENUMERATE);
|
||||
js_FinishStringBuffer(jp->objectKey);
|
||||
js_InitStringBuffer(jp->objectKey);
|
||||
}
|
||||
|
||||
return ok;
|
||||
@ -501,25 +531,33 @@ PushObject(JSContext *cx, JSONParser *jp, JSObject *obj)
|
||||
return JS_FALSE; // decoding error
|
||||
|
||||
jsval v = OBJECT_TO_JSVAL(obj);
|
||||
JSAutoTempValueRooter tvr(cx, v);
|
||||
|
||||
// Check if this is the root object
|
||||
if (len == 0) {
|
||||
*jp->rootVal = v;
|
||||
if (!JS_SetElement(cx, jp->objectStack, 0, jp->rootVal))
|
||||
// This property must be enumerable to keep the array dense
|
||||
if (!OBJ_DEFINE_PROPERTY(cx, jp->objectStack, INT_TO_JSID(0), *jp->rootVal,
|
||||
NULL, NULL, JSPROP_ENUMERATE, NULL)) {
|
||||
return JS_FALSE;
|
||||
}
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
jsval p;
|
||||
if (!JS_GetElement(cx, jp->objectStack, len - 1, &p))
|
||||
if (!OBJ_GET_PROPERTY(cx, jp->objectStack, INT_TO_JSID(len - 1), &p))
|
||||
return JS_FALSE;
|
||||
|
||||
JS_ASSERT(JSVAL_IS_OBJECT(p));
|
||||
JSObject *parent = JSVAL_TO_OBJECT(p);
|
||||
if (!PushValue(cx, jp, parent, OBJECT_TO_JSVAL(obj)))
|
||||
return JS_FALSE;
|
||||
|
||||
if (!JS_SetElement(cx, jp->objectStack, len, &v))
|
||||
// This property must be enumerable to keep the array dense
|
||||
if (!OBJ_DEFINE_PROPERTY(cx, jp->objectStack, INT_TO_JSID(len), v,
|
||||
NULL, NULL, JSPROP_ENUMERATE, NULL)) {
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
return JS_TRUE;
|
||||
}
|
||||
@ -532,7 +570,7 @@ GetTopOfObjectStack(JSContext *cx, JSONParser *jp)
|
||||
return NULL;
|
||||
|
||||
jsval o;
|
||||
if (!JS_GetElement(cx, jp->objectStack, length - 1, &o))
|
||||
if (!OBJ_GET_PROPERTY(cx, jp->objectStack, INT_TO_JSID(length - 1), &o))
|
||||
return NULL;
|
||||
|
||||
JS_ASSERT(!JSVAL_IS_PRIMITIVE(o));
|
||||
@ -633,26 +671,29 @@ HandleKeyword(JSContext *cx, JSONParser *jp, const jschar *buf, uint32 len)
|
||||
}
|
||||
|
||||
static JSBool
|
||||
HandleData(JSContext *cx, JSONParser *jp, JSONDataType type, const jschar *buf, uint32 len)
|
||||
HandleData(JSContext *cx, JSONParser *jp, JSONDataType type)
|
||||
{
|
||||
JSBool ok = JS_FALSE;
|
||||
|
||||
if (!STRING_BUFFER_OK(jp->buffer))
|
||||
return JS_FALSE;
|
||||
|
||||
switch (type) {
|
||||
case JSON_DATA_STRING:
|
||||
ok = HandleString(cx, jp, buf, len);
|
||||
ok = HandleString(cx, jp, jp->buffer->base, STRING_BUFFER_OFFSET(jp->buffer));
|
||||
break;
|
||||
|
||||
case JSON_DATA_KEYSTRING:
|
||||
jp->objectKey = js_NewStringCopyN(cx, buf, len);
|
||||
ok = JS_TRUE;
|
||||
js_AppendUCString(jp->objectKey, jp->buffer->base, STRING_BUFFER_OFFSET(jp->buffer));
|
||||
ok = STRING_BUFFER_OK(jp->objectKey);
|
||||
break;
|
||||
|
||||
case JSON_DATA_NUMBER:
|
||||
ok = HandleNumber(cx, jp, buf, len);
|
||||
ok = HandleNumber(cx, jp, jp->buffer->base, STRING_BUFFER_OFFSET(jp->buffer));
|
||||
break;
|
||||
|
||||
case JSON_DATA_KEYWORD:
|
||||
ok = HandleKeyword(cx, jp, buf, len);
|
||||
ok = HandleKeyword(cx, jp, jp->buffer->base, STRING_BUFFER_OFFSET(jp->buffer));
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -783,7 +824,7 @@ js_ConsumeJSONText(JSContext *cx, JSONParser *jp, const jschar *data, uint32 len
|
||||
} else {
|
||||
jdt = JSON_DATA_STRING;
|
||||
}
|
||||
if (!HandleData(cx, jp, jdt, jp->buffer->base, STRING_BUFFER_OFFSET(jp->buffer)))
|
||||
if (!HandleData(cx, jp, jdt))
|
||||
return JS_FALSE;
|
||||
} else if (c == '\\') {
|
||||
*jp->statep = JSON_PARSE_STATE_STRING_ESCAPE;
|
||||
@ -845,7 +886,7 @@ js_ConsumeJSONText(JSContext *cx, JSONParser *jp, const jschar *data, uint32 len
|
||||
if (!PopState(jp))
|
||||
return JS_FALSE;
|
||||
|
||||
if (!HandleData(cx, jp, JSON_DATA_KEYWORD, jp->buffer->base, STRING_BUFFER_OFFSET(jp->buffer)))
|
||||
if (!HandleData(cx, jp, JSON_DATA_KEYWORD))
|
||||
return JS_FALSE;
|
||||
}
|
||||
break;
|
||||
@ -858,7 +899,7 @@ js_ConsumeJSONText(JSContext *cx, JSONParser *jp, const jschar *data, uint32 len
|
||||
i--;
|
||||
if (!PopState(jp))
|
||||
return JS_FALSE;
|
||||
if (!HandleData(cx, jp, JSON_DATA_NUMBER, jp->buffer->base, STRING_BUFFER_OFFSET(jp->buffer)))
|
||||
if (!HandleData(cx, jp, JSON_DATA_NUMBER))
|
||||
return JS_FALSE;
|
||||
}
|
||||
break;
|
||||
|
@ -88,7 +88,7 @@ struct JSONParser {
|
||||
JSONParserState *statep;
|
||||
JSONParserState stateStack[JSON_MAX_DEPTH];
|
||||
jsval *rootVal;
|
||||
JSString *objectKey;
|
||||
JSStringBuffer *objectKey;
|
||||
JSStringBuffer *buffer;
|
||||
JSObject *objectStack;
|
||||
};
|
||||
|
@ -749,6 +749,22 @@ js_AppendChar(JSStringBuffer *sb, jschar c)
|
||||
sb->ptr = bp;
|
||||
}
|
||||
|
||||
void
|
||||
js_AppendUCString(JSStringBuffer *sb, const jschar *buf, uintN len)
|
||||
{
|
||||
jschar *bp;
|
||||
|
||||
if (!STRING_BUFFER_OK(sb))
|
||||
return;
|
||||
if (len == 0 || !ENSURE_STRING_BUFFER(sb, len))
|
||||
return;
|
||||
bp = sb->ptr;
|
||||
js_strncpy(bp, buf, len);
|
||||
bp += len;
|
||||
*bp = 0;
|
||||
sb->ptr = bp;
|
||||
}
|
||||
|
||||
#if JS_HAS_XML_SUPPORT
|
||||
|
||||
void
|
||||
@ -786,19 +802,7 @@ js_AppendCString(JSStringBuffer *sb, const char *asciiz)
|
||||
void
|
||||
js_AppendJSString(JSStringBuffer *sb, JSString *str)
|
||||
{
|
||||
size_t length;
|
||||
jschar *bp;
|
||||
|
||||
if (!STRING_BUFFER_OK(sb))
|
||||
return;
|
||||
length = JSSTRING_LENGTH(str);
|
||||
if (length == 0 || !ENSURE_STRING_BUFFER(sb, length))
|
||||
return;
|
||||
bp = sb->ptr;
|
||||
js_strncpy(bp, JSSTRING_CHARS(str), length);
|
||||
bp += length;
|
||||
*bp = 0;
|
||||
sb->ptr = bp;
|
||||
js_AppendUCString(sb, JSSTRING_CHARS(str), JSSTRING_LENGTH(str));
|
||||
}
|
||||
|
||||
static JSBool
|
||||
|
@ -181,6 +181,9 @@ js_RepeatChar(JSStringBuffer *sb, jschar c, uintN count);
|
||||
extern void
|
||||
js_AppendCString(JSStringBuffer *sb, const char *asciiz);
|
||||
|
||||
extern void
|
||||
js_AppendUCString(JSStringBuffer *sb, const jschar *buf, uintN len);
|
||||
|
||||
extern void
|
||||
js_AppendJSString(JSStringBuffer *sb, JSString *str);
|
||||
|
||||
|
@ -184,10 +184,6 @@ static JSBool
|
||||
XPC_NW_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
|
||||
jsval *rval);
|
||||
|
||||
static JSBool
|
||||
XPCNativeWrapperCtor(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
|
||||
jsval *rval);
|
||||
|
||||
static inline
|
||||
JSBool
|
||||
ThrowException(nsresult ex, JSContext *cx)
|
||||
@ -790,7 +786,7 @@ MirrorWrappedNativeParent(JSContext *cx, XPCWrappedNative *wrapper,
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
JSBool
|
||||
XPCNativeWrapperCtor(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
|
||||
jsval *rval)
|
||||
{
|
||||
|
@ -81,6 +81,10 @@ XPC_XOW_WrapperMoved(JSContext *cx, XPCWrappedNative *innerObj,
|
||||
nsresult
|
||||
CanAccessWrapper(JSContext *cx, JSObject *wrappedObj);
|
||||
|
||||
JSBool
|
||||
XPCNativeWrapperCtor(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
|
||||
jsval *rval);
|
||||
|
||||
inline JSBool
|
||||
XPC_XOW_ClassNeedsXOW(const char *name)
|
||||
{
|
||||
|
@ -48,6 +48,7 @@
|
||||
#include "nsIScriptObjectPrincipal.h"
|
||||
#include "nsIDOMWindow.h"
|
||||
#include "xpcJSWeakReference.h"
|
||||
#include "XPCWrapper.h"
|
||||
|
||||
#ifdef MOZ_JSLOADER
|
||||
#include "mozJSComponentLoader.h"
|
||||
@ -2725,6 +2726,21 @@ nsXPCComponents_Utils::GetSandbox(nsIXPCComponents_utils_Sandbox **aSandbox)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
MethodWrapper(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
|
||||
jsval *rval)
|
||||
{
|
||||
jsval v;
|
||||
if (!JS_GetReservedSlot(cx, JSVAL_TO_OBJECT(argv[-2]), 0, &v) ||
|
||||
!JS_CallFunctionValue(cx, obj, v, argc, argv, rval)) {
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
if (JSVAL_IS_PRIMITIVE(*rval))
|
||||
return JS_TRUE;
|
||||
return XPCNativeWrapperCtor(cx, nsnull, 1, rval, rval);
|
||||
}
|
||||
|
||||
/* void lookupMethod (); */
|
||||
NS_IMETHODIMP
|
||||
nsXPCComponents_Utils::LookupMethod()
|
||||
@ -2831,10 +2847,35 @@ nsXPCComponents_Utils::LookupMethod()
|
||||
&funval))
|
||||
return NS_ERROR_XPC_BAD_CONVERT_JS;
|
||||
|
||||
// return the function and let xpconnect know we did so
|
||||
// Stick the function in the return value. This roots it.
|
||||
*retval = funval;
|
||||
cc->SetReturnValueWasSet(PR_TRUE);
|
||||
|
||||
// Callers of this method are implicitly buying into
|
||||
// XPCNativeWrapper-like protection. The easiest way
|
||||
// to enforce this is to use our own wrapper.
|
||||
// Note: We use the outer call context to ensure that we wrap
|
||||
// the function in the right scope.
|
||||
NS_ASSERTION(JSVAL_IS_OBJECT(funval), "Function is not an object");
|
||||
JSContext *outercx;
|
||||
cc->GetJSContext(&outercx);
|
||||
JSFunction *oldfunction = JS_ValueToFunction(outercx, funval);
|
||||
NS_ASSERTION(oldfunction, "Function is not a function");
|
||||
|
||||
JSFunction *f = JS_NewFunction(outercx, MethodWrapper,
|
||||
JS_GetFunctionArity(oldfunction), 0,
|
||||
JS_GetScopeChain(outercx),
|
||||
JS_GetFunctionName(oldfunction));
|
||||
if(!f)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
JSObject *funobj = JS_GetFunctionObject(f);
|
||||
if(!JS_SetReservedSlot(outercx, funobj, 0, funval))
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
*retval = OBJECT_TO_JSVAL(funobj);
|
||||
|
||||
// Tell XPConnect that we returned the function through the call context.
|
||||
cc->SetReturnValueWasSet(PR_TRUE);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -3010,7 +3051,7 @@ SandboxFunForwarder(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
|
||||
|
||||
if (JSVAL_IS_PRIMITIVE(*rval))
|
||||
return JS_TRUE; // nothing more to do.
|
||||
|
||||
|
||||
XPCThrower::Throw(NS_ERROR_NOT_IMPLEMENTED, cx);
|
||||
return JS_FALSE;
|
||||
}
|
||||
@ -3023,7 +3064,7 @@ SandboxImport(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
|
||||
XPCThrower::Throw(NS_ERROR_INVALID_ARG, cx);
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
|
||||
JSFunction *fun = JS_ValueToFunction(cx, argv[0]);
|
||||
if (!fun) {
|
||||
XPCThrower::Throw(NS_ERROR_INVALID_ARG, cx);
|
||||
|
@ -2678,7 +2678,7 @@ nsLayoutUtils::DrawImage(nsIRenderingContext* aRenderingContext,
|
||||
const nsPoint& aAnchor,
|
||||
const nsRect& aDirty)
|
||||
{
|
||||
if (aDest.IsEmpty())
|
||||
if (aDest.IsEmpty() || aFill.IsEmpty())
|
||||
return NS_OK;
|
||||
|
||||
nsCOMPtr<nsIDeviceContext> dc;
|
||||
@ -2687,14 +2687,15 @@ nsLayoutUtils::DrawImage(nsIRenderingContext* aRenderingContext,
|
||||
gfxContext *ctx = aRenderingContext->ThebesContext();
|
||||
|
||||
// Compute the pixel-snapped area that should be drawn
|
||||
gfxRect fill(aFill.x/appUnitsPerDevPixel,
|
||||
aFill.y/appUnitsPerDevPixel,
|
||||
aFill.width/appUnitsPerDevPixel,
|
||||
aFill.height/appUnitsPerDevPixel);
|
||||
gfxRect devPixelFill(aFill.x/appUnitsPerDevPixel,
|
||||
aFill.y/appUnitsPerDevPixel,
|
||||
aFill.width/appUnitsPerDevPixel,
|
||||
aFill.height/appUnitsPerDevPixel);
|
||||
PRBool ignoreScale = PR_FALSE;
|
||||
#ifdef MOZ_GFX_OPTIMIZE_MOBILE
|
||||
ignoreScale = PR_TRUE;
|
||||
#endif
|
||||
gfxRect fill = devPixelFill;
|
||||
PRBool didSnap = ctx->UserToDevicePixelSnapped(fill, ignoreScale);
|
||||
|
||||
// Compute dirty rect in gfx space
|
||||
@ -2735,7 +2736,13 @@ nsLayoutUtils::DrawImage(nsIRenderingContext* aRenderingContext,
|
||||
gfxMatrix currentMatrix = ctx->CurrentMatrix();
|
||||
gfxRect finalFillRect = fill;
|
||||
if (didSnap) {
|
||||
ctx->UserToDevicePixelSnapped(anchorPoint, ignoreScale);
|
||||
NS_ASSERTION(!currentMatrix.HasNonAxisAlignedTransform(),
|
||||
"How did we snap, then?");
|
||||
anchorPoint.x = fill.pos.x +
|
||||
(anchorPoint.x - devPixelFill.pos.x)*fill.size.width/devPixelFill.size.width;
|
||||
anchorPoint.y = fill.pos.y +
|
||||
(anchorPoint.y - devPixelFill.pos.y)*fill.size.height/devPixelFill.size.height;
|
||||
anchorPoint.Round();
|
||||
|
||||
// This form of Transform is safe to call since non-axis-aligned
|
||||
// transforms wouldn't be snapped.
|
||||
|
@ -3730,21 +3730,47 @@ nsEventStatus nsPluginInstanceOwner::ProcessEvent(const nsGUIEvent& anEvent)
|
||||
// we can get synthetic events from the nsEventStateManager... these
|
||||
// have no nativeMsg
|
||||
nsPluginEvent pluginEvent;
|
||||
if (!pPluginEvent) {
|
||||
switch (anEvent.message) {
|
||||
case NS_FOCUS_CONTENT:
|
||||
pluginEvent.event = WM_SETFOCUS;
|
||||
pluginEvent.wParam = 0;
|
||||
pluginEvent.lParam = 0;
|
||||
pPluginEvent = &pluginEvent;
|
||||
break;
|
||||
case NS_BLUR_CONTENT:
|
||||
pluginEvent.event = WM_KILLFOCUS;
|
||||
pluginEvent.wParam = 0;
|
||||
pluginEvent.lParam = 0;
|
||||
pPluginEvent = &pluginEvent;
|
||||
break;
|
||||
}
|
||||
switch (anEvent.eventStructType) {
|
||||
case NS_MOUSE_EVENT:
|
||||
// XXX we could synthesize Windows mouse events here for our
|
||||
// synthetic mouse events (i.e. !pPluginEvent)
|
||||
if (pPluginEvent) {
|
||||
// Make event coordinates relative to our enclosing widget,
|
||||
// not the widget they were received on.
|
||||
// See use of nsPluginEvent in widget/src/windows/nsWindow.cpp
|
||||
// for why this assert should be safe
|
||||
NS_ASSERTION(anEvent.message == NS_MOUSE_BUTTON_DOWN ||
|
||||
anEvent.message == NS_MOUSE_BUTTON_UP ||
|
||||
anEvent.message == NS_MOUSE_DOUBLECLICK ||
|
||||
anEvent.message == NS_MOUSE_MOVE,
|
||||
"Incorrect event type for coordinate translation");
|
||||
nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(&anEvent, mOwner);
|
||||
nsPresContext* presContext = mOwner->PresContext();
|
||||
nsIntPoint ptPx(presContext->AppUnitsToDevPixels(pt.x),
|
||||
presContext->AppUnitsToDevPixels(pt.y));
|
||||
nsIntPoint widgetPtPx = ptPx + mOwner->GetWindowOriginInPixels(PR_TRUE);
|
||||
pPluginEvent->lParam = MAKELPARAM(widgetPtPx.x, widgetPtPx.y);
|
||||
}
|
||||
break;
|
||||
|
||||
case NS_FOCUS_EVENT:
|
||||
if (!pPluginEvent) {
|
||||
switch (anEvent.message) {
|
||||
case NS_FOCUS_CONTENT:
|
||||
pluginEvent.event = WM_SETFOCUS;
|
||||
pluginEvent.wParam = 0;
|
||||
pluginEvent.lParam = 0;
|
||||
pPluginEvent = &pluginEvent;
|
||||
break;
|
||||
case NS_BLUR_CONTENT:
|
||||
pluginEvent.event = WM_KILLFOCUS;
|
||||
pluginEvent.wParam = 0;
|
||||
pluginEvent.lParam = 0;
|
||||
pPluginEvent = &pluginEvent;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (pPluginEvent) {
|
||||
|
Before Width: | Height: | Size: 206 B After Width: | Height: | Size: 213 B |
Before Width: | Height: | Size: 112 B After Width: | Height: | Size: 109 B |
Before Width: | Height: | Size: 120 B After Width: | Height: | Size: 118 B |
Before Width: | Height: | Size: 89 B After Width: | Height: | Size: 87 B |
Before Width: | Height: | Size: 98 B After Width: | Height: | Size: 96 B |
@ -28,8 +28,8 @@
|
||||
<div>
|
||||
<div class="cell"><p>32 x 32</p><div style="width:32px; background-position:-16px -16px;" class="image"></div></div>
|
||||
<div class="cell"><p>32.1 x 32</p><div style="width:32px; background-position:-16px -16px;" class="image"></div></div>
|
||||
<div class="cell"><p>32.5 x 32</p><div style="width:33px; background-position:-16px -16px;" class="image"></div></div>
|
||||
<div class="cell"><p>32.8 x 32</p><div style="width:33px; background-position:-16px -16px;" class="image"></div></div>
|
||||
<div class="cell"><p>32.5 x 32</p><div style="width:33px; background-position:-15px -16px;" class="image"></div></div>
|
||||
<div class="cell"><p>32.8 x 32</p><div style="width:33px; background-position:-15px -16px;" class="image"></div></div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
@ -42,8 +42,8 @@
|
||||
<div>
|
||||
<div class="cell"><p>32 x 32 </p><div style="height:32px; background-position:-16px -16px;" class="image"></div></div>
|
||||
<div class="cell"><p>32 x 32.1 </p><div style="height:32px; background-position:-16px -16px;" class="image"></div></div>
|
||||
<div class="cell"><p>32 x 32.5 </p><div style="height:33px; background-position:-16px -16px;" class="image"></div></div>
|
||||
<div class="cell"><p>32 x 32.8 </p><div style="height:33px; background-position:-16px -16px;" class="image"></div></div>
|
||||
<div class="cell"><p>32 x 32.5 </p><div style="height:33px; background-position:-16px -15px;" class="image"></div></div>
|
||||
<div class="cell"><p>32 x 32.8 </p><div style="height:33px; background-position:-16px -15px;" class="image"></div></div>
|
||||
</div>
|
||||
|
||||
</body></html>
|
||||
|
BIN
layout/reftests/bugs/456330-1-ref.png
Normal file
After Width: | Height: | Size: 153 B |
BIN
layout/reftests/bugs/456330-1.gif
Normal file
After Width: | Height: | Size: 62 B |
17
layout/reftests/bugs/463204-1-ref.html
Normal file
@ -0,0 +1,17 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
span {
|
||||
background-image: url(data:image/gif;base64,R0lGODlhEwATAKIAAP//AMzMADMzAP8AAAAAAP///wAAAAAAACH5BAEAAAUALAAAAAATABMAAANWWLrUTisyEoC1oUlFr8dQRHykFRad+Y0gdzlv86KVKdsskOUAjHu312rFK5FuxaMNIMgYe85GrVfKZVDAR7DHmVoG4IHn6vqEgZLU90xOq8OazUS7SQAAOw==);
|
||||
display: inline-block;
|
||||
width: 19px;
|
||||
height: 19px;
|
||||
margin-left: 1px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<span></span>
|
||||
</body>
|
||||
</html>
|
19
layout/reftests/bugs/463204-1.html
Normal file
@ -0,0 +1,19 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
span {
|
||||
background-image: url(data:image/gif;base64,R0lGODlhEwATAKIAAP//AMzMADMzAP8AAAAAAP///wAAAAAAACH5BAEAAAUALAAAAAATABMAAANWWLrUTisyEoC1oUlFr8dQRHykFRad+Y0gdzlv86KVKdsskOUAjHu312rFK5FuxaMNIMgYe85GrVfKZVDAR7DHmVoG4IHn6vqEgZLU90xOq8OazUS7SQAAOw==);
|
||||
display: inline-block;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center center;
|
||||
width: 19px;
|
||||
height: 19px;
|
||||
margin-left: 0.6px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<span></span>
|
||||
</body>
|
||||
</html>
|
@ -939,6 +939,7 @@ fails == 441259-2.html 441259-2-ref.html # bug 441400
|
||||
== 455105-2.html 455105-ref.html
|
||||
== 455280-1.xhtml 455280-1-ref.xhtml
|
||||
fails-if(MOZ_WIDGET_TOOLKIT=="cocoa") == 456147.xul 456147-ref.html # bug 456147, but not caused by it
|
||||
== 456330-1.gif 456330-1-ref.png
|
||||
== 456484-1.html 456484-1-ref.html
|
||||
== 458487-1a.html 458487-1-ref.html
|
||||
== 458487-1b.html 458487-1-ref.html
|
||||
@ -957,3 +958,4 @@ fails-if(MOZ_WIDGET_TOOLKIT=="cocoa") == 456147.xul 456147-ref.html # bug 456147
|
||||
== 458487-5b.html 458487-5-ref.html
|
||||
== 461266-1.html 461266-1-ref.html
|
||||
fails == 461512-1.html 461512-1-ref.html # Bug 461512
|
||||
== 463204-1.html 463204-1-ref.html
|
||||
|
Before Width: | Height: | Size: 135 B After Width: | Height: | Size: 148 B |
Before Width: | Height: | Size: 85 B After Width: | Height: | Size: 82 B |
Before Width: | Height: | Size: 112 B After Width: | Height: | Size: 119 B |
Before Width: | Height: | Size: 112 B After Width: | Height: | Size: 119 B |
Before Width: | Height: | Size: 114 B After Width: | Height: | Size: 115 B |
Before Width: | Height: | Size: 115 B After Width: | Height: | Size: 114 B |
Before Width: | Height: | Size: 394 B After Width: | Height: | Size: 391 B |
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 14 KiB |
23
layout/reftests/text/font-selection-by-lang-01-ref.html
Normal file
@ -0,0 +1,23 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<meta http-equiv="Content-Style-Type" content="text/css">
|
||||
<title>test for font selection by language reference</title>
|
||||
<!-- A unique name is included in font-family
|
||||
to force a new cache entry for each element.
|
||||
-->
|
||||
<style type="text/css">
|
||||
p.a {
|
||||
font-family: sans-serif, font-selection-by-lang-1;
|
||||
}
|
||||
p.b {
|
||||
font-family: sans-serif, font-selection-by-lang-2;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<p class="a" lang="ja">0123456789<p>
|
||||
<p class="b" lang="en">0123456789<p>
|
||||
</body>
|
||||
</html>
|
20
layout/reftests/text/font-selection-by-lang-01.html
Normal file
@ -0,0 +1,20 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<meta http-equiv="Content-Style-Type" content="text/css">
|
||||
<title>test for font selection by language</title>
|
||||
<!-- Checks that caches do not cause the lang="ja" font to be used for
|
||||
the lang="en" element.
|
||||
-->
|
||||
<style type="text/css">
|
||||
p {
|
||||
font-family: sans-serif;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<p lang="ja">0123456789<p>
|
||||
<p lang="en">0123456789<p>
|
||||
</body>
|
||||
</html>
|
@ -1,4 +1,5 @@
|
||||
== fallback-01.xhtml fallback-01-ref.xhtml
|
||||
== font-selection-by-lang-01.html font-selection-by-lang-01-ref.html
|
||||
== justification-1.html justification-1-ref.html
|
||||
== justification-2a.html justification-2-ref.html
|
||||
== justification-2b.html justification-2-ref.html
|
||||
|
Before Width: | Height: | Size: 217 B After Width: | Height: | Size: 228 B |
Before Width: | Height: | Size: 133 B After Width: | Height: | Size: 146 B |
@ -85,9 +85,13 @@ endif
|
||||
endif
|
||||
endif
|
||||
|
||||
ifndef MOZ_SUITE
|
||||
# XXX - Until Suite builds off XULRunner we can't guarantee our implementation
|
||||
# of nsIDownloadManagerUI overrides toolkit's.
|
||||
EXTRA_COMPONENTS = \
|
||||
nsDownloadManagerUI.js \
|
||||
$(NULL)
|
||||
endif
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
|
@ -338,7 +338,8 @@ menupopup,
|
||||
panel,
|
||||
tooltip {
|
||||
display: -moz-popup;
|
||||
z-index: 2147483647;
|
||||
z-index: 2147483647;
|
||||
text-shadow: none;
|
||||
}
|
||||
|
||||
tooltip {
|
||||
|
Before Width: | Height: | Size: 675 B After Width: | Height: | Size: 775 B |
Before Width: | Height: | Size: 773 B After Width: | Height: | Size: 840 B |
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.8 KiB |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 790 B After Width: | Height: | Size: 805 B |
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 412 B After Width: | Height: | Size: 581 B |
Before Width: | Height: | Size: 291 B After Width: | Height: | Size: 377 B |
@ -2419,6 +2419,7 @@ NSEvent* gLastDragEvent = nil;
|
||||
PR_LOG(sCocoaLog, PR_LOG_ALWAYS, ("ChildView initWithFrame: registering drag types\n"));
|
||||
[self registerForDraggedTypes:[NSArray arrayWithObjects:NSFilenamesPboardType,
|
||||
NSStringPboardType,
|
||||
NSHTMLPboardType,
|
||||
NSURLPboardType,
|
||||
NSFilesPromisePboardType,
|
||||
kWildcardPboardType,
|
||||
@ -3152,6 +3153,13 @@ static const PRInt32 sShadowInvalidationInterval = 100;
|
||||
if (!gRollupWidget)
|
||||
return YES;
|
||||
|
||||
// Don't bother if we've been destroyed: mWindow will now be nil, which
|
||||
// makes all our work here pointless, and can even cause us to resend the
|
||||
// event to ourselves in an infinte loop (since targetWindow == mWindow no
|
||||
// longer tests whether targetWindow is us).
|
||||
if (!mGeckoChild || !mWindow)
|
||||
return YES;
|
||||
|
||||
// If this is the rollup widget and the event is not a mouse move then trust the OS routing.
|
||||
// The reason for this trust is complicated.
|
||||
//
|
||||
|
@ -40,6 +40,7 @@
|
||||
#define nsClipboard_h_
|
||||
|
||||
#include "nsBaseClipboard.h"
|
||||
#include "nsXPIDLString.h"
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
@ -59,6 +60,7 @@ public:
|
||||
|
||||
// Helper methods, used also by nsDragService
|
||||
static NSDictionary* PasteboardDictFromTransferable(nsITransferable *aTransferable);
|
||||
static PRBool IsStringType(const nsCString& aMIMEType, const NSString** aPasteboardType);
|
||||
|
||||
protected:
|
||||
|
||||
|
@ -115,6 +115,7 @@ nsClipboard::SetNativeClipboardData(PRInt32 aWhichClipboard)
|
||||
NSString* currentKey = [outputKeys objectAtIndex:i];
|
||||
id currentValue = [pasteboardOutputDict valueForKey:currentKey];
|
||||
if (currentKey == NSStringPboardType ||
|
||||
currentKey == NSHTMLPboardType ||
|
||||
currentKey == kCorePboardType_url ||
|
||||
currentKey == kCorePboardType_urld ||
|
||||
currentKey == kCorePboardType_urln)
|
||||
@ -197,8 +198,9 @@ nsClipboard::GetNativeClipboardData(nsITransferable* aTransferable, PRInt32 aWhi
|
||||
|
||||
// printf("looking for clipboard data of type %s\n", flavorStr.get());
|
||||
|
||||
if (flavorStr.EqualsLiteral(kUnicodeMime)) {
|
||||
NSString* pString = [cocoaPasteboard stringForType:NSStringPboardType];
|
||||
const NSString *pboardType;
|
||||
if (nsClipboard::IsStringType(flavorStr, &pboardType)) {
|
||||
NSString* pString = [cocoaPasteboard stringForType:pboardType];
|
||||
if (!pString)
|
||||
continue;
|
||||
|
||||
@ -339,9 +341,12 @@ nsClipboard::HasDataMatchingFlavors(const char** aFlavorList, PRUint32 aLength,
|
||||
NSPasteboard* generalPBoard = [NSPasteboard generalPasteboard];
|
||||
|
||||
for (PRUint32 i = 0; i < aLength; i++) {
|
||||
if (!strcmp(aFlavorList[i], kUnicodeMime)) {
|
||||
NSString* availableType = [generalPBoard availableTypeFromArray:[NSArray arrayWithObject:NSStringPboardType]];
|
||||
if (availableType && [availableType isEqualToString:NSStringPboardType]) {
|
||||
nsDependentCString mimeType(aFlavorList[i]);
|
||||
const NSString *pboardType;
|
||||
|
||||
if (nsClipboard::IsStringType(mimeType, &pboardType)) {
|
||||
NSString* availableType = [generalPBoard availableTypeFromArray:[NSArray arrayWithObject:pboardType]];
|
||||
if (availableType && [availableType isEqualToString:pboardType]) {
|
||||
*outResult = PR_TRUE;
|
||||
break;
|
||||
}
|
||||
@ -395,7 +400,9 @@ nsClipboard::PasteboardDictFromTransferable(nsITransferable* aTransferable)
|
||||
|
||||
PR_LOG(sCocoaLog, PR_LOG_ALWAYS, ("writing out clipboard data of type %s (%d)\n", flavorStr.get(), i));
|
||||
|
||||
if (flavorStr.EqualsLiteral(kUnicodeMime)) {
|
||||
const NSString *pboardType;
|
||||
|
||||
if (nsClipboard::IsStringType(flavorStr, &pboardType)) {
|
||||
void* data = nsnull;
|
||||
PRUint32 dataSize = 0;
|
||||
nsCOMPtr<nsISupports> genericDataWrapper;
|
||||
@ -405,7 +412,8 @@ nsClipboard::PasteboardDictFromTransferable(nsITransferable* aTransferable)
|
||||
NSString* nativeString = [NSString stringWithCharacters:(const unichar*)data length:(dataSize / sizeof(PRUnichar))];
|
||||
// be nice to Carbon apps, normalize the receiver's contents using Form C.
|
||||
nativeString = [nativeString precomposedStringWithCanonicalMapping];
|
||||
[pasteboardOutputDict setObject:nativeString forKey:NSStringPboardType];
|
||||
|
||||
[pasteboardOutputDict setObject:nativeString forKey:pboardType];
|
||||
|
||||
nsMemory::Free(data);
|
||||
}
|
||||
@ -530,3 +538,17 @@ nsClipboard::PasteboardDictFromTransferable(nsITransferable* aTransferable)
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
|
||||
}
|
||||
|
||||
PRBool nsClipboard::IsStringType(const nsCString& aMIMEType, const NSString** aPasteboardType)
|
||||
{
|
||||
if (aMIMEType.EqualsLiteral(kUnicodeMime) ||
|
||||
aMIMEType.EqualsLiteral(kHTMLMime)) {
|
||||
if (aMIMEType.EqualsLiteral(kUnicodeMime))
|
||||
*aPasteboardType = NSStringPboardType;
|
||||
else
|
||||
*aPasteboardType = NSHTMLPboardType;
|
||||
return PR_TRUE;
|
||||
} else {
|
||||
return PR_FALSE;
|
||||
}
|
||||
}
|
||||
|
@ -138,6 +138,7 @@ static nsresult SetUpDragClipboard(nsISupportsArray* aTransferableArray)
|
||||
NSString* currentKey = [types objectAtIndex:i];
|
||||
id currentValue = [pasteboardOutputDict valueForKey:currentKey];
|
||||
if (currentKey == NSStringPboardType ||
|
||||
currentKey == NSHTMLPboardType ||
|
||||
currentKey == kCorePboardType_url ||
|
||||
currentKey == kCorePboardType_urld ||
|
||||
currentKey == kCorePboardType_urln) {
|
||||
@ -411,11 +412,13 @@ nsDragService::GetData(nsITransferable* aTransferable, PRUint32 aItemIndex)
|
||||
break;
|
||||
}
|
||||
|
||||
if (flavorStr.EqualsLiteral(kUnicodeMime) ||
|
||||
const NSString *pboardType = NSStringPboardType;
|
||||
|
||||
if (nsClipboard::IsStringType(flavorStr, &pboardType) ||
|
||||
flavorStr.EqualsLiteral(kURLMime) ||
|
||||
flavorStr.EqualsLiteral(kURLDataMime) ||
|
||||
flavorStr.EqualsLiteral(kURLDescriptionMime)) {
|
||||
NSString* pString = [globalDragPboard stringForType:NSStringPboardType];
|
||||
NSString* pString = [globalDragPboard stringForType:pboardType];
|
||||
if (!pString)
|
||||
continue;
|
||||
|
||||
@ -512,6 +515,8 @@ nsDragService::IsDataFlavorSupported(const char *aDataFlavor, PRBool *_retval)
|
||||
}
|
||||
}
|
||||
|
||||
const NSString *pboardType;
|
||||
|
||||
if (dataFlavor.EqualsLiteral(kFileMime)) {
|
||||
NSString* availableType = [globalDragPboard availableTypeFromArray:[NSArray arrayWithObject:NSFilenamesPboardType]];
|
||||
if (availableType && [availableType isEqualToString:NSFilenamesPboardType])
|
||||
@ -522,9 +527,9 @@ nsDragService::IsDataFlavorSupported(const char *aDataFlavor, PRBool *_retval)
|
||||
if (availableType && [availableType isEqualToString:kCorePboardType_url])
|
||||
*_retval = PR_TRUE;
|
||||
}
|
||||
else if (dataFlavor.EqualsLiteral(kUnicodeMime)) {
|
||||
NSString* availableType = [globalDragPboard availableTypeFromArray:[NSArray arrayWithObject:NSStringPboardType]];
|
||||
if (availableType && [availableType isEqualToString:NSStringPboardType])
|
||||
else if (nsClipboard::IsStringType(dataFlavor, &pboardType)) {
|
||||
NSString* availableType = [globalDragPboard availableTypeFromArray:[NSArray arrayWithObject:pboardType]];
|
||||
if (availableType && [availableType isEqualToString:pboardType])
|
||||
*_retval = PR_TRUE;
|
||||
}
|
||||
|
||||
|
@ -79,8 +79,11 @@ endif
|
||||
|
||||
# Suite specific includes
|
||||
ifdef MOZ_SUITE
|
||||
ifdef SUITE_USING_XPFE_DM
|
||||
REQUIRES += downloadmanager
|
||||
endif
|
||||
|
||||
REQUIRES += \
|
||||
downloadmanager \
|
||||
intl \
|
||||
mork \
|
||||
widget \
|
||||
|