You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Library/public注释.md

124 KiB

// 清除供应商前缀缓存的方法 cleanPrefixes: function() { // 将 mVENDOR_PREFIXES 属性置为 null清除之前缓存的供应商前缀信息 this.mVENDOR_PREFIXES = null; },

// 根据属性获取对应的供应商前缀数组的方法 prefixesForProperty: function(aProperty) { // 检查 mVENDOR_PREFIXES 是否为 null如果为 null 则进行初始化 if (!this.mVENDOR_PREFIXES) { // 初始化 mVENDOR_PREFIXES 为一个空对象 this.mVENDOR_PREFIXES = {}; // 遍历 kCSS_VENDOR_PREFIXES.properties 数组 for (var i = 0; i < kCSS_VENDOR_PREFIXES.properties.length; i++) { // 获取当前属性 var p = kCSS_VENDOR_PREFIXES.properties[i]; // 检查该属性是否有 gecko 前缀,并且有 webkit、presto 或 trident 前缀之一 if (p.gecko && (p.webkit || p.presto || p.trident)) { // 初始化一个空对象 o 用于存储不同前缀 var o = {}; // 如果 kEXPORTS_FOR_GECKO 为 true则将 gecko 前缀添加到 o 中 if (this.kEXPORTS_FOR_GECKO) o[p.gecko] = true; // 如果 kEXPORTS_FOR_WEBKIT 为 true 且有 webkit 前缀,则将 webkit 前缀添加到 o 中 if (this.kEXPORTS_FOR_WEBKIT && p.webkit) o[p.webkit] = true; // 如果 kEXPORTS_FOR_PRESTO 为 true 且有 presto 前缀,则将 presto 前缀添加到 o 中 if (this.kEXPORTS_FOR_PRESTO && p.presto) o[p.presto] = true; // 如果 kEXPORTS_FOR_TRIDENT 为 true 且有 trident 前缀,则将 trident 前缀添加到 o 中 if (this.kEXPORTS_FOR_TRIDENT && p.trident) o[p.trident] = true; // 在 mVENDOR_PREFIXES 中为 gecko 前缀创建一个空数组 this.mVENDOR_PREFIXES[p.gecko] = []; // 遍历 o 对象,将其中的前缀添加到 mVENDOR_PREFIXES[p.gecko] 数组中 for (var j in o) this.mVENDOR_PREFIXES[p.gecko].push(j) } } } // 检查传入的属性是否存在于 mVENDOR_PREFIXES 中 if (aProperty in this.mVENDOR_PREFIXES) // 如果存在,则对该属性对应的前缀数组进行排序并返回 return this.mVENDOR_PREFIXES[aProperty].sort(); // 如果不存在,则返回 null return null; },

// 解析颜色停止点的方法 parseColorStop: function(parser, token) { // 调用 parser 的 parseColor 方法解析颜色 var color = parser.parseColor(token); // 初始化位置为空字符串 var position = ""; // 如果颜色解析失败,则返回 null if (!color) return null; // 获取下一个标记 token = parser.getToken(true, true); // 检查标记是否为百分比或指定单位的尺寸 if (token.isPercentage() || token.isDimensionOfUnit("cm") || token.isDimensionOfUnit("mm") || token.isDimensionOfUnit("in") || token.isDimensionOfUnit("pc") || token.isDimensionOfUnit("px") || token.isDimensionOfUnit("em") || token.isDimensionOfUnit("ex") || token.isDimensionOfUnit("pt")) { // 如果是,则将标记的值赋给位置 position = token.value; // 获取下一个标记 token = parser.getToken(true, true); } // 返回包含颜色和位置的对象 return { color: color, position: position } },

// 解析渐变的方法 parseGradient: function (parser, token) { // 初始化是否为径向渐变的标志为 false var isRadial = false; // 初始化渐变对象,设置是否重复为 false var gradient = { isRepeating: false }; // 检查标记是否不为空 if (token.isNotNull()) { // 检查标记是否为特定的渐变函数 if (token.isFunction("-moz-linear-gradient(") || token.isFunction("-moz-radial-gradient(") || token.isFunction("-moz-repeating-linear-gradient(") || token.isFunction("-moz-repeating-radial-gradient(")) { // 如果是径向渐变函数,则将 isRadial 标志置为 true if (token.isFunction("-moz-radial-gradient(") || token.isFunction("-moz-repeating-radial-gradient(")) { gradient.isRadial = true; } // 如果是重复渐变函数,则将 isRepeating 标志置为 true if (token.isFunction("-moz-repeating-linear-gradient(") || token.isFunction("-moz-repeating-radial-gradient(")) { gradient.isRepeating = true; }

        // 获取下一个标记
        token = parser.getToken(true, true);
        // 初始化是否有渐变线的标志为 false
        var haveGradientLine = false;
        // 初始化是否找到水平位置的标志为 false
        var foundHorizPosition = false;
        // 初始化是否有角度的标志为 false
        var haveAngle = false;

        // 检查标记是否为角度
        if (token.isAngle()) {
            // 如果是,则将角度值赋给渐变对象的 angle 属性
            gradient.angle = token.value;
            // 将 haveGradientLine 标志置为 true
            haveGradientLine = true;
            // 将 haveAngle 标志置为 true
            haveAngle = true;
            // 获取下一个标记
            token = parser.getToken(true, true);
        }

        // 检查标记是否为长度或特定的标识符
        if (token.isLength()
            || token.isIdent("top")
            || token.isIdent("center")
            || token.isIdent("bottom")
            || token.isIdent("left")
            || token.isIdent("right")) {
            // 如果是,则将 haveGradientLine 标志置为 true
            haveGradientLine = true;
            // 检查标记是否为长度或水平位置标识符
            if (token.isLength()
                || token.isIdent("left")
                || token.isIdent("right")) {
                // 如果是,则将 foundHorizPosition 标志置为 true
                foundHorizPosition = true;
            }
            // 将标记的值赋给渐变对象的 position 属性
            gradient.position = token.value;
            // 获取下一个标记
            token = parser.getToken(true, true);
        }

        // 如果有渐变线
        if (haveGradientLine) {
            // 如果没有角度且标记为角度
            if (!haveAngle && token.isAngle()) {
                // 将角度值赋给渐变对象的 angle 属性
                gradient.angle = token.value;
                // 将 haveAngle 标志置为 true
                haveAngle = true;
                // 获取下一个标记
                token = parser.getToken(true, true);
            }
            // 检查标记是否符合特定条件
            else if (token.isLength()
                || (foundHorizPosition && (token.isIdent("top")
                                           || token.isIdent("center")
                                           || token.isIdent("bottom")))
                || (!foundHorizPosition && (token.isLength()
                                            || token.isIdent("top")
                                            || token.isIdent("center")
                                            || token.isIdent("bottom")
                                            || token.isIdent("left")
                                            || token.isIdent("right")))) {
                // 如果符合条件,则更新渐变对象的 position 属性
                gradient.position = ("position" in gradient) ? gradient.position + " ": "";
                gradient.position += token.value;
                // 获取下一个标记
                token = parser.getToken(true, true);
            }

            // 如果没有角度且标记为角度
            if (!haveAngle && token.isAngle()) {
                // 将角度值赋给渐变对象的 angle 属性
                gradient.angle = token.value;
                // 将 haveAngle 标志置为 true
                haveAngle = true;
                // 获取下一个标记
                token = parser.getToken(true, true);
            }

            // 检查标记是否为逗号
            if (!token.isSymbol(","))
                // 如果不是,则返回 null
                return null;
            // 获取下一个标记
            token = parser.getToken(true, true);
        }

        // 如果是径向渐变
        if (gradient.isRadial) {
            // 检查标记是否为圆形或椭圆形标识符
            if (token.isIdent("circle") ||
                token.isIdent("ellipse")) {
                // 如果是,则将标识符的值赋给渐变对象的 shape 属性
                gradient.shape = token.value;
                // 获取下一个标记
                token = parser.getToken(true, true);
            }
            // 检查标记是否为特定的尺寸标识符
            if (token.isIdent("closest-side") ||
                token.isIdent("closest-corner") ||
                token.isIdent("farthest-side") ||
                token.isIdent("farthest-corner") ||
                token.isIdent("contain") ||
                token.isIdent("cover")) {
                // 如果是,则将标识符的值赋给渐变对象的 size 属性
                gradient.size = token.value;
                // 获取下一个标记
                token = parser.getToken(true, true);
            }
            // 如果 shape 属性不存在且标记为圆形或椭圆形标识符
            if (!("shape" in gradient) &&
                (token.isIdent("circle") ||
                 token.isIdent("ellipse"))) {
                // 将标识符的值赋给渐变对象的 shape 属性
                gradient.shape = token.value;
                // 获取下一个标记
                token = parser.getToken(true, true);
            }
            // 如果 shape 或 size 属性存在且标记不是逗号
            if ((("shape" in gradient) || ("size" in gradient)) && !token.isSymbol(","))
                // 返回 null
                return null;
            // 如果 shape 或 size 属性存在
            else if (("shape" in gradient) || ("size" in gradient))
                // 获取下一个标记
                token = parser.getToken(true, true);
        }

        // 解析第一个颜色停止点
        var stop1 = this.parseColorStop(parser, token);
        // 如果解析失败,则返回 null
        if (!stop1)
            return null;
        // 获取当前标记
        token = parser.currentToken();
        // 检查标记是否为逗号
        if (!token.isSymbol(","))
            // 如果不是,则返回 null
            return null;
        // 获取下一个标记
        token = parser.getToken(true, true);
        // 解析第二个颜色停止点
        var stop2 = this.parseColorStop(parser, token);
        // 如果解析失败,则返回 null
        if (!stop2)
            return null;
        // 获取当前标记
        token = parser.currentToken();
        // 如果标记为逗号
        if (token.isSymbol(",")) {
            // 获取下一个标记
            token = parser.getToken(true, true);
        }
        // 将前两个颜色停止点添加到渐变对象的 stops 数组中
        gradient.stops = [stop1, stop2];
        // 循环解析剩余的颜色停止点,直到遇到右括号
        while (!token.isSymbol(")")) {
            // 解析颜色停止点
            var colorstop = this.parseColorStop(parser, token);
            // 如果解析失败,则返回 null
            if (!colorstop)
                return null;
            // 获取当前标记
            token = parser.currentToken();
            // 检查标记是否为右括号或逗号
            if (!token.isSymbol(")") && !token.isSymbol(","))
                // 如果不是,则返回 null
                return null;
            // 如果标记为逗号
            if (token.isSymbol(","))
                // 获取下一个标记
                token = parser.getToken(true, true);
            // 将颜色停止点添加到渐变对象的 stops 数组中
            gradient.stops.push(colorstop);
        }
        // 返回解析好的渐变对象
        return gradient;
    }
}
// 如果解析失败,则返回 null
return null;

},

// 解析盒阴影的方法 parseBoxShadows: function(aString) { // 创建一个 CSSParser 实例 var parser = new CSSParser(); // 初始化解析器 parser._init(); // 设置解析器不保留空白字符 parser.mPreserveWS = false; // 设置解析器不保留注释 parser.mPreserveComments = false; // 初始化保留标记数组 parser.mPreservedTokens = []; // 初始化扫描器,传入要解析的字符串 parser.mScanner.init(aString);

