зеркало из https://github.com/mozilla/gecko-dev.git
Merge last PGO-green changeset of mozilla-inbound to mozilla-central
This commit is contained in:
Коммит
b1b1282206
|
@ -64,6 +64,33 @@ SettingsListener.observe('audio.volume.master', 0.5, function(value) {
|
|||
audioManager.masterVolume = Math.max(0.0, Math.min(value, 1.0));
|
||||
});
|
||||
|
||||
const nsIAudioManager = Ci.nsIAudioManager;
|
||||
let audioSettings = [
|
||||
// settings name, default value, stream type
|
||||
['audio.volume.voice_call', 10, nsIAudioManager.STREAM_TYPE_VOICE_CALL],
|
||||
['audio.volume.system', 10, nsIAudioManager.STREAM_TYPE_SYSTEM],
|
||||
['audio.volume.ring', 7, nsIAudioManager.STREAM_TYPE_RING],
|
||||
['audio.volume.music', 15, nsIAudioManager.STREAM_TYPE_MUSIC],
|
||||
['audio.volume.alarm', 7, nsIAudioManager.STREAM_TYPE_ALARM],
|
||||
['audio.volume.notification', 7, nsIAudioManager.STREAM_TYPE_NOTIFICATION],
|
||||
['audio.volume.bt_sco', 15, nsIAudioManager.STREAM_TYPE_BLUETOOTH_SCO],
|
||||
['audio.volume.enforced_audible', 7, nsIAudioManager.STREAM_TYPE_ENFORCED_AUDIBLE],
|
||||
['audio.volume.dtmf', 15, nsIAudioManager.STREAM_TYPE_DTMF],
|
||||
['audio.volume.tts', 15, nsIAudioManager.STREAM_TYPE_TTS],
|
||||
['audio.volume.fm', 10, nsIAudioManager.STREAM_TYPE_FM],
|
||||
];
|
||||
|
||||
for each (let [setting, defaultValue, streamType] in audioSettings) {
|
||||
(function AudioStreamSettings(s, d, t) {
|
||||
SettingsListener.observe(s, d, function(value) {
|
||||
let audioManager = Services.audioManager;
|
||||
if (!audioManager)
|
||||
return;
|
||||
|
||||
audioManager.setStreamVolumeIndex(t, Math.min(value, d));
|
||||
});
|
||||
})(setting, defaultValue, streamType);
|
||||
}
|
||||
|
||||
// =================== Languages ====================
|
||||
SettingsListener.observe('language.current', 'en-US', function(value) {
|
||||
|
|
|
@ -271,6 +271,7 @@ _BROWSER_FILES = \
|
|||
browser_tabDrop.js \
|
||||
browser_lastAccessedTab.js \
|
||||
browser_bug734076.js \
|
||||
browser_social.js \
|
||||
browser_social_toolbar.js \
|
||||
browser_social_shareButton.js \
|
||||
browser_social_sidebar.js \
|
||||
|
|
|
@ -0,0 +1,92 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
// a place for miscellaneous social tests
|
||||
|
||||
|
||||
const pb = Cc["@mozilla.org/privatebrowsing;1"].
|
||||
getService(Ci.nsIPrivateBrowsingService);
|
||||
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
let manifest = { // normal provider
|
||||
name: "provider 1",
|
||||
origin: "https://example.com",
|
||||
sidebarURL: "https://example.com/browser/browser/base/content/test/social_sidebar.html",
|
||||
workerURL: "https://example.com/browser/browser/base/content/test/social_worker.js",
|
||||
iconURL: "https://example.com/browser/browser/base/content/test/moz.png"
|
||||
};
|
||||
runSocialTestWithProvider(manifest, function (finishcb) {
|
||||
runSocialTests(tests, undefined, undefined, finishcb);
|
||||
});
|
||||
}
|
||||
|
||||
var tests = {
|
||||
testPrivateBrowsing: function(next) {
|
||||
let port = Social.provider.getWorkerPort();
|
||||
ok(port, "provider has a port");
|
||||
port.postMessage({topic: "test-init"});
|
||||
port.onmessage = function (e) {
|
||||
let topic = e.data.topic;
|
||||
switch (topic) {
|
||||
case "got-sidebar-message":
|
||||
ok(true, "got sidebar message");
|
||||
port.close();
|
||||
togglePrivateBrowsing(function () {
|
||||
ok(!Social.enabled, "Social shuts down during private browsing");
|
||||
togglePrivateBrowsing(function () {
|
||||
ok(Social.enabled, "Social enabled after private browsing");
|
||||
next();
|
||||
});
|
||||
});
|
||||
break;
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
testPrivateBrowsingSocialDisabled: function(next) {
|
||||
// test PB from the perspective of entering PB without social enabled
|
||||
// we expect social to be enabled at the start of the test, we need
|
||||
// to disable it before testing PB transitions.
|
||||
let port = Social.provider.getWorkerPort();
|
||||
ok(port, "provider has a port");
|
||||
port.postMessage({topic: "test-init"});
|
||||
port.onmessage = function (e) {
|
||||
let topic = e.data.topic;
|
||||
switch (topic) {
|
||||
case "got-sidebar-message":
|
||||
ok(true, "got sidebar message");
|
||||
port.close();
|
||||
Social.enabled = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// wait for disable, then do some pb toggling. We expect social to remain
|
||||
// disabled through these tests
|
||||
Services.obs.addObserver(function observer(aSubject, aTopic) {
|
||||
Services.obs.removeObserver(observer, aTopic);
|
||||
ok(!Social.enabled, "Social is not enabled");
|
||||
togglePrivateBrowsing(function () {
|
||||
ok(!Social.enabled, "Social not available during private browsing");
|
||||
togglePrivateBrowsing(function () {
|
||||
ok(!Social.enabled, "Social is not enabled after private browsing");
|
||||
// social will be reenabled on start of next social test
|
||||
next();
|
||||
});
|
||||
});
|
||||
}, "social:pref-changed", false);
|
||||
}
|
||||
}
|
||||
|
||||
function togglePrivateBrowsing(aCallback) {
|
||||
Services.obs.addObserver(function observe(subject, topic, data) {
|
||||
Services.obs.removeObserver(observe, topic);
|
||||
executeSoon(aCallback);
|
||||
}, "private-browsing-transition-complete", false);
|
||||
|
||||
pb.privateBrowsingEnabled = !pb.privateBrowsingEnabled;
|
||||
}
|
|
@ -28,6 +28,11 @@ this.Social = {
|
|||
return;
|
||||
}
|
||||
|
||||
if (!this._addedPrivateBrowsingObserver) {
|
||||
Services.obs.addObserver(this, "private-browsing", false);
|
||||
this._addedPrivateBrowsingObserver = true;
|
||||
}
|
||||
|
||||
// Eventually this might want to retrieve a specific provider, but for now
|
||||
// just use the first available.
|
||||
SocialService.getProviderList(function (providers) {
|
||||
|
@ -37,6 +42,17 @@ this.Social = {
|
|||
}.bind(this));
|
||||
},
|
||||
|
||||
observe: function(aSubject, aTopic, aData) {
|
||||
if (aTopic == "private-browsing") {
|
||||
if (aData == "enter") {
|
||||
this._enabledBeforePrivateBrowsing = this.enabled;
|
||||
this.enabled = false;
|
||||
} else if (aData == "exit") {
|
||||
this.enabled = this._enabledBeforePrivateBrowsing;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
get uiVisible() {
|
||||
return this.provider && this.provider.enabled;
|
||||
},
|
||||
|
|
|
@ -3648,6 +3648,41 @@ CanvasRenderingContext2D::IsPointInPath(float x, float y, bool *retVal)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
bool
|
||||
CanvasRenderingContext2D::MozIsPointInStroke(double x, double y)
|
||||
{
|
||||
if (!FloatValidate(x,y)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
EnsureUserSpacePath(false);
|
||||
if (!mPath) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const ContextState &state = CurrentState();
|
||||
|
||||
StrokeOptions strokeOptions(state.lineWidth,
|
||||
state.lineJoin,
|
||||
state.lineCap,
|
||||
state.miterLimit,
|
||||
state.dash.Length(),
|
||||
state.dash.Elements(),
|
||||
state.dashOffset);
|
||||
|
||||
if (mPathTransformWillUpdate) {
|
||||
return mPath->StrokeContainsPoint(strokeOptions, Point(x, y), mPathToDS);
|
||||
}
|
||||
return mPath->StrokeContainsPoint(strokeOptions, Point(x, y), mTarget->GetTransform());
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
CanvasRenderingContext2D::MozIsPointInStroke(float x, float y, bool *retVal)
|
||||
{
|
||||
*retVal = MozIsPointInStroke(x, y);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//
|
||||
// image
|
||||
//
|
||||
|
|
|
@ -246,6 +246,7 @@ public:
|
|||
void Stroke();
|
||||
void Clip();
|
||||
bool IsPointInPath(double x, double y);
|
||||
bool MozIsPointInStroke(double x, double y);
|
||||
void FillText(const nsAString& text, double x, double y,
|
||||
const mozilla::dom::Optional<double>& maxWidth,
|
||||
mozilla::ErrorResult& error);
|
||||
|
|
|
@ -55,6 +55,7 @@ MOCHITEST_FILES = \
|
|||
test_toDataURL_lowercase_ascii.html \
|
||||
test_toDataURL_parameters.html \
|
||||
test_mozGetAsFile.html \
|
||||
test_mozIsPointInStroke.html \
|
||||
test_canvas_strokeStyle_getter.html \
|
||||
test_bug613794.html \
|
||||
test_bug753758.html \
|
||||
|
|
|
@ -0,0 +1,244 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Canvas test: mozIsPointInStroke</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<canvas id="c" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
|
||||
<script type="application/javascript">
|
||||
|
||||
var canvas = document.getElementById('c');
|
||||
var ctx = canvas.getContext('2d');
|
||||
|
||||
|
||||
ctx.lineWidth = 5;
|
||||
|
||||
|
||||
ok(ctx.mozIsPointInStroke(50, 25) === false, 'ctx.mozIsPointInStroke(50, 25) === false');
|
||||
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.rect(0, 0, 20, 20);
|
||||
|
||||
ok(ctx.mozIsPointInStroke(-4, -4) === false, 'ctx.mozIsPointInStroke(-4, -4) === false');
|
||||
ok(ctx.mozIsPointInStroke(4, 4) === false, 'ctx.mozIsPointInStroke(4, 4) === false');
|
||||
ok(ctx.mozIsPointInStroke(16, 16) === false, 'ctx.mozIsPointInStroke(16, 16) === false');
|
||||
ok(ctx.mozIsPointInStroke(24, 24) === false, 'ctx.mozIsPointInStroke(24, 24) === false');
|
||||
|
||||
ok(ctx.mozIsPointInStroke(-2, -2) === true, 'ctx.mozIsPointInStroke(-2, -2) === true');
|
||||
ok(ctx.mozIsPointInStroke(2, 2) === true, 'ctx.mozIsPointInStroke(2, 2) === true');
|
||||
ok(ctx.mozIsPointInStroke(18, 18) === true, 'ctx.mozIsPointInStroke(18, 18) === true');
|
||||
ok(ctx.mozIsPointInStroke(22, 22) === true, 'ctx.mozIsPointInStroke(22, 22) === true');
|
||||
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.rect(25, 25, 20, 20);
|
||||
|
||||
ok(ctx.mozIsPointInStroke(21, 21) === false, 'ctx.mozIsPointInStroke(21, 21) === false');
|
||||
ok(ctx.mozIsPointInStroke(29, 29) === false, 'ctx.mozIsPointInStroke(29, 29) === false');
|
||||
ok(ctx.mozIsPointInStroke(42, 42) === false, 'ctx.mozIsPointInStroke(42, 42) === false');
|
||||
ok(ctx.mozIsPointInStroke(50, 50) === false, 'ctx.mozIsPointInStroke(50, 50) === false');
|
||||
|
||||
ok(ctx.mozIsPointInStroke(23, 23) === true, 'ctx.mozIsPointInStroke(23, 23) === true');
|
||||
ok(ctx.mozIsPointInStroke(27, 27) === true, 'ctx.mozIsPointInStroke(27, 27) === true');
|
||||
ok(ctx.mozIsPointInStroke(43, 43) === true, 'ctx.mozIsPointInStroke(43, 43) === true');
|
||||
ok(ctx.mozIsPointInStroke(47, 47) === true, 'ctx.mozIsPointInStroke(47, 47) === true');
|
||||
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(25, 25);
|
||||
ctx.bezierCurveTo(50, -50, 50, 100, 75, 25);
|
||||
|
||||
ok(ctx.mozIsPointInStroke(23, 26) === false, 'ctx.mozIsPointInStroke(23, 26) === false');
|
||||
ok(ctx.mozIsPointInStroke(75, 23) === false, 'ctx.mozIsPointInStroke(75, 23) === false');
|
||||
ok(ctx.mozIsPointInStroke(37, 8) === false, 'ctx.mozIsPointInStroke(37, 8) === false');
|
||||
ok(ctx.mozIsPointInStroke(61, 42) === false, 'ctx.mozIsPointInStroke(61, 42) === false');
|
||||
|
||||
ok(ctx.mozIsPointInStroke(24, 24) === true, 'ctx.mozIsPointInStroke(24, 24) === true');
|
||||
ok(ctx.mozIsPointInStroke(74, 25) === true, 'ctx.mozIsPointInStroke(74, 25) === true');
|
||||
ok(ctx.mozIsPointInStroke(37, 2) === true, 'ctx.mozIsPointInStroke(37, 2) === true');
|
||||
ok(ctx.mozIsPointInStroke(61, 47) === true, 'ctx.mozIsPointInStroke(61, 47) === true');
|
||||
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.arc(50, 25, 10, 0, Math.PI, false);
|
||||
|
||||
ok(ctx.mozIsPointInStroke(39, 23) === false, 'ctx.mozIsPointInStroke(39, 23) === false');
|
||||
ok(ctx.mozIsPointInStroke(50, 15) === false, 'ctx.mozIsPointInStroke(50, 15) === false');
|
||||
ok(ctx.mozIsPointInStroke(60, 23) === false, 'ctx.mozIsPointInStroke(60, 23) === false');
|
||||
ok(ctx.mozIsPointInStroke(50, 25) === false, 'ctx.mozIsPointInStroke(50, 25) === false');
|
||||
|
||||
ok(ctx.mozIsPointInStroke(39, 26) === true, 'ctx.mozIsPointInStroke(39, 26) === true');
|
||||
ok(ctx.mozIsPointInStroke(45, 33) === true, 'ctx.mozIsPointInStroke(45, 33) === true');
|
||||
ok(ctx.mozIsPointInStroke(53, 33) === true, 'ctx.mozIsPointInStroke(53, 33) === true');
|
||||
ok(ctx.mozIsPointInStroke(59, 26) === true, 'ctx.mozIsPointInStroke(59, 26) === true');
|
||||
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.arc(50, 25, 10, 0, 2 * Math.PI, false);
|
||||
|
||||
ok(ctx.mozIsPointInStroke(34, 25) === false, 'ctx.mozIsPointInStroke(34, 25) === false');
|
||||
ok(ctx.mozIsPointInStroke(44, 25) === false, 'ctx.mozIsPointInStroke(44, 25) === false');
|
||||
ok(ctx.mozIsPointInStroke(49, 30) === false, 'ctx.mozIsPointInStroke(49, 30) === false');
|
||||
ok(ctx.mozIsPointInStroke(49, 40) === false, 'ctx.mozIsPointInStroke(49, 40) === false');
|
||||
|
||||
ok(ctx.mozIsPointInStroke(39, 23) === true, 'ctx.mozIsPointInStroke(39, 23) === true');
|
||||
ok(ctx.mozIsPointInStroke(50, 15) === true, 'ctx.mozIsPointInStroke(50, 15) === true');
|
||||
ok(ctx.mozIsPointInStroke(60, 23) === true, 'ctx.mozIsPointInStroke(60, 23) === true');
|
||||
ok(ctx.mozIsPointInStroke(49, 34) === true, 'ctx.mozIsPointInStroke(49, 34) === true');
|
||||
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.save();
|
||||
ctx.translate(20, 20);
|
||||
ctx.rect(0, 0, 20, 20);
|
||||
|
||||
ok(ctx.mozIsPointInStroke(16, 16) === false, 'ctx.mozIsPointInStroke(16, 16) === false');
|
||||
ok(ctx.mozIsPointInStroke(24, 24) === false, 'ctx.mozIsPointInStroke(24, 24) === false');
|
||||
ok(ctx.mozIsPointInStroke(36, 36) === false, 'ctx.mozIsPointInStroke(36, 36) === false');
|
||||
ok(ctx.mozIsPointInStroke(44, 44) === false, 'ctx.mozIsPointInStroke(44, 44) === false');
|
||||
|
||||
ok(ctx.mozIsPointInStroke(18, 18) === true, 'ctx.mozIsPointInStroke(18, 18) === true');
|
||||
ok(ctx.mozIsPointInStroke(22, 22) === true, 'ctx.mozIsPointInStroke(22, 22) === true');
|
||||
ok(ctx.mozIsPointInStroke(38, 38) === true, 'ctx.mozIsPointInStroke(38, 38) === true');
|
||||
ok(ctx.mozIsPointInStroke(42, 42) === true, 'ctx.mozIsPointInStroke(42, 42) === true');
|
||||
|
||||
ctx.restore();
|
||||
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.save();
|
||||
ctx.scale(-1, 1);
|
||||
ctx.rect(-30, 20, 20, 20);
|
||||
|
||||
ok(ctx.mozIsPointInStroke(16, 16) === false, 'ctx.mozIsPointInStroke(16, 16) === false');
|
||||
ok(ctx.mozIsPointInStroke(14, 24) === false, 'ctx.mozIsPointInStroke(14, 24) === false');
|
||||
ok(ctx.mozIsPointInStroke(26, 36) === false, 'ctx.mozIsPointInStroke(26, 36) === false');
|
||||
ok(ctx.mozIsPointInStroke(34, 44) === false, 'ctx.mozIsPointInStroke(34, 44) === false');
|
||||
|
||||
ok(ctx.mozIsPointInStroke(8, 18) === true, 'ctx.mozIsPointInStroke(8, 18) === true');
|
||||
ok(ctx.mozIsPointInStroke(12, 22) === true, 'ctx.mozIsPointInStroke(12, 22) === true');
|
||||
ok(ctx.mozIsPointInStroke(28, 38) === true, 'ctx.mozIsPointInStroke(28, 38) === true');
|
||||
ok(ctx.mozIsPointInStroke(32, 42) === true, 'ctx.mozIsPointInStroke(32, 42) === true');
|
||||
|
||||
ctx.restore();
|
||||
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.save();
|
||||
ctx.lineWidth = 2;
|
||||
ctx.translate(50, 25);
|
||||
ctx.rotate(180 * Math.PI / 180);
|
||||
ctx.scale(5, 5);
|
||||
ctx.arc(0, 0, 2, 0, Math.PI, false);
|
||||
|
||||
ok(ctx.mozIsPointInStroke(39, 26) === false, 'ctx.mozIsPointInStroke(39, 26) === false');
|
||||
ok(ctx.mozIsPointInStroke(45, 33) === false, 'ctx.mozIsPointInStroke(45, 33) === false');
|
||||
ok(ctx.mozIsPointInStroke(53, 33) === false, 'ctx.mozIsPointInStroke(53, 33) === false');
|
||||
ok(ctx.mozIsPointInStroke(59, 26) === false, 'ctx.mozIsPointInStroke(59, 26) === false');
|
||||
|
||||
ok(ctx.mozIsPointInStroke(39, 23) === true, 'ctx.mozIsPointInStroke(39, 23) === true');
|
||||
ok(ctx.mozIsPointInStroke(45, 15) === true, 'ctx.mozIsPointInStroke(50, 15) === true');
|
||||
ok(ctx.mozIsPointInStroke(55, 15) === true, 'ctx.mozIsPointInStroke(50, 25) === true');
|
||||
ok(ctx.mozIsPointInStroke(60, 23) === true, 'ctx.mozIsPointInStroke(60, 23) === true');
|
||||
|
||||
ctx.restore();
|
||||
|
||||
|
||||
ctx.beginPath();
|
||||
|
||||
ctx.moveTo(10, 10);
|
||||
ctx.lineTo(30, 10);
|
||||
ctx.save();
|
||||
ctx.lineWidth = 2;
|
||||
ctx.scale(5, 5);
|
||||
ctx.lineTo(6, 6);
|
||||
ctx.lineTo(2, 6);
|
||||
ctx.restore();
|
||||
ctx.closePath();
|
||||
|
||||
ok(ctx.mozIsPointInStroke(6, 6) === false, 'ctx.mozIsPointInStroke(6, 6) === false');
|
||||
ok(ctx.mozIsPointInStroke(14, 14) === false, 'ctx.mozIsPointInStroke(14, 14) === false');
|
||||
ok(ctx.mozIsPointInStroke(26, 26) === false, 'ctx.mozIsPointInStroke(26, 26) === false');
|
||||
ok(ctx.mozIsPointInStroke(34, 34) === false, 'ctx.mozIsPointInStroke(34, 34) === false');
|
||||
|
||||
ok(ctx.mozIsPointInStroke(8, 8) === true, 'ctx.mozIsPointInStroke(8, 8) === true');
|
||||
ok(ctx.mozIsPointInStroke(12, 12) === true, 'ctx.mozIsPointInStroke(12, 12) === true');
|
||||
ok(ctx.mozIsPointInStroke(28, 28) === true, 'ctx.mozIsPointInStroke(28, 28) === true');
|
||||
ok(ctx.mozIsPointInStroke(32, 32) === true, 'ctx.mozIsPointInStroke(32, 32) === true');
|
||||
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.rect(-30, -30, 20, 20);
|
||||
|
||||
ok(ctx.mozIsPointInStroke(-34, -34) === false, 'ctx.mozIsPointInStroke(-34, -34) === false');
|
||||
ok(ctx.mozIsPointInStroke(-26, -26) === false, 'ctx.mozIsPointInStroke(-26, -26) === false');
|
||||
ok(ctx.mozIsPointInStroke(-14, -14) === false, 'ctx.mozIsPointInStroke(-14, -14) === false');
|
||||
ok(ctx.mozIsPointInStroke(-6, -6) === false, 'ctx.mozIsPointInStroke(-6, -6) === false');
|
||||
|
||||
ok(ctx.mozIsPointInStroke(-32, -32) === true, 'ctx.mozIsPointInStroke(-32, -32) === true');
|
||||
ok(ctx.mozIsPointInStroke(-28, -28) === true, 'ctx.mozIsPointInStroke(-28, -28) === true');
|
||||
ok(ctx.mozIsPointInStroke(-12, -12) === true, 'ctx.mozIsPointInStroke(-12, -12) === true');
|
||||
ok(ctx.mozIsPointInStroke(-8, -8) === true, 'ctx.mozIsPointInStroke(-8, -8) === true');
|
||||
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(20, 25);
|
||||
ctx.lineTo(80, 25);
|
||||
|
||||
ok(ctx.mozIsPointInStroke(19, 25) === false, 'ctx.mozIsPointInStroke(19, 25) === false');
|
||||
ok(ctx.mozIsPointInStroke(50, 21) === false, 'ctx.mozIsPointInStroke(50, 21) === false');
|
||||
ok(ctx.mozIsPointInStroke(81, 25) === false, 'ctx.mozIsPointInStroke(81, 25) === false');
|
||||
ok(ctx.mozIsPointInStroke(50, 29) === false, 'ctx.mozIsPointInStroke(50, 29) === false');
|
||||
|
||||
ok(ctx.mozIsPointInStroke(21, 25) === true, 'ctx.mozIsPointInStroke(21, 25) === true');
|
||||
ok(ctx.mozIsPointInStroke(50, 23) === true, 'ctx.mozIsPointInStroke(50, 23) === true');
|
||||
ok(ctx.mozIsPointInStroke(79, 25) === true, 'ctx.mozIsPointInStroke(79, 25) === true');
|
||||
ok(ctx.mozIsPointInStroke(50, 27) === true, 'ctx.mozIsPointInStroke(50, 27) === true');
|
||||
|
||||
|
||||
ctx.lineWidth = 15;
|
||||
ctx.lineCap = 'round';
|
||||
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(20, 25);
|
||||
ctx.lineTo(80, 25);
|
||||
|
||||
ok(ctx.mozIsPointInStroke(13, 18) === false, 'ctx.mozIsPointInStroke(13, 18) === false');
|
||||
ok(ctx.mozIsPointInStroke(13, 31) === false, 'ctx.mozIsPointInStroke(13, 31) === false');
|
||||
ok(ctx.mozIsPointInStroke(86, 18) === false, 'ctx.mozIsPointInStroke(86, 18) === false');
|
||||
ok(ctx.mozIsPointInStroke(86, 31) === false, 'ctx.mozIsPointInStroke(86, 31) === false');
|
||||
|
||||
ok(ctx.mozIsPointInStroke(13, 25) === true, 'ctx.mozIsPointInStroke(13, 25) === true');
|
||||
ok(ctx.mozIsPointInStroke(50, 18) === true, 'ctx.mozIsPointInStroke(50, 18) === true');
|
||||
ok(ctx.mozIsPointInStroke(86, 25) === true, 'ctx.mozIsPointInStroke(86, 25) === true');
|
||||
ok(ctx.mozIsPointInStroke(50, 31) === true, 'ctx.mozIsPointInStroke(50, 31) === true');
|
||||
|
||||
|
||||
ctx.lineJoin = 'round';
|
||||
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(20, 15);
|
||||
ctx.lineTo(80, 15);
|
||||
ctx.lineTo(80, 35);
|
||||
|
||||
ok(ctx.mozIsPointInStroke(86, 8) === false, 'ctx.mozIsPointInStroke(86, 8) === false');
|
||||
ok(ctx.mozIsPointInStroke(70, 24) === false, 'ctx.mozIsPointInStroke(70, 24) === false');
|
||||
ok(ctx.mozIsPointInStroke(73, 41) === false, 'ctx.mozIsPointInStroke(73, 41) === false');
|
||||
ok(ctx.mozIsPointInStroke(86, 41) === false, 'ctx.mozIsPointInStroke(86, 41) === false');
|
||||
|
||||
ok(ctx.mozIsPointInStroke(14, 15) === true, 'ctx.mozIsPointInStroke(14, 15) === true');
|
||||
ok(ctx.mozIsPointInStroke(81, 15) === true, 'ctx.mozIsPointInStroke(81, 15) === true');
|
||||
ok(ctx.mozIsPointInStroke(79, 41) === true, 'ctx.mozIsPointInStroke(79, 41) === true');
|
||||
ok(ctx.mozIsPointInStroke(73, 21) === true, 'ctx.mozIsPointInStroke(73, 21) === true');
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1755,8 +1755,6 @@ nsFocusManager::Focus(nsPIDOMWindow* aWindow,
|
|||
// if switching to a new document, first fire the focus event on the
|
||||
// document and then the window.
|
||||
if (aIsNewDocument) {
|
||||
nsIMEStateManager::OnChangeFocus(presShell->GetPresContext(), nullptr,
|
||||
GetFocusMoveActionCause(aFlags));
|
||||
nsIDocument* doc = aWindow->GetExtantDoc();
|
||||
if (doc)
|
||||
SendFocusOrBlurEvent(NS_FOCUS_CONTENT, presShell, doc,
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include <algorithm>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "BindingUtils.h"
|
||||
|
@ -44,6 +45,58 @@ ThrowErrorMessage(JSContext* aCx, const ErrNum aErrorNumber, ...)
|
|||
return false;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
|
||||
struct ErrorResult::Message {
|
||||
nsTArray<nsString> mArgs;
|
||||
dom::ErrNum mErrorNumber;
|
||||
};
|
||||
|
||||
void
|
||||
ErrorResult::ThrowTypeError(const dom::ErrNum errorNumber, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, errorNumber);
|
||||
if (IsTypeError()) {
|
||||
delete mMessage;
|
||||
}
|
||||
mResult = NS_ERROR_TYPE_ERR;
|
||||
Message* message = new Message();
|
||||
message->mErrorNumber = errorNumber;
|
||||
uint16_t argCount =
|
||||
dom::GetErrorMessage(nullptr, nullptr, errorNumber)->argCount;
|
||||
MOZ_ASSERT(argCount <= 10);
|
||||
argCount = std::min<uint16_t>(argCount, 10);
|
||||
while (argCount--) {
|
||||
message->mArgs.AppendElement(*va_arg(ap, nsString*));
|
||||
}
|
||||
mMessage = message;
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void
|
||||
ErrorResult::ReportTypeError(JSContext* aCx)
|
||||
{
|
||||
MOZ_ASSERT(mMessage, "ReportTypeError() can be called only once");
|
||||
|
||||
Message* message = mMessage;
|
||||
const uint32_t argCount = message->mArgs.Length();
|
||||
const jschar* args[11];
|
||||
for (uint32_t i = 0; i < argCount; ++i) {
|
||||
args[i] = message->mArgs.ElementAt(i).get();
|
||||
}
|
||||
args[argCount] = nullptr;
|
||||
|
||||
JS_ReportErrorNumberUCArray(aCx, dom::GetErrorMessage, nullptr,
|
||||
static_cast<const unsigned>(message->mErrorNumber),
|
||||
argCount > 0 ? args : nullptr);
|
||||
|
||||
delete message;
|
||||
mMessage = nullptr;
|
||||
}
|
||||
|
||||
namespace dom {
|
||||
|
||||
bool
|
||||
DefineConstants(JSContext* cx, JSObject* obj, ConstantSpec* cs)
|
||||
{
|
||||
|
|
|
@ -31,14 +31,6 @@ class nsGlobalWindow;
|
|||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
enum ErrNum {
|
||||
#define MSG_DEF(_name, _argc, _str) \
|
||||
_name,
|
||||
#include "mozilla/dom/Errors.msg"
|
||||
#undef MSG_DEF
|
||||
Err_Limit
|
||||
};
|
||||
|
||||
bool
|
||||
ThrowErrorMessage(JSContext* aCx, const ErrNum aErrorNumber, ...);
|
||||
|
||||
|
@ -61,10 +53,14 @@ Throw(JSContext* cx, nsresult rv)
|
|||
|
||||
template<bool mainThread>
|
||||
inline bool
|
||||
ThrowMethodFailedWithDetails(JSContext* cx, const ErrorResult& rv,
|
||||
ThrowMethodFailedWithDetails(JSContext* cx, ErrorResult& rv,
|
||||
const char* /* ifaceName */,
|
||||
const char* /* memberName */)
|
||||
{
|
||||
if (rv.IsTypeError()) {
|
||||
rv.ReportTypeError(cx);
|
||||
return false;
|
||||
}
|
||||
return Throw<mainThread>(cx, rv.ErrorCode());
|
||||
}
|
||||
|
||||
|
|
|
@ -353,14 +353,9 @@ DOMInterfaces = {
|
|||
},
|
||||
|
||||
'TextEncoder': {
|
||||
'headerFile': 'mozilla/dom/TextEncoder.h',
|
||||
'implicitJSContext': [ 'encode' ],
|
||||
},
|
||||
|
||||
'TextDecoder': {
|
||||
'headerFile': 'mozilla/dom/TextDecoder.h',
|
||||
},
|
||||
|
||||
'WebGLActiveInfo': {
|
||||
'nativeType': 'mozilla::WebGLActiveInfo',
|
||||
'headerFile': 'WebGLContext.h',
|
||||
|
|
|
@ -11,22 +11,48 @@
|
|||
#ifndef mozilla_ErrorResult_h
|
||||
#define mozilla_ErrorResult_h
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "jsapi.h"
|
||||
#include "nscore.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
namespace dom {
|
||||
|
||||
enum ErrNum {
|
||||
#define MSG_DEF(_name, _argc, _str) \
|
||||
_name,
|
||||
#include "mozilla/dom/Errors.msg"
|
||||
#undef MSG_DEF
|
||||
Err_Limit
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
||||
class ErrorResult {
|
||||
public:
|
||||
ErrorResult() {
|
||||
mResult = NS_OK;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
~ErrorResult() {
|
||||
MOZ_ASSERT_IF(IsTypeError(), !mMessage);
|
||||
}
|
||||
#endif
|
||||
|
||||
void Throw(nsresult rv) {
|
||||
MOZ_ASSERT(NS_FAILED(rv), "Please don't try throwing success");
|
||||
MOZ_ASSERT(rv != NS_ERROR_TYPE_ERR, "Use ThrowTypeError()");
|
||||
MOZ_ASSERT(!IsTypeError(), "Don't overwite TypeError");
|
||||
mResult = rv;
|
||||
}
|
||||
|
||||
void ThrowTypeError(const dom::ErrNum errorNumber, ...);
|
||||
void ReportTypeError(JSContext* cx);
|
||||
bool IsTypeError() const { return ErrorCode() == NS_ERROR_TYPE_ERR; }
|
||||
|
||||
// In the future, we can add overloads of Throw that take more
|
||||
// interesting things, like strings or DOM exception types or
|
||||
// something if desired.
|
||||
|
@ -35,6 +61,8 @@ public:
|
|||
// Throw() here because people can easily pass success codes to
|
||||
// this.
|
||||
void operator=(nsresult rv) {
|
||||
MOZ_ASSERT(rv != NS_ERROR_TYPE_ERR, "Use ThrowTypeError()");
|
||||
MOZ_ASSERT(!IsTypeError(), "Don't overwite TypeError");
|
||||
mResult = rv;
|
||||
}
|
||||
|
||||
|
@ -48,6 +76,9 @@ public:
|
|||
|
||||
private:
|
||||
nsresult mResult;
|
||||
struct Message;
|
||||
// Do not use nsAutoPtr to avoid extra initalizatoin and check.
|
||||
Message* mMessage;
|
||||
|
||||
// Not to be implemented, to make sure people always pass this by
|
||||
// reference, not by value.
|
||||
|
|
|
@ -32,3 +32,5 @@ MSG_DEF(MSG_ENFORCE_RANGE_OUT_OF_RANGE, 1, "Value is out of range for {0}.")
|
|||
MSG_DEF(MSG_NOT_SEQUENCE, 0, "object can not be converted to a sequence")
|
||||
MSG_DEF(MSG_INVALID_ARG, 2, "argument {0} is not valid for any of the {1}-argument overloads")
|
||||
MSG_DEF(MSG_GLOBAL_NOT_NATIVE, 0, "global is not a native object")
|
||||
MSG_DEF(MSG_ENCODING_NOT_SUPPORTED, 1, "The given encoding '{0}' is not supported.")
|
||||
MSG_DEF(MSG_DOM_ENCODING_NOT_UTF, 0, "The encoding must be utf-8, utf-16, or utf-16be.")
|
||||
|
|
|
@ -191,7 +191,6 @@ nsGonkCameraControl::nsGonkCameraControl(uint32_t aCameraId, nsIThread* aCameraT
|
|||
, mDiscardedFrameCount(0)
|
||||
, mMediaProfiles(nullptr)
|
||||
, mRecorder(nullptr)
|
||||
, mVideoRotation(0)
|
||||
, mVideoFile()
|
||||
, mProfileManager(nullptr)
|
||||
, mRecorderProfile(nullptr)
|
||||
|
@ -1172,7 +1171,7 @@ nsGonkCameraControl::HandleRecorderEvent(int msg, int ext1, int ext2)
|
|||
}
|
||||
|
||||
nsresult
|
||||
nsGonkCameraControl::SetupRecording(int aFd, int64_t aMaxFileSizeBytes, int64_t aMaxVideoLengthMs)
|
||||
nsGonkCameraControl::SetupRecording(int aFd, int aRotation, int64_t aMaxFileSizeBytes, int64_t aMaxVideoLengthMs)
|
||||
{
|
||||
// choosing a size big enough to hold the params
|
||||
const size_t SIZE = 256;
|
||||
|
@ -1200,7 +1199,15 @@ nsGonkCameraControl::SetupRecording(int aFd, int64_t aMaxFileSizeBytes, int64_t
|
|||
snprintf(buffer, SIZE, "max-filesize=%lld", aMaxFileSizeBytes);
|
||||
CHECK_SETARG(mRecorder->setParameters(String8(buffer)));
|
||||
|
||||
snprintf(buffer, SIZE, "video-param-rotation-angle-degrees=%d", mVideoRotation);
|
||||
// adjust rotation by camera sensor offset
|
||||
int r = aRotation;
|
||||
r += GonkCameraHardware::GetSensorOrientation(mHwHandle, GonkCameraHardware::RAW_SENSOR_ORIENTATION);
|
||||
r %= 360;
|
||||
r += 45;
|
||||
r /= 90;
|
||||
r *= 90;
|
||||
DOM_CAMERA_LOGI("setting video rotation to %d degrees (mapped from %d)\n", r, aRotation);
|
||||
snprintf(buffer, SIZE, "video-param-rotation-angle-degrees=%d", r);
|
||||
CHECK_SETARG(mRecorder->setParameters(String8(buffer)));
|
||||
|
||||
CHECK_SETARG(mRecorder->setListener(new GonkRecorderListener(this)));
|
||||
|
@ -1218,7 +1225,6 @@ nsGonkCameraControl::GetPreviewStreamVideoModeImpl(GetPreviewStreamVideoModeTask
|
|||
StopPreviewInternal(true /* forced */);
|
||||
|
||||
// setup the video mode
|
||||
mVideoRotation = aGetPreviewStreamVideoMode->mOptions.rotation;
|
||||
nsresult rv = SetupVideoMode(aGetPreviewStreamVideoMode->mOptions.profile);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
|
@ -1226,7 +1232,7 @@ nsGonkCameraControl::GetPreviewStreamVideoModeImpl(GetPreviewStreamVideoModeTask
|
|||
int width = video->GetWidth();
|
||||
int height = video->GetHeight();
|
||||
int fps = video->GetFramerate();
|
||||
DOM_CAMERA_LOGI("recording preview format: %d x %d (rotated %d degrees)\n", width, height, fps);
|
||||
DOM_CAMERA_LOGI("recording preview format: %d x %d (%d fps)\n", width, height, fps);
|
||||
|
||||
// create and return new preview stream object
|
||||
nsCOMPtr<GetPreviewStreamResult> getPreviewStreamResult = new GetPreviewStreamResult(this, width, height, fps, aGetPreviewStreamVideoMode->mOnSuccessCb, mWindowId);
|
||||
|
|
|
@ -56,7 +56,7 @@ public:
|
|||
nsresult GetVideoSizes(nsTArray<CameraSize>& aVideoSizes);
|
||||
nsresult PushParameters();
|
||||
|
||||
nsresult SetupRecording(int aFd, int64_t aMaxFileSizeBytes = -1, int64_t aMaxVideoLengthMs = -1);
|
||||
nsresult SetupRecording(int aFd, int aRotation = 0, int64_t aMaxFileSizeBytes = -1, int64_t aMaxVideoLengthMs = -1);
|
||||
nsresult SetupVideoMode(const nsAString& aProfile);
|
||||
|
||||
void AutoFocusComplete(bool aSuccess);
|
||||
|
@ -107,7 +107,6 @@ protected:
|
|||
android::MediaProfiles* mMediaProfiles;
|
||||
android::GonkRecorder* mRecorder;
|
||||
|
||||
uint32_t mVideoRotation;
|
||||
nsString mVideoFile;
|
||||
|
||||
// camcorder profile settings for the desired quality level
|
||||
|
|
|
@ -193,18 +193,21 @@ GonkCameraHardware::Init()
|
|||
if (rv != 0) {
|
||||
return;
|
||||
}
|
||||
mSensorOrientation = info.orientation;
|
||||
mRawSensorOrientation = info.orientation;
|
||||
mSensorOrientation = mRawSensorOrientation;
|
||||
|
||||
// Some kernels report the wrong sensor orientation through
|
||||
// get_camera_info()...
|
||||
char propname[PROP_NAME_MAX];
|
||||
char prop[PROP_VALUE_MAX];
|
||||
int offset = 0;
|
||||
snprintf(propname, sizeof(propname), "ro.moz.cam.%d.sensor_offset", mCamera);
|
||||
if (__system_property_get(propname, prop) > 0) {
|
||||
int offset = clamped(atoi(prop), 0, 270);
|
||||
offset = clamped(atoi(prop), 0, 270);
|
||||
mSensorOrientation += offset;
|
||||
mSensorOrientation %= 360;
|
||||
}
|
||||
DOM_CAMERA_LOGI("Sensor orientation: base=%d, offset=%d, final=%d\n", info.orientation, offset, mSensorOrientation);
|
||||
|
||||
if (sHwHandle == 0) {
|
||||
sHwHandle = 1; // don't use 0
|
||||
|
@ -271,14 +274,24 @@ GonkCameraHardware::GetHandle(GonkCamera* aTarget, uint32_t aCamera)
|
|||
}
|
||||
|
||||
int
|
||||
GonkCameraHardware::GetSensorOrientation(uint32_t aHwHandle)
|
||||
GonkCameraHardware::GetSensorOrientation(uint32_t aHwHandle, uint32_t aType)
|
||||
{
|
||||
DOM_CAMERA_LOGI("%s: aHwHandle = %d\n", __func__, aHwHandle);
|
||||
GonkCameraHardware* hw = GetHardware(aHwHandle);
|
||||
if (!hw) {
|
||||
return 0;
|
||||
}
|
||||
return hw->mSensorOrientation;
|
||||
switch (aType) {
|
||||
case OFFSET_SENSOR_ORIENTATION:
|
||||
return hw->mSensorOrientation;
|
||||
|
||||
case RAW_SENSOR_ORIENTATION:
|
||||
return hw->mRawSensorOrientation;
|
||||
|
||||
default:
|
||||
DOM_CAMERA_LOGE("%s:%d : unknown aType=%d\n", __func__, __LINE__, aType);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
|
|
|
@ -65,8 +65,16 @@ public:
|
|||
* right edge of the screen in natural orientation, the value should be
|
||||
* 90. If the top side of a front-facing camera sensor is aligned with the
|
||||
* right of the screen, the value should be 270.
|
||||
*
|
||||
* RAW_SENSOR_ORIENTATION is the uncorrected orientation returned directly
|
||||
* by get_camera_info(); OFFSET_SENSOR_ORIENTATION is the offset adjusted
|
||||
* orientation.
|
||||
*/
|
||||
static int GetSensorOrientation(uint32_t aHwHandle);
|
||||
enum {
|
||||
RAW_SENSOR_ORIENTATION,
|
||||
OFFSET_SENSOR_ORIENTATION
|
||||
};
|
||||
static int GetSensorOrientation(uint32_t aHwHandle, uint32_t aType = OFFSET_SENSOR_ORIENTATION);
|
||||
|
||||
static int AutoFocus(uint32_t aHwHandle);
|
||||
static void CancelAutoFocus(uint32_t aHwHandle);
|
||||
|
@ -116,6 +124,7 @@ protected:
|
|||
#endif
|
||||
sp<GonkCameraListener> mListener;
|
||||
bool mInitialized;
|
||||
int mRawSensorOrientation;
|
||||
int mSensorOrientation;
|
||||
|
||||
bool IsInitialized()
|
||||
|
|
|
@ -21,21 +21,10 @@ TextDecoder::Init(const nsAString& aEncoding,
|
|||
nsAutoString label(aEncoding);
|
||||
EncodingUtils::TrimSpaceCharacters(label);
|
||||
|
||||
// If label is a case-insensitive match for "utf-16"
|
||||
// then set the internal useBOM flag.
|
||||
if (label.LowerCaseEqualsLiteral("utf-16")) {
|
||||
mUseBOM = true;
|
||||
mIsUTF16Family = true;
|
||||
mEncoding = "utf-16le";
|
||||
// If BOM is used, we can't determine the converter yet.
|
||||
return;
|
||||
}
|
||||
|
||||
// Run the steps to get an encoding from Encoding.
|
||||
// Let encoding be the result of getting an encoding from label.
|
||||
// If encoding is failure, throw a TypeError.
|
||||
if (!EncodingUtils::FindEncodingForLabel(label, mEncoding)) {
|
||||
// If the steps result in failure,
|
||||
// throw a "EncodingError" exception and terminate these steps.
|
||||
aRv.Throw(NS_ERROR_DOM_ENCODING_NOT_SUPPORTED_ERR);
|
||||
aRv.ThrowTypeError(MSG_ENCODING_NOT_SUPPORTED, &label);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -47,12 +36,6 @@ TextDecoder::Init(const nsAString& aEncoding,
|
|||
// set the internal fatal flag of the decoder object.
|
||||
mFatal = aFatal.fatal;
|
||||
|
||||
CreateDecoder(aRv);
|
||||
}
|
||||
|
||||
void
|
||||
TextDecoder::CreateDecoder(ErrorResult& aRv)
|
||||
{
|
||||
// Create a decoder object for mEncoding.
|
||||
nsCOMPtr<nsICharsetConverterManager> ccm =
|
||||
do_GetService(NS_CHARSETCONVERTERMANAGER_CONTRACTID);
|
||||
|
@ -73,12 +56,10 @@ TextDecoder::CreateDecoder(ErrorResult& aRv)
|
|||
}
|
||||
|
||||
void
|
||||
TextDecoder::ResetDecoder(bool aResetOffset)
|
||||
TextDecoder::ResetDecoder()
|
||||
{
|
||||
mDecoder->Reset();
|
||||
if (aResetOffset) {
|
||||
mOffset = 0;
|
||||
}
|
||||
mOffset = 0;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -192,22 +173,7 @@ TextDecoder::HandleBOM(const char*& aData, uint32_t& aLength,
|
|||
strcmp(encoding, mEncoding)) {
|
||||
// If the stream doesn't start with BOM or the BOM doesn't match the
|
||||
// encoding, feed a BOM to workaround decoder's bug (bug 634541).
|
||||
if (!mUseBOM) {
|
||||
FeedBytes(!strcmp(mEncoding, "utf-16le") ? "\xFF\xFE" : "\xFE\xFF");
|
||||
}
|
||||
}
|
||||
if (mUseBOM) {
|
||||
// Select a decoder corresponding to the BOM.
|
||||
if (!*encoding) {
|
||||
encoding = "utf-16le";
|
||||
}
|
||||
// If the endian has not been changed, reuse the decoder.
|
||||
if (mDecoder && !strcmp(encoding, mEncoding)) {
|
||||
ResetDecoder(false);
|
||||
} else {
|
||||
mEncoding = encoding;
|
||||
CreateDecoder(aRv);
|
||||
}
|
||||
FeedBytes(!strcmp(mEncoding, "utf-16le") ? "\xFF\xFE" : "\xFE\xFF");
|
||||
}
|
||||
FeedBytes(mInitialBytes, &aOutString);
|
||||
}
|
||||
|
@ -235,7 +201,7 @@ TextDecoder::GetEncoding(nsAString& aEncoding)
|
|||
// "utf-16".
|
||||
// This workaround should not be exposed to the public API and so "utf-16"
|
||||
// is returned by GetEncoding() if the internal encoding name is "utf-16le".
|
||||
if (mUseBOM || !strcmp(mEncoding, "utf-16le")) {
|
||||
if (!strcmp(mEncoding, "utf-16le")) {
|
||||
aEncoding.AssignLiteral("utf-16");
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -41,8 +41,7 @@ public:
|
|||
}
|
||||
|
||||
TextDecoder(nsISupports* aGlobal)
|
||||
: mGlobal(aGlobal)
|
||||
, mFatal(false), mUseBOM(false), mOffset(0), mIsUTF16Family(false)
|
||||
: mGlobal(aGlobal), mFatal(false), mOffset(0), mIsUTF16Family(false)
|
||||
{
|
||||
MOZ_ASSERT(aGlobal);
|
||||
SetIsDOMBinding();
|
||||
|
@ -97,7 +96,6 @@ private:
|
|||
nsCOMPtr<nsIUnicodeDecoder> mDecoder;
|
||||
nsCOMPtr<nsISupports> mGlobal;
|
||||
bool mFatal;
|
||||
bool mUseBOM;
|
||||
uint8_t mOffset;
|
||||
char mInitialBytes[3];
|
||||
bool mIsUTF16Family;
|
||||
|
@ -117,8 +115,7 @@ private:
|
|||
ErrorResult& aRv);
|
||||
|
||||
// Internal helper functions.
|
||||
void CreateDecoder(ErrorResult& aRv);
|
||||
void ResetDecoder(bool aResetOffset = true);
|
||||
void ResetDecoder();
|
||||
void HandleBOM(const char*& aData, uint32_t& aLength,
|
||||
const TextDecodeOptions& aOptions,
|
||||
nsAString& aOutString, ErrorResult& aRv);
|
||||
|
|
|
@ -18,21 +18,18 @@ TextEncoder::Init(const nsAString& aEncoding,
|
|||
nsAutoString label(aEncoding);
|
||||
EncodingUtils::TrimSpaceCharacters(label);
|
||||
|
||||
// Run the steps to get an encoding from Encoding.
|
||||
// Let encoding be the result of getting an encoding from label.
|
||||
// If encoding is failure, or is none of utf-8, utf-16, and utf-16be,
|
||||
// throw a TypeError.
|
||||
if (!EncodingUtils::FindEncodingForLabel(label, mEncoding)) {
|
||||
// If the steps result in failure,
|
||||
// throw an "EncodingError" exception and terminate these steps.
|
||||
aRv.Throw(NS_ERROR_DOM_ENCODING_NOT_SUPPORTED_ERR);
|
||||
aRv.ThrowTypeError(MSG_ENCODING_NOT_SUPPORTED, &label);
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise, if the Name of the returned encoding is not one of
|
||||
// "utf-8", "utf-16", or "utf-16be" throw an "EncodingError" exception
|
||||
// and terminate these steps.
|
||||
if (PL_strcasecmp(mEncoding, "utf-8") &&
|
||||
PL_strcasecmp(mEncoding, "utf-16le") &&
|
||||
PL_strcasecmp(mEncoding, "utf-16be")) {
|
||||
aRv.Throw(NS_ERROR_DOM_ENCODING_NOT_UTF_ERR);
|
||||
aRv.ThrowTypeError(MSG_DOM_ENCODING_NOT_UTF);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@ function testBOMEncodingUTF8() {
|
|||
|
||||
// test empty encoding provided with invalid byte OM also provided.
|
||||
data = [0xFF, 0xFE, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27];
|
||||
testBOMCharset({encoding: "", data: data, error: "EncodingError",
|
||||
testBOMCharset({encoding: "", data: data, error: "TypeError",
|
||||
msg: "empty encoding provided with invalid utf-8 BOM test."});
|
||||
}
|
||||
|
||||
|
@ -65,18 +65,17 @@ function testMoreBOMEncoding() {
|
|||
// Testing user provided encoding is UTF-16LE & bom encoding is utf-16be
|
||||
var dataUTF16 = [0xFE, 0xFF, 0x22, 0x00, 0x12, 0x04, 0x41, 0x04, 0x35, 0x04, 0x20, 0x00, 0x41, 0x04, 0x47, 0x04, 0x30, 0x04, 0x41, 0x04, 0x42, 0x04, 0x3B, 0x04, 0x38, 0x04, 0x32, 0x04, 0x4B, 0x04, 0x35, 0x04, 0x20, 0x00, 0x41, 0x04, 0x35, 0x04, 0x3C, 0x04, 0x4C, 0x04, 0x38, 0x04, 0x20, 0x00, 0x3F, 0x04, 0x3E, 0x04, 0x45, 0x04, 0x3E, 0x04, 0x36, 0x04, 0x38, 0x04, 0x20, 0x00, 0x34, 0x04, 0x40, 0x04, 0x43, 0x04, 0x33, 0x04, 0x20, 0x00, 0x3D, 0x04, 0x30, 0x04, 0x20, 0x00, 0x34, 0x04, 0x40, 0x04, 0x43, 0x04, 0x33, 0x04, 0x30, 0x04, 0x2C, 0x00, 0x20, 0x00, 0x3A, 0x04, 0x30, 0x04, 0x36, 0x04, 0x34, 0x04, 0x30, 0x04, 0x4F, 0x04, 0x20, 0x00, 0x3D, 0x04, 0x35, 0x04, 0x41, 0x04, 0x47, 0x04, 0x30, 0x04, 0x41, 0x04, 0x42, 0x04, 0x3B, 0x04, 0x38, 0x04, 0x32, 0x04, 0x30, 0x04, 0x4F, 0x04, 0x20, 0x00, 0x41, 0x04, 0x35, 0x04, 0x3C, 0x04, 0x4C, 0x04, 0x4F, 0x04, 0x20, 0x00, 0x3D, 0x04, 0x35, 0x04, 0x41, 0x04, 0x47, 0x04, 0x30, 0x04, 0x41, 0x04, 0x42, 0x04, 0x3B, 0x04, 0x38, 0x04, 0x32, 0x04, 0x30, 0x04, 0x20, 0x00, 0x3F, 0x04, 0x3E, 0x04, 0x2D, 0x00, 0x41, 0x04, 0x32, 0x04, 0x3E, 0x04, 0x35, 0x04, 0x3C, 0x04, 0x43, 0x04, 0x2E, 0x00, 0x22, 0x00];
|
||||
testBOMCharset({encoding: "utf-16le", fatal: true, data: dataUTF16, expected: "\ufffe" + expectedString,
|
||||
msg: "test decoder invalid BOM encoding for utf-16 fatal."});
|
||||
msg: "test decoder invalid BOM encoding for utf-16le fatal."});
|
||||
|
||||
testBOMCharset({encoding: "utf-16le", data: dataUTF16, expected: "\ufffe" + expectedString,
|
||||
msg: "test decoder invalid BOM encoding for utf-16."});
|
||||
msg: "test decoder invalid BOM encoding for utf-16le."});
|
||||
|
||||
// Testing user provided encoding is UTF-16 & bom encoding is utf-16be
|
||||
data = [0xFE, 0xFF, 0x00, 0x22, 0x04, 0x12, 0x04, 0x41, 0x04, 0x35, 0x00, 0x20, 0x04, 0x41, 0x04, 0x47, 0x04, 0x30, 0x04, 0x41, 0x04, 0x42, 0x04, 0x3B, 0x04, 0x38, 0x04, 0x32, 0x04, 0x4B, 0x04, 0x35, 0x00, 0x20, 0x04, 0x41, 0x04, 0x35, 0x04, 0x3C, 0x04, 0x4C, 0x04, 0x38, 0x00, 0x20, 0x04, 0x3F, 0x04, 0x3E, 0x04, 0x45, 0x04, 0x3E, 0x04, 0x36, 0x04, 0x38, 0x00, 0x20, 0x04, 0x34, 0x04, 0x40, 0x04, 0x43, 0x04, 0x33, 0x00, 0x20, 0x04, 0x3D, 0x04, 0x30, 0x00, 0x20, 0x04, 0x34, 0x04, 0x40, 0x04, 0x43, 0x04, 0x33, 0x04, 0x30, 0x00, 0x2C, 0x00, 0x20, 0x04, 0x3A, 0x04, 0x30, 0x04, 0x36, 0x04, 0x34, 0x04, 0x30, 0x04, 0x4F, 0x00, 0x20, 0x04, 0x3D, 0x04, 0x35, 0x04, 0x41, 0x04, 0x47, 0x04, 0x30, 0x04, 0x41, 0x04, 0x42, 0x04, 0x3B, 0x04, 0x38, 0x04, 0x32, 0x04, 0x30, 0x04, 0x4F, 0x00, 0x20, 0x04, 0x41, 0x04, 0x35, 0x04, 0x3C, 0x04, 0x4C, 0x04, 0x4F, 0x00, 0x20, 0x04, 0x3D, 0x04, 0x35, 0x04, 0x41, 0x04, 0x47, 0x04, 0x30, 0x04, 0x41, 0x04, 0x42, 0x04, 0x3B, 0x04, 0x38, 0x04, 0x32, 0x04, 0x30, 0x00, 0x20, 0x04, 0x3F, 0x04, 0x3E, 0x00, 0x2D, 0x04, 0x41, 0x04, 0x32, 0x04, 0x3E, 0x04, 0x35, 0x04, 0x3C, 0x04, 0x43, 0x00, 0x2E, 0x00, 0x22];
|
||||
testBOMCharset({encoding: "utf-16", fatal: true, data: data, expected: expectedString,
|
||||
msg: "test decoder BOM encoding for utf-16 fatal."});
|
||||
testBOMCharset({encoding: "utf-16", fatal: true, data: dataUTF16, expected: "\ufffe" + expectedString,
|
||||
msg: "test decoder invalid BOM encoding for utf-16 fatal."});
|
||||
|
||||
testBOMCharset({encoding: "utf-16", data: data, expected: expectedString,
|
||||
msg: "test decoder BOM encoding for utf-16."});
|
||||
testBOMCharset({encoding: "utf-16", data: dataUTF16, expected: "\ufffe" + expectedString,
|
||||
msg: "test decoder invalid BOM encoding for utf-16."});
|
||||
|
||||
// Testing user provided encoding is UTF-16 & bom encoding is utf-16le
|
||||
dataUTF16 = [0xFF, 0xFE, 0x22, 0x00, 0x12, 0x04, 0x41, 0x04, 0x35, 0x04, 0x20, 0x00, 0x41, 0x04, 0x47, 0x04, 0x30, 0x04, 0x41, 0x04, 0x42, 0x04, 0x3B, 0x04, 0x38, 0x04, 0x32, 0x04, 0x4B, 0x04, 0x35, 0x04, 0x20, 0x00, 0x41, 0x04, 0x35, 0x04, 0x3C, 0x04, 0x4C, 0x04, 0x38, 0x04, 0x20, 0x00, 0x3F, 0x04, 0x3E, 0x04, 0x45, 0x04, 0x3E, 0x04, 0x36, 0x04, 0x38, 0x04, 0x20, 0x00, 0x34, 0x04, 0x40, 0x04, 0x43, 0x04, 0x33, 0x04, 0x20, 0x00, 0x3D, 0x04, 0x30, 0x04, 0x20, 0x00, 0x34, 0x04, 0x40, 0x04, 0x43, 0x04, 0x33, 0x04, 0x30, 0x04, 0x2C, 0x00, 0x20, 0x00, 0x3A, 0x04, 0x30, 0x04, 0x36, 0x04, 0x34, 0x04, 0x30, 0x04, 0x4F, 0x04, 0x20, 0x00, 0x3D, 0x04, 0x35, 0x04, 0x41, 0x04, 0x47, 0x04, 0x30, 0x04, 0x41, 0x04, 0x42, 0x04, 0x3B, 0x04, 0x38, 0x04, 0x32, 0x04, 0x30, 0x04, 0x4F, 0x04, 0x20, 0x00, 0x41, 0x04, 0x35, 0x04, 0x3C, 0x04, 0x4C, 0x04, 0x4F, 0x04, 0x20, 0x00, 0x3D, 0x04, 0x35, 0x04, 0x41, 0x04, 0x47, 0x04, 0x30, 0x04, 0x41, 0x04, 0x42, 0x04, 0x3B, 0x04, 0x38, 0x04, 0x32, 0x04, 0x30, 0x04, 0x20, 0x00, 0x3F, 0x04, 0x3E, 0x04, 0x2D, 0x00, 0x41, 0x04, 0x32, 0x04, 0x3E, 0x04, 0x35, 0x04, 0x3C, 0x04, 0x43, 0x04, 0x2E, 0x00, 0x22, 0x00];
|
||||
|
|
|
@ -72,19 +72,19 @@ function testConstructorEncodingOption(aData, aExpectedString)
|
|||
msg: "decoder testing constructor valid encoding."});
|
||||
|
||||
// invalid encoding passed
|
||||
testCharset({encoding: "asdfasdf", input: aData, error: "EncodingError",
|
||||
testCharset({encoding: "asdfasdf", input: aData, error: "TypeError",
|
||||
msg: "constructor encoding, invalid encoding test."});
|
||||
|
||||
// passing spaces for encoding
|
||||
testCharset({encoding: " ", input: aData, error: "EncodingError",
|
||||
testCharset({encoding: " ", input: aData, error: "TypeError",
|
||||
msg: "constructor encoding, spaces encoding test."});
|
||||
|
||||
// passing null for encoding
|
||||
testCharset({encoding: null, input: aData, error: "EncodingError",
|
||||
testCharset({encoding: null, input: aData, error: "TypeError",
|
||||
msg: "constructor encoding, \"null\" encoding test."});
|
||||
|
||||
// empty encoding passed
|
||||
testCharset({encoding: "", input: aData, error: "EncodingError",
|
||||
testCharset({encoding: "", input: aData, error: "TypeError",
|
||||
msg: "constuctor encoding, empty encoding test."});
|
||||
|
||||
// replacement character test
|
||||
|
@ -184,10 +184,10 @@ function testDecodeStreamCompositions() {
|
|||
{encoding: "utf-16", input: [0xFF,0xFE,0x01,0x00], expected: ["","","","\x01"]},
|
||||
{encoding: "utf-16", input: [0xFF,0xFE,0xFF,0xFE], expected: ["","","","\uFEFF"]},
|
||||
{encoding: "utf-16", input: [0xFF,0xFE,0xFE,0xFF], expected: ["","","","\uFFFE"]},
|
||||
{encoding: "utf-16", input: [0xFE,0xFF], expected: ["",""]},
|
||||
{encoding: "utf-16", input: [0xFE,0xFF,0x01,0x00], expected: ["","","","\u0100"]},
|
||||
{encoding: "utf-16", input: [0xFE,0xFF,0xFF,0xFE], expected: ["","","","\uFFFE"]},
|
||||
{encoding: "utf-16", input: [0xFE,0xFF,0xFE,0xFF], expected: ["","","","\uFEFF"]},
|
||||
{encoding: "utf-16", input: [0xFE,0xFF], expected: ["","\uFFFE"]},
|
||||
{encoding: "utf-16", input: [0xFE,0xFF,0x01,0x00], expected: ["","\uFFFE","","\x01"]},
|
||||
{encoding: "utf-16", input: [0xFE,0xFF,0xFF,0xFE], expected: ["","\uFFFE","","\uFEFF"]},
|
||||
{encoding: "utf-16", input: [0xFE,0xFF,0xFE,0xFF], expected: ["","\uFFFE","","\uFFFE"]},
|
||||
{encoding: "utf-16le", input: [0x01,0x00], expected: ["","\x01"]},
|
||||
{encoding: "utf-16le", input: [0x01,0x00,0x03,0x02], expected: ["","\x01","","\u0203"]},
|
||||
{encoding: "utf-16le", input: [0xFF,0xFE,0x01,0x00], expected: ["","","","\x01"]},
|
||||
|
@ -337,7 +337,7 @@ function testDecoderGetEncoding()
|
|||
{encoding: "utf-16", labels: ["utf-16", "utf-16le"]},
|
||||
{encoding: "utf-16be", labels: ["utf-16be"]},
|
||||
{encoding: "x-user-defined", labels: ["x-user-defined"]},
|
||||
{error: "EncodingError", labels: ["x-windows-949", "\u0130SO-8859-1"]},
|
||||
{error: "TypeError", labels: ["x-windows-949", "\u0130SO-8859-1"]},
|
||||
];
|
||||
|
||||
for (var le of labelEncodings) {
|
||||
|
|
|
@ -95,26 +95,26 @@ function testConstructorEncodingOption(aData, aExpectedString)
|
|||
msg: "testing encoding with valid utf-8 encoding."});
|
||||
|
||||
// passing spaces for encoding
|
||||
testSingleString({encoding: " ", input: aData, error: "EncodingError",
|
||||
testSingleString({encoding: " ", input: aData, error: "TypeError",
|
||||
msg: "constructor encoding, spaces encoding test."});
|
||||
|
||||
// invalid encoding passed
|
||||
testSingleString({encoding: "asdfasdf", input: aData, error: "EncodingError",
|
||||
testSingleString({encoding: "asdfasdf", input: aData, error: "TypeError",
|
||||
msg: "constructor encoding, invalid encoding test."});
|
||||
|
||||
// null encoding passed
|
||||
testSingleString({encoding: null, input: aData, error: "EncodingError",
|
||||
testSingleString({encoding: null, input: aData, error: "TypeError",
|
||||
msg: "constructor encoding, \"null\" encoding test."});
|
||||
|
||||
// null encoding passed
|
||||
testSingleString({encoding: "", input: aData, error: "EncodingError",
|
||||
testSingleString({encoding: "", input: aData, error: "TypeError",
|
||||
msg: "constructor encoding, empty encoding test."});
|
||||
}
|
||||
|
||||
function testEncodingValues(aData, aExpectedString)
|
||||
{
|
||||
var encoding = "ISO-8859-11";
|
||||
testSingleString({encoding: aData, input: encoding, error: "EncodingError",
|
||||
testSingleString({encoding: aData, input: encoding, error: "TypeError",
|
||||
msg: "encoder encoding values test."});
|
||||
}
|
||||
|
||||
|
|
|
@ -1,30 +1,30 @@
|
|||
<!DOCTYPE html>
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset=utf-8>
|
||||
<title>Encoding API Tests</title>
|
||||
<link rel="stylesheet" href="/resources/testharness.css">
|
||||
</head>
|
||||
<body>
|
||||
<h1>Encoding API Tests</h1>
|
||||
<div id="log"></div>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script>
|
||||
var _test = test;
|
||||
test = function(msg, no, func) { _test(func || no, msg); };
|
||||
equal = assert_equals;
|
||||
ok = assert_true;
|
||||
raises = function(func) { assert_throws(null, func); };
|
||||
expect = function() {};
|
||||
setup({explicit_timeout: true});
|
||||
</script>
|
||||
|
||||
<div id="log"></div>
|
||||
|
||||
<script type="text/javascript" src="unit/test_singlebytes.js"></script>
|
||||
<!-- TODO: test for all single-byte encoding indexes -->
|
||||
|
||||
<script type="text/javascript" src="unit/test_gbk.js"></script>
|
||||
<!-- TODO: gb18030 -->
|
||||
<script type="text/javascript" src="unit/test_hz-gb-2312.js"></script>
|
||||
|
||||
<script type="text/javascript" src="unit/test_big5.js"></script>
|
||||
|
||||
<script type="text/javascript" src="unit/test_euc-jp.js"></script>
|
||||
<script type="text/javascript" src="unit/test_iso-2022-jp.js"></script>
|
||||
<script type="text/javascript" src="unit/test_shift_jis.js"></script>
|
||||
|
||||
<script type="text/javascript" src="unit/test_euc-kr.js"></script>
|
||||
<script type="text/javascript" src="unit/test_iso-2022-kr.js"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -5,34 +5,48 @@
|
|||
|
||||
const { 'classes': Cc, 'interfaces': Ci } = Components;
|
||||
|
||||
function equal(a, b, msg) {
|
||||
dump("equal(" + a + ", " + b + ", \"" + msg + "\")");
|
||||
// Instantiate nsIDOMScriptObjectFactory so that DOMException is usable in xpcshell
|
||||
Components.classesByID["{9eb760f0-4380-11d2-b328-00805f8a3859}"].getService(Ci.nsISupports);
|
||||
|
||||
function assert_equals(a, b, msg) {
|
||||
dump("assert_equals(" + a + ", " + b + ", \"" + msg + "\")");
|
||||
do_check_eq(a, b, Components.stack.caller);
|
||||
}
|
||||
|
||||
function ok(cond, msg) {
|
||||
dump("ok(" + cond + ", \"" + msg + "\")");
|
||||
function assert_not_equals(a, b, msg) {
|
||||
dump("assert_not_equals(" + a + ", " + b + ", \"" + msg + "\")");
|
||||
do_check_neq(a, b, Components.stack.caller);
|
||||
}
|
||||
|
||||
function assert_array_equals(a, b, msg) {
|
||||
dump("assert_array_equals(\"" + msg + "\")");
|
||||
do_check_eq(a.length, b.length, Components.stack.caller);
|
||||
for (var i = 0; i < a.length; ++i) {
|
||||
if (a[i] !== b[i]) {
|
||||
do_check_eq(a[i], b[i], Components.stack.caller);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function assert_true(cond, msg) {
|
||||
dump("assert_true(" + cond + ", \"" + msg + "\")");
|
||||
do_check_true(!!cond, Components.stack.caller);
|
||||
}
|
||||
|
||||
function raises(func) {
|
||||
dump("raises(" + func + ")");
|
||||
function assert_throws(ex, func) {
|
||||
dump("assert_throws(\"" + ex + "\", " + func + ")");
|
||||
try {
|
||||
func();
|
||||
do_check_true(false, Components.stack.caller);
|
||||
} catch (e) {
|
||||
do_check_true(true, Components.stack.caller);
|
||||
do_check_eq(e.name, ex.name, Components.stack.caller);
|
||||
}
|
||||
}
|
||||
|
||||
var tests = [];
|
||||
|
||||
function test(msg, no, func) {
|
||||
tests.push({msg: msg, func: func || no});
|
||||
}
|
||||
|
||||
function expect(count) {
|
||||
dump("expect(", count, ")");
|
||||
function test(func, msg) {
|
||||
tests.push({msg: msg, func: func});
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -1,15 +1,5 @@
|
|||
// NOTE: relies on http://docs.jquery.com/QUnit
|
||||
|
||||
function arrayEqual(a, b, msg) {
|
||||
// deepEqual() is too picky
|
||||
equal(a.length, b.length, msg + " - array length");
|
||||
for (var i = 0; i < a.length; i += 1) {
|
||||
// equal() is too slow to call each time
|
||||
if (a[i] !== b[i]) { equal(a[i], b[i], msg + " - first array index: " + String(i) ); return; }
|
||||
}
|
||||
ok(true, msg);
|
||||
}
|
||||
|
||||
// NOTE: Requires testharness.js
|
||||
// http://www.w3.org/2008/webapps/wiki/Harness
|
||||
|
||||
function testEncodeDecode(encoding, min, max) {
|
||||
function cpname(n) {
|
||||
|
@ -19,7 +9,6 @@ function testEncodeDecode(encoding, min, max) {
|
|||
}
|
||||
|
||||
test(
|
||||
encoding + " - Encode/Decode Range " + cpname(min) + " - " + cpname(max),
|
||||
function() {
|
||||
var string, i, j, BATCH_SIZE = 0x1000;
|
||||
for (i = min; i < max; i += BATCH_SIZE) {
|
||||
|
@ -31,25 +20,24 @@ function testEncodeDecode(encoding, min, max) {
|
|||
} else if (j > 0xffff) {
|
||||
// outside BMP - encode as surrogate pair
|
||||
string += String.fromCharCode(
|
||||
0xd800 + ((j >> 10) & 0x3ff),
|
||||
0xdc00 + (j & 0x3ff));
|
||||
0xd800 + ((j >> 10) & 0x3ff),
|
||||
0xdc00 + (j & 0x3ff));
|
||||
} else {
|
||||
string += String.fromCharCode(i);
|
||||
}
|
||||
}
|
||||
var encoded = TextEncoder(encoding).encode(string);
|
||||
var decoded = TextDecoder(encoding).decode(encoded);
|
||||
equal(string, decoded, 'Round trip ' + cpname(i) + " - " + cpname(j));
|
||||
assert_equals(string, decoded, 'Round trip ' + cpname(i) + " - " + cpname(j));
|
||||
}
|
||||
});
|
||||
},
|
||||
encoding + " - Encode/Decode Range " + cpname(min) + " - " + cpname(max)
|
||||
);
|
||||
}
|
||||
|
||||
testEncodeDecode('UTF-8', 0, 0x10FFFF);
|
||||
testEncodeDecode('UTF-16LE', 0, 0x10FFFF);
|
||||
testEncodeDecode('UTF-16BE', 0, 0x10FFFF);
|
||||
// TextEncoder no longer supports non-UTF encodings
|
||||
//testEncodeDecode('windows-1252', 0, 0xFF);
|
||||
|
||||
|
||||
// Inspired by:
|
||||
// http://ecmanaut.blogspot.com/2006/07/encoding-decoding-utf8-in-javascript.html
|
||||
|
@ -68,10 +56,7 @@ function decode_utf8(octets) {
|
|||
}
|
||||
|
||||
test(
|
||||
"UTF-8 encoding (compare against unescape/encodeURIComponent)",
|
||||
function() {
|
||||
expect(544);
|
||||
|
||||
var actual, expected, str, i, j, BATCH_SIZE = 0x1000;
|
||||
|
||||
for (i = 0; i < 0x10FFFF; i += BATCH_SIZE) {
|
||||
|
@ -83,8 +68,8 @@ test(
|
|||
} else if (j > 0xffff) {
|
||||
// outside BMP - encode as surrogate pair
|
||||
str += String.fromCharCode(
|
||||
0xd800 + ((j >> 10) & 0x3ff),
|
||||
0xdc00 + (j & 0x3ff));
|
||||
0xd800 + ((j >> 10) & 0x3ff),
|
||||
0xdc00 + (j & 0x3ff));
|
||||
} else {
|
||||
str += String.fromCharCode(i);
|
||||
}
|
||||
|
@ -92,15 +77,14 @@ test(
|
|||
expected = encode_utf8(str);
|
||||
|
||||
actual = TextEncoder('UTF-8').encode(str);
|
||||
arrayEqual(actual, expected, 'expected equal encodings');
|
||||
assert_array_equals(actual, expected, 'expected equal encodings');
|
||||
}
|
||||
});
|
||||
},
|
||||
"UTF-8 encoding (compare against unescape/encodeURIComponent)"
|
||||
);
|
||||
|
||||
test(
|
||||
"UTF-8 decoding (compare against decodeURIComponent/escape)",
|
||||
function() {
|
||||
expect(272);
|
||||
|
||||
var encoded, actual, expected, str, i, j, BATCH_SIZE = 0x1000;
|
||||
|
||||
for (i = 0; i < 0x10FFFF; i += BATCH_SIZE) {
|
||||
|
@ -112,8 +96,8 @@ test(
|
|||
} else if (j > 0xffff) {
|
||||
// outside BMP - encode as surrogate pair
|
||||
str += String.fromCharCode(
|
||||
0xd800 + ((j >> 10) & 0x3ff),
|
||||
0xdc00 + (j & 0x3ff));
|
||||
0xd800 + ((j >> 10) & 0x3ff),
|
||||
0xdc00 + (j & 0x3ff));
|
||||
} else {
|
||||
str += String.fromCharCode(i);
|
||||
}
|
||||
|
@ -124,32 +108,25 @@ test(
|
|||
expected = decode_utf8(encoded);
|
||||
actual = TextDecoder('UTF-8').decode(new Uint8Array(encoded));
|
||||
|
||||
equal(actual, expected, 'expected equal decodings');
|
||||
assert_equals(actual, expected, 'expected equal decodings');
|
||||
}
|
||||
});
|
||||
},
|
||||
"UTF-8 decoding (compare against decodeURIComponent/escape)"
|
||||
);
|
||||
|
||||
function testEncodeDecodeSample(encoding, string, expected) {
|
||||
test(
|
||||
encoding + " - Encode/Decode - reference sample",
|
||||
function() {
|
||||
expect(/^utf-/i.test(encoding) ? 3 : 1);
|
||||
|
||||
if (/^utf-/i.test(encoding)) {
|
||||
var encoded = TextEncoder(encoding).encode(string);
|
||||
arrayEqual(encoded, expected, 'expected equal encodings ' + encoding);
|
||||
}
|
||||
var encoded = TextEncoder(encoding).encode(string);
|
||||
assert_array_equals(encoded, expected, 'expected equal encodings ' + encoding);
|
||||
|
||||
var decoded = TextDecoder(encoding).decode(new Uint8Array(expected));
|
||||
equal(decoded, string, 'expected equal decodings ' + encoding);
|
||||
});
|
||||
assert_equals(decoded, string, 'expected equal decodings ' + encoding);
|
||||
},
|
||||
encoding + " - Encode/Decode - reference sample"
|
||||
);
|
||||
}
|
||||
|
||||
testEncodeDecodeSample(
|
||||
"windows-1252",
|
||||
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f\u20ac\x81\u201a\u0192\u201e\u2026\u2020\u2021\u02c6\u2030\u0160\u2039\u0152\x8d\u017d\x8f\x90\u2018\u2019\u201c\u201d\u2022\u2013\u2014\u02dc\u2122\u0161\u203a\u0153\x9d\u017e\u0178\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
|
||||
(function() { var i = 0, a = []; while (i < 256) { a.push(i++); } return a; }())
|
||||
);
|
||||
|
||||
testEncodeDecodeSample(
|
||||
"utf-8",
|
||||
"z\xA2\u6C34\uD834\uDD1E\uDBFF\uDFFD", // z, cent, CJK water, G-Clef, Private-use character
|
||||
|
@ -172,10 +149,7 @@ testEncodeDecodeSample(
|
|||
);
|
||||
|
||||
test(
|
||||
"bad data",
|
||||
function() {
|
||||
expect(5);
|
||||
|
||||
var badStrings = [
|
||||
{ input: '\ud800', expected: '\ufffd' }, // Surrogate half
|
||||
{ input: '\udc00', expected: '\ufffd' }, // Surrogate half
|
||||
|
@ -188,15 +162,14 @@ test(
|
|||
function(t) {
|
||||
var encoded = TextEncoder('utf-8').encode(t.input);
|
||||
var decoded = TextDecoder('utf-8').decode(encoded);
|
||||
equal(decoded, t.expected);
|
||||
assert_equals(t.expected, decoded);
|
||||
});
|
||||
});
|
||||
},
|
||||
"bad data"
|
||||
);
|
||||
|
||||
test(
|
||||
"fatal flag",
|
||||
function() {
|
||||
expect(14);
|
||||
|
||||
var bad = [
|
||||
{ encoding: 'utf-8', input: [0xC0] }, // ends early
|
||||
{ encoding: 'utf-8', input: [0xC0, 0x00] }, // invalid trail
|
||||
|
@ -208,98 +181,90 @@ test(
|
|||
{ encoding: 'utf-8', input: [0xE0, 0x80, 0xC0] }, // invalid trail
|
||||
{ encoding: 'utf-8', input: [0xFC, 0x80, 0x80, 0x80, 0x80, 0x80] }, // > 0x10FFFF
|
||||
{ encoding: 'utf-16', input: [0x00] }, // truncated code unit
|
||||
{ encoding: 'utf-16', input: [0x00, 0xd8] }, // surrogate half
|
||||
{ encoding: 'utf-16', input: [0x00, 0xd8, 0x00, 0x00] }, // surrogate half
|
||||
{ encoding: 'utf-16', input: [0x00, 0xdc, 0x00, 0x00] }, // trail surrogate
|
||||
{ encoding: 'utf-16', input: [0x00, 0xdc, 0x00, 0xd8] } // swapped surrogates
|
||||
//TODO: Gecko doesn't throw for unpaired surrogates
|
||||
//{ encoding: 'utf-16', input: [0x00, 0xd8] }, // surrogate half
|
||||
//{ encoding: 'utf-16', input: [0x00, 0xd8, 0x00, 0x00] }, // surrogate half
|
||||
//{ encoding: 'utf-16', input: [0x00, 0xdc, 0x00, 0x00] }, // trail surrogate
|
||||
//{ encoding: 'utf-16', input: [0x00, 0xdc, 0x00, 0xd8] } // swapped surrogates
|
||||
// TODO: Single byte encoding cases
|
||||
];
|
||||
|
||||
bad.forEach(
|
||||
function(t) {
|
||||
raises(function () { TextDecoder('utf-8').encode(t.input, {fatal: true}); });
|
||||
assert_throws({name: 'EncodingError'}, function () {
|
||||
TextDecoder(t.encoding, {fatal: true}).decode(new Uint8Array(t.input));
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
"fatal flag"
|
||||
);
|
||||
|
||||
test(
|
||||
"Encoding names are case insensitive", function() {
|
||||
var utfencodings = [
|
||||
{ encoding: 'UTF-8', string: 'z\xA2\u6C34\uD834\uDD1E\uDBFF\uDFFD' },
|
||||
{ encoding: 'UTF-16', string: 'z\xA2\u6C34\uD834\uDD1E\uDBFF\uDFFD' },
|
||||
{ encoding: 'UTF-16LE', string: 'z\xA2\u6C34\uD834\uDD1E\uDBFF\uDFFD' },
|
||||
{ encoding: 'UTF-16BE', string: 'z\xA2\u6C34\uD834\uDD1E\uDBFF\uDFFD' },
|
||||
];
|
||||
|
||||
utfencodings.forEach(
|
||||
function(test) {
|
||||
var lower = test.encoding.toLowerCase();
|
||||
var upper = test.encoding.toUpperCase();
|
||||
equal(
|
||||
TextDecoder(lower).decode(TextEncoder(lower).encode(test.string)),
|
||||
TextDecoder(upper).decode(TextEncoder(upper).encode(test.string))
|
||||
);
|
||||
});
|
||||
|
||||
function() {
|
||||
var encodings = [
|
||||
{ encoding: 'ASCII', input: [0x41, 0x42, 0x43, 0x61, 0x62, 0x63, 0x31, 0x32, 0x33, 0x21, 0x40, 0x23] },
|
||||
{ encoding: 'ISO-8859-1', input: [0x41, 0x42, 0x43, 0x61, 0x62, 0x63, 0x31, 0x32, 0x33, 0x21, 0x40, 0x23, 0xA2] }
|
||||
{ label: 'utf-8', encoding: 'utf-8' },
|
||||
{ label: 'utf-16', encoding: 'utf-16' },
|
||||
{ label: 'utf-16le', encoding: 'utf-16' },
|
||||
{ label: 'utf-16be', encoding: 'utf-16be' },
|
||||
{ label: 'ascii', encoding: 'windows-1252' },
|
||||
{ label: 'iso-8859-1', encoding: 'windows-1252' }
|
||||
];
|
||||
|
||||
encodings.forEach(
|
||||
function(test) {
|
||||
var lower = test.encoding.toLowerCase();
|
||||
var upper = test.encoding.toUpperCase();
|
||||
equal(
|
||||
TextDecoder(lower).decode(new Uint8Array(test.input)),
|
||||
TextDecoder(upper).decode(new Uint8Array(test.input))
|
||||
);
|
||||
assert_equals(TextDecoder(test.label.toLowerCase()).encoding, test.encoding);
|
||||
assert_equals(TextDecoder(test.label.toUpperCase()).encoding, test.encoding);
|
||||
});
|
||||
});
|
||||
},
|
||||
"Encoding names are case insensitive"
|
||||
);
|
||||
|
||||
test(
|
||||
"Byte-order marks",
|
||||
function() {
|
||||
//expect(11);
|
||||
expect(5);
|
||||
var utf8_bom = [0xEF, 0xBB, 0xBF];
|
||||
var utf8 = [0x7A, 0xC2, 0xA2, 0xE6, 0xB0, 0xB4, 0xF0, 0x9D, 0x84, 0x9E, 0xF4, 0x8F, 0xBF, 0xBD];
|
||||
|
||||
var utf8 = [0xEF, 0xBB, 0xBF, 0x7A, 0xC2, 0xA2, 0xE6, 0xB0, 0xB4, 0xF0, 0x9D, 0x84, 0x9E, 0xF4, 0x8F, 0xBF, 0xBD];
|
||||
var utf16le = [0xff, 0xfe, 0x7A, 0x00, 0xA2, 0x00, 0x34, 0x6C, 0x34, 0xD8, 0x1E, 0xDD, 0xFF, 0xDB, 0xFD, 0xDF];
|
||||
var utf16be = [0xfe, 0xff, 0x00, 0x7A, 0x00, 0xA2, 0x6C, 0x34, 0xD8, 0x34, 0xDD, 0x1E, 0xDB, 0xFF, 0xDF, 0xFD];
|
||||
var utf16le_bom = [0xff, 0xfe];
|
||||
var utf16le = [0x7A, 0x00, 0xA2, 0x00, 0x34, 0x6C, 0x34, 0xD8, 0x1E, 0xDD, 0xFF, 0xDB, 0xFD, 0xDF];
|
||||
|
||||
var utf16be_bom = [0xfe, 0xff];
|
||||
var utf16be = [0x00, 0x7A, 0x00, 0xA2, 0x6C, 0x34, 0xD8, 0x34, 0xDD, 0x1E, 0xDB, 0xFF, 0xDF, 0xFD];
|
||||
|
||||
var string = "z\xA2\u6C34\uD834\uDD1E\uDBFF\uDFFD"; // z, cent, CJK water, G-Clef, Private-use character
|
||||
|
||||
// Basic cases
|
||||
equal(TextDecoder('utf-8').decode(new Uint8Array(utf8)), string);
|
||||
equal(TextDecoder('utf-16le').decode(new Uint8Array(utf16le)), string);
|
||||
equal(TextDecoder('utf-16be').decode(new Uint8Array(utf16be)), string);
|
||||
equal(TextDecoder('utf-16').decode(new Uint8Array(utf16le)), string);
|
||||
equal(TextDecoder('utf-16').decode(new Uint8Array(utf16be)), string);
|
||||
// missing BOMs
|
||||
assert_equals(TextDecoder('utf-8').decode(new Uint8Array(utf8)), string);
|
||||
assert_equals(TextDecoder('utf-16le').decode(new Uint8Array(utf16le)), string);
|
||||
assert_equals(TextDecoder('utf-16be').decode(new Uint8Array(utf16be)), string);
|
||||
|
||||
/*
|
||||
// TODO: New API?
|
||||
// Verify that BOM wins
|
||||
equal(stringEncoding.decode(new Uint8Array(utf8), 'utf-16le'), string);
|
||||
equal(stringEncoding.decode(new Uint8Array(utf8), 'utf-16be'), string);
|
||||
equal(stringEncoding.decode(new Uint8Array(utf16le), 'utf-8'), string);
|
||||
equal(stringEncoding.decode(new Uint8Array(utf16le), 'utf-16be'), string);
|
||||
equal(stringEncoding.decode(new Uint8Array(utf16be), 'utf-8'), string);
|
||||
equal(stringEncoding.decode(new Uint8Array(utf16be), 'utf-16le'), string);
|
||||
*/
|
||||
});
|
||||
// matching BOMs
|
||||
assert_equals(TextDecoder('utf-8').decode(new Uint8Array(utf8_bom.concat(utf8))), string);
|
||||
assert_equals(TextDecoder('utf-16le').decode(new Uint8Array(utf16le_bom.concat(utf16le))), string);
|
||||
assert_equals(TextDecoder('utf-16be').decode(new Uint8Array(utf16be_bom.concat(utf16be))), string);
|
||||
|
||||
// mismatching BOMs
|
||||
assert_not_equals(TextDecoder('utf-8').decode(new Uint8Array(utf16le_bom.concat(utf8))), string);
|
||||
assert_not_equals(TextDecoder('utf-8').decode(new Uint8Array(utf16be_bom.concat(utf8))), string);
|
||||
assert_not_equals(TextDecoder('utf-16le').decode(new Uint8Array(utf8_bom.concat(utf16le))), string);
|
||||
assert_not_equals(TextDecoder('utf-16le').decode(new Uint8Array(utf16be_bom.concat(utf16le))), string);
|
||||
assert_not_equals(TextDecoder('utf-16be').decode(new Uint8Array(utf8_bom.concat(utf16be))), string);
|
||||
assert_not_equals(TextDecoder('utf-16be').decode(new Uint8Array(utf16le_bom.concat(utf16be))), string);
|
||||
},
|
||||
"Byte-order marks"
|
||||
);
|
||||
|
||||
test(
|
||||
"Encoding names",
|
||||
function () {
|
||||
equal(TextEncoder("utf-8").encoding, "utf-8"); // canonical case
|
||||
equal(TextEncoder("UTF-16").encoding, "utf-16"); // canonical case and name
|
||||
equal(TextEncoder("UTF-16BE").encoding, "utf-16be"); // canonical case and name
|
||||
equal(TextDecoder("iso8859-1").encoding, "windows-1252"); // canonical case and name
|
||||
equal(TextDecoder("iso-8859-1").encoding, "windows-1252"); // canonical case and name
|
||||
|
||||
});
|
||||
assert_equals(TextDecoder("utf-8").encoding, "utf-8"); // canonical case
|
||||
assert_equals(TextDecoder("UTF-16").encoding, "utf-16"); // canonical case and name
|
||||
assert_equals(TextDecoder("UTF-16BE").encoding, "utf-16be"); // canonical case and name
|
||||
assert_equals(TextDecoder("iso8859-1").encoding, "windows-1252"); // canonical case and name
|
||||
assert_equals(TextDecoder("iso-8859-1").encoding, "windows-1252"); // canonical case and name
|
||||
},
|
||||
"Encoding names"
|
||||
);
|
||||
|
||||
test(
|
||||
"Streaming Decode",
|
||||
function () {
|
||||
["utf-8", "utf-16le", "utf-16be"].forEach(function (encoding) {
|
||||
var string = "\x00123ABCabc\x80\xFF\u0100\u1000\uFFFD\uD800\uDC00\uDBFF\uDFFF";
|
||||
|
@ -315,24 +280,25 @@ test(
|
|||
out += decoder.decode(new Uint8Array(sub), {stream: true});
|
||||
}
|
||||
out += decoder.decode();
|
||||
equal(out, string, "streaming decode " + encoding);
|
||||
assert_equals(out, string, "streaming decode " + encoding);
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
"Streaming Decode"
|
||||
);
|
||||
|
||||
test(
|
||||
"Shift_JIS Decode",
|
||||
function () {
|
||||
var jis = [0x82, 0xC9, 0x82, 0xD9, 0x82, 0xF1];
|
||||
var expected = "\u306B\u307B\u3093"; // Nihon
|
||||
equal(TextDecoder("shift_jis").decode(new Uint8Array(jis)), expected);
|
||||
});
|
||||
assert_equals(TextDecoder("shift_jis").decode(new Uint8Array(jis)), expected);
|
||||
},
|
||||
"Shift_JIS Decode"
|
||||
);
|
||||
|
||||
test(
|
||||
"Supersets of ASCII decode ASCII correctly",
|
||||
38,
|
||||
function () {
|
||||
var encodings = ["utf-8", "ibm866", "iso-8859-2", "iso-8859-3", "iso-8859-4", "iso-8859-5", "iso-8859-6", "iso-8859-7", "iso-8859-8", "iso-8859-10", "iso-8859-13", "iso-8859-14", "iso-8859-15", "iso-8859-16", "koi8-r", "koi8-u", "macintosh", "windows-874", "windows-1250", "windows-1251", "windows-1252", "windows-1253", "windows-1254", "windows-1255", "windows-1256", "windows-1257", "windows-1258", "x-mac-cyrillic", "gbk", "gb18030", "hz-gb-2312", "big5", "euc-jp", "iso-2022-jp", "shift_jis", "euc-kr", "iso-2022-kr"];
|
||||
var encodings = ["utf-8", "ibm866", "iso-8859-2", "iso-8859-3", "iso-8859-4", "iso-8859-5", "iso-8859-6", "iso-8859-7", "iso-8859-8", "iso-8859-8-i", "iso-8859-10", "iso-8859-13", "iso-8859-14", "iso-8859-15", "iso-8859-16", "koi8-r", "koi8-u", "macintosh", "windows-874", "windows-1250", "windows-1251", "windows-1252", "windows-1253", "windows-1254", "windows-1255", "windows-1256", "windows-1257", "windows-1258", "x-mac-cyrillic", "gbk", "gb18030", "hz-gb-2312", "big5", "euc-jp", "iso-2022-jp", "shift_jis", "euc-kr", "iso-2022-kr", "x-user-defined"];
|
||||
|
||||
encodings.forEach(function (encoding) {
|
||||
var string = '', bytes = [];
|
||||
|
@ -350,9 +316,46 @@ test(
|
|||
bytes.push(i);
|
||||
}
|
||||
var ascii_encoded = TextEncoder('utf-8').encode(string);
|
||||
equal(TextDecoder(encoding).decode(ascii_encoded), string, encoding);
|
||||
if (encoding === "utf-8") {
|
||||
arrayEqual(TextEncoder(encoding).encode(string), bytes, encoding);
|
||||
}
|
||||
assert_equals(TextDecoder(encoding).decode(ascii_encoded), string, encoding);
|
||||
//assert_array_equals(TextEncoder(encoding).encode(string), bytes, encoding);
|
||||
});
|
||||
});
|
||||
},
|
||||
"Supersets of ASCII decode ASCII correctly"
|
||||
);
|
||||
|
||||
test(
|
||||
function () {
|
||||
assert_throws({name: 'EncodingError'}, function() { TextDecoder("utf-8", {fatal: true}).decode(new Uint8Array([0xff])); });
|
||||
// This should not hang:
|
||||
TextDecoder("utf-8").decode(new Uint8Array([0xff]));
|
||||
|
||||
assert_throws({name: 'EncodingError'}, function() { TextDecoder("utf-16", {fatal: true}).decode(new Uint8Array([0x00])); });
|
||||
// This should not hang:
|
||||
TextDecoder("utf-16").decode(new Uint8Array([0x00]));
|
||||
|
||||
assert_throws({name: 'EncodingError'}, function() { TextDecoder("utf-16be", {fatal: true}).decode(new Uint8Array([0x00])); });
|
||||
// This should not hang:
|
||||
TextDecoder("utf-16be").decode(new Uint8Array([0x00]));
|
||||
},
|
||||
"Non-fatal errors at EOF"
|
||||
);
|
||||
|
||||
test(
|
||||
function () {
|
||||
|
||||
var utf_encodings = ["utf-8", "utf-16", "utf-16be"];
|
||||
|
||||
var legacy_encodings = ["ibm866", "iso-8859-2", "iso-8859-3", "iso-8859-4", "iso-8859-5", "iso-8859-6", "iso-8859-7", "iso-8859-8", "iso-8859-8-i", "iso-8859-10", "iso-8859-13", "iso-8859-14", "iso-8859-15", "iso-8859-16", "koi8-r", "koi8-u", "macintosh", "windows-874", "windows-1250", "windows-1251", "windows-1252", "windows-1253", "windows-1254", "windows-1255", "windows-1256", "windows-1257", "windows-1258", "x-mac-cyrillic", "gbk", "gb18030", "hz-gb-2312", "big5", "euc-jp", "iso-2022-jp", "shift_jis", "euc-kr", "iso-2022-kr", "x-user-defined"];
|
||||
|
||||
utf_encodings.forEach(function(encoding) {
|
||||
assert_equals(TextDecoder(encoding).encoding, encoding);
|
||||
assert_equals(TextEncoder(encoding).encoding, encoding);
|
||||
});
|
||||
|
||||
legacy_encodings.forEach(function(encoding) {
|
||||
assert_equals(TextDecoder(encoding).encoding, encoding);
|
||||
assert_throws({name: 'TypeError'}, function() { TextEncoder(encoding); });
|
||||
});
|
||||
},
|
||||
"Non-UTF encodings supported only for decode, not encode"
|
||||
);
|
||||
|
|
|
@ -28,7 +28,11 @@ ArchiveItem::~ArchiveItem()
|
|||
nsCString
|
||||
ArchiveItem::GetType()
|
||||
{
|
||||
return mType.IsEmpty() ? nsCString("binary/octet-stream") : mType;
|
||||
if (mType.IsEmpty()) {
|
||||
return NS_LITERAL_CSTRING("binary/octet-stream");
|
||||
}
|
||||
|
||||
return mType;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -109,20 +113,29 @@ ArchiveReaderEvent::ShareMainThread()
|
|||
for (uint32_t index = 0; index < mFileList.Length(); ++index) {
|
||||
nsRefPtr<ArchiveItem> item = mFileList[index];
|
||||
|
||||
int32_t offset = item->GetFilename().RFindChar('.');
|
||||
nsString tmp;
|
||||
nsresult rv = item->GetFilename(tmp);
|
||||
nsCString filename = NS_ConvertUTF16toUTF8(tmp);
|
||||
if (NS_FAILED(rv)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int32_t offset = filename.RFindChar('.');
|
||||
if (offset != kNotFound) {
|
||||
nsCString ext(item->GetFilename());
|
||||
ext.Cut(0, offset + 1);
|
||||
filename.Cut(0, offset + 1);
|
||||
|
||||
// Just to be sure, if something goes wrong, the mimetype is an empty string:
|
||||
nsCString type;
|
||||
if (NS_SUCCEEDED(GetType(ext, type)))
|
||||
if (NS_SUCCEEDED(GetType(filename, type))) {
|
||||
item->SetType(type);
|
||||
}
|
||||
}
|
||||
|
||||
// This is a nsDOMFile:
|
||||
nsRefPtr<nsIDOMFile> file = item->File(mArchiveReader);
|
||||
fileList.AppendElement(file);
|
||||
if (file) {
|
||||
fileList.AppendElement(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -17,8 +17,10 @@
|
|||
|
||||
BEGIN_FILE_NAMESPACE
|
||||
|
||||
// This class contains all the info needed for a single item
|
||||
// It must contain the implementation of the File() method.
|
||||
/**
|
||||
* This class contains all the info needed for a single item
|
||||
* It must contain the implementation of the File() method.
|
||||
*/
|
||||
class ArchiveItem : public nsISupports
|
||||
{
|
||||
public:
|
||||
|
@ -28,11 +30,11 @@ public:
|
|||
virtual ~ArchiveItem();
|
||||
|
||||
// Getter/Setter for the type
|
||||
virtual nsCString GetType();
|
||||
virtual void SetType(const nsCString& aType);
|
||||
nsCString GetType();
|
||||
void SetType(const nsCString& aType);
|
||||
|
||||
// Getter for the filename
|
||||
virtual nsCString GetFilename() = 0;
|
||||
virtual nsresult GetFilename(nsString& aFilename) = 0;
|
||||
|
||||
// Generate a DOMFile
|
||||
virtual nsIDOMFile* File(ArchiveReader* aArchiveReader) = 0;
|
||||
|
@ -41,9 +43,11 @@ protected:
|
|||
nsCString mType;
|
||||
};
|
||||
|
||||
// This class must be extended by any archive format supported by ArchiveReader API
|
||||
// This class runs in a different thread and it calls the 'exec()' method.
|
||||
// The exec() must populate mFileList and mStatus then it must call RunShare();
|
||||
/**
|
||||
* This class must be extended by any archive format supported by ArchiveReader API
|
||||
* This class runs in a different thread and it calls the 'exec()' method.
|
||||
* The exec() must populate mFileList and mStatus then it must call RunShare();
|
||||
*/
|
||||
class ArchiveReaderEvent : public nsRunnable
|
||||
{
|
||||
public:
|
||||
|
|
|
@ -40,11 +40,11 @@ ArchiveReader::Initialize(nsISupports* aOwner,
|
|||
uint32_t aArgc,
|
||||
JS::Value* aArgv)
|
||||
{
|
||||
NS_ENSURE_TRUE(aArgc > 0, NS_ERROR_UNEXPECTED);
|
||||
NS_ENSURE_TRUE(aArgc == 1 || aArgc == 2, NS_ERROR_INVALID_ARG);
|
||||
|
||||
// We expect to get a Blob object
|
||||
if (!aArgv[0].isObject()) {
|
||||
return NS_ERROR_UNEXPECTED; // We're not interested
|
||||
return NS_ERROR_INVALID_ARG; // We're not interested
|
||||
}
|
||||
|
||||
JSObject* obj = &aArgv[0].toObject();
|
||||
|
@ -52,16 +52,22 @@ ArchiveReader::Initialize(nsISupports* aOwner,
|
|||
nsCOMPtr<nsIDOMBlob> blob;
|
||||
blob = do_QueryInterface(nsContentUtils::XPConnect()->GetNativeOfWrapper(aCx, obj));
|
||||
if (!blob) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
mBlob = blob;
|
||||
// Extra param is an object
|
||||
if (aArgc > 1) {
|
||||
nsresult rv = mOptions.Init(aCx, &aArgv[1]);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
mWindow = do_QueryInterface(aOwner);
|
||||
if (!mWindow) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
mBlob = blob;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -122,7 +128,7 @@ ArchiveReader::OpenArchive()
|
|||
nsRefPtr<ArchiveReaderEvent> event;
|
||||
|
||||
/* FIXME: If we want to support more than 1 format we should check the content type here: */
|
||||
event = new ArchiveReaderZipEvent(this);
|
||||
event = new ArchiveReaderZipEvent(this, mOptions);
|
||||
rv = target->Dispatch(event, NS_DISPATCH_NORMAL);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
|
@ -186,6 +192,17 @@ ArchiveReader::GetFile(const nsAString& filename,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
/* nsIDOMArchiveRequest getFiles (); */
|
||||
NS_IMETHODIMP
|
||||
ArchiveReader::GetFiles(nsIDOMArchiveRequest** _retval)
|
||||
{
|
||||
nsRefPtr<ArchiveRequest> request = GenerateArchiveRequest();
|
||||
request->OpGetFiles();
|
||||
|
||||
request.forget(_retval);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
already_AddRefed<ArchiveRequest>
|
||||
ArchiveReader::GenerateArchiveRequest()
|
||||
{
|
||||
|
|
|
@ -16,11 +16,15 @@
|
|||
#include "nsIChannel.h"
|
||||
#include "nsIDOMFile.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "DictionaryHelpers.h"
|
||||
|
||||
BEGIN_FILE_NAMESPACE
|
||||
|
||||
class ArchiveRequest;
|
||||
|
||||
/**
|
||||
* This is the ArchiveReader object
|
||||
*/
|
||||
class ArchiveReader MOZ_FINAL : public nsIDOMArchiveReader,
|
||||
public nsIJSNativeInitializer
|
||||
{
|
||||
|
@ -39,7 +43,7 @@ public:
|
|||
JSContext* aCx,
|
||||
JSObject* aObj,
|
||||
uint32_t aArgc,
|
||||
jsval* aArgv);
|
||||
JS::Value* aArgv);
|
||||
|
||||
nsresult GetInputStream(nsIInputStream** aInputStream);
|
||||
nsresult GetSize(uint64_t* aSize);
|
||||
|
@ -90,6 +94,8 @@ protected:
|
|||
nsTArray<nsCOMPtr<nsIDOMFile> > fileList;
|
||||
nsresult status;
|
||||
} mData;
|
||||
|
||||
ArchiveReaderOptions mOptions;
|
||||
};
|
||||
|
||||
END_FILE_NAMESPACE
|
||||
|
|
|
@ -44,7 +44,7 @@ ArchiveRequestEvent::Run()
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
/* ArchiveRequest */
|
||||
// ArchiveRequest
|
||||
|
||||
ArchiveRequest::ArchiveRequest(nsIDOMWindow* aWindow,
|
||||
ArchiveReader* aReader)
|
||||
|
@ -90,8 +90,9 @@ ArchiveRequest::Run()
|
|||
// Register this request to the reader.
|
||||
// When the reader is ready to return data, a 'Ready()' will be called
|
||||
nsresult rv = mArchiveReader->RegisterRequest(this);
|
||||
if (NS_FAILED(rv))
|
||||
if (NS_FAILED(rv)) {
|
||||
FireError(rv);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -107,6 +108,12 @@ ArchiveRequest::OpGetFile(const nsAString& aFilename)
|
|||
mFilename = aFilename;
|
||||
}
|
||||
|
||||
void
|
||||
ArchiveRequest::OpGetFiles()
|
||||
{
|
||||
mOperation = GetFiles;
|
||||
}
|
||||
|
||||
nsresult
|
||||
ArchiveRequest::ReaderReady(nsTArray<nsCOMPtr<nsIDOMFile> >& aFileList,
|
||||
nsresult aStatus)
|
||||
|
@ -116,7 +123,7 @@ ArchiveRequest::ReaderReady(nsTArray<nsCOMPtr<nsIDOMFile> >& aFileList,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
jsval result;
|
||||
JS::Value result;
|
||||
nsresult rv;
|
||||
|
||||
nsIScriptContext* sc = GetContextForEventHandlers(&rv);
|
||||
|
@ -139,6 +146,10 @@ ArchiveRequest::ReaderReady(nsTArray<nsCOMPtr<nsIDOMFile> >& aFileList,
|
|||
case GetFile:
|
||||
rv = GetFileResult(cx, &result, aFileList);
|
||||
break;
|
||||
|
||||
case GetFiles:
|
||||
rv = GetFilesResult(cx, &result, aFileList);
|
||||
break;
|
||||
}
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
|
@ -157,7 +168,7 @@ ArchiveRequest::ReaderReady(nsTArray<nsCOMPtr<nsIDOMFile> >& aFileList,
|
|||
|
||||
nsresult
|
||||
ArchiveRequest::GetFilenamesResult(JSContext* aCx,
|
||||
jsval* aValue,
|
||||
JS::Value* aValue,
|
||||
nsTArray<nsCOMPtr<nsIDOMFile> >& aFileList)
|
||||
{
|
||||
JSObject* array = JS_NewArrayObject(aCx, aFileList.Length(), nullptr);
|
||||
|
@ -177,7 +188,7 @@ ArchiveRequest::GetFilenamesResult(JSContext* aCx,
|
|||
JSString* str = JS_NewUCStringCopyZ(aCx, filename.get());
|
||||
NS_ENSURE_TRUE(str, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
jsval item = STRING_TO_JSVAL(str);
|
||||
JS::Value item = STRING_TO_JSVAL(str);
|
||||
|
||||
if (NS_FAILED(rv) || !JS_SetElement(aCx, array, i, &item)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
|
@ -187,14 +198,14 @@ ArchiveRequest::GetFilenamesResult(JSContext* aCx,
|
|||
if (!JS_FreezeObject(aCx, array)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
|
||||
*aValue = OBJECT_TO_JSVAL(array);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
ArchiveRequest::GetFileResult(JSContext* aCx,
|
||||
jsval* aValue,
|
||||
JS::Value* aValue,
|
||||
nsTArray<nsCOMPtr<nsIDOMFile> >& aFileList)
|
||||
{
|
||||
for (uint32_t i = 0; i < aFileList.Length(); ++i) {
|
||||
|
@ -205,8 +216,9 @@ ArchiveRequest::GetFileResult(JSContext* aCx,
|
|||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (filename == mFilename) {
|
||||
JSObject* scope = JS_GetGlobalForScopeChain(aCx);
|
||||
nsresult rv = nsContentUtils::WrapNative(aCx, scope, file, aValue, nullptr, true);
|
||||
nsresult rv = nsContentUtils::WrapNative(
|
||||
aCx, JS_GetGlobalForScopeChain(aCx),
|
||||
file, &NS_GET_IID(nsIDOMFile), aValue);
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
@ -214,6 +226,31 @@ ArchiveRequest::GetFileResult(JSContext* aCx,
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsresult
|
||||
ArchiveRequest::GetFilesResult(JSContext* aCx,
|
||||
JS::Value* aValue,
|
||||
nsTArray<nsCOMPtr<nsIDOMFile> >& aFileList)
|
||||
{
|
||||
JSObject* array = JS_NewArrayObject(aCx, aFileList.Length(), nullptr);
|
||||
if (!array) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
for (PRUint32 i = 0; i < aFileList.Length(); ++i) {
|
||||
nsCOMPtr<nsIDOMFile> file = aFileList[i];
|
||||
|
||||
JS::Value value;
|
||||
nsresult rv = nsContentUtils::WrapNative(aCx, JS_GetGlobalForScopeChain(aCx),
|
||||
file, &NS_GET_IID(nsIDOMFile), &value);
|
||||
if (NS_FAILED(rv) || !JS_SetElement(aCx, array, i, &value)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
aValue->setObject(*array);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// static
|
||||
already_AddRefed<ArchiveRequest>
|
||||
ArchiveRequest::Create(nsIDOMWindow* aOwner,
|
||||
|
|
|
@ -16,11 +16,15 @@
|
|||
|
||||
BEGIN_FILE_NAMESPACE
|
||||
|
||||
/**
|
||||
* This is the ArchiveRequest that handles any operation
|
||||
* related to ArchiveReader
|
||||
*/
|
||||
class ArchiveRequest : public mozilla::dom::DOMRequest,
|
||||
public nsIDOMArchiveRequest
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_NSIDOMARCHIVEREQUEST
|
||||
|
||||
NS_FORWARD_NSIDOMDOMREQUEST(DOMRequest::)
|
||||
|
@ -40,6 +44,7 @@ public:
|
|||
// Set the types for this request
|
||||
void OpGetFilenames();
|
||||
void OpGetFile(const nsAString& aFilename);
|
||||
void OpGetFiles();
|
||||
|
||||
nsresult ReaderReady(nsTArray<nsCOMPtr<nsIDOMFile> >& aFileList,
|
||||
nsresult aStatus);
|
||||
|
@ -52,11 +57,14 @@ private:
|
|||
~ArchiveRequest();
|
||||
|
||||
nsresult GetFilenamesResult(JSContext* aCx,
|
||||
jsval* aValue,
|
||||
JS::Value* aValue,
|
||||
nsTArray<nsCOMPtr<nsIDOMFile> >& aFileList);
|
||||
nsresult GetFileResult(JSContext* aCx,
|
||||
jsval* aValue,
|
||||
JS::Value* aValue,
|
||||
nsTArray<nsCOMPtr<nsIDOMFile> >& aFileList);
|
||||
nsresult GetFilesResult(JSContext* aCx,
|
||||
JS::Value* aValue,
|
||||
nsTArray<nsCOMPtr<nsIDOMFile> >& aFileList);
|
||||
|
||||
protected:
|
||||
// The reader:
|
||||
|
@ -65,7 +73,8 @@ protected:
|
|||
// The operation:
|
||||
enum {
|
||||
GetFilenames,
|
||||
GetFile
|
||||
GetFile,
|
||||
GetFiles
|
||||
} mOperation;
|
||||
|
||||
// The filename (needed by GetFile):
|
||||
|
|
|
@ -8,19 +8,24 @@
|
|||
#include "ArchiveZipFile.h"
|
||||
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsIPlatformCharset.h"
|
||||
#include "nsNativeCharsetUtils.h"
|
||||
#include "nsCExternalHandlerService.h"
|
||||
|
||||
using namespace mozilla::dom;
|
||||
|
||||
USING_FILE_NAMESPACE
|
||||
|
||||
#ifndef PATH_MAX
|
||||
# define PATH_MAX 65536 // The filename length is stored in 2 bytes
|
||||
#endif
|
||||
|
||||
// ArchiveZipItem
|
||||
ArchiveZipItem::ArchiveZipItem(const char* aFilename,
|
||||
ZipCentral& aCentralStruct)
|
||||
const ZipCentral& aCentralStruct,
|
||||
const ArchiveReaderOptions& aOptions)
|
||||
: mFilename(aFilename),
|
||||
mCentralStruct(aCentralStruct)
|
||||
mCentralStruct(aCentralStruct),
|
||||
mOptions(aOptions)
|
||||
{
|
||||
MOZ_COUNT_CTOR(ArchiveZipItem);
|
||||
}
|
||||
|
@ -30,25 +35,58 @@ ArchiveZipItem::~ArchiveZipItem()
|
|||
MOZ_COUNT_DTOR(ArchiveZipItem);
|
||||
}
|
||||
|
||||
// Getter/Setter for the filename
|
||||
nsCString
|
||||
ArchiveZipItem::GetFilename()
|
||||
nsresult
|
||||
ArchiveZipItem::ConvertFilename()
|
||||
{
|
||||
return mFilename;
|
||||
if (mOptions.encoding.IsEmpty()) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsString filenameU;
|
||||
nsresult rv = nsContentUtils::ConvertStringFromCharset(
|
||||
NS_ConvertUTF16toUTF8(mOptions.encoding),
|
||||
mFilename, filenameU);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (filenameU.IsEmpty()) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
mFilenameU = filenameU;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
ArchiveZipItem::SetFilename(const nsCString& aFilename)
|
||||
nsresult
|
||||
ArchiveZipItem::GetFilename(nsString& aFilename)
|
||||
{
|
||||
mFilename = aFilename;
|
||||
}
|
||||
if (mFilenameU.IsEmpty()) {
|
||||
// Maybe this string is UTF-8:
|
||||
if (IsUTF8(mFilename, false)) {
|
||||
mFilenameU = NS_ConvertUTF8toUTF16(mFilename);
|
||||
}
|
||||
|
||||
// Let's use the enconding value for the dictionary
|
||||
else {
|
||||
nsresult rv = ConvertFilename();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
}
|
||||
|
||||
aFilename = mFilenameU;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// From zipItem to DOMFile:
|
||||
nsIDOMFile*
|
||||
ArchiveZipItem::File(ArchiveReader* aArchiveReader)
|
||||
{
|
||||
return new ArchiveZipFile(NS_ConvertUTF8toUTF16(mFilename),
|
||||
nsString filename;
|
||||
|
||||
if (NS_FAILED(GetFilename(filename))) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return new ArchiveZipFile(filename,
|
||||
NS_ConvertUTF8toUTF16(GetType()),
|
||||
StrToInt32(mCentralStruct.orglen),
|
||||
mCentralStruct,
|
||||
|
@ -72,8 +110,10 @@ ArchiveZipItem::StrToInt16(const uint8_t* aStr)
|
|||
|
||||
// ArchiveReaderZipEvent
|
||||
|
||||
ArchiveReaderZipEvent::ArchiveReaderZipEvent(ArchiveReader* aArchiveReader)
|
||||
: ArchiveReaderEvent(aArchiveReader)
|
||||
ArchiveReaderZipEvent::ArchiveReaderZipEvent(ArchiveReader* aArchiveReader,
|
||||
const ArchiveReaderOptions& aOptions)
|
||||
: ArchiveReaderEvent(aArchiveReader),
|
||||
mOptions(aOptions)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -104,8 +144,7 @@ ArchiveReaderZipEvent::Exec()
|
|||
}
|
||||
|
||||
// Reading backward.. looking for the ZipEnd signature
|
||||
for (uint64_t curr = size - ZIPEND_SIZE; curr > 4; --curr)
|
||||
{
|
||||
for (uint64_t curr = size - ZIPEND_SIZE; curr > 4; --curr) {
|
||||
seekableStream->Seek(nsISeekableStream::NS_SEEK_SET, curr);
|
||||
|
||||
uint8_t buffer[ZIPEND_SIZE];
|
||||
|
@ -162,7 +201,7 @@ ArchiveReaderZipEvent::Exec()
|
|||
|
||||
// We ignore the directories:
|
||||
if (filename[filenameLen - 1] != '/') {
|
||||
mFileList.AppendElement(new ArchiveZipItem(filename, centralStruct));
|
||||
mFileList.AppendElement(new ArchiveZipItem(filename, centralStruct, mOptions));
|
||||
}
|
||||
|
||||
PR_Free(filename);
|
||||
|
|
|
@ -12,17 +12,22 @@
|
|||
#include "FileCommon.h"
|
||||
#include "zipstruct.h"
|
||||
|
||||
#include "DictionaryHelpers.h"
|
||||
|
||||
BEGIN_FILE_NAMESPACE
|
||||
|
||||
/**
|
||||
* ArchiveZipItem - ArchiveItem for ArchiveReaderZipEvent
|
||||
*/
|
||||
class ArchiveZipItem : public ArchiveItem
|
||||
{
|
||||
public:
|
||||
ArchiveZipItem(const char* aFilename,
|
||||
ZipCentral& aCentralStruct);
|
||||
const ZipCentral& aCentralStruct,
|
||||
const ArchiveReaderOptions& aOptions);
|
||||
virtual ~ArchiveZipItem();
|
||||
|
||||
void SetFilename(const nsCString& aFilename);
|
||||
nsCString GetFilename();
|
||||
nsresult GetFilename(nsString& aFilename);
|
||||
|
||||
// From zipItem to DOMFile:
|
||||
virtual nsIDOMFile* File(ArchiveReader* aArchiveReader);
|
||||
|
@ -31,17 +36,31 @@ public: // for the event
|
|||
static uint32_t StrToInt32(const uint8_t* aStr);
|
||||
static uint16_t StrToInt16(const uint8_t* aStr);
|
||||
|
||||
private:
|
||||
nsresult ConvertFilename();
|
||||
|
||||
private: // data
|
||||
nsCString mFilename;
|
||||
|
||||
nsString mFilenameU;
|
||||
ZipCentral mCentralStruct;
|
||||
|
||||
ArchiveReaderOptions mOptions;
|
||||
};
|
||||
|
||||
/**
|
||||
* ArchiveReaderEvent implements the ArchiveReaderEvent for the ZIP format
|
||||
*/
|
||||
class ArchiveReaderZipEvent : public ArchiveReaderEvent
|
||||
{
|
||||
public:
|
||||
ArchiveReaderZipEvent(ArchiveReader* aArchiveReader);
|
||||
ArchiveReaderZipEvent(ArchiveReader* aArchiveReader,
|
||||
const ArchiveReaderOptions& aOptions);
|
||||
|
||||
nsresult Exec();
|
||||
|
||||
private:
|
||||
ArchiveReaderOptions mOptions;
|
||||
};
|
||||
|
||||
END_FILE_NAMESPACE
|
||||
|
|
|
@ -15,8 +15,9 @@ USING_FILE_NAMESPACE
|
|||
|
||||
#define ZIP_CHUNK 16384
|
||||
|
||||
// a internat input stream object
|
||||
|
||||
/**
|
||||
* Input stream object for zip files
|
||||
*/
|
||||
class ArchiveInputStream MOZ_FINAL : public nsIInputStream,
|
||||
public nsISeekableStream
|
||||
{
|
||||
|
@ -92,22 +93,25 @@ ArchiveInputStream::Init()
|
|||
|
||||
memset(&mZs, 0, sizeof(z_stream));
|
||||
int zerr = inflateInit2(&mZs, -MAX_WBITS);
|
||||
if (zerr != Z_OK)
|
||||
if (zerr != Z_OK) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
mData.sizeToBeRead = ArchiveZipItem::StrToInt32(mCentral.size);
|
||||
|
||||
uint32_t offset = ArchiveZipItem::StrToInt32(mCentral.localhdr_offset);
|
||||
|
||||
// The file is corrupt
|
||||
if (offset + ZIPLOCAL_SIZE > mData.parentSize)
|
||||
if (offset + ZIPLOCAL_SIZE > mData.parentSize) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
// From the input stream to a seekable stream
|
||||
nsCOMPtr<nsISeekableStream> seekableStream;
|
||||
seekableStream = do_QueryInterface(mData.inputStream);
|
||||
if (!seekableStream)
|
||||
if (!seekableStream) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
// Seek + read the ZipLocal struct
|
||||
seekableStream->Seek(nsISeekableStream::NS_SEEK_SET, offset);
|
||||
|
@ -115,12 +119,14 @@ ArchiveInputStream::Init()
|
|||
uint32_t ret;
|
||||
|
||||
rv = mData.inputStream->Read((char*)buffer, ZIPLOCAL_SIZE, &ret);
|
||||
if (NS_FAILED(rv) || ret != ZIPLOCAL_SIZE)
|
||||
if (NS_FAILED(rv) || ret != ZIPLOCAL_SIZE) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
// Signature check:
|
||||
if (ArchiveZipItem::StrToInt32(buffer) != LOCALSIG)
|
||||
if (ArchiveZipItem::StrToInt32(buffer) != LOCALSIG) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
ZipLocal local;
|
||||
memcpy(&local, buffer, ZIPLOCAL_SIZE);
|
||||
|
@ -131,8 +137,9 @@ ArchiveInputStream::Init()
|
|||
ArchiveZipItem::StrToInt16(local.extrafield_len);
|
||||
|
||||
// The file is corrupt if there is not enough data
|
||||
if (offset + mData.sizeToBeRead > mData.parentSize)
|
||||
if (offset + mData.sizeToBeRead > mData.parentSize) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
// Data starts here:
|
||||
seekableStream->Seek(nsISeekableStream::NS_SEEK_SET, offset);
|
||||
|
@ -182,8 +189,9 @@ ArchiveInputStream::Read(char* aBuffer,
|
|||
mStatus = Started;
|
||||
|
||||
rv = Init();
|
||||
if (NS_FAILED(rv))
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Let's set avail_out to -1 so we read something from the stream.
|
||||
mZs.avail_out = (uInt)-1;
|
||||
|
@ -196,8 +204,7 @@ ArchiveInputStream::Read(char* aBuffer,
|
|||
}
|
||||
|
||||
// Stored file:
|
||||
if (!mData.compressed)
|
||||
{
|
||||
if (!mData.compressed) {
|
||||
rv = mData.inputStream->Read(aBuffer,
|
||||
(mData.sizeToBeRead > aCount ?
|
||||
aCount : mData.sizeToBeRead),
|
||||
|
@ -206,23 +213,24 @@ ArchiveInputStream::Read(char* aBuffer,
|
|||
mData.sizeToBeRead -= *_retval;
|
||||
mData.cursor += *_retval;
|
||||
|
||||
if (mData.sizeToBeRead == 0)
|
||||
if (mData.sizeToBeRead == 0) {
|
||||
mStatus = Done;
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
// We have nothing ready to be processed:
|
||||
if (mZs.avail_out != 0 && mData.sizeToBeRead != 0)
|
||||
{
|
||||
if (mZs.avail_out != 0 && mData.sizeToBeRead != 0) {
|
||||
uint32_t ret;
|
||||
rv = mData.inputStream->Read((char*)mData.input,
|
||||
(mData.sizeToBeRead > sizeof(mData.input) ?
|
||||
sizeof(mData.input) : mData.sizeToBeRead),
|
||||
&ret);
|
||||
if (NS_FAILED(rv))
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Terminator:
|
||||
if (ret == 0) {
|
||||
|
@ -239,11 +247,13 @@ ArchiveInputStream::Read(char* aBuffer,
|
|||
mZs.next_out = (unsigned char*)aBuffer;
|
||||
|
||||
int ret = inflate(&mZs, mData.sizeToBeRead ? Z_NO_FLUSH : Z_FINISH);
|
||||
if (ret != Z_BUF_ERROR && ret != Z_OK && ret != Z_STREAM_END)
|
||||
if (ret != Z_BUF_ERROR && ret != Z_OK && ret != Z_STREAM_END) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
if (ret == Z_STREAM_END)
|
||||
if (ret == Z_STREAM_END) {
|
||||
mStatus = Done;
|
||||
}
|
||||
|
||||
*_retval = aCount - mZs.avail_out;
|
||||
mData.cursor += *_retval;
|
||||
|
@ -291,11 +301,13 @@ ArchiveInputStream::Seek(int32_t aWhence, int64_t aOffset)
|
|||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
if (pos == int64_t(mData.cursor))
|
||||
if (pos == int64_t(mData.cursor)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (pos < 0 || pos >= mLength)
|
||||
if (pos < 0 || pos >= mLength) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// We have to terminate the previous operation:
|
||||
nsresult rv;
|
||||
|
@ -312,11 +324,13 @@ ArchiveInputStream::Seek(int32_t aWhence, int64_t aOffset)
|
|||
char buffer[1024];
|
||||
while (pos > 0) {
|
||||
rv = Read(buffer, pos > int64_t(sizeof(buffer)) ? sizeof(buffer) : pos, &ret);
|
||||
if (NS_FAILED(rv))
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (ret == 0)
|
||||
if (ret == 0) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
pos -= ret;
|
||||
}
|
||||
|
@ -342,8 +356,9 @@ ArchiveInputStream::SetEOF()
|
|||
NS_IMETHODIMP
|
||||
ArchiveZipFile::GetInternalStream(nsIInputStream** aStream)
|
||||
{
|
||||
if (mLength > INT32_MAX)
|
||||
if (mLength > INT32_MAX) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
uint64_t size;
|
||||
nsresult rv = mArchiveReader->GetSize(&size);
|
||||
|
@ -351,8 +366,9 @@ ArchiveZipFile::GetInternalStream(nsIInputStream** aStream)
|
|||
|
||||
nsCOMPtr<nsIInputStream> inputStream;
|
||||
rv = mArchiveReader->GetInputStream(getter_AddRefs(inputStream));
|
||||
if (NS_FAILED(rv) || !inputStream)
|
||||
if (NS_FAILED(rv) || !inputStream) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
nsRefPtr<ArchiveInputStream> stream = new ArchiveInputStream(size,
|
||||
inputStream,
|
||||
|
|
|
@ -16,6 +16,9 @@
|
|||
|
||||
BEGIN_FILE_NAMESPACE
|
||||
|
||||
/**
|
||||
* ZipFile to DOMFileCC
|
||||
*/
|
||||
class ArchiveZipFile : public nsDOMFileCC
|
||||
{
|
||||
public:
|
||||
|
|
|
@ -12,6 +12,15 @@ interface nsIDOMArchiveReader : nsISupports
|
|||
{
|
||||
nsIDOMArchiveRequest getFilenames();
|
||||
nsIDOMArchiveRequest getFile(in DOMString filename);
|
||||
nsIDOMArchiveRequest getFiles();
|
||||
};
|
||||
|
||||
/* This dictionary is the optional argument for the
|
||||
* ArchiveReader constructor:
|
||||
* var a = new ArchiveReader(blob, { encoding: "iso-8859-1" }); */
|
||||
dictionary ArchiveReaderOptions
|
||||
{
|
||||
DOMString encoding = "windows-1252"; // Default fallback encoding
|
||||
};
|
||||
|
||||
%{ C++
|
||||
|
|
|
@ -31,6 +31,7 @@ MOCHITEST_FILES = \
|
|||
test_workers.html \
|
||||
test_archivereader.html \
|
||||
test_archivereader_zip_in_zip.html \
|
||||
test_archivereader_nonUnicode.html \
|
||||
test_bug_793311.html \
|
||||
$(NULL)
|
||||
|
||||
|
|
|
@ -62,7 +62,7 @@
|
|||
}
|
||||
}
|
||||
function isFinished() {
|
||||
return handleFinished == 5;
|
||||
return handleFinished == 6;
|
||||
}
|
||||
|
||||
function testSteps()
|
||||
|
@ -232,6 +232,25 @@
|
|||
ok(false, "ArchiveReader.getFile('test/a.txt') should not return an 'error'");
|
||||
markTestDone();
|
||||
}
|
||||
|
||||
var handle5 = r.getFiles();
|
||||
isnot(handle5, null, "ArchiveReader.getFiles() cannot be null");
|
||||
handle5.onsuccess = function() {
|
||||
ok(true, "ArchiveReader.getFiles() should return a 'success'");
|
||||
ok(this.reader, r, "ArchiveRequest.reader should be == ArchiveReader");
|
||||
|
||||
is(this.result.length, 2, "ArchiveReader.getFilenames(): the array contains 2 items");
|
||||
is(this.result[0].name, "test/a.txt", "ArchiveReader.getFilenames(): first file is 'test/a.txt'");
|
||||
is(this.result[1].name, "test/b.txt", "ArchiveReader.getFilenames(): second file is 'test/b.txt'");
|
||||
is(this.result[0].type, "text/plain", "ArchiveReader.getFile('test/a.txt') the type MUST be 'text/plain'");
|
||||
is(this.result[1].type, "text/plain", "ArchiveReader.getFile('test/a.txt') the type MUST be 'text/plain'");
|
||||
|
||||
markTestDone();
|
||||
}
|
||||
handle5.onerror = function() {
|
||||
ok(false, "ArchiveReader.getFiles() should not return an 'error'");
|
||||
markTestDone();
|
||||
}
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
|
|
@ -0,0 +1,104 @@
|
|||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<title>Archive Reader Non-Unicode Test</title>
|
||||
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
|
||||
<script type="text/javascript;version=1.7">
|
||||
function createNonUnicodeData() {
|
||||
const Cc = SpecialPowers.wrap(Components).classes;
|
||||
const Ci = SpecialPowers.wrap(Components).interfaces;
|
||||
|
||||
var dirSvc = Cc["@mozilla.org/file/directory_service;1"].getService(Ci.nsIProperties);
|
||||
var testFile = dirSvc.get("ProfD", Ci.nsIFile);
|
||||
testFile.append("fileArchiveReader_nonUnicode.zip");
|
||||
var outStream = Cc["@mozilla.org/network/file-output-stream;1"].createInstance(Ci.nsIFileOutputStream);
|
||||
outStream.init(testFile, 0x02 | 0x08 | 0x20, // write, create, truncate
|
||||
0666, 0);
|
||||
|
||||
var binaryData = "";
|
||||
for (var i = 0, len = binaryString.length / 2; i < len; ++i) {
|
||||
var hex = binaryString[i * 2] + binaryString[i * 2 + 1];
|
||||
binaryData += String.fromCharCode(parseInt(hex,16));
|
||||
}
|
||||
outStream.write(binaryData, binaryData.length);
|
||||
outStream.close();
|
||||
|
||||
var fileList = document.getElementById('fileList');
|
||||
SpecialPowers.wrap(fileList).value = testFile.path;
|
||||
|
||||
return fileList.files[0];
|
||||
}
|
||||
|
||||
function test1()
|
||||
{
|
||||
var binaryFile = createNonUnicodeData();
|
||||
|
||||
var r = new ArchiveReader(binaryFile, { encoding: "ISO-8859-1" });
|
||||
isnot(r, null, "ArchiveReader cannot be null");
|
||||
|
||||
// GetFilename
|
||||
var handle = r.getFilenames();
|
||||
isnot(handle, null, "ArchiveReader.getFilenames() cannot be null");
|
||||
handle.onsuccess = function() {
|
||||
ok(true, "ArchiveReader.getFilenames() should return a 'success'");
|
||||
is(this.result instanceof Array, true, "ArchiveReader.getFilenames() should return an array");
|
||||
is(this.result.length, 1, "ArchiveReader.getFilenames(): the array contains 1 item");
|
||||
ok(this.reader, r, "ArchiveRequest.reader should be == ArchiveReader");
|
||||
dump('Content: ' + this.result[0] + '\n');
|
||||
test2();
|
||||
}
|
||||
}
|
||||
|
||||
function test2()
|
||||
{
|
||||
var binaryFile = createNonUnicodeData();
|
||||
|
||||
var r = new ArchiveReader(binaryFile, { encoding: "random stuff" });
|
||||
isnot(r, null, "ArchiveReader cannot be null");
|
||||
|
||||
// GetFilename
|
||||
var handle = r.getFilenames();
|
||||
isnot(handle, null, "ArchiveReader.getFilenames() cannot be null");
|
||||
handle.onsuccess = function() {
|
||||
ok(true, "ArchiveReader.getFilenames() should return a 'success'");
|
||||
is(this.result instanceof Array, true, "ArchiveReader.getFilenames() should return an array");
|
||||
is(this.result.length, 0, "ArchiveReader.getFilenames(): the array contains 0 item");
|
||||
ok(this.reader, r, "ArchiveRequest.reader should be == ArchiveReader");
|
||||
finishTest();
|
||||
}
|
||||
}
|
||||
|
||||
function testSteps()
|
||||
{
|
||||
test1();
|
||||
yield;
|
||||
}
|
||||
|
||||
|
||||
</script>
|
||||
<script type="text/javascript;version=1.7" src="helpers.js"></script>
|
||||
|
||||
</head>
|
||||
|
||||
<body onload="runTest();">
|
||||
<p id="display">
|
||||
<input id="fileList" type="file"></input>
|
||||
</p>
|
||||
<script type="text/javascript;version=1.7">
|
||||
var binaryString = '' +
|
||||
'504B0304140000000000255D094100000000000000000000000002000000912F504B03040A0000000000285D09416BB50A5A' +
|
||||
'010000000100000007000000912F9B2E747874D8504B01023F00140000000000255D09410000000000000000000000000200' +
|
||||
'24000000000000001000000000000000912F0A002000000000000100180062505F1A1376CD0162505F1A1376CD01FE3F8D59' +
|
||||
'1176CD01504B01023F000A0000000000285D09416BB50A5A0100000001000000070024000000000000002000000020000000' +
|
||||
'912F9B2E7478740A0020000000000001001800565EF41D1376CD0107BD73631176CD0107BD73631176CD01504B0506000000' +
|
||||
'0002000200AD000000460000000000';
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -30,7 +30,7 @@ interface nsIDOMTextMetrics : nsISupports
|
|||
readonly attribute float width;
|
||||
};
|
||||
|
||||
[scriptable, uuid(c835c768-2dcc-461c-82f5-3653710d2942)]
|
||||
[scriptable, uuid(438fe14d-6501-40ab-b6c2-130fa38bd2c9)]
|
||||
interface nsIDOMCanvasRenderingContext2D : nsISupports
|
||||
{
|
||||
// back-reference to the canvas element for which
|
||||
|
@ -166,6 +166,7 @@ enum CanvasMultiGetterType {
|
|||
|
||||
// point-membership test
|
||||
boolean isPointInPath(in float x, in float y);
|
||||
boolean mozIsPointInStroke(in float x, in float y);
|
||||
|
||||
// pixel manipulation
|
||||
// ImageData getImageData (in float x, in float y, in float width, in float height);
|
||||
|
|
|
@ -4,12 +4,6 @@
|
|||
<title>Test for Power API</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
/** Test for Power API **/
|
||||
|
@ -17,18 +11,42 @@
|
|||
ok('mozPower' in navigator, "navigator.mozPower should exist");
|
||||
|
||||
/** Test permission **/
|
||||
// In b2g, addPermission 'power' is only working after a document reload
|
||||
// See bug 802312
|
||||
|
||||
SpecialPowers.removePermission("power", document);
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
power = navigator.mozPower;
|
||||
ok(!power, "Shouldn't be able to access power manager without permission.");
|
||||
function startTest() {
|
||||
window.frames[0].frameElement.setAttribute('onload', 'doTest2()');
|
||||
power = window.frames[0].navigator.mozPower;
|
||||
ok(!power, "Shouldn't be able to access power manager without permission.");
|
||||
|
||||
SpecialPowers.addPermission("power", true, document);
|
||||
SpecialPowers.addPermission("power", true, window.frames[0].document);
|
||||
window.frames[0].location.reload();
|
||||
}
|
||||
|
||||
power = navigator.mozPower;
|
||||
ok(power, "Shouldn be able to access power manager with permission.");
|
||||
function doTest2() {
|
||||
window.frames[0].frameElement.setAttribute('onload', 'doTest3()');
|
||||
power = window.frames[0].navigator.mozPower;
|
||||
ok(power, "Should be able to access power manager with permission.");
|
||||
|
||||
SpecialPowers.removePermission("power", window.frames[0].document);
|
||||
window.frames[0].location.reload();
|
||||
}
|
||||
|
||||
function doTest3() {
|
||||
power = window.frames[0].navigator.mozPower;
|
||||
ok(!power, "Shouldn't be able to access power manager without permission.");
|
||||
SimpleTest.finish();
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
</div>
|
||||
<iframe onload="startTest()"></iframe>
|
||||
<pre id="test">
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <android/log.h>
|
||||
#include <android/log.h>
|
||||
|
||||
#include "mozilla/Hal.h"
|
||||
#include "AudioManager.h"
|
||||
|
@ -26,7 +26,7 @@ using namespace android;
|
|||
using namespace mozilla::hal;
|
||||
using namespace mozilla;
|
||||
|
||||
#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "AudioManager" , ## args)
|
||||
#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "AudioManager" , ## args)
|
||||
|
||||
#define HEADPHONES_STATUS_CHANGED "headphones-status-changed"
|
||||
#define HEADPHONES_STATUS_ON NS_LITERAL_STRING("on").get()
|
||||
|
@ -34,6 +34,21 @@ using namespace mozilla;
|
|||
#define HEADPHONES_STATUS_UNKNOWN NS_LITERAL_STRING("unknown").get()
|
||||
#define BLUETOOTH_SCO_STATUS_CHANGED "bluetooth-sco-status-changed"
|
||||
|
||||
// Refer AudioService.java from Android
|
||||
static int sMaxStreamVolumeTbl[AUDIO_STREAM_CNT] = {
|
||||
10, // voice call
|
||||
10, // system
|
||||
7, // ring
|
||||
15, // music
|
||||
7, // alarm
|
||||
7, // notification
|
||||
15, // BT SCO
|
||||
7, // enforced audible
|
||||
15, // DTMF
|
||||
15, // TTS
|
||||
10, // FM
|
||||
};
|
||||
|
||||
// A bitwise variable for recording what kind of headset is attached.
|
||||
static int sHeadsetState;
|
||||
static int kBtSampleRate = 8000;
|
||||
|
@ -44,7 +59,7 @@ IsFmRadioAudioOn()
|
|||
if (static_cast<
|
||||
audio_policy_dev_state_t (*) (audio_devices_t, const char *)
|
||||
>(AudioSystem::getDeviceConnectionState)) {
|
||||
return AudioSystem::getDeviceConnectionState(AUDIO_DEVICE_OUT_FM, "") ==
|
||||
return AudioSystem::getDeviceConnectionState(AUDIO_DEVICE_OUT_FM, "") ==
|
||||
AUDIO_POLICY_DEVICE_STATE_AVAILABLE ? true : false;
|
||||
} else {
|
||||
return false;
|
||||
|
@ -187,6 +202,11 @@ AudioManager::AudioManager() : mPhoneState(PHONE_STATE_CURRENT),
|
|||
if (NS_FAILED(obs->AddObserver(this, BLUETOOTH_SCO_STATUS_CHANGED, false))) {
|
||||
NS_WARNING("Failed to add bluetooth-sco-status-changed oberver!");
|
||||
}
|
||||
|
||||
for (int loop = 0; loop < AUDIO_STREAM_CNT; loop++) {
|
||||
AudioSystem::initStreamVolume(static_cast<audio_stream_type_t>(loop), 0,
|
||||
sMaxStreamVolumeTbl[loop]);
|
||||
}
|
||||
}
|
||||
|
||||
AudioManager::~AudioManager() {
|
||||
|
@ -338,7 +358,7 @@ AudioManager::SetFmRadioAudioEnabled(bool aFmRadioAudioEnabled)
|
|||
status_t (*) (AudioSystem::audio_devices, AudioSystem::device_connection_state, const char *)
|
||||
>(AudioSystem::setDeviceConnectionState)) {
|
||||
AudioSystem::setDeviceConnectionState(AUDIO_DEVICE_OUT_FM,
|
||||
aFmRadioAudioEnabled ? AUDIO_POLICY_DEVICE_STATE_AVAILABLE :
|
||||
aFmRadioAudioEnabled ? AUDIO_POLICY_DEVICE_STATE_AVAILABLE :
|
||||
AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE, "");
|
||||
InternalSetAudioRoutes(GetCurrentSwitchState(SWITCH_HEADPHONES));
|
||||
return NS_OK;
|
||||
|
@ -346,3 +366,24 @@ AudioManager::SetFmRadioAudioEnabled(bool aFmRadioAudioEnabled)
|
|||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
AudioManager::SetStreamVolumeIndex(int32_t aStream, int32_t aIndex) {
|
||||
status_t status =
|
||||
AudioSystem::setStreamVolumeIndex(static_cast<audio_stream_type_t>(aStream), aIndex);
|
||||
return status ? NS_ERROR_FAILURE : NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
AudioManager::GetStreamVolumeIndex(int32_t aStream, int32_t* aIndex) {
|
||||
status_t status =
|
||||
AudioSystem::getStreamVolumeIndex(static_cast<audio_stream_type_t>(aStream), aIndex);
|
||||
return status ? NS_ERROR_FAILURE : NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
AudioManager::GetMaxStreamVolumeIndex(int32_t aStream, int32_t* aMaxIndex) {
|
||||
*aMaxIndex = sMaxStreamVolumeTbl[aStream];
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
[scriptable, builtinclass, uuid(d2124467-7209-4b2e-a91a-cf3f90681e3c)]
|
||||
[scriptable, builtinclass, uuid(b76a3de4-79f4-4cbb-a0e2-871095eacb2c)]
|
||||
interface nsIAudioManager : nsISupports
|
||||
{
|
||||
/**
|
||||
|
@ -59,4 +59,23 @@ interface nsIAudioManager : nsISupports
|
|||
|
||||
void setForceForUse(in long usage, in long force);
|
||||
long getForceForUse(in long usage);
|
||||
|
||||
/**
|
||||
* Control the volume of various audio streams
|
||||
*/
|
||||
const long STREAM_TYPE_VOICE_CALL = 0;
|
||||
const long STREAM_TYPE_SYSTEM = 1;
|
||||
const long STREAM_TYPE_RING = 2;
|
||||
const long STREAM_TYPE_MUSIC = 3;
|
||||
const long STREAM_TYPE_ALARM = 4;
|
||||
const long STREAM_TYPE_NOTIFICATION = 5;
|
||||
const long STREAM_TYPE_BLUETOOTH_SCO = 6;
|
||||
const long STREAM_TYPE_ENFORCED_AUDIBLE = 7;
|
||||
const long STREAM_TYPE_DTMF = 8;
|
||||
const long STREAM_TYPE_TTS = 9;
|
||||
const long STREAM_TYPE_FM = 10;
|
||||
|
||||
void setStreamVolumeIndex(in long stream, in long index);
|
||||
long getStreamVolumeIndex(in long stream);
|
||||
long getMaxStreamVolumeIndex(in long stream);
|
||||
};
|
||||
|
|
|
@ -144,6 +144,8 @@ interface CanvasRenderingContext2D {
|
|||
// if scaled.
|
||||
attribute boolean mozImageSmoothingEnabled;
|
||||
|
||||
boolean mozIsPointInStroke(double x, double y);
|
||||
|
||||
// Show the caret if appropriate when drawing
|
||||
[ChromeOnly]
|
||||
const unsigned long DRAWWINDOW_DRAW_CARET = 0x01;
|
||||
|
|
|
@ -398,6 +398,15 @@ public:
|
|||
*/
|
||||
virtual bool ContainsPoint(const Point &aPoint, const Matrix &aTransform) const = 0;
|
||||
|
||||
|
||||
/* This function checks if a point lies within the stroke of a path using the
|
||||
* specified strokeoptions. It allows passing a transform that will transform
|
||||
* the path to the coordinate space in which aPoint is given.
|
||||
*/
|
||||
virtual bool StrokeContainsPoint(const StrokeOptions &aStrokeOptions,
|
||||
const Point &aPoint,
|
||||
const Matrix &aTransform) const = 0;
|
||||
|
||||
/* This functions gets the bounds of this path. These bounds are not
|
||||
* guaranteed to be tight. A transform may be specified that gives the bounds
|
||||
* after application of the transform.
|
||||
|
|
|
@ -198,6 +198,34 @@ ScratchContext()
|
|||
return cg;
|
||||
}
|
||||
|
||||
bool
|
||||
PathCG::StrokeContainsPoint(const StrokeOptions &aStrokeOptions,
|
||||
const Point &aPoint,
|
||||
const Matrix &aTransform) const
|
||||
{
|
||||
Matrix inverse = aTransform;
|
||||
inverse.Invert();
|
||||
Point transformedPoint = inverse*aPoint;
|
||||
// We could probably drop the input transform and just transform the point at the caller?
|
||||
CGPoint point = {transformedPoint.x, transformedPoint.y};
|
||||
|
||||
CGContextRef cg = ScratchContext();
|
||||
|
||||
CGContextSaveGState(cg);
|
||||
|
||||
CGContextBeginPath(cg);
|
||||
CGContextAddPath(cg, mPath);
|
||||
|
||||
SetStrokeOptions(cg, aStrokeOptions);
|
||||
|
||||
CGContextReplacePathWithStrokedPath(cg);
|
||||
CGContextRestoreGState(cg);
|
||||
|
||||
CGPathRef sPath = CGContextCopyPath(cg);
|
||||
|
||||
return CGPathContainsPoint(sPath, nullptr, point, false);
|
||||
}
|
||||
|
||||
//XXX: what should these functions return for an empty path?
|
||||
// currently they return CGRectNull {inf,inf, 0, 0}
|
||||
Rect
|
||||
|
|
|
@ -77,6 +77,9 @@ public:
|
|||
FillRule aFillRule = FILL_WINDING) const;
|
||||
|
||||
virtual bool ContainsPoint(const Point &aPoint, const Matrix &aTransform) const;
|
||||
virtual bool StrokeContainsPoint(const StrokeOptions &aStrokeOptions,
|
||||
const Point &aPoint,
|
||||
const Matrix &aTransform) const;
|
||||
virtual Rect GetBounds(const Matrix &aTransform = Matrix()) const;
|
||||
virtual Rect GetStrokedBounds(const StrokeOptions &aStrokeOptions,
|
||||
const Matrix &aTransform = Matrix()) const;
|
||||
|
|
|
@ -263,6 +263,21 @@ PathCairo::ContainsPoint(const Point &aPoint, const Matrix &aTransform) const
|
|||
return cairo_in_fill(*mPathContext, transformed.x, transformed.y);
|
||||
}
|
||||
|
||||
bool
|
||||
PathCairo::StrokeContainsPoint(const StrokeOptions &aStrokeOptions,
|
||||
const Point &aPoint,
|
||||
const Matrix &aTransform) const
|
||||
{
|
||||
CairoTempMatrix(*mPathContext, mTransform);
|
||||
|
||||
Matrix inverse = aTransform;
|
||||
inverse.Invert();
|
||||
Point transformed = inverse * aPoint;
|
||||
|
||||
SetCairoStrokeOptions(*mPathContext, aStrokeOptions);
|
||||
return cairo_in_stroke(*mPathContext, transformed.x, transformed.y);
|
||||
}
|
||||
|
||||
Rect
|
||||
PathCairo::GetBounds(const Matrix &aTransform) const
|
||||
{
|
||||
|
|
|
@ -125,6 +125,10 @@ public:
|
|||
|
||||
virtual bool ContainsPoint(const Point &aPoint, const Matrix &aTransform) const;
|
||||
|
||||
virtual bool StrokeContainsPoint(const StrokeOptions &aStrokeOptions,
|
||||
const Point &aPoint,
|
||||
const Matrix &aTransform) const;
|
||||
|
||||
virtual Rect GetBounds(const Matrix &aTransform = Matrix()) const;
|
||||
|
||||
virtual Rect GetStrokedBounds(const StrokeOptions &aStrokeOptions,
|
||||
|
|
|
@ -307,6 +307,29 @@ PathD2D::ContainsPoint(const Point &aPoint, const Matrix &aTransform) const
|
|||
return !!result;
|
||||
}
|
||||
|
||||
bool
|
||||
PathD2D::StrokeContainsPoint(const StrokeOptions &aStrokeOptions,
|
||||
const Point &aPoint,
|
||||
const Matrix &aTransform) const
|
||||
{
|
||||
BOOL result;
|
||||
|
||||
RefPtr<ID2D1StrokeStyle> strokeStyle =
|
||||
DrawTargetD2D::CreateStrokeStyleForOptions(aStrokeOptions);
|
||||
HRESULT hr = mGeometry->StrokeContainsPoint(D2DPoint(aPoint),
|
||||
aStrokeOptions.mLineWidth,
|
||||
strokeStyle,
|
||||
D2DMatrix(aTransform),
|
||||
&result);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
// Log
|
||||
return false;
|
||||
}
|
||||
|
||||
return !!result;
|
||||
}
|
||||
|
||||
Rect
|
||||
PathD2D::GetBounds(const Matrix &aTransform) const
|
||||
{
|
||||
|
|
|
@ -75,6 +75,10 @@ public:
|
|||
|
||||
virtual bool ContainsPoint(const Point &aPoint, const Matrix &aTransform) const;
|
||||
|
||||
virtual bool StrokeContainsPoint(const StrokeOptions &aStrokeOptions,
|
||||
const Point &aPoint,
|
||||
const Matrix &aTransform) const;
|
||||
|
||||
virtual Rect GetBounds(const Matrix &aTransform = Matrix()) const;
|
||||
|
||||
virtual Rect GetStrokedBounds(const StrokeOptions &aStrokeOptions,
|
||||
|
|
|
@ -96,6 +96,10 @@ public:
|
|||
FillRule aFillRule = FILL_WINDING) const;
|
||||
virtual bool ContainsPoint(const Point &aPoint, const Matrix &aTransform) const
|
||||
{ return mPath->ContainsPoint(aPoint, aTransform); }
|
||||
virtual bool StrokeContainsPoint(const StrokeOptions &aStrokeOptions,
|
||||
const Point &aPoint,
|
||||
const Matrix &aTransform) const
|
||||
{ return mPath->StrokeContainsPoint(aStrokeOptions, aPoint, aTransform); }
|
||||
|
||||
virtual Rect GetBounds(const Matrix &aTransform = Matrix()) const
|
||||
{ return mPath->GetBounds(aTransform); }
|
||||
|
|
|
@ -148,6 +148,32 @@ static Rect SkRectToRect(const SkRect& aBounds)
|
|||
SkScalarToFloat(aBounds.fBottom - aBounds.fTop));
|
||||
}
|
||||
|
||||
bool
|
||||
PathSkia::StrokeContainsPoint(const StrokeOptions &aStrokeOptions,
|
||||
const Point &aPoint,
|
||||
const Matrix &aTransform) const
|
||||
{
|
||||
Matrix inverse = aTransform;
|
||||
inverse.Invert();
|
||||
Point transformed = inverse * aPoint;
|
||||
|
||||
SkPaint paint;
|
||||
StrokeOptionsToPaint(paint, aStrokeOptions);
|
||||
|
||||
SkPath strokePath;
|
||||
paint.getFillPath(mPath, &strokePath);
|
||||
|
||||
Rect bounds = aTransform.TransformBounds(SkRectToRect(strokePath.getBounds()));
|
||||
|
||||
if (aPoint.x < bounds.x || aPoint.y < bounds.y ||
|
||||
aPoint.x > bounds.XMost() || aPoint.y > bounds.YMost()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return strokePath.contains(SkFloatToScalar(transformed.x),
|
||||
SkFloatToScalar(transformed.y));
|
||||
}
|
||||
|
||||
Rect
|
||||
PathSkia::GetBounds(const Matrix &aTransform) const
|
||||
{
|
||||
|
|
|
@ -57,6 +57,10 @@ public:
|
|||
|
||||
virtual bool ContainsPoint(const Point &aPoint, const Matrix &aTransform) const;
|
||||
|
||||
virtual bool StrokeContainsPoint(const StrokeOptions &aStrokeOptions,
|
||||
const Point &aPoint,
|
||||
const Matrix &aTransform) const;
|
||||
|
||||
virtual Rect GetBounds(const Matrix &aTransform = Matrix()) const;
|
||||
|
||||
virtual Rect GetStrokedBounds(const StrokeOptions &aStrokeOptions,
|
||||
|
|
|
@ -625,21 +625,34 @@ GLContext::CanUploadSubTextures()
|
|||
return true;
|
||||
}
|
||||
|
||||
bool GLContext::sPowerOfTwoForced = false;
|
||||
bool GLContext::sPowerOfTwoPrefCached = false;
|
||||
|
||||
void
|
||||
GLContext::PlatformStartup()
|
||||
{
|
||||
CacheCanUploadNPOT();
|
||||
}
|
||||
|
||||
void
|
||||
GLContext::CacheCanUploadNPOT()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Can't cache prefs off the main thread.");
|
||||
MOZ_ASSERT(!sPowerOfTwoPrefCached, "Must only call this function once!");
|
||||
|
||||
sPowerOfTwoPrefCached = true;
|
||||
mozilla::Preferences::AddBoolVarCache(&sPowerOfTwoForced,
|
||||
"gfx.textures.poweroftwo.force-enabled");
|
||||
}
|
||||
|
||||
bool
|
||||
GLContext::CanUploadNonPowerOfTwo()
|
||||
{
|
||||
MOZ_ASSERT(sPowerOfTwoPrefCached);
|
||||
|
||||
if (!mWorkAroundDriverBugs)
|
||||
return true;
|
||||
|
||||
static bool sPowerOfTwoForced;
|
||||
static bool sPowerOfTwoPrefCached = false;
|
||||
|
||||
if (!sPowerOfTwoPrefCached) {
|
||||
sPowerOfTwoPrefCached = true;
|
||||
mozilla::Preferences::AddBoolVarCache(&sPowerOfTwoForced,
|
||||
"gfx.textures.poweroftwo.force-enabled");
|
||||
}
|
||||
|
||||
// Some GPUs driver crash when uploading non power of two 565 textures.
|
||||
return sPowerOfTwoForced ? false : (Renderer() != RendererAdreno200 &&
|
||||
Renderer() != RendererAdreno205);
|
||||
|
|
|
@ -744,7 +744,17 @@ public:
|
|||
}
|
||||
|
||||
bool CanUploadSubTextures();
|
||||
|
||||
static void PlatformStartup();
|
||||
|
||||
protected:
|
||||
static bool sPowerOfTwoForced;
|
||||
static bool sPowerOfTwoPrefCached;
|
||||
static void CacheCanUploadNPOT();
|
||||
|
||||
public:
|
||||
bool CanUploadNonPowerOfTwo();
|
||||
|
||||
bool WantsSmallTiles();
|
||||
virtual bool HasLockSurface() { return false; }
|
||||
|
||||
|
|
|
@ -537,9 +537,13 @@ BasicLayerManager::EndTransactionInternal(DrawThebesLayerCallback aCallback,
|
|||
mTransactionIncomplete = false;
|
||||
|
||||
if (aFlags & END_NO_COMPOSITE) {
|
||||
// TODO: We should really just set mTarget to null and make sure we can handle that further down the call chain
|
||||
nsRefPtr<gfxASurface> surf = gfxPlatform::GetPlatform()->CreateOffscreenSurface(gfxIntSize(1, 1), gfxASurface::CONTENT_COLOR);
|
||||
mTarget = new gfxContext(surf);
|
||||
if (!mDummyTarget) {
|
||||
// TODO: We should really just set mTarget to null and make sure we can handle that further down the call chain
|
||||
// Creating this temporary surface can be expensive on some platforms (d2d in particular), so cache it between paints.
|
||||
nsRefPtr<gfxASurface> surf = gfxPlatform::GetPlatform()->CreateOffscreenSurface(gfxIntSize(1, 1), gfxASurface::CONTENT_COLOR);
|
||||
mDummyTarget = new gfxContext(surf);
|
||||
}
|
||||
mTarget = mDummyTarget;
|
||||
}
|
||||
|
||||
if (mTarget && mRoot && !(aFlags & END_NO_IMMEDIATE_REDRAW)) {
|
||||
|
|
|
@ -1614,8 +1614,9 @@ gfxContext::PointInStroke(const gfxPoint& pt)
|
|||
if (mCairo) {
|
||||
return cairo_in_stroke(mCairo, pt.x, pt.y);
|
||||
} else {
|
||||
// XXX - Used by SVG, needs fixing.
|
||||
return false;
|
||||
return mPath->StrokeContainsPoint(CurrentState().strokeOptions,
|
||||
ToPoint(pt),
|
||||
mTransform);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -258,16 +258,16 @@ gfxPlatform::Init()
|
|||
|
||||
bool useOffMainThreadCompositing = false;
|
||||
#ifdef MOZ_X11
|
||||
// On X11 platforms only use OMTC if firefox was initalized with thread-safe
|
||||
// On X11 platforms only use OMTC if firefox was initalized with thread-safe
|
||||
// X11 (else it would crash).
|
||||
useOffMainThreadCompositing = (PR_GetEnv("MOZ_USE_OMTC") != NULL);
|
||||
#else
|
||||
useOffMainThreadCompositing = Preferences::GetBool(
|
||||
"layers.offmainthreadcomposition.enabled",
|
||||
"layers.offmainthreadcomposition.enabled",
|
||||
false);
|
||||
#endif
|
||||
|
||||
if (useOffMainThreadCompositing && (XRE_GetProcessType() ==
|
||||
if (useOffMainThreadCompositing && (XRE_GetProcessType() ==
|
||||
GeckoProcessType_Default)) {
|
||||
CompositorParent::StartUp();
|
||||
if (Preferences::GetBool("layers.async-video.enabled",false)) {
|
||||
|
@ -340,6 +340,8 @@ gfxPlatform::Init()
|
|||
|
||||
gPlatform->mWorkAroundDriverBugs = Preferences::GetBool("gfx.work-around-driver-bugs", true);
|
||||
|
||||
mozilla::gl::GLContext::PlatformStartup();
|
||||
|
||||
#ifdef MOZ_WIDGET_ANDROID
|
||||
// Texture pool init
|
||||
mozilla::gl::TexturePoolOGL::Init();
|
||||
|
@ -440,7 +442,7 @@ gfxPlatform::~gfxPlatform()
|
|||
already_AddRefed<gfxASurface>
|
||||
gfxPlatform::CreateOffscreenImageSurface(const gfxIntSize& aSize,
|
||||
gfxASurface::gfxContentType aContentType)
|
||||
{
|
||||
{
|
||||
nsRefPtr<gfxASurface> newSurface;
|
||||
newSurface = new gfxImageSurface(aSize, OptimalFormatForContent(aContentType));
|
||||
|
||||
|
@ -454,7 +456,7 @@ gfxPlatform::OptimizeImage(gfxImageSurface *aSurface,
|
|||
const gfxIntSize& surfaceSize = aSurface->GetSize();
|
||||
|
||||
#ifdef XP_WIN
|
||||
if (gfxWindowsPlatform::GetPlatform()->GetRenderMode() ==
|
||||
if (gfxWindowsPlatform::GetPlatform()->GetRenderMode() ==
|
||||
gfxWindowsPlatform::RENDER_DIRECT2D) {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -871,7 +873,7 @@ AppendGenericFontFromPref(nsString& aFonts, nsIAtom *aLangGroup, const char *aGe
|
|||
genericDotLang.AppendLiteral(".");
|
||||
genericDotLang.Append(langGroupString);
|
||||
|
||||
// fetch font.name.xxx value
|
||||
// fetch font.name.xxx value
|
||||
prefName.AssignLiteral("font.name.");
|
||||
prefName.Append(genericDotLang);
|
||||
nsAdoptingString nameValue = Preferences::GetString(prefName.get());
|
||||
|
@ -881,7 +883,7 @@ AppendGenericFontFromPref(nsString& aFonts, nsIAtom *aLangGroup, const char *aGe
|
|||
aFonts += nameValue;
|
||||
}
|
||||
|
||||
// fetch font.name-list.xxx value
|
||||
// fetch font.name-list.xxx value
|
||||
prefName.AssignLiteral("font.name-list.");
|
||||
prefName.Append(genericDotLang);
|
||||
nsAdoptingString nameListValue = Preferences::GetString(prefName.get());
|
||||
|
@ -911,17 +913,17 @@ bool gfxPlatform::ForEachPrefFont(eFontPrefLang aLangArray[], uint32_t aLangArra
|
|||
for (i = 0; i < aLangArrayLen; i++) {
|
||||
eFontPrefLang prefLang = aLangArray[i];
|
||||
const char *langGroup = GetPrefLangName(prefLang);
|
||||
|
||||
|
||||
nsAutoCString prefName;
|
||||
|
||||
|
||||
prefName.AssignLiteral("font.default.");
|
||||
prefName.Append(langGroup);
|
||||
nsAdoptingCString genericDotLang = Preferences::GetCString(prefName.get());
|
||||
|
||||
|
||||
genericDotLang.AppendLiteral(".");
|
||||
genericDotLang.Append(langGroup);
|
||||
|
||||
// fetch font.name.xxx value
|
||||
|
||||
// fetch font.name.xxx value
|
||||
prefName.AssignLiteral("font.name.");
|
||||
prefName.Append(genericDotLang);
|
||||
nsAdoptingCString nameValue = Preferences::GetCString(prefName.get());
|
||||
|
@ -929,8 +931,8 @@ bool gfxPlatform::ForEachPrefFont(eFontPrefLang aLangArray[], uint32_t aLangArra
|
|||
if (!aCallback(prefLang, NS_ConvertUTF8toUTF16(nameValue), aClosure))
|
||||
return false;
|
||||
}
|
||||
|
||||
// fetch font.name-list.xxx value
|
||||
|
||||
// fetch font.name-list.xxx value
|
||||
prefName.AssignLiteral("font.name-list.");
|
||||
prefName.Append(genericDotLang);
|
||||
nsAdoptingCString nameListValue = Preferences::GetCString(prefName.get());
|
||||
|
@ -1029,7 +1031,7 @@ gfxPlatform::GetFontPrefLangFor(uint8_t aUnicodeRange)
|
|||
}
|
||||
}
|
||||
|
||||
bool
|
||||
bool
|
||||
gfxPlatform::IsLangCJK(eFontPrefLang aLang)
|
||||
{
|
||||
switch (aLang) {
|
||||
|
@ -1045,7 +1047,7 @@ gfxPlatform::IsLangCJK(eFontPrefLang aLang)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
gfxPlatform::GetLangPrefs(eFontPrefLang aPrefLangs[], uint32_t &aLen, eFontPrefLang aCharLang, eFontPrefLang aPageLang)
|
||||
{
|
||||
if (IsLangCJK(aCharLang)) {
|
||||
|
@ -1064,14 +1066,14 @@ gfxPlatform::AppendCJKPrefLangs(eFontPrefLang aPrefLangs[], uint32_t &aLen, eFon
|
|||
if (IsLangCJK(aPageLang)) {
|
||||
AppendPrefLang(aPrefLangs, aLen, aPageLang);
|
||||
}
|
||||
|
||||
|
||||
// if not set up, set up the default CJK order, based on accept lang settings and locale
|
||||
if (mCJKPrefLangs.Length() == 0) {
|
||||
|
||||
|
||||
// temp array
|
||||
eFontPrefLang tempPrefLangs[kMaxLenPrefLangList];
|
||||
uint32_t tempLen = 0;
|
||||
|
||||
|
||||
// Add the CJK pref fonts from accept languages, the order should be same order
|
||||
nsAdoptingCString list = Preferences::GetLocalizedCString("intl.accept_languages");
|
||||
if (!list.IsEmpty()) {
|
||||
|
@ -1148,34 +1150,34 @@ gfxPlatform::AppendCJKPrefLangs(eFontPrefLang aPrefLangs[], uint32_t &aLen, eFon
|
|||
AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_ChineseCN);
|
||||
AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_ChineseHK);
|
||||
AppendPrefLang(tempPrefLangs, tempLen, eFontPrefLang_ChineseTW);
|
||||
|
||||
|
||||
// copy into the cached array
|
||||
uint32_t j;
|
||||
for (j = 0; j < tempLen; j++) {
|
||||
mCJKPrefLangs.AppendElement(tempPrefLangs[j]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// append in cached CJK langs
|
||||
uint32_t i, numCJKlangs = mCJKPrefLangs.Length();
|
||||
|
||||
|
||||
for (i = 0; i < numCJKlangs; i++) {
|
||||
AppendPrefLang(aPrefLangs, aLen, (eFontPrefLang) (mCJKPrefLangs[i]));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
gfxPlatform::AppendPrefLang(eFontPrefLang aPrefLangs[], uint32_t& aLen, eFontPrefLang aAddLang)
|
||||
{
|
||||
if (aLen >= kMaxLenPrefLangList) return;
|
||||
|
||||
|
||||
// make sure
|
||||
uint32_t i = 0;
|
||||
while (i < aLen && aPrefLangs[i] != aAddLang) {
|
||||
i++;
|
||||
}
|
||||
|
||||
|
||||
if (i == aLen) {
|
||||
aPrefLangs[aLen] = aAddLang;
|
||||
aLen++;
|
||||
|
@ -1306,7 +1308,7 @@ gfxPlatform::GetRenderingIntent()
|
|||
return gCMSIntent;
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
gfxPlatform::TransformPixel(const gfxRGBA& in, gfxRGBA& out, qcms_transform *transform)
|
||||
{
|
||||
|
||||
|
@ -1381,7 +1383,7 @@ gfxPlatform::GetCMSOutputProfile()
|
|||
if (!gCMSOutputProfile) {
|
||||
gCMSOutputProfile = GetCMSsRGBProfile();
|
||||
}
|
||||
/* Precache the LUT16 Interpolations for the output profile. See
|
||||
/* Precache the LUT16 Interpolations for the output profile. See
|
||||
bug 444661 for details. */
|
||||
qcms_profile_precache_output_transform(gCMSOutputProfile);
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include "nsThreadUtils.h"
|
||||
#include "mozilla/FileUtils.h"
|
||||
|
||||
#include <cutils/properties.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <linux/videodev2.h>
|
||||
|
@ -70,12 +71,29 @@ static void
|
|||
initTavaruaRadio(hal::FMRadioSettings &aInfo)
|
||||
{
|
||||
mozilla::ScopedClose fd(sRadioFD);
|
||||
char command[64];
|
||||
snprintf(command, sizeof(command), "/system/bin/fm_qsoc_patches %d 0", sTavaruaVersion);
|
||||
int rc = system(command);
|
||||
if (rc) {
|
||||
HAL_LOG(("Unable to initialize radio"));
|
||||
return;
|
||||
char version[64];
|
||||
int rc;
|
||||
snprintf(version, sizeof(version), "%d", sTavaruaVersion);
|
||||
property_set("hw.fm.version", version);
|
||||
|
||||
/* Set the mode for soc downloader */
|
||||
property_set("hw.fm.mode", "normal");
|
||||
/* start fm_dl service */
|
||||
property_set("ctl.start", "fm_dl");
|
||||
|
||||
/*
|
||||
* Fix bug 800263. Wait until the FM radio chips initialization is done
|
||||
* then set other properties, or the system will hang and reboot. This
|
||||
* work around is from codeaurora
|
||||
* (git://codeaurora.org/platform/frameworks/base.git).
|
||||
*/
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
sleep(1);
|
||||
char value[PROPERTY_VALUE_MAX];
|
||||
property_get("hw.fm.init", value, "0");
|
||||
if (!strcmp(value, "1")) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
rc = setControl(V4L2_CID_PRIVATE_TAVARUA_STATE, FM_RECV);
|
||||
|
|
|
@ -519,27 +519,23 @@ class Rooted : public RootedBase<T>
|
|||
{
|
||||
#if defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING)
|
||||
ContextFriendFields *cx = ContextFriendFields::get(cxArg);
|
||||
|
||||
ThingRootKind kind = RootMethods<T>::kind();
|
||||
this->stack = reinterpret_cast<Rooted<T>**>(&cx->thingGCRooters[kind]);
|
||||
this->prev = *stack;
|
||||
*stack = this;
|
||||
|
||||
JS_ASSERT(!RootMethods<T>::poisoned(ptr));
|
||||
commonInit(cx->thingGCRooters);
|
||||
#endif
|
||||
}
|
||||
|
||||
void init(JSRuntime *rtArg)
|
||||
{
|
||||
#if defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING)
|
||||
RuntimeFriendFields *rt = const_cast<RuntimeFriendFields *>(RuntimeFriendFields::get(rtArg));
|
||||
PerThreadDataFriendFields *pt = PerThreadDataFriendFields::getMainThread(rtArg);
|
||||
commonInit(pt->thingGCRooters);
|
||||
#endif
|
||||
}
|
||||
|
||||
ThingRootKind kind = RootMethods<T>::kind();
|
||||
this->stack = reinterpret_cast<Rooted<T>**>(&rt->thingGCRooters[kind]);
|
||||
this->prev = *stack;
|
||||
*stack = this;
|
||||
|
||||
JS_ASSERT(!RootMethods<T>::poisoned(ptr));
|
||||
void init(js::PerThreadData *ptArg)
|
||||
{
|
||||
#if defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING)
|
||||
PerThreadDataFriendFields *pt = PerThreadDataFriendFields::get(ptArg);
|
||||
commonInit(pt->thingGCRooters);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -576,6 +572,22 @@ class Rooted : public RootedBase<T>
|
|||
init(cx);
|
||||
}
|
||||
|
||||
Rooted(js::PerThreadData *pt
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
: ptr(RootMethods<T>::initial())
|
||||
{
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
init(pt);
|
||||
}
|
||||
|
||||
Rooted(js::PerThreadData *pt, T initial
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
: ptr(initial)
|
||||
{
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
init(pt);
|
||||
}
|
||||
|
||||
template <typename S>
|
||||
Rooted(JSContext *cx, const Return<S> &initial
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
|
@ -585,6 +597,15 @@ class Rooted : public RootedBase<T>
|
|||
init(cx);
|
||||
}
|
||||
|
||||
template <typename S>
|
||||
Rooted(js::PerThreadData *pt, const Return<S> &initial
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
: ptr(initial.ptr_)
|
||||
{
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
init(pt);
|
||||
}
|
||||
|
||||
~Rooted()
|
||||
{
|
||||
#if defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING)
|
||||
|
@ -625,6 +646,17 @@ class Rooted : public RootedBase<T>
|
|||
}
|
||||
|
||||
private:
|
||||
void commonInit(Rooted<void*> **thingGCRooters) {
|
||||
#if defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING)
|
||||
ThingRootKind kind = RootMethods<T>::kind();
|
||||
this->stack = reinterpret_cast<Rooted<T>**>(&thingGCRooters[kind]);
|
||||
this->prev = *stack;
|
||||
*stack = this;
|
||||
|
||||
JS_ASSERT(!RootMethods<T>::poisoned(ptr));
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING)
|
||||
Rooted<T> **stack, *prev;
|
||||
#endif
|
||||
|
|
|
@ -676,33 +676,36 @@ static JSBool js_NewRuntimeWasCalled = JS_FALSE;
|
|||
/*
|
||||
* Thread Local Storage slot for storing the runtime for a thread.
|
||||
*/
|
||||
namespace js {
|
||||
mozilla::ThreadLocal<PerThreadData *> TlsPerThreadData;
|
||||
}
|
||||
|
||||
namespace JS {
|
||||
mozilla::ThreadLocal<JSRuntime *> TlsRuntime;
|
||||
|
||||
#ifdef DEBUG
|
||||
JS_FRIEND_API(void)
|
||||
EnterAssertNoGCScope()
|
||||
{
|
||||
++TlsRuntime.get()->gcAssertNoGCDepth;
|
||||
++TlsPerThreadData.get()->gcAssertNoGCDepth;
|
||||
}
|
||||
|
||||
JS_FRIEND_API(void)
|
||||
LeaveAssertNoGCScope()
|
||||
{
|
||||
--TlsRuntime.get()->gcAssertNoGCDepth;
|
||||
JS_ASSERT(TlsRuntime.get()->gcAssertNoGCDepth >= 0);
|
||||
--TlsPerThreadData.get()->gcAssertNoGCDepth;
|
||||
JS_ASSERT(TlsPerThreadData.get()->gcAssertNoGCDepth >= 0);
|
||||
}
|
||||
|
||||
JS_FRIEND_API(bool)
|
||||
InNoGCScope()
|
||||
{
|
||||
return TlsRuntime.get()->gcAssertNoGCDepth > 0;
|
||||
return TlsPerThreadData.get()->gcAssertNoGCDepth > 0;
|
||||
}
|
||||
|
||||
JS_FRIEND_API(bool)
|
||||
NeedRelaxedRootChecks()
|
||||
{
|
||||
return TlsRuntime.get()->gcRelaxRootChecks;
|
||||
return TlsPerThreadData.get()->gcRelaxRootChecks;
|
||||
}
|
||||
#else
|
||||
JS_FRIEND_API(void) EnterAssertNoGCScope() {}
|
||||
|
@ -715,8 +718,17 @@ JS_FRIEND_API(bool) NeedRelaxedRootChecks() { return false; }
|
|||
|
||||
static const JSSecurityCallbacks NullSecurityCallbacks = { };
|
||||
|
||||
js::PerThreadData::PerThreadData(JSRuntime *runtime)
|
||||
: runtime_(runtime)
|
||||
#ifdef DEBUG
|
||||
, gcRelaxRootChecks(false)
|
||||
, gcAssertNoGCDepth(0)
|
||||
#endif
|
||||
{}
|
||||
|
||||
JSRuntime::JSRuntime(JSUseHelperThreads useHelperThreads)
|
||||
: atomsCompartment(NULL),
|
||||
: mainThread(this),
|
||||
atomsCompartment(NULL),
|
||||
#ifdef JS_THREADSAFE
|
||||
ownerThread_(NULL),
|
||||
#endif
|
||||
|
@ -788,10 +800,6 @@ JSRuntime::JSRuntime(JSUseHelperThreads useHelperThreads)
|
|||
gcSliceBudget(SliceBudget::Unlimited),
|
||||
gcIncrementalEnabled(true),
|
||||
gcExactScanningEnabled(true),
|
||||
#ifdef DEBUG
|
||||
gcRelaxRootChecks(false),
|
||||
gcAssertNoGCDepth(0),
|
||||
#endif
|
||||
gcPoke(false),
|
||||
heapState(Idle),
|
||||
#ifdef JS_GC_ZEAL
|
||||
|
@ -885,16 +893,12 @@ JSRuntime::init(uint32_t maxbytes)
|
|||
ownerThread_ = PR_GetCurrentThread();
|
||||
#endif
|
||||
|
||||
JS::TlsRuntime.set(this);
|
||||
js::TlsPerThreadData.set(&mainThread);
|
||||
|
||||
#ifdef JS_METHODJIT_SPEW
|
||||
JMCheckLogging();
|
||||
#endif
|
||||
|
||||
#if defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING)
|
||||
PodArrayZero(thingGCRooters);
|
||||
#endif
|
||||
|
||||
if (!js_InitGC(this, maxbytes))
|
||||
return false;
|
||||
|
||||
|
@ -1018,9 +1022,9 @@ JSRuntime::setOwnerThread()
|
|||
JS_ASSERT(ownerThread_ == (void *)0xc1ea12); /* "clear" */
|
||||
JS_ASSERT(requestDepth == 0);
|
||||
JS_ASSERT(js_NewRuntimeWasCalled);
|
||||
JS_ASSERT(JS::TlsRuntime.get() == NULL);
|
||||
JS_ASSERT(js::TlsPerThreadData.get() == NULL);
|
||||
ownerThread_ = PR_GetCurrentThread();
|
||||
JS::TlsRuntime.set(this);
|
||||
js::TlsPerThreadData.set(&mainThread);
|
||||
nativeStackBase = GetNativeStackBase();
|
||||
if (nativeStackQuota)
|
||||
JS_SetNativeStackQuota(this, nativeStackQuota);
|
||||
|
@ -1033,7 +1037,7 @@ JSRuntime::clearOwnerThread()
|
|||
JS_ASSERT(requestDepth == 0);
|
||||
JS_ASSERT(js_NewRuntimeWasCalled);
|
||||
ownerThread_ = (void *)0xc1ea12; /* "clear" */
|
||||
JS::TlsRuntime.set(NULL);
|
||||
js::TlsPerThreadData.set(NULL);
|
||||
nativeStackBase = 0;
|
||||
#if JS_STACK_GROWTH_DIRECTION > 0
|
||||
nativeStackLimit = UINTPTR_MAX;
|
||||
|
@ -1047,7 +1051,7 @@ JSRuntime::abortIfWrongThread() const
|
|||
{
|
||||
if (ownerThread_ != PR_GetCurrentThread())
|
||||
MOZ_CRASH();
|
||||
if (this != JS::TlsRuntime.get())
|
||||
if (!js::TlsPerThreadData.get()->associatedWith(this))
|
||||
MOZ_CRASH();
|
||||
}
|
||||
|
||||
|
@ -1055,7 +1059,7 @@ JS_FRIEND_API(void)
|
|||
JSRuntime::assertValidThread() const
|
||||
{
|
||||
JS_ASSERT(ownerThread_ == PR_GetCurrentThread());
|
||||
JS_ASSERT(this == JS::TlsRuntime.get());
|
||||
JS_ASSERT(js::TlsPerThreadData.get()->associatedWith(this));
|
||||
}
|
||||
#endif /* JS_THREADSAFE */
|
||||
|
||||
|
@ -1092,7 +1096,7 @@ JS_NewRuntime(uint32_t maxbytes, JSUseHelperThreads useHelperThreads)
|
|||
|
||||
InitMemorySubsystem();
|
||||
|
||||
if (!JS::TlsRuntime.init())
|
||||
if (!js::TlsPerThreadData.init())
|
||||
return NULL;
|
||||
|
||||
js_NewRuntimeWasCalled = JS_TRUE;
|
||||
|
@ -6553,7 +6557,7 @@ JS_ReportErrorNumberVA(JSContext *cx, JSErrorCallback errorCallback,
|
|||
|
||||
JS_PUBLIC_API(void)
|
||||
JS_ReportErrorNumberUC(JSContext *cx, JSErrorCallback errorCallback,
|
||||
void *userRef, const unsigned errorNumber, ...)
|
||||
void *userRef, const unsigned errorNumber, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
|
@ -6564,6 +6568,16 @@ JS_ReportErrorNumberUC(JSContext *cx, JSErrorCallback errorCallback,
|
|||
va_end(ap);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
JS_ReportErrorNumberUCArray(JSContext *cx, JSErrorCallback errorCallback,
|
||||
void *userRef, const unsigned errorNumber,
|
||||
const jschar **args)
|
||||
{
|
||||
AssertHeapIsIdle(cx);
|
||||
js_ReportErrorNumberUCArray(cx, JSREPORT_ERROR, errorCallback, userRef,
|
||||
errorNumber, args);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSBool)
|
||||
JS_ReportWarning(JSContext *cx, const char *format, ...)
|
||||
{
|
||||
|
|
|
@ -2889,8 +2889,6 @@ JS_IsInRequest(JSRuntime *rt);
|
|||
|
||||
namespace JS {
|
||||
|
||||
extern mozilla::ThreadLocal<JSRuntime *> TlsRuntime;
|
||||
|
||||
inline bool
|
||||
IsPoisonedId(jsid iden)
|
||||
{
|
||||
|
@ -5693,6 +5691,11 @@ extern JS_PUBLIC_API(void)
|
|||
JS_ReportErrorNumberUC(JSContext *cx, JSErrorCallback errorCallback,
|
||||
void *userRef, const unsigned errorNumber, ...);
|
||||
|
||||
extern JS_PUBLIC_API(void)
|
||||
JS_ReportErrorNumberUCArray(JSContext *cx, JSErrorCallback errorCallback,
|
||||
void *userRef, const unsigned errorNumber,
|
||||
const jschar **args);
|
||||
|
||||
/*
|
||||
* As above, but report a warning instead (JSREPORT_IS_WARNING(report.flags)).
|
||||
* Return true if there was no error trying to issue the warning, and if the
|
||||
|
|
|
@ -875,6 +875,7 @@ js_ExpandErrorArguments(JSContext *cx, JSErrorCallback callback,
|
|||
const JSErrorFormatString *efs;
|
||||
int i;
|
||||
int argCount;
|
||||
bool messageArgsPassed = !!reportp->messageArgs;
|
||||
|
||||
*messagep = NULL;
|
||||
|
||||
|
@ -897,12 +898,19 @@ js_ExpandErrorArguments(JSContext *cx, JSErrorCallback callback,
|
|||
* null it out to act as the caboose when we free the
|
||||
* pointers later.
|
||||
*/
|
||||
reportp->messageArgs = cx->pod_malloc<const jschar*>(argCount + 1);
|
||||
if (!reportp->messageArgs)
|
||||
return JS_FALSE;
|
||||
reportp->messageArgs[argCount] = NULL;
|
||||
if (messageArgsPassed) {
|
||||
JS_ASSERT(!reportp->messageArgs[argCount]);
|
||||
} else {
|
||||
reportp->messageArgs = cx->pod_malloc<const jschar*>(argCount + 1);
|
||||
if (!reportp->messageArgs)
|
||||
return JS_FALSE;
|
||||
/* NULL-terminate for easy copying. */
|
||||
reportp->messageArgs[argCount] = NULL;
|
||||
}
|
||||
for (i = 0; i < argCount; i++) {
|
||||
if (charArgs) {
|
||||
if (messageArgsPassed) {
|
||||
/* Do nothing. */
|
||||
} else if (charArgs) {
|
||||
char *charArg = va_arg(ap, char *);
|
||||
size_t charArgLength = strlen(charArg);
|
||||
reportp->messageArgs[i] = InflateString(cx, charArg, &charArgLength);
|
||||
|
@ -914,8 +922,6 @@ js_ExpandErrorArguments(JSContext *cx, JSErrorCallback callback,
|
|||
argLengths[i] = js_strlen(reportp->messageArgs[i]);
|
||||
totalArgsLength += argLengths[i];
|
||||
}
|
||||
/* NULL-terminate for easy copying. */
|
||||
reportp->messageArgs[i] = NULL;
|
||||
}
|
||||
/*
|
||||
* Parse the error format, substituting the argument X
|
||||
|
@ -968,6 +974,8 @@ js_ExpandErrorArguments(JSContext *cx, JSErrorCallback callback,
|
|||
goto error;
|
||||
}
|
||||
} else {
|
||||
/* Non-null messageArgs should have at least one non-null arg. */
|
||||
JS_ASSERT(!reportp->messageArgs);
|
||||
/*
|
||||
* Zero arguments: the format string (if it exists) is the
|
||||
* entire message.
|
||||
|
@ -997,7 +1005,7 @@ js_ExpandErrorArguments(JSContext *cx, JSErrorCallback callback,
|
|||
return JS_TRUE;
|
||||
|
||||
error:
|
||||
if (reportp->messageArgs) {
|
||||
if (!messageArgsPassed && reportp->messageArgs) {
|
||||
/* free the arguments only if we allocated them */
|
||||
if (charArgs) {
|
||||
i = 0;
|
||||
|
@ -1063,6 +1071,39 @@ js_ReportErrorNumberVA(JSContext *cx, unsigned flags, JSErrorCallback callback,
|
|||
return warning;
|
||||
}
|
||||
|
||||
bool
|
||||
js_ReportErrorNumberUCArray(JSContext *cx, unsigned flags, JSErrorCallback callback,
|
||||
void *userRef, const unsigned errorNumber,
|
||||
const jschar **args)
|
||||
{
|
||||
if (checkReportFlags(cx, &flags))
|
||||
return true;
|
||||
bool warning = JSREPORT_IS_WARNING(flags);
|
||||
|
||||
JSErrorReport report;
|
||||
PodZero(&report);
|
||||
report.flags = flags;
|
||||
report.errorNumber = errorNumber;
|
||||
PopulateReportBlame(cx, &report);
|
||||
report.messageArgs = args;
|
||||
|
||||
char *message;
|
||||
va_list dummy;
|
||||
if (!js_ExpandErrorArguments(cx, callback, userRef, errorNumber,
|
||||
&message, &report, JS_FALSE, dummy)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ReportError(cx, message, &report, callback, userRef);
|
||||
|
||||
if (message)
|
||||
js_free(message);
|
||||
if (report.ucmessage)
|
||||
js_free((void *)report.ucmessage);
|
||||
|
||||
return warning;
|
||||
}
|
||||
|
||||
JS_FRIEND_API(void)
|
||||
js_ReportErrorAgain(JSContext *cx, const char *message, JSErrorReport *reportp)
|
||||
{
|
||||
|
|
|
@ -389,8 +389,70 @@ struct JSAtomState
|
|||
#define NAME_OFFSET(name) offsetof(JSAtomState, name)
|
||||
#define OFFSET_TO_NAME(rt,off) (*(js::FixedHeapPtr<js::PropertyName>*)((char*)&(rt)->atomState + (off)))
|
||||
|
||||
namespace js {
|
||||
|
||||
/*
|
||||
* Encapsulates portions of the runtime/context that are tied to a
|
||||
* single active thread. Normally, as most JS is single-threaded,
|
||||
* there is only one instance of this struct, embedded in the
|
||||
* JSRuntime as the field |mainThread|. During Parallel JS sections,
|
||||
* however, there will be one instance per worker thread.
|
||||
*
|
||||
* The eventual plan is to designate thread-safe portions of the
|
||||
* interpreter and runtime by having them take |PerThreadData*|
|
||||
* arguments instead of |JSContext*| or |JSRuntime*|.
|
||||
*/
|
||||
class PerThreadData : public js::PerThreadDataFriendFields
|
||||
{
|
||||
/*
|
||||
* Backpointer to the full shared JSRuntime* with which this
|
||||
* thread is associaed. This is private because accessing the
|
||||
* fields of this runtime can provoke race conditions, so the
|
||||
* intention is that access will be mediated through safe
|
||||
* functions like |associatedWith()| below.
|
||||
*/
|
||||
JSRuntime *runtime_;
|
||||
|
||||
public:
|
||||
/*
|
||||
* We save all conservative scanned roots in this vector so that
|
||||
* conservative scanning can be "replayed" deterministically. In DEBUG mode,
|
||||
* this allows us to run a non-incremental GC after every incremental GC to
|
||||
* ensure that no objects were missed.
|
||||
*/
|
||||
#ifdef DEBUG
|
||||
struct SavedGCRoot {
|
||||
void *thing;
|
||||
JSGCTraceKind kind;
|
||||
|
||||
SavedGCRoot(void *thing, JSGCTraceKind kind) : thing(thing), kind(kind) {}
|
||||
};
|
||||
js::Vector<SavedGCRoot, 0, js::SystemAllocPolicy> gcSavedRoots;
|
||||
|
||||
bool gcRelaxRootChecks;
|
||||
int gcAssertNoGCDepth;
|
||||
#endif
|
||||
|
||||
PerThreadData(JSRuntime *runtime);
|
||||
|
||||
bool associatedWith(const JSRuntime *rt) { return runtime_ == rt; }
|
||||
};
|
||||
|
||||
} // namespace js
|
||||
|
||||
struct JSRuntime : js::RuntimeFriendFields
|
||||
{
|
||||
/* Per-thread data for the main thread that is associated with
|
||||
* this JSRuntime, as opposed to any worker threads used in
|
||||
* parallel sections. See definition of |PerThreadData| struct
|
||||
* above for more details.
|
||||
*
|
||||
* NB: This field is statically asserted to be at offset
|
||||
* sizeof(RuntimeFriendFields). See
|
||||
* PerThreadDataFriendFields::getMainThread.
|
||||
*/
|
||||
js::PerThreadData mainThread;
|
||||
|
||||
/* Default compartment. */
|
||||
JSCompartment *atomsCompartment;
|
||||
|
||||
|
@ -654,25 +716,6 @@ struct JSRuntime : js::RuntimeFriendFields
|
|||
*/
|
||||
bool gcExactScanningEnabled;
|
||||
|
||||
/*
|
||||
* We save all conservative scanned roots in this vector so that
|
||||
* conservative scanning can be "replayed" deterministically. In DEBUG mode,
|
||||
* this allows us to run a non-incremental GC after every incremental GC to
|
||||
* ensure that no objects were missed.
|
||||
*/
|
||||
#ifdef DEBUG
|
||||
struct SavedGCRoot {
|
||||
void *thing;
|
||||
JSGCTraceKind kind;
|
||||
|
||||
SavedGCRoot(void *thing, JSGCTraceKind kind) : thing(thing), kind(kind) {}
|
||||
};
|
||||
js::Vector<SavedGCRoot, 0, js::SystemAllocPolicy> gcSavedRoots;
|
||||
|
||||
bool gcRelaxRootChecks;
|
||||
int gcAssertNoGCDepth;
|
||||
#endif
|
||||
|
||||
bool gcPoke;
|
||||
|
||||
enum HeapState {
|
||||
|
@ -1874,6 +1917,11 @@ js_ReportErrorNumberVA(JSContext *cx, unsigned flags, JSErrorCallback callback,
|
|||
void *userRef, const unsigned errorNumber,
|
||||
JSBool charArgs, va_list ap);
|
||||
|
||||
extern bool
|
||||
js_ReportErrorNumberUCArray(JSContext *cx, unsigned flags, JSErrorCallback callback,
|
||||
void *userRef, const unsigned errorNumber,
|
||||
const jschar **args);
|
||||
|
||||
extern JSBool
|
||||
js_ExpandErrorArguments(JSContext *cx, JSErrorCallback callback,
|
||||
void *userRef, const unsigned errorNumber,
|
||||
|
|
|
@ -967,7 +967,8 @@ js_ErrorToException(JSContext *cx, const char *message, JSErrorReport *reportp,
|
|||
return false;
|
||||
tv[1] = OBJECT_TO_JSVAL(errObject);
|
||||
|
||||
RootedString messageStr(cx, JS_NewStringCopyZ(cx, message));
|
||||
RootedString messageStr(cx, reportp->ucmessage ? JS_NewUCStringCopyZ(cx, reportp->ucmessage)
|
||||
: JS_NewStringCopyZ(cx, message));
|
||||
if (!messageStr)
|
||||
return false;
|
||||
tv[2] = STRING_TO_JSVAL(messageStr);
|
||||
|
|
|
@ -22,6 +22,16 @@
|
|||
using namespace js;
|
||||
using namespace JS;
|
||||
|
||||
// Required by PerThreadDataFriendFields::getMainThread()
|
||||
JS_STATIC_ASSERT(offsetof(JSRuntime, mainThread) == sizeof(RuntimeFriendFields));
|
||||
|
||||
PerThreadDataFriendFields::PerThreadDataFriendFields()
|
||||
{
|
||||
#if defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING)
|
||||
PodArrayZero(thingGCRooters);
|
||||
#endif
|
||||
}
|
||||
|
||||
JS_FRIEND_API(void)
|
||||
JS_SetSourceHook(JSRuntime *rt, JS_SourceHook hook)
|
||||
{
|
||||
|
|
|
@ -183,6 +183,8 @@ JS_SetSourceHook(JSRuntime *rt, JS_SourceHook hook);
|
|||
|
||||
namespace js {
|
||||
|
||||
extern mozilla::ThreadLocal<PerThreadData *> TlsPerThreadData;
|
||||
|
||||
inline JSRuntime *
|
||||
GetRuntime(const JSContext *cx)
|
||||
{
|
||||
|
|
|
@ -992,7 +992,7 @@ MarkExactStackRoots(JSTracer *trc)
|
|||
for (ContextIter cx(trc->runtime); !cx.done(); cx.next()) {
|
||||
MarkExactStackRooters(trc, cx->thingGCRooters[i], ThingRootKind(i));
|
||||
}
|
||||
MarkExactStackRooters(trc, rt->thingGCRooters[i], ThingRootKind(i));
|
||||
MarkExactStackRooters(trc, rt->mainThread.thingGCRooters[i], ThingRootKind(i));
|
||||
}
|
||||
}
|
||||
#endif /* JSGC_USE_EXACT_ROOTING */
|
||||
|
@ -1125,7 +1125,8 @@ MarkIfGCThingWord(JSTracer *trc, uintptr_t w)
|
|||
|
||||
#ifdef DEBUG
|
||||
if (trc->runtime->gcIncrementalState == MARK_ROOTS)
|
||||
trc->runtime->gcSavedRoots.append(JSRuntime::SavedGCRoot(thing, traceKind));
|
||||
trc->runtime->mainThread.gcSavedRoots.append(
|
||||
PerThreadData::SavedGCRoot(thing, traceKind));
|
||||
#endif
|
||||
|
||||
return CGCT_VALID;
|
||||
|
@ -1186,8 +1187,8 @@ MarkConservativeStackRoots(JSTracer *trc, bool useSavedRoots)
|
|||
|
||||
#ifdef DEBUG
|
||||
if (useSavedRoots) {
|
||||
for (JSRuntime::SavedGCRoot *root = rt->gcSavedRoots.begin();
|
||||
root != rt->gcSavedRoots.end();
|
||||
for (PerThreadData::SavedGCRoot *root = rt->mainThread.gcSavedRoots.begin();
|
||||
root != rt->mainThread.gcSavedRoots.end();
|
||||
root++)
|
||||
{
|
||||
JS_SET_TRACING_NAME(trc, "cstack");
|
||||
|
@ -1197,7 +1198,7 @@ MarkConservativeStackRoots(JSTracer *trc, bool useSavedRoots)
|
|||
}
|
||||
|
||||
if (rt->gcIncrementalState == MARK_ROOTS)
|
||||
rt->gcSavedRoots.clearAndFree();
|
||||
rt->mainThread.gcSavedRoots.clearAndFree();
|
||||
#endif
|
||||
|
||||
ConservativeGCData *cgcd = &rt->conservativeGC;
|
||||
|
@ -4912,7 +4913,8 @@ CheckStackRoot(JSTracer *trc, uintptr_t *w)
|
|||
bool matched = false;
|
||||
JSRuntime *rt = trc->runtime;
|
||||
for (unsigned i = 0; i < THING_ROOT_LIMIT; i++) {
|
||||
CheckStackRootThings(w, rt->thingGCRooters[i], ThingRootKind(i), &matched);
|
||||
CheckStackRootThings(w, rt->mainThread.thingGCRooters[i],
|
||||
ThingRootKind(i), &matched);
|
||||
for (ContextIter cx(rt); !cx.done(); cx.next()) {
|
||||
CheckStackRootThings(w, cx->thingGCRooters[i], ThingRootKind(i), &matched);
|
||||
SkipRoot *skip = cx->skipGCRooters;
|
||||
|
|
|
@ -307,14 +307,6 @@ struct RuntimeFriendFields {
|
|||
/* Limit pointer for checking native stack consumption. */
|
||||
uintptr_t nativeStackLimit;
|
||||
|
||||
#if defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING)
|
||||
/*
|
||||
* Stack allocated GC roots for stack GC heap pointers, which may be
|
||||
* overwritten if moved during a GC.
|
||||
*/
|
||||
Rooted<void*> *thingGCRooters[THING_ROOT_LIMIT];
|
||||
#endif
|
||||
|
||||
RuntimeFriendFields()
|
||||
: interrupt(0),
|
||||
nativeStackLimit(0) { }
|
||||
|
@ -324,6 +316,32 @@ struct RuntimeFriendFields {
|
|||
}
|
||||
};
|
||||
|
||||
class PerThreadData;
|
||||
|
||||
struct PerThreadDataFriendFields
|
||||
{
|
||||
PerThreadDataFriendFields();
|
||||
|
||||
#if defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING)
|
||||
/*
|
||||
* Stack allocated GC roots for stack GC heap pointers, which may be
|
||||
* overwritten if moved during a GC.
|
||||
*/
|
||||
Rooted<void*> *thingGCRooters[THING_ROOT_LIMIT];
|
||||
#endif
|
||||
|
||||
static PerThreadDataFriendFields *get(js::PerThreadData *pt) {
|
||||
return reinterpret_cast<PerThreadDataFriendFields *>(pt);
|
||||
}
|
||||
|
||||
static PerThreadDataFriendFields *getMainThread(JSRuntime *rt) {
|
||||
// mainThread must always appear directly after |RuntimeFriendFields|.
|
||||
// Tested by a JS_STATIC_ASSERT in |jsfriendapi.cpp|
|
||||
return reinterpret_cast<PerThreadDataFriendFields *>(
|
||||
reinterpret_cast<char*>(rt) + sizeof(RuntimeFriendFields));
|
||||
}
|
||||
};
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
#endif /* __cplusplus */
|
||||
|
|
|
@ -3417,7 +3417,7 @@ RelaxRootChecks(JSContext *cx, unsigned argc, jsval *vp)
|
|||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
cx->runtime->gcRelaxRootChecks = true;
|
||||
cx->runtime->mainThread.gcRelaxRootChecks = true;
|
||||
#endif
|
||||
|
||||
return true;
|
||||
|
|
|
@ -1402,7 +1402,8 @@ StackIter::settleOnNewState()
|
|||
}
|
||||
|
||||
StackIter::StackIter(JSContext *cx, SavedOption savedOption)
|
||||
: maybecx_(cx),
|
||||
: perThread_(&cx->runtime->mainThread),
|
||||
maybecx_(cx),
|
||||
savedOption_(savedOption),
|
||||
script_(cx, NULL)
|
||||
#ifdef JS_ION
|
||||
|
@ -1426,7 +1427,9 @@ StackIter::StackIter(JSContext *cx, SavedOption savedOption)
|
|||
}
|
||||
|
||||
StackIter::StackIter(JSRuntime *rt, StackSegment &seg)
|
||||
: maybecx_(NULL), savedOption_(STOP_AT_SAVED),
|
||||
: perThread_(&rt->mainThread),
|
||||
maybecx_(NULL),
|
||||
savedOption_(STOP_AT_SAVED),
|
||||
script_(rt, NULL)
|
||||
#ifdef JS_ION
|
||||
, ionActivations_(rt),
|
||||
|
@ -1444,14 +1447,15 @@ StackIter::StackIter(JSRuntime *rt, StackSegment &seg)
|
|||
}
|
||||
|
||||
StackIter::StackIter(const StackIter &other)
|
||||
: maybecx_(other.maybecx_),
|
||||
: perThread_(other.perThread_),
|
||||
maybecx_(other.maybecx_),
|
||||
savedOption_(other.savedOption_),
|
||||
state_(other.state_),
|
||||
fp_(other.fp_),
|
||||
calls_(other.calls_),
|
||||
seg_(other.seg_),
|
||||
pc_(other.pc_),
|
||||
script_(other.maybecx_ ? other.maybecx_->runtime : TlsRuntime.get(), other.script_),
|
||||
script_(perThread_, other.script_),
|
||||
args_(other.args_)
|
||||
#ifdef JS_ION
|
||||
, ionActivations_(other.ionActivations_),
|
||||
|
|
|
@ -1712,6 +1712,7 @@ class GeneratorFrameGuard : public FrameGuard
|
|||
class StackIter
|
||||
{
|
||||
friend class ContextStack;
|
||||
PerThreadData *perThread_;
|
||||
JSContext *maybecx_;
|
||||
public:
|
||||
enum SavedOption { STOP_AT_SAVED, GO_THROUGH_SAVED };
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
#include "TypeTraits.h"
|
||||
|
||||
#include <limits>
|
||||
#include <stdint.h>
|
||||
#include "mozilla/StandardInteger.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# undef min
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
namespace JSC { namespace Yarr {
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include "mozilla/StandardInteger.h"
|
||||
|
||||
uint16_t ucs2CharacterSet0[] = { 0x01c4u, 0x01c5u, 0x01c6u, 0 };
|
||||
uint16_t ucs2CharacterSet1[] = { 0x01c7u, 0x01c8u, 0x01c9u, 0 };
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
#ifndef YarrCanonicalizeUCS2_H
|
||||
#define YarrCanonicalizeUCS2_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "mozilla/StandardInteger.h"
|
||||
#include "wtfbridge.h"
|
||||
#include "assembler/wtf/Assertions.h"
|
||||
|
||||
|
|
|
@ -180,7 +180,7 @@ print('#include "assembler/wtf/Assertions.h"');
|
|||
print();
|
||||
print("namespace JSC { namespace Yarr {");
|
||||
print();
|
||||
print("#include <stdint.h>");
|
||||
print('#include "mozilla/StandardInteger.h"');
|
||||
print();
|
||||
|
||||
for (i in characterSetInfo) {
|
||||
|
|
|
@ -1469,7 +1469,7 @@ XPCWrappedNative::ReparentWrapperIfFound(XPCCallContext& ccx,
|
|||
|
||||
nsRefPtr<XPCWrappedNative> wrapper;
|
||||
AutoWrapperChanger wrapperChanger;
|
||||
JSObject *flat;
|
||||
JSObject *flat = nullptr;
|
||||
nsWrapperCache* cache = nullptr;
|
||||
CallQueryInterface(aCOMObj, &cache);
|
||||
if (cache) {
|
||||
|
@ -1490,7 +1490,8 @@ XPCWrappedNative::ReparentWrapperIfFound(XPCCallContext& ccx,
|
|||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
flat = wrapper->GetFlatJSObject();
|
||||
if (wrapper)
|
||||
flat = wrapper->GetFlatJSObject();
|
||||
}
|
||||
|
||||
if (!flat) {
|
||||
|
|
|
@ -20,7 +20,8 @@ dictionaries = [
|
|||
[ 'CameraPosition', 'nsIDOMCameraManager.idl' ],
|
||||
[ 'CameraSelector', 'nsIDOMCameraManager.idl' ],
|
||||
[ 'CameraPictureOptions', 'nsIDOMCameraManager.idl' ],
|
||||
[ 'CameraRecordingOptions', 'nsIDOMCameraManager.idl' ]
|
||||
[ 'CameraRecordingOptions', 'nsIDOMCameraManager.idl' ],
|
||||
[ 'ArchiveReaderOptions', 'nsIDOMArchiveReader.idl' ]
|
||||
]
|
||||
|
||||
# include file names
|
||||
|
|
|
@ -144,7 +144,14 @@ nsPopupBoxObject::SizeTo(int32_t aWidth, int32_t aHeight)
|
|||
height.AppendInt(aHeight);
|
||||
|
||||
nsCOMPtr<nsIContent> content = mContent;
|
||||
content->SetAttr(kNameSpaceID_None, nsGkAtoms::width, width, false);
|
||||
|
||||
// We only want to pass aNotify=true to SetAttr once, but must make sure
|
||||
// we pass it when a value is being changed. Thus, we check if the height
|
||||
// is the same and if so, pass true when setting the width and skip setting
|
||||
// the height.
|
||||
bool heightSame = content->AttrValueIs(kNameSpaceID_None, nsGkAtoms::height, height, eCaseMatters);
|
||||
|
||||
content->SetAttr(kNameSpaceID_None, nsGkAtoms::width, width, heightSame);
|
||||
content->SetAttr(kNameSpaceID_None, nsGkAtoms::height, height, true);
|
||||
|
||||
return NS_OK;
|
||||
|
|
|
@ -19,6 +19,7 @@ MOCHITEST_FILES = test_bug511075.html \
|
|||
MOCHITEST_CHROME_FILES = test_bug381167.xhtml \
|
||||
test_bug393970.xul \
|
||||
test_bug477754.xul \
|
||||
test_popupSizeTo.xul \
|
||||
test_stack.xul \
|
||||
test_resizer.xul \
|
||||
window_resizer.xul \
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
<?xml version="1.0"?>
|
||||
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
|
||||
<!--
|
||||
XUL Panel sizeTo tests
|
||||
-->
|
||||
<window title="XUL Panel sizeTo tests"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
|
||||
|
||||
<!-- test results are displayed in the html:body -->
|
||||
<body xmlns="http://www.w3.org/1999/xhtml">
|
||||
</body>
|
||||
|
||||
<!-- test code goes here -->
|
||||
<script type="application/javascript"><![CDATA[
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
function openPopup()
|
||||
{
|
||||
document.getElementById("panel").
|
||||
openPopupAtScreen(Math.round(window.mozInnerScreenX) + window.innerWidth - 130,
|
||||
Math.round(window.mozInnerScreenY) + window.innerHeight - 130);
|
||||
}
|
||||
|
||||
function sizeAndCheck(width, height) {
|
||||
var panel = document.getElementById("panel");
|
||||
panel.sizeTo(width, height);
|
||||
is(panel.getBoundingClientRect().width, width, "width is correct");
|
||||
is(panel.getBoundingClientRect().height, height, "height is correct");
|
||||
|
||||
}
|
||||
function popupShown(event)
|
||||
{
|
||||
var panel = document.getElementById("panel");
|
||||
var bcr = panel.getBoundingClientRect();
|
||||
// resize to 10px bigger in both dimensions.
|
||||
sizeAndCheck(bcr.width+10, bcr.height+10);
|
||||
// Same width, different height (based on *new* size from last sizeAndCheck)
|
||||
sizeAndCheck(bcr.width+10, bcr.height);
|
||||
// Same height, different width (also based on *new* size from last sizeAndCheck)
|
||||
sizeAndCheck(bcr.width, bcr.height);
|
||||
event.target.hidePopup();
|
||||
}
|
||||
|
||||
SimpleTest.waitForFocus(openPopup);
|
||||
]]></script>
|
||||
|
||||
<panel id="panel" onpopupshown="popupShown(event)" onpopuphidden="SimpleTest.finish()">
|
||||
<resizer id="resizer" dir="bottomend" width="16" height="16"/>
|
||||
<hbox width="50" height="50" flex="1"/>
|
||||
</panel>
|
||||
|
||||
</window>
|
|
@ -75,6 +75,7 @@ typedef enum {
|
|||
AUDIO_STREAM_ENFORCED_AUDIBLE = 7, /* Sounds that cannot be muted by user and must be routed to speaker */
|
||||
AUDIO_STREAM_DTMF = 8,
|
||||
AUDIO_STREAM_TTS = 9,
|
||||
AUDIO_STREAM_FM = 10,
|
||||
|
||||
AUDIO_STREAM_CNT,
|
||||
AUDIO_STREAM_MAX = AUDIO_STREAM_CNT - 1,
|
||||
|
@ -335,6 +336,7 @@ public:
|
|||
ENFORCED_AUDIBLE = 7, // Sounds that cannot be muted by user and must be routed to speaker
|
||||
DTMF = 8,
|
||||
TTS = 9,
|
||||
FM = 10,
|
||||
NUM_STREAM_TYPES
|
||||
};
|
||||
|
||||
|
@ -699,8 +701,13 @@ public:
|
|||
static status_t initStreamVolume(stream_type stream,
|
||||
int indexMin,
|
||||
int indexMax);
|
||||
static status_t initStreamVolume(audio_stream_type_t stream,
|
||||
int indexMin,
|
||||
int indexMax);
|
||||
static status_t setStreamVolumeIndex(stream_type stream, int index);
|
||||
static status_t setStreamVolumeIndex(audio_stream_type_t stream, int index);
|
||||
static status_t getStreamVolumeIndex(stream_type stream, int *index);
|
||||
static status_t getStreamVolumeIndex(audio_stream_type_t stream, int *index);
|
||||
|
||||
static uint32_t getStrategyForStream(stream_type stream);
|
||||
|
||||
|
|
|
@ -0,0 +1,175 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/* A set abstraction for enumeration values. */
|
||||
|
||||
#ifndef mozilla_EnumSet_h
|
||||
#define mozilla_EnumSet_h
|
||||
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/StandardInteger.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
/**
|
||||
* EnumSet<T> is a set of values defined by an enumeration. It is implemented
|
||||
* using a 32 bit mask for each value so it will only work for enums with an int
|
||||
* representation less than 32. It works both for enum and enum class types.
|
||||
*/
|
||||
template<typename T>
|
||||
class EnumSet
|
||||
{
|
||||
public:
|
||||
EnumSet()
|
||||
: mBitField(0)
|
||||
{ }
|
||||
|
||||
EnumSet(T aEnum)
|
||||
: mBitField(aEnum)
|
||||
{ }
|
||||
|
||||
EnumSet(T aEnum1, T aEnum2)
|
||||
: mBitField(bitFor(aEnum1) |
|
||||
bitFor(aEnum2))
|
||||
{ }
|
||||
|
||||
EnumSet(T aEnum1, T aEnum2, T aEnum3)
|
||||
: mBitField(bitFor(aEnum1) |
|
||||
bitFor(aEnum2) |
|
||||
bitFor(aEnum3))
|
||||
{ }
|
||||
|
||||
EnumSet(T aEnum1, T aEnum2, T aEnum3, T aEnum4)
|
||||
: mBitField(bitFor(aEnum1) |
|
||||
bitFor(aEnum2) |
|
||||
bitFor(aEnum3) |
|
||||
bitFor(aEnum4))
|
||||
{ }
|
||||
|
||||
EnumSet(const EnumSet& aEnumSet)
|
||||
: mBitField(aEnumSet.mBitField)
|
||||
{ }
|
||||
|
||||
/**
|
||||
* Add an element
|
||||
*/
|
||||
void operator+=(T aEnum) {
|
||||
mBitField |= bitFor(aEnum);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an element
|
||||
*/
|
||||
EnumSet<T> operator+(T aEnum) const {
|
||||
EnumSet<T> result(*this);
|
||||
result += aEnum;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Union
|
||||
*/
|
||||
void operator+=(const EnumSet<T> aEnumSet) {
|
||||
mBitField |= aEnumSet.mBitField;
|
||||
}
|
||||
|
||||
/**
|
||||
* Union
|
||||
*/
|
||||
EnumSet<T> operator+(const EnumSet<T> aEnumSet) const {
|
||||
EnumSet<T> result(*this);
|
||||
result += aEnumSet;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove an element
|
||||
*/
|
||||
void operator-=(T aEnum) {
|
||||
mBitField &= ~(bitFor(aEnum));
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove an element
|
||||
*/
|
||||
EnumSet<T> operator-(T aEnum) const {
|
||||
EnumSet<T> result(*this);
|
||||
result -= aEnum;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a set of elements
|
||||
*/
|
||||
void operator-=(const EnumSet<T> aEnumSet) {
|
||||
mBitField &= ~(aEnumSet.mBitField);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a set of elements
|
||||
*/
|
||||
EnumSet<T> operator-(const EnumSet<T> aEnumSet) const {
|
||||
EnumSet<T> result(*this);
|
||||
result -= aEnumSet;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Intersection
|
||||
*/
|
||||
void operator&=(const EnumSet<T> aEnumSet) {
|
||||
mBitField &= aEnumSet.mBitField;
|
||||
}
|
||||
|
||||
/**
|
||||
* Intersection
|
||||
*/
|
||||
EnumSet<T> operator&(const EnumSet<T> aEnumSet) const {
|
||||
EnumSet<T> result(*this);
|
||||
result &= aEnumSet;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Equality
|
||||
*/
|
||||
|
||||
bool operator==(const EnumSet<T> aEnumSet) const {
|
||||
return mBitField == aEnumSet.mBitField;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test is an element is contained in the set
|
||||
*/
|
||||
bool contains(T aEnum) const {
|
||||
return mBitField & bitFor(aEnum);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of elements in the set
|
||||
*/
|
||||
|
||||
uint8_t size() {
|
||||
uint8_t count = 0;
|
||||
for (uint32_t bitField = mBitField; bitField; bitField >>= 1) {
|
||||
if (bitField & 1)
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
private:
|
||||
static uint32_t bitFor(T aEnum) {
|
||||
uint32_t bitNumber(aEnum);
|
||||
MOZ_ASSERT(bitNumber < 32);
|
||||
return 1U << bitNumber;
|
||||
}
|
||||
|
||||
uint32_t mBitField;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_EnumSet_h_
|
|
@ -14,6 +14,7 @@ EXPORTS_mozilla += \
|
|||
BloomFilter.h \
|
||||
CheckedInt.h \
|
||||
Constants.h \
|
||||
EnumSet.h \
|
||||
FloatingPoint.h \
|
||||
GuardObjects.h \
|
||||
HashFunctions.h \
|
||||
|
|
|
@ -14,6 +14,7 @@ STL_FLAGS =
|
|||
CPP_UNIT_TESTS = \
|
||||
TestBloomFilter.cpp \
|
||||
TestCheckedInt.cpp \
|
||||
TestEnumSet.cpp \
|
||||
TestSHA1.cpp \
|
||||
TestTypeTraits.cpp \
|
||||
TestWeakPtr.cpp \
|
||||
|
|
|
@ -0,0 +1,232 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla/EnumSet.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
enum SeaBird {
|
||||
PENGUIN,
|
||||
ALBATROSS,
|
||||
FULMAR,
|
||||
PRION,
|
||||
SHEARWATER,
|
||||
GADFLY_PETREL,
|
||||
TRUE_PETREL,
|
||||
DIVING_PETREL,
|
||||
STORM_PETREL,
|
||||
PELICAN,
|
||||
GANNET,
|
||||
BOOBY,
|
||||
CORMORANT,
|
||||
FRIGATEBIRD,
|
||||
TROPICBIRD,
|
||||
SKUA,
|
||||
GULL,
|
||||
TERN,
|
||||
SKIMMER,
|
||||
AUK
|
||||
};
|
||||
|
||||
class EnumSetSuite {
|
||||
public:
|
||||
EnumSetSuite()
|
||||
: mAlcidae(),
|
||||
mDiomedeidae(ALBATROSS),
|
||||
mPetrelProcellariidae(GADFLY_PETREL, TRUE_PETREL),
|
||||
mNonPetrelProcellariidae(FULMAR, PRION, SHEARWATER),
|
||||
mPetrels(GADFLY_PETREL, TRUE_PETREL, DIVING_PETREL, STORM_PETREL)
|
||||
{ }
|
||||
|
||||
void runTests() {
|
||||
testSize();
|
||||
testContains();
|
||||
testAddTo();
|
||||
testAdd();
|
||||
testAddAll();
|
||||
testUnion();
|
||||
testRemoveFrom();
|
||||
testRemove();
|
||||
testRemoveAllFrom();
|
||||
testRemoveAll();
|
||||
testIntersect();
|
||||
testInsersection();
|
||||
testEquality();
|
||||
testDuplicates();
|
||||
}
|
||||
|
||||
private:
|
||||
void testSize() {
|
||||
MOZ_ASSERT(mAlcidae.size() == 0);
|
||||
MOZ_ASSERT(mDiomedeidae.size() == 1);
|
||||
MOZ_ASSERT(mPetrelProcellariidae.size() == 2);
|
||||
MOZ_ASSERT(mNonPetrelProcellariidae.size() == 3);
|
||||
MOZ_ASSERT(mPetrels.size() == 4);
|
||||
}
|
||||
|
||||
void testContains() {
|
||||
MOZ_ASSERT(!mPetrels.contains(PENGUIN));
|
||||
MOZ_ASSERT(!mPetrels.contains(ALBATROSS));
|
||||
MOZ_ASSERT(!mPetrels.contains(FULMAR));
|
||||
MOZ_ASSERT(!mPetrels.contains(PRION));
|
||||
MOZ_ASSERT(!mPetrels.contains(SHEARWATER));
|
||||
MOZ_ASSERT(mPetrels.contains(GADFLY_PETREL));
|
||||
MOZ_ASSERT(mPetrels.contains(TRUE_PETREL));
|
||||
MOZ_ASSERT(mPetrels.contains(DIVING_PETREL));
|
||||
MOZ_ASSERT(mPetrels.contains(STORM_PETREL));
|
||||
MOZ_ASSERT(!mPetrels.contains(PELICAN));
|
||||
MOZ_ASSERT(!mPetrels.contains(GANNET));
|
||||
MOZ_ASSERT(!mPetrels.contains(BOOBY));
|
||||
MOZ_ASSERT(!mPetrels.contains(CORMORANT));
|
||||
MOZ_ASSERT(!mPetrels.contains(FRIGATEBIRD));
|
||||
MOZ_ASSERT(!mPetrels.contains(TROPICBIRD));
|
||||
MOZ_ASSERT(!mPetrels.contains(SKUA));
|
||||
MOZ_ASSERT(!mPetrels.contains(GULL));
|
||||
MOZ_ASSERT(!mPetrels.contains(TERN));
|
||||
MOZ_ASSERT(!mPetrels.contains(SKIMMER));
|
||||
MOZ_ASSERT(!mPetrels.contains(AUK));
|
||||
}
|
||||
|
||||
void testCopy() {
|
||||
EnumSet<SeaBird> likes = mPetrels;
|
||||
likes -= TRUE_PETREL;
|
||||
MOZ_ASSERT(mPetrels.size() == 4);
|
||||
MOZ_ASSERT(mPetrels.contains(TRUE_PETREL));
|
||||
|
||||
MOZ_ASSERT(likes.size() == 3);
|
||||
MOZ_ASSERT(likes.contains(GADFLY_PETREL));
|
||||
MOZ_ASSERT(likes.contains(DIVING_PETREL));
|
||||
MOZ_ASSERT(likes.contains(STORM_PETREL));
|
||||
}
|
||||
|
||||
void testAddTo() {
|
||||
EnumSet<SeaBird> seen = mPetrels;
|
||||
seen += CORMORANT;
|
||||
seen += TRUE_PETREL;
|
||||
MOZ_ASSERT(mPetrels.size() == 4);
|
||||
MOZ_ASSERT(!mPetrels.contains(CORMORANT));
|
||||
MOZ_ASSERT(seen.size() == 5);
|
||||
MOZ_ASSERT(seen.contains(GADFLY_PETREL));
|
||||
MOZ_ASSERT(seen.contains(TRUE_PETREL));
|
||||
MOZ_ASSERT(seen.contains(DIVING_PETREL));
|
||||
MOZ_ASSERT(seen.contains(STORM_PETREL));
|
||||
MOZ_ASSERT(seen.contains(CORMORANT));
|
||||
}
|
||||
|
||||
void testAdd() {
|
||||
EnumSet<SeaBird> seen = mPetrels + CORMORANT +
|
||||
STORM_PETREL;
|
||||
MOZ_ASSERT(mPetrels.size() == 4);
|
||||
MOZ_ASSERT(!mPetrels.contains(CORMORANT));
|
||||
MOZ_ASSERT(seen.size() == 5);
|
||||
MOZ_ASSERT(seen.contains(GADFLY_PETREL));
|
||||
MOZ_ASSERT(seen.contains(TRUE_PETREL));
|
||||
MOZ_ASSERT(seen.contains(DIVING_PETREL));
|
||||
MOZ_ASSERT(seen.contains(STORM_PETREL));
|
||||
MOZ_ASSERT(seen.contains(CORMORANT));
|
||||
}
|
||||
|
||||
void testAddAll() {
|
||||
EnumSet<SeaBird> procellariidae;
|
||||
procellariidae += mPetrelProcellariidae;
|
||||
procellariidae += mNonPetrelProcellariidae;
|
||||
MOZ_ASSERT(procellariidae.size() == 5);
|
||||
|
||||
// Both procellariidae and mPetrels include GADFLY_PERTEL and TRUE_PETREL
|
||||
EnumSet<SeaBird> procellariiformes;
|
||||
procellariiformes += mDiomedeidae;
|
||||
procellariiformes += procellariidae;
|
||||
procellariiformes += mPetrels;
|
||||
MOZ_ASSERT(procellariiformes.size() == 8);
|
||||
}
|
||||
|
||||
void testUnion() {
|
||||
EnumSet<SeaBird> procellariidae = mPetrelProcellariidae +
|
||||
mNonPetrelProcellariidae;
|
||||
MOZ_ASSERT(procellariidae.size() == 5);
|
||||
|
||||
// Both procellariidae and mPetrels include GADFLY_PETREL and TRUE_PETREL
|
||||
EnumSet<SeaBird> procellariiformes = mDiomedeidae + procellariidae +
|
||||
mPetrels;
|
||||
MOZ_ASSERT(procellariiformes.size() == 8);
|
||||
}
|
||||
|
||||
void testRemoveFrom() {
|
||||
EnumSet<SeaBird> likes = mPetrels;
|
||||
likes -= TRUE_PETREL;
|
||||
likes -= DIVING_PETREL;
|
||||
MOZ_ASSERT(likes.size() == 2);
|
||||
MOZ_ASSERT(likes.contains(GADFLY_PETREL));
|
||||
MOZ_ASSERT(likes.contains(STORM_PETREL));
|
||||
}
|
||||
|
||||
void testRemove() {
|
||||
EnumSet<SeaBird> likes = mPetrels - TRUE_PETREL -
|
||||
DIVING_PETREL;
|
||||
MOZ_ASSERT(likes.size() == 2);
|
||||
MOZ_ASSERT(likes.contains(GADFLY_PETREL));
|
||||
MOZ_ASSERT(likes.contains(STORM_PETREL));
|
||||
}
|
||||
|
||||
void testRemoveAllFrom() {
|
||||
EnumSet<SeaBird> likes = mPetrels;
|
||||
likes -= mPetrelProcellariidae;
|
||||
MOZ_ASSERT(likes.size() == 2);
|
||||
MOZ_ASSERT(likes.contains(DIVING_PETREL));
|
||||
MOZ_ASSERT(likes.contains(STORM_PETREL));
|
||||
}
|
||||
|
||||
void testRemoveAll() {
|
||||
EnumSet<SeaBird> likes = mPetrels - mPetrelProcellariidae;
|
||||
MOZ_ASSERT(likes.size() == 2);
|
||||
MOZ_ASSERT(likes.contains(DIVING_PETREL));
|
||||
MOZ_ASSERT(likes.contains(STORM_PETREL));
|
||||
}
|
||||
|
||||
void testIntersect() {
|
||||
EnumSet<SeaBird> likes = mPetrels;
|
||||
likes &= mPetrelProcellariidae;
|
||||
MOZ_ASSERT(likes.size() == 2);
|
||||
MOZ_ASSERT(likes.contains(GADFLY_PETREL));
|
||||
MOZ_ASSERT(likes.contains(TRUE_PETREL));
|
||||
}
|
||||
|
||||
void testInsersection() {
|
||||
EnumSet<SeaBird> likes = mPetrels & mPetrelProcellariidae;
|
||||
MOZ_ASSERT(likes.size() == 2);
|
||||
MOZ_ASSERT(likes.contains(GADFLY_PETREL));
|
||||
MOZ_ASSERT(likes.contains(TRUE_PETREL));
|
||||
}
|
||||
|
||||
void testEquality() {
|
||||
EnumSet<SeaBird> likes = mPetrels & mPetrelProcellariidae;
|
||||
MOZ_ASSERT(likes == EnumSet<SeaBird>(GADFLY_PETREL,
|
||||
TRUE_PETREL));
|
||||
}
|
||||
|
||||
void testDuplicates() {
|
||||
EnumSet<SeaBird> likes = mPetrels;
|
||||
likes += GADFLY_PETREL;
|
||||
likes += TRUE_PETREL;
|
||||
likes += DIVING_PETREL;
|
||||
likes += STORM_PETREL;
|
||||
MOZ_ASSERT(likes.size() == 4);
|
||||
MOZ_ASSERT(likes == mPetrels);
|
||||
}
|
||||
|
||||
|
||||
EnumSet<SeaBird> mAlcidae;
|
||||
EnumSet<SeaBird> mDiomedeidae;
|
||||
EnumSet<SeaBird> mPetrelProcellariidae;
|
||||
EnumSet<SeaBird> mNonPetrelProcellariidae;
|
||||
EnumSet<SeaBird> mPetrels;
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
EnumSetSuite suite;
|
||||
suite.runTests();
|
||||
return 0;
|
||||
}
|
|
@ -97,6 +97,7 @@ public class BrowserToolbar implements ViewSwitcher.ViewFactory,
|
|||
private TranslateAnimation mTitleSlideRight;
|
||||
|
||||
private int mCount;
|
||||
private int mFaviconSize;
|
||||
|
||||
private static final int TABS_CONTRACTED = 1;
|
||||
private static final int TABS_EXPANDED = 2;
|
||||
|
@ -226,6 +227,7 @@ public class BrowserToolbar implements ViewSwitcher.ViewFactory,
|
|||
mFavicon.setOnClickListener(faviconListener);
|
||||
if (Build.VERSION.SDK_INT >= 16)
|
||||
mFavicon.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
|
||||
mFaviconSize = Math.round(mActivity.getResources().getDimension(R.dimen.browser_toolbar_favicon_size));
|
||||
|
||||
mSiteSecurity = (ImageButton) mLayout.findViewById(R.id.site_security);
|
||||
mSiteSecurity.setOnClickListener(faviconListener);
|
||||
|
@ -683,10 +685,12 @@ public class BrowserToolbar implements ViewSwitcher.ViewFactory,
|
|||
if (Tabs.getInstance().getSelectedTab().getState() == Tab.STATE_LOADING)
|
||||
return;
|
||||
|
||||
if (image != null)
|
||||
if (image != null) {
|
||||
image = Bitmap.createScaledBitmap(image, mFaviconSize, mFaviconSize, false);
|
||||
mFavicon.setImageBitmap(image);
|
||||
else
|
||||
} else {
|
||||
mFavicon.setImageResource(R.drawable.favicon);
|
||||
}
|
||||
}
|
||||
|
||||
public void setSecurityMode(String mode) {
|
||||
|
|
|
@ -810,7 +810,8 @@ public class AllPagesTab extends AwesomeBarTab implements GeckoEventListener {
|
|||
private void displayFavicon(AwesomeEntryViewHolder viewHolder) {
|
||||
final String url = viewHolder.urlView.getText().toString();
|
||||
Favicons favicons = GeckoApp.mAppContext.getFavicons();
|
||||
viewHolder.faviconView.setImageBitmap(favicons.getFaviconFromMemCache(url));
|
||||
Bitmap bitmap = favicons.getFaviconFromMemCache(url);
|
||||
updateFavicon(viewHolder.faviconView, bitmap);
|
||||
}
|
||||
|
||||
private void updateFavicons() {
|
||||
|
|
|
@ -41,9 +41,13 @@ abstract public class AwesomeBarTab {
|
|||
// FIXME: This value should probably come from a prefs key
|
||||
public static final int MAX_RESULTS = 100;
|
||||
protected Context mContext = null;
|
||||
private static int sFaviconSize = -1;
|
||||
|
||||
public AwesomeBarTab(Context context) {
|
||||
mContext = context;
|
||||
if (sFaviconSize < 0) {
|
||||
sFaviconSize = Math.round(mContext.getResources().getDimension(R.dimen.awesomebar_row_favicon_size));
|
||||
}
|
||||
}
|
||||
|
||||
public void setListTouchListener(View.OnTouchListener listener) {
|
||||
|
@ -94,6 +98,15 @@ abstract public class AwesomeBarTab {
|
|||
faviconView.setImageDrawable(null);
|
||||
} else {
|
||||
Bitmap bitmap = BitmapFactory.decodeByteArray(b, 0, b.length);
|
||||
updateFavicon(faviconView, bitmap);
|
||||
}
|
||||
}
|
||||
|
||||
protected void updateFavicon(ImageView faviconView, Bitmap bitmap) {
|
||||
if (bitmap == null) {
|
||||
faviconView.setImageDrawable(null);
|
||||
} else {
|
||||
bitmap = Bitmap.createScaledBitmap(bitmap, sFaviconSize, sFaviconSize, false);
|
||||
faviconView.setImageBitmap(bitmap);
|
||||
}
|
||||
}
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче