Merge mozilla-central to tracemonkey.

This commit is contained in:
Robert Sayre 2008-11-08 02:21:20 -05:00
commit a1bf2f89c4
83 changed files with 2259 additions and 890 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.7 KiB

After

Width:  |  Height:  |  Size: 7.7 KiB

View File

@ -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 ()

View File

@ -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">

View File

@ -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);
}

View File

@ -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)) {

View File

@ -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();

View File

@ -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();
}

View File

@ -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();
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 773 B

After

Width:  |  Height:  |  Size: 840 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.2 KiB

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.5 KiB

After

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.7 KiB

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.8 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 807 B

After

Width:  |  Height:  |  Size: 804 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 356 B

After

Width:  |  Height:  |  Size: 395 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 356 B

After

Width:  |  Height:  |  Size: 395 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 379 B

After

Width:  |  Height:  |  Size: 413 B

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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.");

View 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();
}

View File

@ -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 {

View File

@ -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 */

View File

@ -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:

View File

@ -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;
}

View File

@ -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;
};

File diff suppressed because it is too large Load Diff

View File

@ -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;

View File

@ -88,7 +88,7 @@ struct JSONParser {
JSONParserState *statep;
JSONParserState stateStack[JSON_MAX_DEPTH];
jsval *rootVal;
JSString *objectKey;
JSStringBuffer *objectKey;
JSStringBuffer *buffer;
JSObject *objectStack;
};

View File

@ -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

View File

@ -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);

View File

@ -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)
{

View File

@ -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)
{

View File

@ -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);

View File

@ -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.

View File

@ -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) {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 206 B

After

Width:  |  Height:  |  Size: 213 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 112 B

After

Width:  |  Height:  |  Size: 109 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 120 B

After

Width:  |  Height:  |  Size: 118 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 89 B

After

Width:  |  Height:  |  Size: 87 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 98 B

After

Width:  |  Height:  |  Size: 96 B

View File

@ -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>

Binary file not shown.

After

Width:  |  Height:  |  Size: 153 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 B

View 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>

View 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>

View File

@ -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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 135 B

After

Width:  |  Height:  |  Size: 148 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 85 B

After

Width:  |  Height:  |  Size: 82 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 112 B

After

Width:  |  Height:  |  Size: 119 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 112 B

After

Width:  |  Height:  |  Size: 119 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 114 B

After

Width:  |  Height:  |  Size: 115 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 115 B

After

Width:  |  Height:  |  Size: 114 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 394 B

After

Width:  |  Height:  |  Size: 391 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 14 KiB

View 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>

View 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>

View File

@ -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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 217 B

After

Width:  |  Height:  |  Size: 228 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 133 B

After

Width:  |  Height:  |  Size: 146 B

View File

@ -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

View File

@ -338,7 +338,8 @@ menupopup,
panel,
tooltip {
display: -moz-popup;
z-index: 2147483647;
z-index: 2147483647;
text-shadow: none;
}
tooltip {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 675 B

After

Width:  |  Height:  |  Size: 775 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 773 B

After

Width:  |  Height:  |  Size: 840 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 790 B

After

Width:  |  Height:  |  Size: 805 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 412 B

After

Width:  |  Height:  |  Size: 581 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 291 B

After

Width:  |  Height:  |  Size: 377 B

View File

@ -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.
//

View File

@ -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:

View File

@ -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;
}
}

View File

@ -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;
}

View File

@ -79,8 +79,11 @@ endif
# Suite specific includes
ifdef MOZ_SUITE
ifdef SUITE_USING_XPFE_DM
REQUIRES += downloadmanager
endif
REQUIRES += \
downloadmanager \
intl \
mork \
widget \