// 初始化阴影数组
var shadows = [];
// 获取第一个标记
var token = parser.getToken(true, true);
// 初始化颜色、模糊半径、水平偏移、垂直偏移和扩展半径
var color = "", blurRadius = "0px", offsetX = "0px", offsetY = "0px", spreadRadius = "0px";
// 初始化是否为内阴影的标志为 false
var inset = false;
// 循环处理标记,直到标记为空
while (token.isNotNull()) {
    // 检查标记是否为 "none"
    if (token.isIdent("none")) {
        // 如果是,则将一个包含 none 为 true 的对象添加到阴影数组中
        shadows.push( { none: true } );
        // 获取下一个标记
        token = parser.getToken(true, true);
    }
    else {
        // 检查标记是否为 "inset"
        if (token.isIdent('inset')) {
            // 如果是,则将 inset 标志置为 true
            inset = true;
            // 获取下一个标记
            token = parser.getToken(true, true);
        }

        // 检查标记是否为百分比或指定单位的尺寸
        if (token.isPercentage() ||
            token.isDimensionOfUnit("cm") ||
            token.isDimensionOfUnit("mm") ||
            token.isDimensionOfUnit("in") ||
            token.isDimensionOfUnit("pc") ||
            token.isDimensionOfUnit("px") ||
            token.isDimensionOfUnit("em") ||
            token.isDimensionOfUnit("ex") ||
            token.isDimensionOfUnit("pt")) {
            // 如果是,则将标记的值赋给 offsetX
            var offsetX = token.value;
            // 获取下一个标记
            token = parser.getToken(true, true);
        }
        else
            // 如果不是,则返回空数组
            return [];

        // 如果不是内阴影且标记为 "inset"
        if (!inset && token.isIdent('inset')) {
            // 将 inset 标志置为 true
            inset = true;
            // 获取下一个标记
            token = parser.getToken(true, true);
        }

        // 检查标记是否为百分比或指定单位的尺寸
        if (token.isPercentage() ||
            token.isDimensionOfUnit("cm") ||
            token.isDimensionOfUnit("mm") ||
            token.isDimensionOfUnit("in") ||
            token.isDimensionOfUnit("pc") ||
            token.isDimensionOfUnit("px") ||
            token.isDimensionOfUnit("em") ||
            token.isDimensionOfUnit("ex") ||
            token.isDimensionOfUnit("pt")) {
            // 如果是,则将标记的值赋给 offsetY
            var offsetY = token.value;
            // 获取下一个标记
            token = parser.getToken(true, true);
        }
        else
            // 如果不是,则返回空数组
            return [];

        // 如果不是内阴影且标记为 "inset"
        if (!inset && token.isIdent('inset')) {
            // 将 inset 标志置为 true
            inset = true;
            // 获取下一个标记
            token = parser.getToken(true, true);
        }

        // 检查标记是否为百分比或指定单位的尺寸
        if (token.isPercentage() ||
            token.isDimensionOfUnit("cm") ||
            token.isDimensionOfUnit("mm") ||
            token.isDimensionOfUnit("in") ||
            token.isDimensionOfUnit("pc") ||
            token.isDimensionOfUnit("px") ||
            token.isDimensionOfUnit("em") ||
            token.isDimensionOfUnit("ex") ||
            token.isDimensionOfUnit("pt")) {
            // 如果是,则将标记的值赋给 blurRadius
            var blurRadius = token.value;
            // 获取下一个标记
            token = parser.getToken(true, true);
        }

        // 如果不是内阴影且标记为 "inset"
        if (!inset && token.isIdent('inset')) {
            // 将 inset 标志置为 true
            inset = true;
            // 获取下一个标记
            token = parser.getToken(true, true);
        }

        // 检查标记是否为颜色函数、符号或标识符
        if (token.isFunction("rgb(") ||
            token.isFunction("rgba(") ||
            token.isFunction("hsl(") ||
            token.isFunction("hsla(") ||
            token.isSymbol("#") ||
            token.isIdent()) {
            // 如果是,则调用解析器的 parseColor 方法解析颜色
            var color = parser.parseColor(token);
            // 获取下一个标记
            token = parser.getToken(true, true);
        }

        // 如果不是内阴影且标记为 "inset"
        if (!inset && token.isIdent('inset')) {
            // 将 inset 标志置为 true
            inset = true;
            // 获取下一个标记
            token = parser.getToken(true, true);
        }

        // 将解析好的阴影信息添加到阴影数组中
        shadows.push( { none: false,
                        color: color,
                        offsetX: offsetX, offsetY: offsetY,
                        blurRadius: blurRadius,
                        spreadRadius: spreadRadius } );

        // 检查标记是否为逗号
        if (token.isSymbol(",")) {
            // 如果是,则重置相关变量
            inset = false;
            color = "";
            blurRadius = "0px";
            spreadRadius = "0px"
            offsetX = "0px";
            offsetY = "0px"; 
            // 获取下一个标记
            token = parser.getToken(true, true);
        }
        else if (!token.isNotNull())
            // 如果标记为空,则返回阴影数组
            return shadows;
        else
            // 否则返回空数组
            return [];
    }
}
// 返回阴影数组
return shadows;

},

// 解析文本阴影的方法 parseTextShadows: function(aString) { // 创建一个 CSSParser 实例 var parser = new CSSParser(); // 初始化解析器 parser._init(); // 设置解析器不保留空白字符 parser.mPreserveWS = false; // 设置解析器不保留注释 parser.mPreserveComments = false; // 初始化保留标记数组 parser.mPreservedTokens = []; // 初始化扫描器,传入要解析的字符串 parser.mScanner.init(aString);

// 初始化阴影数组
var shadows = [];
// 获取第一个标记
var token = parser.getToken(true, true);
// 初始化颜色、模糊半径、水平偏移和垂直偏移
var color = "", blurRadius = "0px", offsetX = "0px", offsetY = "0px"; 
// 循环处理标记,直到标记为空
while (token.isNotNull()) {
    // 检查标记是否为 "none"
    if (token.isIdent("none")) {
        // 如果是,则将一个包含 none 为 true 的对象添加到阴影数组中
        shadows.push( { none: true } );
        // 获取下一个标记
        token = parser.getToken(true, true);
    }
    else {
        // 检查标记是否为颜色函数、符号或标识符
        if (token.isFunction("rgb(") ||
            token.isFunction("rgba(") ||
            token.isFunction("hsl(") ||
            token.isFunction("hsla(") ||
            token.isSymbol("#") ||
            token.isIdent()) {
            // 如果是,则调用解析器的 parseColor 方法解析颜色
            var color = parser.parseColor(token);
            // 获取下一个标记
            token = parser.getToken(true, true);
        }
        // 检查标记是否为百分比或指定单位的尺寸
        if (token.isPercentage() ||
            token.isDimensionOfUnit("cm") ||
            token.isDimensionOfUnit("mm") ||
            token.isDimensionOfUnit("in") ||
            token.isDimensionOfUnit("pc") ||
            token.isDimensionOfUnit("px") ||
            token.isDimensionOfUnit("em") ||
            token.isDimensionOfUnit("ex") ||
            token.isDimensionOfUnit("pt")) {
            // 如果是,则将标记的值赋给 offsetX
            var offsetX = token.value;
            // 获取下一个标记
            token = parser.getToken(true, true);
        }
        else
            // 如果不是,则返回空数组
            return [];
        // 检查标记是否为百分比或指定单位的尺寸
        if (token.isPercentage() ||
            token.isDimensionOfUnit("cm") ||
            token.isDimensionOfUnit("mm") ||
            token.isDimensionOfUnit("in") ||
            token.isDimensionOfUnit("pc") ||
            token.isDimensionOfUnit("px") ||
            token.isDimensionOfUnit("em") ||
            token.isDimensionOfUnit("ex") ||
            token.isDimensionOfUnit("pt")) {
            // 如果是,则将标记的值赋给 offsetY
            var offsetY = token.value;
            // 获取下一个标记
            token = parser.getToken(true, true);
        }
        else
            // 如果不是,则返回空数组
            return [];
        // 检查标记是否为百分比或指定单位的尺寸
        if (token.isPercentage() ||
            token.isDimensionOfUnit("cm") ||
            token.isDimensionOfUnit("mm") ||
            token.isDimensionOfUnit("in") ||
            token.isDimensionOfUnit("pc") ||
            token.isDimensionOfUnit("px") ||
            token.isDimensionOfUnit("em") ||
            token.isDimensionOfUnit("ex") ||
            token.isDimensionOfUnit("pt")) {
            // 如果是,则将标记的值赋给 blurRadius
            var blurRadius = token.value;
            // 获取下一个标记
            token = parser.getToken(true, true);
        }
        // 如果颜色为空且标记为颜色函数、符号或标识符
        if (!color &&
            (token.isFunction("rgb(") ||
             token.isFunction("rgba(") ||
             token.isFunction("hsl(") ||
             token.isFunction("hsla(") ||
             token.isSymbol("#") ||
             token.isIdent())) {
            // 调用解析器的 parseColor 方法解析颜色
            var color = parser.parseColor(token);
            // 获取下一个标记
            token = parser.getToken(true, true);
        }

        // 将解析好的阴影信息添加到阴影数组中
        shadows.push( { none: false,
                        color: color,
                        offsetX: offsetX, offsetY: offsetY,
                        blurRadius: blurRadius } );

        // 检查标记是否为逗号
        if (token.isSymbol(",")) {
            // 如果是,则重置相关变量
            color = "";
            blurRadius = "0px";
            offsetX = "0px";
            offsetY = "0px"; 
            // 获取下一个标记
            token = parser.getToken(true, true);
        }
        else if (!token.isNotNull())
            // 如果标记为空,则返回阴影数组
            return shadows;
        else
            // 否则返回空数组
            return [];
    }
}
// 返回阴影数组
return shadows;

},

// 解析背景图像的方法 parseBackgroundImages: function(aString) { // 创建一个 CSSParser 实例 var parser = new CSSParser(); // 初始化解析器 parser._init(); // 设置解析器不保留空白字符 parser.mPreserveWS = false; // 设置解析器不保留注释 parser.mPreserveComments = false; // 初始化保留标记数组 parser.mPreservedTokens = []; // 初始化扫描器,传入要解析的字符串 parser.mScanner.init(aString);

// 初始化背景数组
var backgrounds = [];
// 获取第一个标记
var token = parser.getToken(true, true);
// 循环处理标记,直到标记为空
while (token.isNotNull()) {
    /*if (token.isFunction("rgb(") ||
        token.isFunction("rgba(") ||
        token.isFunction("hsl(") ||
        token.isFunction("hsla(") ||
        token.isSymbol("#") ||
        token.isIdent()) {
        // 如果标记为颜色相关,解析颜色并添加到背景数组中
        var color = parser.parseColor(token);
        backgrounds.push( { type: "color", value: color });
        token = parser.getToken(true, true);
    }
    else */
    // 检查标记是否为 url 函数
    if (token.isFunction("url(")) {
        // 获取下一个标记
        token = parser.getToken(true, true);
        // 调用解析器的 parseURL 方法解析 URL
        var urlContent = parser.parseURL(token);
        // 将解析好的 URL 信息添加到背景数组中
        backgrounds.push( { type: "image", value: "url(" + urlContent });
        // 获取下一个标记
        token = parser.getToken(true, true);
    }
    // 检查标记是否为渐变函数
    else if (token.isFunction("-moz-linear-gradient(") ||
             token.isFunction("-moz-radial-gradient(") ||
             token.isFunction("-moz-repeating-linear-gradient(") ||
             token.isFunction("-moz-repeating-radial-gradient(")) {
        // 调用 parseGradient 方法解析渐变
        var gradient = this.parseGradient(parser, token);
        // 根据渐变类型将渐变信息添加到背景数组中
        backgrounds.push( { type: gradient.isRadial ? "radial-gradient" : "linear-gradient", value: gradient });
        // 获取下一个标记
        token = parser.getToken(true, true);
    }
    else
        // 如果标记不符合要求,则返回 null
        return null;
    // 检查标记是否为逗号
    if (token.isSymbol(",")) {
        // 获取下一个标记
        token = parser.getToken(true, true);
        // 如果标记为空,则返回 null
        if (!token.isNotNull())
            return null;
    }
}
// 返回背景数组
return backgrounds;

},

// 序列化渐变对象为字符串的方法
serializeGradient: function(gradient)
{
// 根据渐变类型和是否重复构建渐变字符串的开头部分
var s = gradient.isRadial
? (gradient.isRepeating ? "-moz-repeating-radial-gradient(" : "-moz-radial-gradient(" )
(gradient.isRepeating ? "-moz-repeating-linear-gradient(" : "-moz-linear-gradient(" ); // 如果渐变有角度或位置信息 if (gradient.angle || gradient.position) s += (gradient.angle ? gradient.angle + " ": "") + (gradient.position ? gradient.position : "") + ", "; // 如果是径向渐变且有形状或尺寸信息 if (gradient.isRadial && (gradient.shape || gradient.size)) s += (gradient.shape ? gradient.shape : "") + " " + (gradient.size ? gradient.size : "") + ", "; // 遍历渐变的颜色停止点数组 for (var i = 0; i < gradient.stops.length; i++) { // 获取当前颜色停止点 var colorstop = gradient.stops[i]; // 将颜色停止点信息添加到渐变字符串中 s += colorstop.color + (colorstop.position ? " " + colorstop.position : ""); // 如果不是最后一个颜色停止点,则添加逗号 if (i != gradient.stops.length -1) s += ", "; } // 添加右括号完成渐变字符串 s += ")"; // 返回序列化后的渐变字符串 return s; },

// 解析边框图像的方法 parseBorderImage: function(aString) { // 创建一个 CSSParser 实例 var parser = new CSSParser(); // 初始化解析器 parser._init(); // 设置解析器不保留空白字符 parser.mPreserveWS = false; // 设置解析器不保留注释 parser.mPreserveComments = false; // 初始化保留标记数组 parser.mPreservedTokens = []; // 初始化扫描器,传入要解析的字符串 parser.mScanner.init(aString);

// 初始化边框图像对象
var borderImage = {url: "", offsets: [], widths: [], sizes: []};
// 获取第一个标记
var token = parser.getToken(true, true);
// 检查标记是否为 url 函数
if (token.isFunction("url(")) {
    // 获取下一个标记
    token = parser.getToken(true, true);
    // 调用解析器的 parseURL 方法解析 URL
    var urlContent = parser.parseURL(token);
    // 如果 URL 解析成功
    if (urlContent) {
        // 处理 URL 字符串,去除首尾引号
        borderImage.url = urlContent.substr(0, urlContent.length - 1).trim();
        if ((borderImage.url[0] == '"' && borderImage.url[borderImage.url.length - 1] == '"') ||
            (borderImage.url[0] == "'" && borderImage.url[borderImage.url.length - 1] == "'"))
            borderImage.url = borderImage.url.substr(1, borderImage.url.length - 2);
    }
    else
        // 如果 URL 解析失败,则返回 null
        return null;
}
else
    // 如果标记不是 url 函数,则返回 null
    return null; 

// 获取下一个标记
token = parser.getToken(true, true);
// 检查标记是否为数字或百分比
if (token.isNumber() || token.isPercentage())
    // 如果是,则将标记的值添加到边框图像的 offsets 数组中
    borderImage.offsets.push(token.value);
else
    // 如果不是,则返回 null
    return null;
// 循环处理后续的标记,最多处理 3 个
var i;
for (i= 0; i < 3; i++) {
    // 获取下一个标记
    token = parser.getToken(true, true);
    // 检查标记是否为数字或百分比
    if (token.isNumber() || token.isPercentage())
        // 如果是,则将标记的值添加到边框图像的 offsets 数组中
        borderImage.offsets.push(token.value);
    else
        // 如果不是,则跳出循环
        break;
}
// 如果处理了 3 个标记,则获取下一个标记
if (i == 3)
    token = parser.getToken(true, true);

// 检查标记是否为斜杠
if (token.isSymbol("/")) {
    // 获取下一个标记
    token = parser.getToken(true, true);
    // 检查标记是否为尺寸、数字 0 或特定的边框宽度名称
    if (token.isDimension()
        || token.isNumber("0")
        || (token.isIdent() && token.value in parser.kBORDER_WIDTH_NAMES))
        // 如果是,则将标记的值添加到边框图像的 widths 数组中
        borderImage.widths.push(token.value);
    else
        // 如果不是,则返回 null
        return null;

    // 循环处理后续的标记,最多处理 3 个
    for (var i = 0; i < 3; i++) {
        // 获取下一个标记
        token = parser.getToken(true, true);
        // 检查标记是否为尺寸、数字 0 或特定的边框宽度名称
        if (token.isDimension()
            || token.isNumber("0")
            || (token.isIdent() && token.value in parser.kBORDER_WIDTH_NAMES))
            // 如果是,则将标记的值添加到边框图像的 widths 数组中
            borderImage.widths.push(token.value);
        else
            // 如果不是,则跳出循环
            break;
    }
    // 如果处理了 3 个标记,则获取下一个标记
    if (i == 3)
        token = parser.getToken(true, true);
}

// 循环处理后续的标记,最多处理 2 个
for (var i = 0; i < 2; i++) {
    // 检查标记是否为特定的尺寸标识符
    if (token.isIdent("stretch")
        || token.isIdent("repeat")
        || token.isIdent("round"))
        // 如果是,则将标记的值添加到边框图像的 sizes 数组中
        borderImage.sizes.push(token.value);
    else if (!token.isNotNull())
        // 如果标记为空,则返回边框图像对象
        return borderImage;
    else
        // 如果标记不符合要求,则返回 null
        return null;
    // 获取下一个标记
    token = parser.getToken(true, true);
}
// 如果标记为空,则返回边框图像对象
if (!token.isNotNull())
    return borderImage;

// 如果解析失败,则返回 null
return null;

},

