Bug 1107378 part 1: Create a JS-implemented "CSS Unprefixing Service" that can convert certain -webkit prefixed CSS to an unprefixed form. r=dbaron

This commit is contained in:
Daniel Holbert 2015-02-26 12:07:05 -08:00
parent 48489c507b
commit a7d0fb5935
7 changed files with 224 additions and 0 deletions

View File

@ -537,6 +537,8 @@
@BINPATH@/components/formautofill.manifest
@BINPATH@/components/FormAutofillContentService.js
@BINPATH@/components/FormAutofillStartup.js
@BINPATH@/components/CSSUnprefixingService.js
@BINPATH@/components/CSSUnprefixingService.manifest
@BINPATH@/components/contentAreaDropListener.manifest
@BINPATH@/components/contentAreaDropListener.js
@BINPATH@/components/messageWakeupService.js

View File

@ -476,6 +476,8 @@
@RESPATH@/components/formautofill.manifest
@RESPATH@/components/FormAutofillContentService.js
@RESPATH@/components/FormAutofillStartup.js
@RESPATH@/components/CSSUnprefixingService.js
@RESPATH@/components/CSSUnprefixingService.manifest
@RESPATH@/components/contentAreaDropListener.manifest
@RESPATH@/components/contentAreaDropListener.js
@RESPATH@/browser/components/BrowserProfileMigrators.manifest

View File

@ -0,0 +1,157 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- /
/* vim: set shiftwidth=2 tabstop=8 autoindent cindent expandtab: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* Implementation of a service that converts certain vendor-prefixed CSS
properties to their unprefixed equivalents, for sites on a whitelist. */
// XXXdholbert whitelist is coming in bug 1132743
"use strict";
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
function CSSUnprefixingService() {
}
CSSUnprefixingService.prototype = {
// Boilerplate:
classID: Components.ID("{f0729490-e15c-4a2f-a3fb-99e1cc946b42}"),
_xpcom_factory: XPCOMUtils.generateSingletonFactory(CSSUnprefixingService),
QueryInterface: XPCOMUtils.generateQI([Ci.nsICSSUnprefixingService]),
// See documentation in nsICSSUnprefixingService.idl
generateUnprefixedDeclaration: function(aPropName, aRightHalfOfDecl,
aUnprefixedDecl /*out*/) {
// Convert our input strings to lower-case, for easier string-matching.
// (NOTE: If we ever need to add support for unprefixing properties that
// have case-sensitive parts, then we should do these toLowerCase()
// conversions in a more targeted way, to avoid breaking those properties.)
aPropName = aPropName.toLowerCase();
aRightHalfOfDecl = aRightHalfOfDecl.toLowerCase();
// We have several groups of supported properties:
// FIRST GROUP: Properties that can just be handled as aliases:
// ============================================================
const propertiesThatAreJustAliases = {
"-webkit-background-size": "background-size",
"-webkit-box-flex": "flex-grow",
"-webkit-box-ordinal-group": "order",
"-webkit-box-sizing": "box-sizing",
"-webkit-transform": "transform",
};
let unprefixedPropName = propertiesThatAreJustAliases[aPropName];
if (unprefixedPropName !== undefined) {
aUnprefixedDecl.value = unprefixedPropName + ":" + aRightHalfOfDecl;
return true;
}
// SECOND GROUP: Properties that take a single keyword, where the
// unprefixed version takes a different (but analogous) set of keywords:
// =====================================================================
const propertiesThatNeedKeywordMapping = {
"-webkit-box-align" : {
unprefixedPropName : "align-items",
valueMap : {
"start" : "flex-start",
"center" : "center",
"end" : "flex-end",
"baseline" : "baseline",
"stretch" : "stretch"
}
},
"-webkit-box-orient" : {
unprefixedPropName : "flex-direction",
valueMap : {
"horizontal" : "row",
"inline-axis" : "row",
"vertical" : "column",
"block-axis" : "column"
}
},
"-webkit-box-pack" : {
unprefixedPropName : "justify-content",
valueMap : {
"start" : "flex-start",
"center" : "center",
"end" : "flex-end",
"justify" : "space-between"
}
},
};
let propInfo = propertiesThatNeedKeywordMapping[aPropName];
if (typeof(propInfo) != "undefined") {
// Regexp for parsing the right half of a declaration, for keyword-valued
// properties. Divides the right half of the declaration into:
// 1) any leading whitespace
// 2) the property value (one or more alphabetical character or hyphen)
// 3) anything after that (e.g. "!important", ";")
// Then we can look up the appropriate unprefixed-property value for the
// value (part 2), and splice that together with the other parts and with
// the unprefixed property-name to make the final declaration.
const keywordValuedPropertyRegexp = /^(\s*)([a-z\-]+)(.*)/;
let parts = keywordValuedPropertyRegexp.exec(aRightHalfOfDecl);
if (!parts) {
// Failed to parse a keyword out of aRightHalfOfDecl. (It probably has
// no alphabetical characters.)
return false;
}
let mappedKeyword = propInfo.valueMap[parts[2]];
if (mappedKeyword === undefined) {
// We found a keyword in aRightHalfOfDecl, but we don't have a mapping
// to an equivalent keyword for the unprefixed version of the property.
return false;
}
aUnprefixedDecl.value = propInfo.unprefixedPropName + ":" +
parts[1] + // any leading whitespace
mappedKeyword +
parts[3]; // any trailing text (e.g. !important, semicolon, etc)
return true;
}
// THIRD GROUP: Properties that may need arbitrary string-replacement:
// ===================================================================
const propertiesThatNeedStringReplacement = {
// "-webkit-transition" takes a multi-part value. If "-webkit-transform"
// appears as part of that value, replace it w/ "transform".
// And regardless, we unprefix the "-webkit-transition" property-name.
// (We could handle other prefixed properties in addition to 'transform'
// here, but in practice "-webkit-transform" is the main one that's
// likely to be transitioned & that we're concerned about supporting.)
"-webkit-transition": {
unprefixedPropName : "transition",
stringMap : {
"-webkit-transform" : "transform",
}
},
};
propInfo = propertiesThatNeedStringReplacement[aPropName];
if (typeof(propInfo) != "undefined") {
let newRightHalf = aRightHalfOfDecl;
for (let strToReplace in propInfo.stringMap) {
let replacement = propInfo.stringMap[strToReplace];
newRightHalf = newRightHalf.replace(strToReplace, replacement, "g");
}
aUnprefixedDecl.value = propInfo.unprefixedPropName + ":" + newRightHalf;
return true;
}
// No known mapping for property aPropName.
return false;
},
};
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([CSSUnprefixingService]);

