Bug 747820 - Style editor breaks with non-latin encoding. r=msucan f=cedricv

This commit is contained in:
Thaddee Tyl 2012-08-30 19:10:39 +03:00
parent 02685b8e7c
commit 994d41bdd1
4 changed files with 99 additions and 3 deletions

View File

@ -758,6 +758,87 @@ StyleEditor.prototype = {
}
},
/**
* Decode a CSS source string to unicode according to the character set rules
* defined in <http://www.w3.org/TR/CSS2/syndata.html#charset>.
*
* @param string aString
* Source of a CSS stylesheet, loaded from file or cache.
* @param string aChannelCharset
* Charset of the source string if set by the HTTP channel.
* @return string
* The CSS string, in unicode.
*/
_decodeCSSCharset: function SE__decodeCSSCharset(aString, aChannelCharset)
{
// StyleSheet's charset can be specified from multiple sources
if (aChannelCharset.length > 0) {
// step 1 of syndata.html: charset given in HTTP header.
return this._convertToUnicode(aString, aChannelCharset);
}
let sheet = this.styleSheet;
if (sheet) {
// Do we have a @charset rule in the stylesheet?
// step 2 of syndata.html (without the BOM check).
if (sheet.cssRules) {
let rules = sheet.cssRules;
if (rules.length
&& rules.item(0).type == Ci.nsIDOMCSSRule.CHARSET_RULE) {
return this._convertToUnicode(aString, rules.item(0).encoding);
}
}
if (sheet.ownerNode) {
// step 3: see <link charset="…">
let linkCharset = sheet.ownerNode.getAttribute("charset");
if (linkCharset != null) {
return this._convertToUnicode(aString, linkCharset);
}
}
// step 4 (1 of 2): charset of referring stylesheet.
let parentSheet = sheet.parentStyleSheet;
if (parentSheet && parentSheet.cssRules &&
parentSheet.cssRules[0].type == Ci.nsIDOMCSSRule.CHARSET_RULE) {
return this._convertToUnicode(aString,
parentSheet.cssRules[0].encoding);
}
// step 4 (2 of 2): charset of referring document.
if (sheet.ownerNode && sheet.ownerNode.ownerDocument.characterSet) {
return this._convertToUnicode(aString,
sheet.ownerNode.ownerDocument.characterSet);
}
}
// step 5: default to utf-8.
return this._convertToUnicode(aString, "UTF-8");
},
/**
* Convert a given string, encoded in a given character set, to unicode.
* @param string aString
* A string.
* @param string aCharset
* A character set.
* @return string
* A unicode string.
*/
_convertToUnicode: function SE__convertToUnicode(aString, aCharset) {
// Decoding primitives.
let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"]
.createInstance(Ci.nsIScriptableUnicodeConverter);
try {
converter.charset = aCharset;
return converter.ConvertToUnicode(aString);
} catch(e) {
return aString;
}
},
/**
* Load source from a file or file-like resource.
*
@ -790,6 +871,7 @@ StyleEditor.prototype = {
{
let channel = Services.io.newChannel(aHref, null, null);
let chunks = [];
let channelCharset = "";
let streamListener = { // nsIStreamListener inherits nsIRequestObserver
onStartRequest: function (aRequest, aContext, aStatusCode) {
if (!Components.isSuccessCode(aStatusCode)) {
@ -797,6 +879,10 @@ StyleEditor.prototype = {
}
}.bind(this),
onDataAvailable: function (aRequest, aContext, aStream, aOffset, aCount) {
let channel = aRequest.QueryInterface(Ci.nsIChannel);
if (!channelCharset) {
channelCharset = channel.contentCharset;
}
chunks.push(NetUtil.readInputStreamToString(aStream, aCount));
},
onStopRequest: function (aRequest, aContext, aStatusCode) {
@ -804,7 +890,7 @@ StyleEditor.prototype = {
return this._signalError(LOAD_ERROR);
}
this._onSourceLoad(chunks.join(""));
this._onSourceLoad(chunks.join(""), channelCharset);
}.bind(this)
};
@ -816,9 +902,14 @@ StyleEditor.prototype = {
* Called when source has been loaded.
*
* @param string aSourceText
* @param string aCharset
* Optional. The character set to use. The default is to detect the
* character set following the standard (see
* <http://www.w3.org/TR/CSS2/syndata.html#charset>).
*/
_onSourceLoad: function SE__onSourceLoad(aSourceText)
_onSourceLoad: function SE__onSourceLoad(aSourceText, aCharset)
{
aSourceText = this._decodeCSSCharset(aSourceText, aCharset || "");
this._restoreExpando();
this._state.text = prettifyCSS(aSourceText);
this._loaded = true;

View File

@ -71,6 +71,10 @@ function testEditorAdded(aChrome, aEditor)
function testFirstStyleSheetEditor(aChrome, aEditor)
{
// Note: the html <link> contains charset="UTF-8".
ok(aEditor._state.text.indexOf("\u263a") >= 0,
"stylesheet is unicode-aware.");
//testing TESTCASE's simple.css stylesheet
is(aEditor.styleSheetIndex, 0,
"first stylesheet is at index 0");

View File

@ -1,6 +1,7 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/* ☺ */
body {
margin: 0;

View File

@ -2,7 +2,7 @@
<html>
<head>
<title>simple testcase</title>
<link rel="stylesheet" type="text/css" media="screen" href="simple.css"/>
<link rel="stylesheet" charset="UTF-8" type="text/css" media="screen" href="simple.css"/>
<style type="text/css">
body {
background: white;