// 解析媒体查询的方法 parseMediaQuery: function(aString) { // 定义一个包含所有有效约束条件的对象 var kCONSTRAINTS = { "width": true, "min-width": true, "max-width": true, "height": true, "min-height": true, "max-height": true, "device-width": true, "min-device-width": true, "max-device-width": true, "device-height": true, "min-device-height": true, "max-device-height": true, "orientation": true, "aspect-ratio": true, "min-aspect-ratio": true, "max-aspect-ratio": true, "device-aspect-ratio": true, "min-device-aspect-ratio": true, "max-device-aspect-ratio": true, "color": true, "min-color": true, "max-color": true, "color-index": true, "min-color-index": true, "max-color-index": true, "monochrome": true, "min-monochrome": true, "max-monochrome": true, "resolution": true, "min-resolution

// 模拟 kCSS_VENDOR_PREFIXES const kCSS_VENDOR_PREFIXES = { properties: [ { gecko: '-moz-example', webkit: '-webkit-example', presto: '-o-example', trident: '-ms-example' } ] };

// 模拟 CSSParser 类 class CSSParser { constructor() { this.mScanner = { init: function (aString) { // 初始化扫描器逻辑 } }; }

_init() {
    // 初始化解析器逻辑
}

getToken() {
    // 模拟获取标记逻辑
    return {
        isNotNull: function () { return true; },
        isFunction: function (name) { return false; },
        isAngle: function () { return false; },
        isLength: function () { return false; },
        isIdent: function (value) { return false; },
        isSymbol: function (symbol) { return false; },
        isPercentage: function () { return false; },
        isDimensionOfUnit: function (unit) { return false; },
        parseColor: function (token) { return 'color'; },
        currentToken: function () { return { isSymbol: function (symbol) { return false; } }; },
        parseURL: function (token) { return 'url-content'; }
    };
}

}

// 定义对象 const obj = { kEXPORTS_FOR_GECKO: true, kEXPORTS_FOR_WEBKIT: true, kEXPORTS_FOR_PRESTO: true, kEXPORTS_FOR_TRIDENT: true, mVENDOR_PREFIXES: null,

// 清除前缀缓存
cleanPrefixes: function () {
    this.mVENDOR_PREFIXES = null;
},

// 获取属性的前缀列表
prefixesForProperty: function (aProperty) {
    if (!this.mVENDOR_PREFIXES) {
        this.mVENDOR_PREFIXES = {};
        // 遍历所有属性前缀
        for (var i = 0; i < kCSS_VENDOR_PREFIXES.properties.length; i++) {
            var p = kCSS_VENDOR_PREFIXES.properties[i];
            if (p.gecko && (p.webkit || p.presto || p.trident)) {
                var o = {};
                // 根据导出标志添加前缀
                if (this.kEXPORTS_FOR_GECKO) o[p.gecko] = true;
                if (this.kEXPORTS_FOR_WEBKIT && p.webkit) o[p.webkit] = true;
                if (this.kEXPORTS_FOR_PRESTO && p.presto) o[p.presto] = true;
                if (this.kEXPORTS_FOR_TRIDENT && p.trident) o[p.trident] = true;
                this.mVENDOR_PREFIXES[p.gecko] = [];
                for (var j in o)
                    this.mVENDOR_PREFIXES[p.gecko].push(j)
            }
        }
    }
    if (aProperty in this.mVENDOR_PREFIXES)
        return this.mVENDOR_PREFIXES[aProperty].sort();
    return null;
},

// 解析颜色停止点
parseColorStop: function (parser, token) {
    var color = parser.parseColor(token);
    var position = "";
    if (!color)
        return null;
    token = parser.getToken(true, true);
    // 检查是否有位置信息
    if (token.isPercentage() ||
        token.isDimensionOfUnit("cm") ||
        token.isDimensionOfUnit("mm") ||
        token.isDimensionOfUnit("in") ||
        token.isDimensionOfUnit("pc") ||
        token.isDimensionOfUnit("px") ||
        token.isDimensionOfUnit("em") ||
        token.isDimensionOfUnit("ex") ||
        token.isDimensionOfUnit("pt")) {
        position = token.value;
        token = parser.getToken(true, true);
    }
    return { color: color, position: position }
},

// 解析渐变
parseGradient: function (parser, token) {
    var isRadial = false;
    var gradient = { isRepeating: false };
    if (token.isNotNull()) {
        if (token.isFunction("-moz-linear-gradient(") ||
            token.isFunction("-moz-radial-gradient(") ||
            token.isFunction("-moz-repeating-linear-gradient(") ||
            token.isFunction("-moz-repeating-radial-gradient(")) {
            if (token.isFunction("-moz-radial-gradient(") ||
                token.isFunction("-moz-repeating-radial-gradient(")) {
                gradient.isRadial = true;
            }
            if (token.isFunction("-moz-repeating-linear-gradient(") ||
                token.isFunction("-moz-repeating-radial-gradient(")) {
                gradient.isRepeating = true;
            }

            token = parser.getToken(true, true);
            var haveGradientLine = false;
            var foundHorizPosition = false;
            var haveAngle = false;

            // 检查是否有角度信息
            if (token.isAngle()) {
                gradient.angle = token.value;
                haveGradientLine = true;
                haveAngle = true;
                token = parser.getToken(true, true);
            }

            // 检查是否有位置信息
            if (token.isLength()
                || token.isIdent("top")
                || token.isIdent("center")
                || token.isIdent("bottom")
                || token.isIdent("left")
                || token.isIdent("right")) {
                haveGradientLine = true;
                if (token.isLength()
                    || token.isIdent("left")
                    || token.isIdent("right")) {
                    foundHorizPosition = true;
                }
                gradient.position = token.value;
                token = parser.getToken(true, true);
            }

            if (haveGradientLine) {
                if (!haveAngle && token.isAngle()) {
                    gradient.angle = token.value;
                    haveAngle = true;
                    token = parser.getToken(true, true);
                }

                else if (token.isLength()
                    || (foundHorizPosition && (token.isIdent("top")
                        || token.isIdent("center")
                        || token.isIdent("bottom")))
                    || (!foundHorizPosition && (token.isLength()
                        || token.isIdent("top")
                        || token.isIdent("center")
                        || token.isIdent("bottom")
                        || token.isIdent("left")
                        || token.isIdent("right")))) {
                    gradient.position = ("position" in gradient) ? gradient.position + " " : "";
                    gradient.position += token.value;
                    token = parser.getToken(true, true);
                }

                if (!haveAngle && token.isAngle()) {
                    gradient.angle = token.value;
                    haveAngle = true;
                    token = parser.getToken(true, true);
                }

                if (!token.isSymbol(","))
                    return null;
                token = parser.getToken(true, true);
            }

            if (gradient.isRadial) {
                // 检查是否有形状信息
                if (token.isIdent("circle") ||
                    token.isIdent("ellipse")) {
                    gradient.shape = token.value;
                    token = parser.getToken(true, true);
                }
                // 检查是否有大小信息
                if (token.isIdent("closest-side") ||
                    token.isIdent("closest-corner") ||
                    token.isIdent("farthest-side") ||
                    token.isIdent("farthest-corner") ||
                    token.isIdent("contain") ||
                    token.isIdent("cover")) {
                    gradient.size = token.value;
                    token = parser.getToken(true, true);
                }
                if (!("shape" in gradient) &&
                    (token.isIdent("circle") ||
                        token.isIdent("ellipse"))) {
                    gradient.shape = token.value;
                    token = parser.getToken(true, true);
                }
                if ((("shape" in gradient) || ("size" in gradient)) && !token.isSymbol(","))
                    return null;
                else if (("shape" in gradient) || ("size" in gradient))
                    token = parser.getToken(true, true);
            }

            var stop1 = this.parseColorStop(parser, token);
            if (!stop1)
                return null;
            token = parser.currentToken();
            if (!token.isSymbol(","))
                return null;
            token = parser.getToken(true, true);
            var stop2 = this.parseColorStop(parser, token);
            if (!stop2)
                return null;
            token = parser.currentToken();
            if (token.isSymbol(",")) {
                token = parser.getToken(true, true);
            }
            gradient.stops = [stop1, stop2];
            // 解析所有颜色停止点
            while (!token.isSymbol(")")) {
                var colorstop = this.parseColorStop(parser, token);
                if (!colorstop)
                    return null;
                token = parser.currentToken();
                if (!token.isSymbol(")") && !token.isSymbol(","))
                    return null;
                if (token.isSymbol(","))
                    token = parser.getToken(true, true);
                gradient.stops.push(colorstop);
            }
            return gradient;
        }
    }
    return null;
},

// 解析盒子阴影
parseBoxShadows: function (aString) {
    var parser = new CSSParser();
    parser._init();
    parser.mPreserveWS = false;
    parser.mPreserveComments = false;
    parser.mPreservedTokens = [];
    parser.mScanner.init(aString);

    var shadows = [];
    var token = parser.getToken(true, true);
    var color = "", blurRadius = "0px", offsetX = "0px", offsetY = "0px", spreadRadius = "0px";
    var inset = false;
    while (token.isNotNull()) {
        if (token.isIdent("none")) {
            shadows.push({ none: true });
            token = parser.getToken(true, true);
        }
        else {
            // 检查是否有 inset 关键字
            if (token.isIdent('inset')) {
                inset = true;
                token = parser.getToken(true, true);
            }

            // 解析偏移量 X
            if (token.isPercentage() ||
                token.isDimensionOfUnit("cm") ||
                token.isDimensionOfUnit("mm") ||
                token.isDimensionOfUnit("in") ||
                token.isDimensionOfUnit("pc") ||
                token.isDimensionOfUnit("px") ||
                token.isDimensionOfUnit("em") ||
                token.isDimensionOfUnit("ex") ||
                token.isDimensionOfUnit("pt")) {
                var offsetX = token.value;
                token = parser.getToken(true, true);
            }
            else
                return [];

            if (!inset && token.isIdent('inset')) {
                inset = true;
                token = parser.getToken(true, true);
            }

            // 解析偏移量 Y
            if (token.isPercentage() ||
                token.isDimensionOfUnit("cm") ||
                token.isDimensionOfUnit("mm") ||
                token.isDimensionOfUnit("in") ||
                token.isDimensionOfUnit("pc") ||
                token.isDimensionOfUnit("px") ||
                token.isDimensionOfUnit("em") ||
                token.isDimensionOfUnit("ex") ||
                token.isDimensionOfUnit("pt")) {
                var offsetY = token.value;
                token = parser.getToken(true, true);
            }
            else
                return [];

            if (!inset && token.isIdent('inset')) {
                inset = true;
                token = parser.getToken(true, true);
            }

            // 解析模糊半径
            if (token.isPercentage() ||
                token.isDimensionOfUnit("cm") ||
                token.isDimensionOfUnit("mm") ||
                token.isDimensionOfUnit("in") ||
                token.isDimensionOfUnit("pc") ||
                token.isDimensionOfUnit("px") ||
                token.isDimensionOfUnit("em") ||
                token.isDimensionOfUnit("ex") ||
                token.isDimensionOfUnit("pt")) {
                var blurRadius = token.value;
                token = parser.getToken(true, true);
            }

            if (!inset && token.isIdent('inset')) {
                inset = true;
                token = parser.getToken(true, true);
            }

            // 解析颜色
            if (token.isFunction("rgb(") ||
                token.isFunction("rgba(") ||
                token.isFunction("hsl(") ||
                token.isFunction("hsla(") ||
                token.isSymbol("#") ||
                token.isIdent()) {
                var color = parser.parseColor(token);
                token = parser.getToken(true, true);
            }

            if (!inset && token.isIdent('inset')) {
                inset = true;
                token = parser.getToken(true, true);
            }

            shadows.push({ none: false,
                color: color,
                offsetX: offsetX, offsetY: offsetY,
                blurRadius: blurRadius,
                spreadRadius: spreadRadius });

            if (token.isSymbol(",")) {
                inset = false;
                color = "";
                blurRadius = "0px";
                spreadRadius = "0px"
                offsetX = "0px";
                offsetY = "0px";
                token = parser.getToken(true, true);
            }
            else if (!token.isNotNull())
                return shadows;
            else
                return [];
        }
    }
    return shadows;
},