View File

@ -0,0 +1,2 @@
component {f0729490-e15c-4a2f-a3fb-99e1cc946b42} CSSUnprefixingService.js
contract @mozilla.org/css-unprefixing-service;1 {f0729490-e15c-4a2f-a3fb-99e1cc946b42}

View File

@ -7,6 +7,12 @@
DIRS += ['xbl-marquee']
TEST_DIRS += ['test']
XPIDL_SOURCES += [
'nsICSSUnprefixingService.idl',
]
XPIDL_MODULE = 'layout_base'
EXPORTS += [
'AnimationCommon.h',
'CounterStyleManager.h',
@ -147,6 +153,11 @@ SOURCES += [
'nsCSSRuleProcessor.cpp',
]
EXTRA_COMPONENTS += [
'CSSUnprefixingService.js',
'CSSUnprefixingService.manifest',
]
FAIL_ON_WARNINGS = True
MSVC_ENABLE_PGO = True

View File

@ -0,0 +1,48 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* interface for a service that converts certain vendor-prefixed CSS properties
to their unprefixed equivalents */
#include "nsISupports.idl"
[scriptable, uuid(927a5c60-0378-4bcb-a50d-99e6d1fe6063)]
interface nsICSSUnprefixingService : nsISupports
{
/**
* This function helps to convert unsupported vendor-prefixed CSS into
* supported unprefixed CSS. Given a vendor-prefixed property name and a
* value (or e.g. value + trailing junk like " !important;}"), this function
* will attempt to produce an equivalent CSS declaration that uses a
* supported unprefixed CSS property.
*
* @param aPropName
* The vendor-prefixed property name.
*
* @param aRightHalfOfDecl
* Everything after the ":" in the CSS declaration. This includes
* the property's value, along with possibly some leading whitespace
* and trailing text like "!important", and possibly a ';' and/or
* '}' (along with any other bogus text the author happens to
* include before those, which will probably make the decl invalid).
*
* @param aUnprefixedDecl[out]
* The resulting unprefixed declaration, if we return true.
*
* @return true if we were able to unprefix -- i.e. if we were able to
* convert the property to a known unprefixed equivalent, and we also
* performed any known-to-be-necessary fixup on the value, and we put
* the result in aUnprefixedDecl.
* Otherwise, this function returns false.
*/
boolean generateUnprefixedDeclaration(in AString aPropName,
in AString aRightHalfOfDecl,
out AString aUnprefixedDecl);
};
%{C++
#define NS_CSSUNPREFIXINGSERVICE_CONTRACTID \
"@mozilla.org/css-unprefixing-service;1"
%}

View File

@ -391,6 +391,8 @@
@BINPATH@/components/formautofill.manifest
@BINPATH@/components/FormAutofillContentService.js
@BINPATH@/components/FormAutofillStartup.js
@BINPATH@/components/CSSUnprefixingService.js
@BINPATH@/components/CSSUnprefixingService.manifest
@BINPATH@/components/contentAreaDropListener.manifest
@BINPATH@/components/contentAreaDropListener.js
@BINPATH@/components/messageWakeupService.js