// 解析文本阴影
parseTextShadows: function (aString) {
    var parser = new CSSParser();
    parser._init();
    parser.mPreserveWS = false;
    parser.mPreserveComments = false;
    parser.mPreservedTokens = [];
    parser.mScanner.init(aString);

    var shadows = [];
    var token = parser.getToken(true, true);
    var color = "", blurRadius = "0px", offsetX = "0px", offsetY = "0px";
    while (token.isNotNull()) {
        if (token.isIdent("none")) {
            shadows.push({ none: true });
            token = parser.getToken(true, true);
        }
        else {
            // 解析颜色
            if (token.isFunction("rgb(") ||
                token.isFunction("rgba(") ||
                token.isFunction("hsl(") ||
                token.isFunction("hsla(") ||
                token.isSymbol("#") ||
                token.isIdent()) {
                var color = parser.parseColor(token);
                token = parser.getToken(true, true);
            }
            // 解析偏移量 X
            if (token.isPercentage() ||
                token.isDimensionOfUnit("cm") ||
                token.isDimensionOfUnit("mm") ||
                token.isDimensionOfUnit("in") ||
                token.isDimensionOfUnit("pc") ||
                token.isDimensionOfUnit("px") ||
                token.isDimensionOfUnit("em") ||
                token.isDimensionOfUnit("ex") ||
                token.isDimensionOfUnit("pt")) {
                var offsetX = token.value;
                token = parser.getToken(true, true);
            }
            else
                return [];
            // 解析偏移量 Y
            if (token.isPercentage() ||
                token.isDimensionOfUnit("cm") ||
                token.isDimensionOfUnit("mm") ||
                token.isDimensionOfUnit("in") ||
                token.isDimensionOfUnit("pc") ||
                token.isDimensionOfUnit("px") ||
                token.isDimensionOfUnit("em") ||
                token.isDimensionOfUnit("ex") ||
                token.isDimensionOfUnit("pt")) {
                var offsetY = token.value;
                token = parser.getToken(true, true);
            }
            else
                return [];
            // 解析模糊半径
            if (token.isPercentage() ||
                token.isDimensionOfUnit("cm") ||
                token.isDimensionOfUnit("mm") ||
                token.isDimensionOfUnit("in") ||
                token.isDimensionOfUnit("pc") ||
                token.isDimensionOfUnit("px") ||
                token.isDimensionOfUnit("em") ||
                token.isDimensionOfUnit("ex") ||
                token.isDimensionOfUnit("pt")) {
                var blurRadius = token.value;
                token = parser.getToken(true, true);
            }
            if (!color &&
                (token.isFunction("rgb(") ||
                    token.isFunction("rgba(") ||
                    token.isFunction("hsl(") ||
                    token.isFunction("hsla(") ||
                    token.isSymbol("#") ||
                    token.isIdent())) {
                var color = parser.parseColor(token);
                token = parser.getToken(true, true);
            }

            shadows.push({ none: false,
                color: color,
                offsetX: offsetX, offsetY: offsetY,
                blurRadius: blurRadius });

            if (token.isSymbol(",")) {
                color = "";
                blurRadius = "0px";
                offsetX = "0px";
                offsetY = "0px";
                token = parser.getToken(true, true);
            }
            else if (!token.isNotNull())
                return shadows;
            else
                return [];
        }
    }
    return shadows;
},

// 解析背景图像
parseBackgroundImages: function (aString) {
    var parser = new CSSParser();
    parser._init();
    parser.mPreserveWS = false;
    parser.mPreserveComments = false;
    parser.mPreservedTokens = [];
    parser.mScanner.init(aString);

    var backgrounds = [];
    var token = parser.getToken(true, true);
    while (token.isNotNull()) {
        if (token.isFunction("url(")) {
            token = parser.getToken(true, true);
            var urlContent = parser.parseURL(token);
            backgrounds.push({ type: "image", value: "url(" + urlContent });
            token = parser.getToken(true, true);
        }
        else if (token.isFunction("-moz-linear-gradient(") ||
            token.isFunction("-moz-radial-gradient(") ||
            token.isFunction("-moz-repeating-linear-gradient(") ||
            token.isFunction("-moz-repeating-radial-gradient(")) {
            var gradient = this.parseGradient(parser, token);
            backgrounds.push({ type: gradient.isRadial ? "radial-gradient" : "linear-gradient", value: gradient });
            token = parser.getToken(true, true);
        }
        else
            return null;
        if (token.isSymbol(",")) {
            token = parser.getToken(true, true);
            if (!token.isNotNull())
                return null;
        }
    }
    return backgrounds;
},

// 序列化渐变
serializeGradient: function (gradient) {
    var s = gradient.isRadial
       ? (gradient.isRepeating ? "-moz-repeating-radial-gradient(" : "-moz-radial-gradient(" )
        : (gradient.isRepeating ? "-moz-repeating-linear-gradient(" : "-moz-linear-gradient(" );
    if (gradient.angle || gradient.position)
        s += (gradient.angle ? gradient.angle + " " : "") +
            (gradient.position ? gradient.position : "") +
            ", ";
    if (gradient.isRadial && (gradient.shape || gradient.size))
        s += (gradient.shape ? gradient.shape : "") +
            " " +
            (gradient.size ? gradient.size : "") +
            ", ";
    for (var i = 0; i < gradient.stops.length; i++) {
        var colorstop = gradient.stops[i];
        s += colorstop.color + (colorstop.position ? " " + colorstop.position : "");
        if (i != gradient.stops.length - 1)
            s += ", ";
    }
    s += ")";
    return s;
},

// 解析边框图像
parseBorderImage: function (aString) {
    var parser = new CSSParser();
    parser._init();
    parser.mPreserveWS = false;
    parser.mPreserveComments = false;
    parser.mPreservedTokens = [];
    parser.mScanner.init(aString);

    var borderImage = { url: "", offsets: [], widths: [], sizes: [] };
    var token = parser.getToken(true, true);
    if (token.isFunction("url(")) {
        token = parser.getToken(true, true);
        var urlContent = parser.parseURL(token);
        if (urlContent) {
            borderImage.url = urlContent.substr(0, urlContent.length - 1).trim();
            if ((borderImage.url[0] == '"' && borderImage.url[borderImage.url.length - 1] == '"') ||
                (borderImage.url[0] == "'" && borderImage.url[borderImage.url.length - 1] == "'"))
                borderImage.url = borderImage.url.substr(1, borderImage.url.length - 2);
        }
        else
            return null;
    }
    else
        return null;

    token = parser.getToken(true, true);
    if (token.isNumber() || token.isPercentage())
        borderImage.offsets.push(token.value);
    else
        return null;
    var i;
    for (i = 0; i < 3; i++) {
        token = parser.getToken(true, true);
        if (token.isNumber() || token.isPercentage())
            borderImage.offsets.push(token.value);
        else
            break;
    }
    if (i == 3)
        token = parser.getToken(true, true);

    if (token.isSymbol("/")) {
        token = parser.getToken(true, true);
        if (token.isDimension()
            || token.isNumber("0")
            || (token.isIdent() && token.value in parser.kBORDER_WIDTH_NAMES))
            borderImage.widths.push(token.value);
        else
            return null;

        for (var i = 0; i < 3; i++) {
            token = parser.getToken(true, true);
            if (token.isDimension()
                || token.isNumber("0")
                || (token.isIdent() && token.value in parser.kBORDER_WIDTH_NAMES))
                borderImage.widths.push(token.value);
            else
                break;
        }
        if (i == 3)
            token = parser.getToken(true, true);
    }

    for (var i = 0; i < 2; i++) {
        if (token.isIdent("stretch")
            || token.isIdent("repeat")
            || token.isIdent("round"))
            borderImage.sizes.push(token.value);
        else if (!token.isNotNull())
            return borderImage;
        else
            return null;
        token = parser.getToken(true, true);
    }
    if (!token.isNotNull())
        return borderImage;

    return null;
},

// 解析媒体查询
parseMediaQuery: function (aString) {
    var kCONSTRAINTS = {
        "width": true,
        "min-width": true,
        "max-width": true,
        "height": true,
        "min-height": true,
        "max-height": true,
        "device-width": true,
        "min-device-width": true,
        "max-device-width": true,
        "device-height": true,
        "min-device-height": true,
        "max-device-height": true,
        "orientation": true,
        "aspect-ratio": true,
        "min-aspect-ratio": true,
        "max-aspect-ratio": true,
        "device-aspect-ratio": true,
        "min-device-aspect-ratio": true,
        "max-device-aspect-ratio": true,
        "color": true,
        "min-color": true,
        "max-color": true,
        "color-index": true,
        "min-color-index": true,
        "max-color-index": true,
        "monochrome": true,
        "min-monochrome": true,
        "max-monochrome": true,
        "resolution": true,
        "min-resolution": true,
        "max-resolution": true,
        "scan": true,
        "grid": true
    };
    var parser = new CSSParser();
    parser._init();
    parser.mPreserveWS = false;
    parser.mPreserveComments = false;
    parser.mPreservedTokens = [];
    parser.mScanner.init(aString);

    var m = { amplifier: "", medium: "", constraints: [] };
    var token = parser.getToken(true, true);

    if (token.isIdent("all") ||
        token.isIdent("aural") ||
        token.isIdent("braille") ||
        token.isIdent("handheld") ||
        token.isIdent("print") ||
        token.isIdent("projection") ||
        token.isIdent("screen") ||
        token.isIdent("tty") ||
        token.isIdent("tv")) {
        m.medium = token.value;
        token = parser.getToken(true, true);
    }
    else if (token.isIdent("not") || token.isIdent("only")) {
        m.amplifier = token.value;
        token = parser.getToken(true, true);
        if (token.isIdent("all") ||
            token.isIdent("aural") ||
            token.isIdent("braille") ||
            token.isIdent("handheld") ||
            token.isIdent("print") ||
            token.isIdent("projection") ||
            token.isIdent("screen") ||
            token.isIdent("tty") ||
            token.isIdent("tv")) {
            m.medium = token.value;
            token = parser.getToken(true, true);
        }
        else
            return null;
    }

    if (m.medium) {
        if (!token.isNotNull())
            return m;
        if (token.isIdent("and")) {
            token = parser.getToken(true, true);
        }
        else
            return null;
    }

    while (token.isSymbol("(")) {
        token = parser.getToken(true, true);
        if (token.isIdent() && (token.value in kCONSTRAINTS)) {
            var constraint = token.value;
            token = parser.getToken(true, true);
            if (token.isSymbol(":")) {
                token = parser.getToken(true, true);
                var values = [];
                while (!token.isSymbol(")")) {
                    values.push(token.value);
                    token = parser.getToken(true, true);
                }
                if (token.isSymbol(")")) {
                    m.constraints.push({ constraint: constraint, value: values });
                    token = parser.getToken(true, true);
                    if (token.isNotNull()) {
                        if (token.isIdent("and")) {
                            token = parser.getToken(true, true);
                        }
                        else
                            return null;
                    }
                    else
                        return m;
                }
                else
                    return null;
            }
            else if (token.isSymbol(")")) {
                m.constraints.push({ constraint: constraint, value: null });
                token = parser.getToken(true, true);
                if (token.isNotNull()) {
                    if (token.isIdent("and")) {
                        token = parser.getToken(true, true);
                    }
                    else
                        return null;
                }
                else
                    return m;
            }
            else
                return null;
        }
        else
            return null;
    }
    return m;
}

};

// 简单测试 console.log(obj.prefixesForProperty('-moz-example'));

// 解析命名空间规则 parseNamespaceRule: function(aToken, aSheet) { // 获取当前行号,通过 CountLF 函数统计已扫描内容中的换行符数量 var currentLine = CountLF(this.mScanner.getAlreadyScanned()); // 初始化规则字符串,赋值为当前 token 的值 var s = aToken.value; // 标记规则是否有效,初始为 false var valid = false; // 保存当前解析状态 this.preserveState(); // 获取下一个 token var token = this.getToken(true, true); if (token.isNotNull()) { // 初始化前缀为空字符串 var prefix = ""; // 初始化 URL 为空字符串 var url = ""; if (token.isIdent()) { // 如果 token 是标识符,将其赋值给前缀 prefix = token.value; // 将前缀添加到规则字符串中 s += " " + prefix; // 获取下一个 token token = this.getToken(true, true); } if (token) { // 标记是否找到 URL初始为 false var foundURL = false; if (token.isString()) { // 如果 token 是字符串,标记找到 URL foundURL = true; // 将字符串赋值给 URL url = token.value; // 将 URL 添加到规则字符串中 s += " " + url; } else if (token.isFunction("url(")) { // 如果 token 是 url 函数,获取下一个 token token = this.getToken(true, true); // 解析 URL 内容 var urlContent = this.parseURL(token); if (urlContent) { // 如果解析成功,将 url 内容添加到 URL 中 url += "url(" + urlContent; // 标记找到 URL foundURL = true; // 将 url 内容添加到规则字符串中 s += " " + urlContent; } } } if (foundURL) { // 如果找到 URL获取下一个 token token = this.getToken(true, true); if (token.isSymbol(";")) { // 如果 token 是分号,将分号添加到规则字符串中 s += ";"; // 忘记之前保存的状态 this.forgetState(); // 创建一个新的 jscsspNamespaceRule 对象 var rule = new jscsspNamespaceRule(); // 设置规则的当前行号 rule.currentLine = currentLine; // 设置规则的解析后的 CSS 文本 rule.parsedCssText = s; // 设置规则的前缀 rule.prefix = prefix; // 设置规则的 URL rule.url = url; // 设置规则的父样式表 rule.parentStyleSheet = aSheet; // 将规则添加到父样式表的 CSS 规则列表中 aSheet.cssRules.push(rule); // 返回 true 表示规则解析成功 return true; } } } // 恢复之前保存的状态 this.restoreState(); // 将未知的 @namespace 规则添加到样式表中 this.addUnknownAtRule(aSheet, "@namespace"); // 返回 false 表示规则解析失败 return false; },

// 解析字体规则 parseFontFaceRule: function(aToken, aSheet) { // 获取当前行号,通过 CountLF 函数统计已扫描内容中的换行符数量 var currentLine = CountLF(this.mScanner.getAlreadyScanned()); // 初始化规则字符串,赋值为当前 token 的值 var s = aToken.value; // 标记规则是否有效,初始为 false var valid = false; // 初始化描述符数组 var descriptors = []; // 保存当前解析状态 this.preserveState(); // 获取下一个 token var token = this.getToken(true, true); if (token.isNotNull()) { // 期望遇到块开始符号 { if (token.isSymbol("{")) { // 将块开始符号添加到规则字符串中 s += " " + token.value; // 获取下一个 token var token = this.getToken(true, false); while (true) { if (token.isSymbol("}")) { // 如果遇到块结束符号 },将其添加到规则字符串中 s += "}"; // 标记规则有效 valid = true; // 跳出循环 break; } else { // 解析声明 var d = this.parseDeclaration(token, descriptors, false, false, aSheet); // 将声明添加到规则字符串中 s += ((d && descriptors.length) ? " " : "") + d; } // 获取下一个 token token = this.getToken(true, false); } } } if (valid) { // 如果规则有效,忘记之前保存的状态 this.forgetState(); // 创建一个新的 jscsspFontFaceRule 对象 var rule = new jscsspFontFaceRule(); // 设置规则的当前行号 rule.currentLine = currentLine; // 设置规则的解析后的 CSS 文本 rule.parsedCssText = s; // 设置规则的描述符 rule.descriptors = descriptors; // 设置规则的父样式表 rule.parentStyleSheet = aSheet; // 将规则添加到父样式表的 CSS 规则列表中 aSheet.cssRules.push(rule); // 返回 true 表示规则解析成功 return true; } // 恢复之前保存的状态 this.restoreState(); // 返回 false 表示规则解析失败 return false; },

// 解析页面规则 parsePageRule: function(aToken, aSheet) { // 获取当前行号,通过 CountLF 函数统计已扫描内容中的换行符数量 var currentLine = CountLF(this.mScanner.getAlreadyScanned()); // 初始化规则字符串,赋值为当前 token 的值 var s = aToken.value; // 标记规则是否有效,初始为 false var valid = false; // 初始化声明数组 var declarations = []; // 保存当前解析状态 this.preserveState(); // 获取下一个 token var token = this.getToken(true, true); // 初始化页面选择器为空字符串 var pageSelector = ""; if (token.isSymbol(":") || token.isIdent()) { if (token.isSymbol(":")) { // 如果 token 是冒号,将其添加到页面选择器中 pageSelector = ":"; // 获取下一个 token token = this.getToken(false, false); } if (token.isIdent()) { // 如果 token 是标识符,将其添加到页面选择器中 pageSelector += token.value; // 将页面选择器添加到规则字符串中 s += " " + pageSelector; // 获取下一个 token token = this.getToken(true, true); } } if (token.isNotNull()) { // 期望遇到块开始符号 { if (token.isSymbol("{")) { // 将块开始符号添加到规则字符串中 s += " " + token.value; // 获取下一个 token var token = this.getToken(true, false); while (true) { if (token.isSymbol("}")) { // 如果遇到块结束符号 },将其添加到规则字符串中 s += "}"; // 标记规则有效 valid = true; // 跳出循环 break; } else { // 解析声明 var d = this.parseDeclaration(token, declarations, true, true, aSheet); // 将声明添加到规则字符串中 s += ((d && declarations.length) ? " " : "") + d; } // 获取下一个 token token = this.getToken(true, false); } } } if (valid) { // 如果规则有效,忘记之前保存的状态 this.forgetState(); // 创建一个新的 jscsspPageRule 对象 var rule = new jscsspPageRule(); // 设置规则的当前行号 rule.currentLine = currentLine; // 设置规则的解析后的 CSS 文本 rule.parsedCssText = s; // 设置规则的页面选择器 rule.pageSelector = pageSelector; // 设置规则的声明 rule.declarations = declarations; // 设置规则的父样式表 rule.parentStyleSheet = aSheet; // 将规则添加到父样式表的 CSS 规则列表中 aSheet.cssRules.push(rule); // 返回 true 表示规则解析成功 return true; } // 恢复之前保存的状态 this.restoreState(); // 返回 false 表示规则解析失败 return false; },

// 解析默认属性值 parseDefaultPropertyValue: function(token, aDecl, aAcceptPriority, descriptor, aSheet) { // 初始化属性值文本为空字符串 var valueText = ""; // 初始化块栈,用于处理嵌套的块 var blocks = []; // 标记是否找到优先级,初始为 false var foundPriority = false; // 初始化值数组 var values = []; while (token.isNotNull()) { if ((token.isSymbol(";") || token.isSymbol("}") || token.isSymbol("!")) && !blocks.length) { if (token.isSymbol("}")) { // 如果遇到块结束符号 },将其放回扫描器 this.ungetToken(); } // 跳出循环 break; } if (token.isIdent(this.kINHERIT)) { if (values.length) { // 如果值数组不为空,返回空字符串表示解析失败 return ""; } else { // 将 inherit 赋值给属性值文本 valueText = this.kINHERIT; // 创建一个新的 jscsspVariable 对象表示 inherit 值 var value = new jscsspVariable(kJscsspINHERIT_VALUE, aSheet); // 将值添加到值数组中 values.push(value); // 获取下一个 token token = this.getToken(true, true); // 跳出循环 break; } } else if (token.isSymbol("{") || token.isSymbol("(") || token.isSymbol("[")) { // 如果遇到块开始符号,将其添加到块栈中 blocks.push(token.value); } else if (token.isSymbol("}") || token.isSymbol("]")) { if (blocks.length) { // 获取块栈顶元素 var ontop = blocks[blocks.length - 1]; if ((token.isSymbol("}") && ontop == "{") || (token.isSymbol(")") && ontop == "(") || (token.isSymbol("]") && ontop == "[")) { // 如果匹配到对应的块结束符号,将栈顶元素弹出 blocks.pop(); } } } // 处理函数调用 if (token.isFunction()) { if (token.isFunction("var(")) { // 如果是 var 函数,获取下一个 token token = this.getToken(true, true); if (token.isIdent()) { // 如果是标识符,获取变量名 var name = token.value; // 获取下一个 token token = this.getToken(true, true); if (token.isSymbol(")")) { // 如果是右括号,创建一个新的 jscsspVariable 对象表示变量值 var value = new jscsspVariable(kJscsspVARIABLE_VALUE, aSheet); // 将变量名添加到属性值文本中 valueText += "var(" + name + ")"; // 设置变量名 value.name = name; // 将值添加到值数组中 values.push(value); } else { // 解析失败,返回空字符串 return ""; } } else { // 解析失败,返回空字符串 return ""; } } else { // 如果是其他函数,获取函数名 var fn = token.value; // 获取下一个 token token = this.getToken(false, true); // 解析函数参数 var arg = this.parseFunctionArgument(token); if (arg) { // 如果解析成功,将函数名和参数添加到属性值文本中 valueText += fn + arg; // 创建一个新的 jscsspVariable 对象表示函数值 var value = new jscsspVariable(kJscsspPRIMITIVE_VALUE, aSheet); // 设置函数值 value.value = fn + arg; // 将值添加到值数组中 values.push(value); } else { // 解析失败,返回空字符串 return ""; } } } else if (token.isSymbol("#")) { // 如果是 # 符号,解析颜色值 var color = this.parseColor(token); if (color) { // 如果解析成功,将颜色值添加到属性值文本中 valueText += color; // 创建一个新的 jscsspVariable 对象表示颜色值 var value = new jscsspVariable(kJscsspPRIMITIVE_VALUE, aSheet); // 设置颜色值 value.value = color; // 将值添加到值数组中 values.push(value); } else { // 解析失败,返回空字符串 return ""; } } else if (!token.isWhiteSpace() && !token.isSymbol(",")) { // 如果不是空白字符或逗号,创建一个新的 jscsspVariable 对象表示原始值 var value = new jscsspVariable(kJscsspPRIMITIVE_VALUE, aSheet); // 设置原始值 value.value = token.value; // 将值添加到值数组中 values.push(value); // 将原始值添加到属性值文本中 valueText += token.value; } else { // 将空白字符或逗号添加到属性值文本中 valueText += token.value; } // 获取下一个 token token = this.getToken(false, true); } if (values.length && valueText) { // 如果值数组和属性值文本都不为空,忘记之前保存的状态 this.forgetState(); // 创建一个新的 jscsspDeclaration 对象并添加到声明数组中 aDecl.push(this._createJscsspDeclarationFromValuesArray(descriptor, values, valueText)); // 返回属性值文本 return valueText; } // 解析失败,返回空字符串 return ""; },

// 解析边距或内边距简写属性 parseMarginOrPaddingShorthand: function(token, aDecl, aAcceptPriority, aProperty) { // 初始化顶部边距或内边距为 null var top = null; // 初始化底部边距或内边距为 null var bottom = null; // 初始化左边距或内边距为 null var left = null; // 初始化右边距或内边距为 null var right = null; // 初始化值数组 var values = []; while (true) { if (!token.isNotNull()) { // 如果 token 为空,跳出循环 break; } if (token.isSymbol(";") || (aAcceptPriority && token.isSymbol("!")) || token.isSymbol("}")) { if (token.isSymbol("}")) { // 如果遇到块结束符号 },将其放回扫描器 this.ungetToken(); } // 跳出循环 break; } else if (!values.length && token.isIdent(this.kINHERIT)) { // 如果值数组为空且 token 是 inherit将 inherit 添加到值数组中 values.push(token.value); // 获取下一个 token token = this.getToken(true, true); // 跳出循环 break; } else if (token.isDimension() || token.isNumber("0") || token.isPercentage() || token.isIdent("auto")) { // 如果 token 是尺寸、数字 0、百分比或 auto将其添加到值数组中 values.push(token.value); } else { // 解析失败,返回空字符串 return ""; } // 获取下一个 token token = this.getToken(true, true); } // 获取值数组的长度 var count = values.length; switch (count) { case 1: // 如果只有一个值,将其赋值给顶部、底部、左边和右边的边距或内边距 top = values[0]; bottom = top; left = top; right = top; break; case 2: // 如果有两个值,将第一个值赋值给顶部和底部,第二个值赋值给左边和右边 top = values[0]; bottom = top; left = values[1]; right = left; break; case 3: // 如果有三个值,将第一个值赋值给顶部,第二个值赋值给左边和右边,第三个值赋值给底部 top = values[0]; left = values[1]; right = left; bottom = values[2]; break; case 4: // 如果有四个值,分别赋值给顶部、右边、底部和左边 top = values[0]; right = values[1]; bottom = values[2]; left = values[3]; break; default: // 解析失败,返回空字符串 return ""; } // 忘记之前保存的状态 this.forgetState(); // 创建顶部边距或内边距的声明并添加到声明数组中 aDecl.push(this._createJscsspDeclarationFromValue(aProperty + "-top", top)); // 创建右边距或内边距的声明并添加到声明数组中 aDecl.push(this._createJscsspDeclarationFromValue(aProperty + "-right", right)); // 创建底部边距或内边距的声明并添加到声明数组中 aDecl.push(this._createJscsspDeclarationFromValue(aProperty + "-bottom", bottom)); // 创建左边距或内边距的声明并添加到声明数组中 aDecl.push(this._createJscsspDeclarationFromValue(aProperty + "-left", left)); // 返回边距或内边距的值 return top + " " + right + " " + bottom + " " + left; },

// 解析边框颜色简写属性 parseBorderColorShorthand: function(token, aDecl, aAcceptPriority) { // 初始化顶部边框颜色为 null var top = null; // 初始化底部边框颜色为 null var bottom = null; // 初始化左边框颜色为 null var left = null; // 初始化右边框颜色为 null var right = null; // 初始化值数组 var values = []; while (true) { if (!token.isNotNull()) { // 如果 token 为空,跳出循环 break; } if (token.isSymbol(";") || (aAcceptPriority && token.isSymbol("!")) || token.isSymbol("}")) { if (token.isSymbol("}")) { // 如果遇到块结束符号 },将其放回扫描器 this.ungetToken(); } // 跳出循环 break; } else if (!values.length && token.isIdent(this.kINHERIT)) { // 如果值数组为空且 token 是 inherit将 inherit 添加到值数组中 values.push(token.value); // 获取下一个 token token = this.getToken(true, true); // 跳出循环 break; } else { // 解析颜色值 var color = this.parseColor(token); if (color) { // 如果解析成功,将颜色值添加到值数组中 values.push(color); } else { // 解析失败,返回空字符串 return ""; } } // 获取下一个 token token = this.getToken(true, true); } // 获取值数组的长度 var count = values.length; switch (count) { case 1: // 如果只有一个值,将其赋值给顶部、底部、左边和右边的边框颜色 top = values[0]; bottom = top; left = top; right = top; break; case 2: // 如果有两个值,将第一个值赋值给顶部和底部,第二个值赋值给左边和右边 top = values[0]; bottom = top; left = values[1]; right = left; break; case 3: // 如果有三个值,将第一个值赋值给顶部,第二个值赋值给左边和右边,第三个值赋值给底部 top = values[0]; left = values[1]; right = left; bottom = values[2]; break; case 4: // 如果有四个值,分别赋值给顶部、右边、底部和左边 top = values[0]; right = values[1]; bottom = values[2]; left = values[3]; break; default: // 解析失败,返回空字符串 return ""; } // 忘记之前保存的状态 this.forgetState(); // 创建顶部边框颜色的声明并添加到声明数组中 aDecl.push(this._createJscsspDeclarationFromValue("border-top-color", top)); // 创建右边框颜色的声明并添加到声明数组中 aDecl.push(this._createJscsspDeclarationFromValue("border-right-color", right)); // 创建底部边框颜色的声明并添加到声明数组中 aDecl.push(this._createJscsspDeclarationFromValue("border-bottom-color", bottom)); // 创建左边框颜色的声明并添加到声明数组中 aDecl.push(this._createJscsspDeclarationFromValue("border-left-color", left)); // 返回边框颜色的值 return top + " " + right + " " + bottom + " " + left; },

// 解析提示音简写属性 parseCueShorthand: function(token, declarations, aAcceptPriority) { // 初始化提示音开始为空字符串 var before = ""; // 初始化提示音结束为空字符串 var after = ""; // 初始化值数组 var values = []; while (true) { if (!token.isNotNull()) { // 如果 token 为空,跳出循环 break; } if (token.isSymbol(";") || (aAcceptPriority && token.isSymbol("!")) || token.isSymbol("}")) { if (token.isSymbol("}")) { // 如果遇到块结束符号 },将其放回扫描器 this.ungetToken(); } // 跳出循环 break; } else if (!values.length && token.isIdent(this.kINHERIT)) { // 如果值数组为空且 token 是 inherit将 inherit 添加到值数组中 values.push(token.value); } else if (token.isIdent("none")) { // 如果 token 是 none将其添加到值数组中 values.push(token.value); } else if (token.isFunction("url(")) { // 如果 token 是 url 函数,获取下一个 token var token = this.getToken(true, true); // 解析 URL 内容 var urlContent = this.parseURL(token); if (urlContent) { // 如果解析成功,将 url 内容添加到值数组中 values.push("url(" + urlContent); } else { // 解析失败,返回空字符串 return ""; } } else { // 解析失败,返回空字符串 return ""; } // 获取下一个 token token = this.getToken(true, true); } // 获取值数组的长度 var count = values.length; switch (count) { case 1: // 如果只有一个值,将其赋值给提示音开始和结束 before = values[0]; after = before; break; case 2: // 如果有两个值,分别赋值给提示音开始和结束 before = values[0]; after = values[1]; break; default: // 解析失败,返回空字符串 return ""; } // 忘记之前保存的状态 this.forgetState(); // 创建提示音开始的声明并添加到声明数组中 aDecl.push(this._createJscsspDeclarationFromValue("cue-before", before)); // 创建提示音结束的声明并添加到声明数组中 aDecl.push(this._createJscsspDeclarationFromValue("cue-after", after)); // 返回提示音的值 return before + " " + after; },

// 解析暂停时间简写属性 parsePauseShorthand: function(token, declarations, aAcceptPriority) { // 初始化暂停开始时间为空字符串 var before = ""; // 初始化暂停结束时间为空字符串 var after = ""; // 初始化值数组 var values = []; while (true) { if (!token.isNotNull()) { // 如果 token 为空,跳出循环 break; } if (token.isSymbol(";") || (aAcceptPriority && token.isSymbol("!")) || token.isSymbol("}")) { if (token.isSymbol("}")) { // 如果遇到块结束符号 },将其放回扫描器 this.ungetToken(); } // 跳出循环 break; } else if (!values.length && token.isIdent(this.kINHERIT)) { // 如果值数组为空且 token 是 inherit将 inherit 添加到值数组中 values.push(token.value); } else if (token.isDimensionOfUnit("ms") || token.isDimensionOfUnit("s") || token.isPercentage() || token.isNumber("0")) { // 如果 token 是毫秒、秒、百分比或数字 0将其添加到值数组中 values.push(token.value); } else { // 解析失败,返回空字符串 return ""; } // 获取下一个 token token = this.getToken(true, true); } // 获取值数组的长度 var count = values.length; switch (count) { case 1: // 如果只有一个值,将其赋值给暂停开始和结束时间 before = values[0]; after = before; break; case 2: // 如果有两个值,分别赋值给暂停开始和结束时间 before = values[0]; after = values[1]; break; default: // 解析失败,返回空字符串 return ""; } // 忘记之前保存的状态 this.forgetState(); // 创建暂停开始时间的声明并添加到声明数组中 aDecl.push(this._createJscsspDeclarationFromValue("pause-before", before)); // 创建暂停结束时间的声明并添加到声明数组中 aDecl.push(this._createJscsspDeclarationFromValue("pause-after", after)); // 返回暂停时间的值 return before + " " + after; },

// 解析边框宽度简写属性 parseBorderWidthShorthand: function(token, aDecl, aAcceptPriority) { // 初始化顶部边框宽度为 null var top = null; // 初始化底部边框宽度为 null var bottom = null; // 初始化左边框宽度为 null var left = null; // 初始化右边框宽度为 null var right = null; // 初始化值数组 var values = []; while (true) { if (!token.isNotNull()) { // 如果 token 为空,跳出循环 break; } if (token.isSymbol(";") || (aAcceptPriority && token.isSymbol("!")) || token.isSymbol("}")) { if (token.isSymbol("}")) { // 如果遇到块结束符号 },将其放回扫描器 this.ungetToken(); } // 跳出循环 break; } else if (!values.length && token.isIdent(this.kINHERIT)) { // 如果值数组为空且 token 是 inherit将 inherit 添加到值数组中 values.push(token.value); } else if (token.isDimension() || token.isNumber("0") || (token.isIdent() && token.value in this.kBORDER_WIDTH_NAMES)) { // 如果 token 是尺寸、数字 0 或边框宽度名称,将其添加到值数组中 values.push(token.value); } else { // 解析失败,返回空字符串 return ""; } // 获取下一个 token token = this.getToken(true, true); } // 获取值数组的长度 var count = values.length; switch (count) { case 1: // 如果只有一个值,将其赋值给顶部、底部、左边和右边的边框宽度 top = values[0]; bottom = top; left = top; right = top; break; case 2: // 如果有两个值,将第一个值赋值给顶部和底部,第二个值赋值给左边和右边 top = values[0]; bottom = top; left = values[1]; right = left; break; case 3: // 如果有三个值,将第一个值赋值给顶部,第二个值赋值给左边和右边,第三个值赋值给底部 top = values[0]; left = values[1]; right = left; bottom = values[2]; break; case 4: // 如果有四个值,分别赋值给顶部、右边、底部和左边 top = values[0]; right = values[1]; bottom = values[2]; left = values[3]; break; default: // 解析失败,返回空字符串 return ""; } // 忘记之前保存的状态 this.forgetState(); // 创建顶部边框宽度的声明并添加到声明数组中 aDecl.push(this._createJscsspDeclarationFromValue("border-top-width", top)); // 创建右边框宽度的声明并添加到声明数组中 aDecl.push(this._createJscsspDeclarationFromValue("border-right-width", right)); // 创建底部边框宽度的声明并添加到声明数组中 aDecl.push(this._createJscsspDeclarationFromValue("border-bottom-width", bottom)); // 创建左边框宽度的声明并添加到声明数组中 aDecl.push(this._createJscsspDeclarationFromValue("border-left-width", left)); // 返回边框宽度的值 return top + " " + right + " " + bottom + " " + left; },

// 解析边框样式简写属性 parseBorderStyleShorthand: function(token, aDecl, aAcceptPriority) { // 初始化顶部边框样式为 null var top = null; // 初始化底部边框样式为 null var bottom = null; // 初始化左边框样式为 null var left = null; // 初始化右边框样式为 null var right = null; // 初始化值数组 var values = []; while (true) { if (!token.isNotNull()) { // 如果 token 为空,跳出循环 break; } if (token.isSymbol(";") || (aAcceptPriority && token.isSymbol("!")) || token.isSymbol("}")) { if (token.isSymbol("}")) { // 如果遇到块结束符号 },将其放回扫描器 this.ungetToken(); } // 跳出循环 break; } else if (!values.length && token.isIdent(this.kINHERIT)) { // 如果值数组为空且 token 是 inherit将 inherit 添加到值数组中 values.push(token.value); } else if (token.isIdent() && token.value in this.kBORDER_STYLE_NAMES) { // 如果 token 是边框样式名称,将其添加到值数组中 values.push(token.value); } else { // 解析失败,返回空字符串 return ""; } // 获取下一个 token token = this.getToken(true, true); } // 获取值数组的长度 var count = values.length; switch (count) { case 1: // 如果只有一个值,将其赋值给顶部、底部、左边和右边的边框样式 top = values[0]; bottom = top; left = top; right = top; break; case 2: // 如果有两个值,将第一个值赋值给顶部和底部,第二个值赋值给左边和右边 top = values[0]; bottom = top; left = values[1]; right = left; break; case 3: // 如果有三个值,将第一个值赋值给顶部,第二个值赋值给左边和右边,第三个值赋值给底部 top = values[0]; left = values[1]; right = left; bottom = values[2]; break; case 4: // 如果有四个值,分别赋值给顶部、右边、底部和左边 top = values[0]; right = values[1]; bottom = values[2]; left = values[3]; break; default: // 解析失败,返回空字符串 return ""; } // 忘记之前保存的状态 this.forgetState(); // 创建顶部边框样式的声明并添加到声明数组中 aDecl.push(this._createJscsspDeclarationFrom

以下是为你提供的代码注释:

// 解析媒体规则的函数
// aToken: 当前的 token
// aSheet: 当前的样式表
parseMediaRule: function(aToken, aSheet) {
    // 开启媒体查询模式
    this.mScanner.mMediaQueryMode = true;
    // 计算当前行数
    var currentLine = CountLF(this.mScanner.getAlreadyScanned());
    // 获取当前 token 的值
    var s = aToken.value;
    // 标记规则是否有效
    var valid = false;
    // 创建一个新的媒体规则对象
    var mediaRule = new jscsspMediaRule();
    // 设置媒体规则的当前行数
    mediaRule.currentLine = currentLine;
    // 保存当前状态
    this.preserveState();
    // 获取下一个 token
    var token = this.getToken(true, true);
    // 标记是否找到媒体类型
    var foundMedia = false;
    // 循环处理 token
    while (token.isNotNull()) {
        if (token.isIdent()) {
            // 找到媒体类型
            foundMedia = true;
            // 拼接媒体类型到字符串 s 中
            s += " " + token.value;
            // 将媒体类型添加到媒体规则的媒体列表中
            mediaRule.media.push(token.value);
            // 获取下一个 token
            token = this.getToken(true, true);
            if (token.isSymbol(",")) {
                // 如果是逗号,拼接逗号到字符串 s 中
                s += ",";
            } else {
                if (token.isSymbol("{"))
                    // 如果是左花括号,将 token 放回队列
                    this.ungetToken();
                else {
                    // 错误处理,将 token 类型设为 NULL_TYPE
                    token.type = jscsspToken.NULL_TYPE;
                    break;
                }
            }
        }
        else if (token.isSymbol("{"))
            // 如果是左花括号,跳出循环
            break;
        else if (foundMedia) {
            // 如果已经找到媒体类型,但当前 token 不符合要求,将 token 类型设为 NULL_TYPE
            token.type = jscsspToken.NULL_TYPE;
            // 不是有效的媒体列表,跳出循环
            break;
        }
        // 获取下一个 token
        token = this.getToken(true, true);
    }
    if (token.isSymbol("{") && mediaRule.media.length) {
        // 如果是左花括号且媒体列表不为空,开始解析样式规则
        s += " { ";
        // 获取下一个 token
        token = this.getToken(true, false);
        while (token.isNotNull()) {
            if (token.isComment() && this.mPreserveComments) {
                // 如果是注释且需要保留注释,拼接注释到字符串 s 中
                s += " " + token.value;
                // 创建一个新的注释对象
                var comment = new jscsspComment();
                // 设置注释对象的解析后的 CSS 文本
                comment.parsedCssText = token.value;
                // 将注释对象添加到媒体规则的 CSS 规则列表中
                mediaRule.cssRules.push(comment);
            } else if (token.isSymbol("}")) {
                // 如果是右花括号,标记规则有效
                valid = true;
                break;
            } else {
                // 解析样式规则
                var r = this.parseStyleRule(token, mediaRule, true);
                if (r)
                    // 如果解析成功,拼接解析结果到字符串 s 中
                    s += r;
            }
            // 获取下一个 token
            token = this.getToken(true, false);
        }
    }
    if (valid) {
        // 如果规则有效,忘记保存的状态
        this.forgetState();
        // 设置媒体规则的解析后的 CSS 文本
        mediaRule.parsedCssText = s;
        // 将媒体规则添加到样式表的 CSS 规则列表中
        aSheet.cssRules.push(mediaRule);
        return true;
    }
    // 恢复保存的状态
    this.restoreState();
    return false;
},

// 去除字符串首尾空格的函数
// str: 要处理的字符串
trim11: function(str) {
    // 去除字符串开头的空格
    str = str.replace(/^\s+/, '');
    // 从字符串末尾开始遍历
    for (var i = str.length - 1; i >= 0; i--) {
        if (/\S/.test( str.charAt(i) )) { 
            // 如果当前字符不是空格,截取字符串
            str = str.substring(0, i + 1);
            break;
        }
    }
    return str;
},

// 解析样式规则的函数
// aToken: 当前的 token
// aOwner: 规则的所有者
// aIsInsideMediaRule: 是否在媒体规则内部
parseStyleRule: function(aToken, aOwner, aIsInsideMediaRule)
{
    // 计算当前行数
    var currentLine = CountLF(this.mScanner.getAlreadyScanned());
    // 保存当前状态
    this.preserveState();
    // 解析选择器
    var selector = this.parseSelector(aToken, false);
    // 标记规则是否有效
    var valid = false;
    // 声明列表
    var declarations = [];
    if (selector) {
        // 去除选择器首尾空格
        selector = this.trim11(selector.selector);
        // 选择器字符串
        var s = selector;
        // 获取下一个 token
        var token = this.getToken(true, true);
        if (token.isSymbol("{")) {
            // 如果是左花括号,拼接左花括号到字符串 s 中
            s += " { ";
            // 获取下一个 token
            var token = this.getToken(true, false);
            while (true) {
                if (!token.isNotNull()) {
                    // 如果 token 为空,标记规则有效
                    valid = true;
                    break;
                }
                if (token.isSymbol("}")) {
                    // 如果是右花括号,拼接右花括号到字符串 s 中,标记规则有效
                    s += "}";
                    valid = true;
                    break;
                } else {
                    // 解析声明
                    var d = this.parseDeclaration(token, declarations, true, true, aOwner);
                    s += ((d && declarations.length) ? " " : "") + d;
                }
                // 获取下一个 token
                token = this.getToken(true, false);
            }
        }
    }
    else {
        // 选择器无效,整个规则无效
    }

    if (valid) {
        // 如果规则有效,创建一个新的样式规则对象
        var rule = new jscsspStyleRule();
        // 设置样式规则的当前行数
        rule.currentLine = currentLine;
        // 设置样式规则的解析后的 CSS 文本
        rule.parsedCssText = s;
        // 设置样式规则的声明列表
        rule.declarations = declarations;
        // 设置样式规则的选择器文本
        rule.mSelectorText = selector;
        if (aIsInsideMediaRule)
            // 如果在媒体规则内部,设置样式规则的父规则
            rule.parentRule = aOwner;
        else
            // 否则,设置样式规则的父样式表
            rule.parentStyleSheet = aOwner;
        // 将样式规则添加到所有者的 CSS 规则列表中
        aOwner.cssRules.push(rule);
        return s;
    }
    // 恢复保存的状态
    this.restoreState();
    // 获取当前 token 的值
    s = this.currentToken().value;
    // 添加未知的 @ 规则
    this.addUnknownAtRule(aOwner, s);
    return "";
},

// 解析选择器的函数
// aToken: 当前的 token
// aParseSelectorOnly: 是否只解析选择器
parseSelector: function(aToken, aParseSelectorOnly) {
    // 选择器字符串
    var s = "";
    // 选择器的优先级
    var specificity = {a: 0, b: 0, c: 0, d: 0}; 
    // 标记是否是选择器链的第一个元素
    var isFirstInChain = true;
    // 当前 token
    var token = aToken;
    // 标记选择器是否有效
    var valid = false;
    // 标记是否找到组合器
    var combinatorFound = false;
    while (true) {
        if (!token.isNotNull()) {
            if (aParseSelectorOnly)
                // 如果只解析选择器,返回选择器和优先级
                return {selector: s, specificity: specificity };
            return "";
        }

        if (!aParseSelectorOnly && token.isSymbol("{")) {
            // 如果不是只解析选择器且遇到左花括号,结束选择器解析
            valid = !combinatorFound;
            if (valid) this.ungetToken();
            break;
        }

        if (token.isSymbol(",")) { 
            // 如果是逗号,拼接逗号到字符串 s 中
            s += token.value;
            // 标记是选择器链的第一个元素
            isFirstInChain = true;
            // 标记未找到组合器
            combinatorFound = false;
            // 获取下一个 token
            token = this.getToken(false, true);
            continue;
        }
        // 处理组合器和分组
        else if (!combinatorFound
                 && (token.isWhiteSpace()
                      || token.isSymbol(">")
                      || token.isSymbol("+")
                      || token.isSymbol("~"))) {
            if (token.isWhiteSpace()) {
                // 如果是空格,拼接空格到字符串 s 中
                s += " ";
                // 查看下一个 token
                var nextToken = this.lookAhead(true, true);
                if (!nextToken.isNotNull()) {
                    if (aParseSelectorOnly)
                        // 如果只解析选择器,返回选择器和优先级
                        return {selector: s, specificity: specificity };
                    return "";
                }
                if (nextToken.isSymbol(">")
                    || nextToken.isSymbol("+")
                    || nextToken.isSymbol("~")) {
                    // 如果下一个 token 是组合器,获取下一个 token 并拼接
                    token = this.getToken(true, true);
                    s += token.value + " ";
                    // 标记找到组合器
                    combinatorFound = true;
                }
            }
            else {
                // 如果不是空格,拼接组合器到字符串 s 中
                s += token.value;
                // 标记找到组合器
                combinatorFound = true;
            }
            // 标记是选择器链的第一个元素
            isFirstInChain = true;
            // 获取下一个 token
            token = this.getToken(true, true);
            continue;
        }
        else {
            // 解析简单选择器
            var simpleSelector = this.parseSimpleSelector(token, isFirstInChain, true);
            if (!simpleSelector)
                // 如果解析失败,跳出循环
                break; 
            // 拼接简单选择器到字符串 s 中
            s += simpleSelector.selector;
            // 更新选择器的优先级
            specificity.b += simpleSelector.specificity.b;
            specificity.c += simpleSelector.specificity.c;
            specificity.d += simpleSelector.specificity.d;
            // 标记不是选择器链的第一个元素
            isFirstInChain = false;
            // 标记未找到组合器
            combinatorFound = false;
        }

        // 获取下一个 token
        token = this.getToken(false, true);
    }

    if (valid) {
        // 如果选择器有效,返回选择器和优先级
        return {selector: s, specificity: specificity };
    }
    return "";
},

// 判断是否为伪元素的函数
// aIdent: 要判断的标识符
isPseudoElement: function(aIdent)
{
    switch (aIdent) {
        case "first-letter":
        case "first-line":
        case "before":
        case "after":
        case "marker":
            return true;
            break;
        default: return false;
            break;
    }
},

// 解析简单选择器的函数
// token: 当前的 token
// isFirstInChain: 是否是选择器链的第一个元素
// canNegate: 是否可以使用否定伪类
parseSimpleSelector: function(token, isFirstInChain, canNegate)
{
    // 简单选择器字符串
    var s = "";
    // 简单选择器的优先级
    var specificity = {a: 0, b: 0, c: 0, d: 0}; 

    if (isFirstInChain
        && (token.isSymbol("*") || token.isSymbol("|") || token.isIdent())) {
        // 如果是选择器链的第一个元素,处理类型或通用选择器
        if (token.isSymbol("*") || token.isIdent()) {
            // 可能是前缀或通用选择器
            s += token.value;
            // 标记是否为标识符
            var isIdent = token.isIdent();
            // 获取下一个 token
            token = this.getToken(false, true);
            if (token.isSymbol("|")) {
                // 如果是竖线,拼接竖线到字符串 s 中
                s += token.value;
                // 获取下一个 token
                token = this.getToken(false, true);
                if (token.isIdent() || token.isSymbol("*")) {
                    // 如果是标识符或星号,拼接标识符或星号到字符串 s 中
                    s += token.value;
                    if (token.isIdent())
                        // 如果是标识符,更新优先级
                        specificity.d++;
                } else
                    // 错误处理,返回 null
                    return null;
            } else {
                // 将 token 放回队列
                this.ungetToken();
                if (isIdent)
                    // 如果是标识符,更新优先级
                    specificity.d++;
            }
        } else if (token.isSymbol("|")) {
            // 如果是竖线,拼接竖线到字符串 s 中
            s += token.value;
            // 获取下一个 token
            token = this.getToken(false, true);
            if (token.isIdent() || token.isSymbol("*")) {
                // 如果是标识符或星号,拼接标识符或星号到字符串 s 中
                s += token.value;
                if (token.isIdent())
                    // 如果是标识符,更新优先级
                    specificity.d++;
            } else
                // 错误处理,返回 null
                return null;
        }
    }
  
    else if (token.isSymbol(".") || token.isSymbol("#")) {
        // 如果是点号或井号,处理类选择器或 ID 选择器
        var isClass = token.isSymbol(".");
        // 拼接点号或井号到字符串 s 中
        s += token.value;
        // 获取下一个 token
        token = this.getToken(false, true);
        if (token.isIdent()) {
            // 如果是标识符,拼接标识符到字符串 s 中
            s += token.value;
            if (isClass)
                // 如果是类选择器,更新优先级
                specificity.c++;
            else
                // 如果是 ID 选择器,更新优先级
                specificity.b++;
        }
        else
            // 错误处理,返回 null
            return null;
    }

    else if (token.isSymbol(":")) {
        // 如果是冒号,处理伪类或伪元素
        s += token.value;
        // 获取下一个 token
        token = this.getToken(false, true);
        if (token.isSymbol(":")) {
            // 如果是双冒号,拼接双冒号到字符串 s 中
            s += token.value;
            // 获取下一个 token
            token = this.getToken(false, true);
        }
        if (token.isIdent()) {
            // 如果是标识符,拼接标识符到字符串 s 中
            s += token.value;
            if (this.isPseudoElement(token.value))
                // 如果是伪元素,更新优先级
                specificity.d++;
            else
                // 如果是伪类,更新优先级
                specificity.c++;
        }
        else if (token.isFunction()) {
            // 如果是函数,拼接函数到字符串 s 中
            s += token.value;
            if (token.isFunction(":not(")) {
                // 如果是 :not() 函数
                if (!canNegate)
                    // 如果不允许使用否定伪类,返回 null
                    return null;
                // 获取下一个 token
                token = this.getToken(true, true);
                // 解析简单选择器
                var simpleSelector = this.parseSimpleSelector(token, isFirstInChain, false);
                if (!simpleSelector)
                    // 如果解析失败,返回 null
                    return null;
                else {
                    // 拼接简单选择器到字符串 s 中
                    s += simpleSelector.selector;
                    // 获取下一个 token
                    token = this.getToken(true, true);
                    if (token.isSymbol(")"))
                        // 如果是右括号,拼接右括号到字符串 s 中
                        s += ")";
                    else
                        // 错误处理,返回 null
                        return null;
                }
                // 更新优先级
                specificity.c++;
            }
            else {
                while (true) {
                    // 处理函数参数
                    token = this.getToken(false, true);
                    if (token.isSymbol(")")) {
                        // 如果是右括号,拼接右括号到字符串 s 中
                        s += ")";
                        break;
                    } else
                        // 拼接参数到字符串 s 中
                        s += token.value;
                }
                // 更新优先级
                specificity.c++;
            }
        } else
            // 错误处理,返回 null
            return null;
  
    } else if (token.isSymbol("[")) {
        // 如果是左方括号,处理属性选择器
        s += "[";
        // 获取下一个 token
        token = this.getToken(true, true);
        if (token.isIdent() || token.isSymbol("*")) {
            // 如果是标识符或星号,拼接标识符或星号到字符串 s 中
            s += token.value;
            // 获取下一个 token
            var nextToken = this.getToken(true, true);
            if (token.isSymbol("|")) {
                // 如果是竖线,拼接竖线到字符串 s 中
                s += "|";
                // 获取下一个 token
                token = this.getToken(true, true);
                if (token.isIdent())
                    // 如果是标识符,拼接标识符到字符串 s 中
                    s += token.value;
                else
                    // 错误处理,返回 null
                    return null;
            } else
                // 将 token 放回队列
                this.ungetToken();
        } else if (token.isSymbol("|")) {
            // 如果是竖线,拼接竖线到字符串 s 中
            s += "|";
            // 获取下一个 token
            token = this.getToken(true, true);
            if (token.isIdent())
                // 如果是标识符,拼接标识符到字符串 s 中
                s += token.value;
            else
                // 错误处理,返回 null
                return null;
        }
        else
            // 错误处理,返回 null
            return null;
  
        // 处理属性选择器的操作符
        token = this.getToken(true, true);
        if (token.isIncludes()
            || token.isDashmatch()
            || token.isBeginsmatch()
            || token.isEndsmatch()
            || token.isContainsmatch()
            || token.isSymbol("=")) {
            // 如果是操作符,拼接操作符到字符串 s 中
            s += token.value;
            // 获取下一个 token
            token = this.getToken(true, true);
            if (token.isString() || token.isIdent()) {
                // 如果是字符串或标识符,拼接字符串或标识符到字符串 s 中
                s += token.value;
                // 获取下一个 token
                token = this.getToken(true, true);
            }
            else
                // 错误处理,返回 null
                return null;
    
            if (token.isSymbol("]")) {
                // 如果是右方括号,拼接右方括号到字符串 s 中
                s += token.value;
                // 更新优先级
                specificity.c++;
            }
            else
                // 错误处理,返回 null
                return null;
        }
        else if (token.isSymbol("]")) {
            // 如果是右方括号,拼接右方括号到字符串 s 中
            s += token.value;
            // 更新优先级
            specificity.c++;
        }
        else
            // 错误处理,返回 null
            return null;
        
    }
    else if (token.isWhiteSpace()) {
        // 如果是空格,查看下一个 token
        var t = this.lookAhead(true, true);
        if (t.isSymbol('{'))
            // 如果下一个 token 是左花括号,返回空字符串
            return ""
    }
    if (s)
        // 如果简单选择器字符串不为空,返回简单选择器和优先级
        return {selector: s, specificity: specificity };
    return null;
},

// 保存当前状态的函数
preserveState: function() {
    // 将当前 token 保存到保存的 token 列表中
    this.mPreservedTokens.push(this.currentToken());
    // 保存扫描器的状态
    this.mScanner.preserveState();
},

// 恢复保存状态的函数
restoreState: function() {
    if (this.mPreservedTokens.length) {
        // 如果保存的 token 列表不为空,恢复扫描器的状态
        this.mScanner.restoreState();
        // 从保存的 token 列表中取出最后一个 token
        this.mToken = this.mPreservedTokens.pop();
    }
},

// 忘记保存状态的函数
forgetState: function() {
    if (this.mPreservedTokens.length) {
        // 如果保存的 token 列表不为空,忘记扫描器的状态
        this.mScanner.forgetState();
        // 从保存的 token 列表中取出最后一个 token
        this.mPreservedTokens.pop();
    }
},

// 解析 CSS 字符串的函数
// aString: 要解析的 CSS 字符串
// aTryToPreserveWhitespaces: 是否尝试保留空格
// aTryToPreserveComments: 是否尝试保留注释
parse: function(aString, aTryToPreserveWhitespaces, aTryToPreserveComments) {
    if (!aString)
        // 如果字符串为空,返回 null
        return null; 

    // 设置是否保留空格
    this.mPreserveWS       = aTryToPreserveWhitespaces;
    // 设置是否保留注释
    this.mPreserveComments = aTryToPreserveComments;
    // 初始化保存的 token 列表
    this.mPreservedTokens = [];
    // 初始化扫描器
    this.mScanner.init(aString);
    // 创建一个新的样式表对象
    var sheet = new jscsspStylesheet();

    // @charset 规则只能出现在样式表的开头
    var token = this.getToken(false, false);
    if (!token.isNotNull())
        return;
    if (token.isAtRule("@charset")) {
        // 解析 @charset 规则
        this.parseCharsetRule(token, sheet);
        // 获取下一个 token
        token = this.getToken(false, false);
    }

    // 标记是否找到样式规则
    var foundStyleRules = false;
    // 标记是否找到 @import 规则
    var foundImportRules = false;
    // 标记是否找到 @namespace 规则
    var foundNameSpaceRules = false;
    while (true) {
        if (!token.isNotNull())
            // 如果 token 为空,跳出循环
            break;
        if (token.isWhiteSpace())
        {
            if (aTryToPreserveWhitespaces)
                // 如果需要保留空格,添加空格到样式表中
                this.addWhitespace(sheet, token.value);
        }

        else if (token.isComment())
        {
            if (this.mPreserveComments)
                // 如果需要保留注释,添加注释到样式表中
                this.addComment(sheet, token.value);
        }

        else if (token.isAtRule()) {
            if (token.isAtRule("@variables")) {
                // 如果是 @variables 规则
                if (!foundImportRules && !foundStyleRules)
                    // 如果还没有找到 @import 规则和样式规则,解析 @variables 规则
                    this.parseVariablesRule(token, sheet);
                else {
                    // 错误处理,报告错误并添加未知的 @ 规则
                    this.reportError(kVARIABLES_RULE_POSITION);
                    this.addUnknownAtRule(sheet, token.value);
                }
            }
            else if (token.isAtRule("@import")) {
                // 如果是 @import 规则
                // @import 规则必须出现在所有样式规则和 @namespace 规则之前
                if (!foundStyleRules && !foundNameSpaceRules)
                    // 如果还没有找到样式规则和 @namespace 规则,解析 @import 规则
                    foundImportRules = this.parseImportRule(token, sheet);
                else {
                    // 错误处理,报告错误并添加未知的 @ 规则
                    this.reportError(kIMPORT_RULE_POSITION);
                    this.addUnknownAtRule(sheet, token.value);
                }
            }
            else if (token.isAtRule("@namespace")) {
                // 如果是 @namespace 规则
                // @namespace 规则必须出现在所有样式规则之后,所有 @import 规则之前
                if (!foundStyleRules)
                    // 如果还没有找到样式规则,解析 @namespace 规则
                    foundNameSpaceRules = this.parseNamespaceRule(token, sheet);
                else {
                    // 错误处理,报告错误并添加未知的 @ 规则
                    this.reportError(kNAMESPACE_RULE_POSITION);
                    this.addUnknownAtRule(sheet, token.value);
                }
            }
            else if (token.isAtRule("@font-face")) {
                // 如果是 @font-face 规则
                if (this.parseFontFaceRule(token, sheet))
                    // 如果解析成功,标记找到样式规则
                    foundStyleRules = true;
                else
                    // 解析失败,添加未知的 @ 规则
                    this.addUnknownAtRule(sheet, token.value);
            }
            else if (token.isAtRule("@page")) {
                // 如果是 @page 规则
                if (this.parsePageRule(token, sheet))
                    // 如果解析成功,标记找到样式规则
                    foundStyleRules = true;
                else
                    // 解析失败,添加未知的 @ 规则
                    this.addUnknownAtRule(sheet, token.value);
            }
            else if (token.isAtRule("@media")) {
                // 如果是 @media 规则
                if (this.parseMediaRule(token, sheet))
                    // 如果解析成功,标记找到样式规则
                    foundStyleRules = true;
                else
                    // 解析失败,添加未知的 @ 规则
                    this.addUnknownAtRule(sheet, token.value);
            }
            else if (token.isAtRule("@keyframes")) {
                // 如果是 @keyframes 规则
                if (!this.parseKeyframesRule(token, sheet))
                    // 如果解析失败,添加未知的 @ 规则
                    this.addUnknownAtRule(sheet, token.value);
            }
            else if (token.isAtRule("@charset")) {
                // 如果是 @charset 规则出现在非开头位置,报告错误并添加未知的 @ 规则
                this.reportError(kCHARSET_RULE_CHARSET_SOF);
                this.addUnknownAtRule(sheet, token.value);
            }
            else {
                // 未知的 @ 规则,报告错误并添加未知的 @ 规则
                this.reportError(kUNKNOWN_AT_RULE);
                this.addUnknownAtRule(sheet, token.value);
            }
        }

        else // 普通样式规则
        {
            // 解析样式规则
            var ruleText = this.parseStyleRule(token, sheet, false);
            if (ruleText)
                // 如果解析成功,标记找到样式规则
                foundStyleRules = true;
        }
        // 获取下一个 token
        token = this.getToken(false);
    }

    return sheet;
}

};

// jscsspToken 构造函数
// aType: token 的类型
// aValue: token 的值
// aUnit: token 的单位
function jscsspToken(aType, aValue, aUnit)
{
    // 设置 token 的类型
    this.type = aType;
    // 设置 token 的值
    this.value = aValue;
    // 设置 token 的单位
    this.unit = aUnit;
}

// 定义 token 的类型
jscsspToken.NULL_TYPE = 0;

jscsspToken.WHITESPACE_TYPE = 1;
jscsspToken.STRING_TYPE = 2;
jscsspToken.COMMENT_TYPE = 3;
jscsspToken.NUMBER_TYPE = 4;
jscsspToken.IDENT_TYPE = 5;
jscsspToken.FUNCTION_TYPE = 6;
jscsspToken.ATRULE_TYPE = 7;
jscsspToken.INCLUDES_TYPE = 8;
jscsspToken.DASHMATCH_TYPE = 9;
jscsspToken.BEGINSMATCH_TYPE = 10;
jscsspToken.ENDSMATCH_TYPE = 11;
jscsspToken.CONTAINSMATCH_TYPE = 12;
jscsspToken.SYMBOL_TYPE = 13;
jscsspToken.DIMENSION_TYPE = 14;
jscsspToken.PERCENTAGE_TYPE = 15;
jscsspToken.HEX_TYPE = 16;

// jscsspToken 原型对象
jscsspToken.prototype = {

    // 判断 token 是否不为空的函数
    isNotNull: function ()
    {
        return this.type;
    },

    // 判断 token 是否为指定类型和值的函数
    _isOfType: function (aType, aValue)
    {
        return (this.type == aType && (!aValue || this.value.toLowerCase() == aValue));
    },

    // 判断 token 是否为空格的函数
    isWhiteSpace: function(w)
    {
        return this._isOfType(jscsspToken.WHITESPACE_TYPE, w);
    },

    // 判断 token 是否为字符串的函数
    isString: function()
    {
        return this._isOfType(jscsspToken.STRING_TYPE);
    },

    // 判断 token 是否为注释的函数
    isComment: function()
    {
        return this._isOfType(jscsspToken.COMMENT_TYPE);
    },

    // 判断 token 是否为数字的函数
    isNumber: function(n)
    {
        return this._isOfType(jscsspToken.NUMBER_TYPE, n);
    },

    // 判断 token 是否为符号的函数
    isSymbol: function(c)
    {
        return this._isOfType(jscsspToken.SYMBOL_TYPE, c);
    },

    // 判断 token 是否为标识符的函数
    isIdent: function(i)
    {
        return this._isOfType(jscsspToken.IDENT_TYPE, i);
    },

    // 判断 token 是否为函数的函数
    isFunction: function(f)
    {
        return this._isOfType(jscsspToken.FUNCTION_TYPE, f);
    },

    // 判断 token 是否为 @ 规则的函数
    isAtRule: function(a)
    {
        return this._isOfType(jscsspToken.ATRULE_TYPE, a);
    },

    // 判断 token 是否为包含操作符的函数
    isIncludes: function()
    {
        return this._isOfType(jscsspToken.INCLUDES_TYPE);
    },

    // 判断 token 是否为连字符匹配操作符的函数
    isDashmatch: function()
    {
        return this._isOfType(jscsspToken.DASHMATCH_TYPE);
    },

    // 判断 token 是否为开头匹配操作符的函数
    isBeginsmatch: function()
    {
        return this._isOfType(jscsspToken.BEGINSMATCH_TYPE);
    },

    // 判断 token 是否为结尾匹配操作符的函数
    isEndsmatch: function()
    {
        return this._isOfType(jscsspToken.ENDSMATCH_TYPE);
    },

    // 判断 token 是否为包含匹配操作符的函数
    isContainsmatch: function()
    {
        return this._isOfType(jscsspToken.CONTAINSMATCH_TYPE);
    },

    // 判断 token 是否为符号的函数
    isSymbol: function(c)
    {
        return this._isOfType(jscsspToken.SYMBOL_TYPE, c);
    },

    // 判断 token 是否为维度的函数
    isDimension: function()
    {
        return this._isOfType(jscsspToken.DIMENSION_TYPE);
    },

    // 判断 token 是否为百分比的函数
    isPercentage: function()
    {
        return this._isOfType(jscsspToken.PERCENTAGE_TYPE);
    },

    // 判断 token 是否为十六进制的函数
    isHex: function()
    {
        return this._isOfType(jscsspToken.HEX_TYPE);
    },

    // 判断 token 是否为指定单位的维度的函数
    isDimensionOfUnit: function(aUnit)
    {
        return (this.isDimension() && this.unit == aUnit);
    },

    // 判断 token 是否为长度的函数
    isLength: function()
    {
        return (this.isPercentage() ||
                this.isDimensionOfUnit("cm") ||
                this.isDimensionOfUnit("mm") ||
                this.isDimensionOfUnit("in") ||
                this.isDimensionOfUnit("pc") ||
                this.isDimensionOfUnit("px") ||
                this.isDimensionOfUnit("em") ||
                this.isDimensionOfUnit("ex") ||
                this.isDimensionOfUnit("pt"));
    },

    // 判断 token 是否为角度的函数
    isAngle: function()
    {
        return (this.isDimensionOfUnit("deg") ||
                this.isDimensionOfUnit("rad") ||
                this.isDimensionOfUnit("grad"));
    }
}

// 定义规则类型常量
var kJscsspUNKNOWN_RULE   = 0;
var kJscsspSTYLE_RULE     = 1
var kJscsspCHARSET_RULE   = 2;
var kJscsspIMPORT_RULE    = 3;
var kJscsspMEDIA_RULE     = 4;
var kJscsspFONT_FACE_RULE = 5;
var kJscsspPAGE_RULE      = 6;

var kJscsspKEYFRAMES_RULE = 7;
var kJscsspKEYFRAME_RULE  = 8;

var kJscsspNAMESPACE_RULE = 100;
var kJscsspCOMMENT        = 101;
var kJscsspWHITE_SPACE