Diff
Modified: trunk/LayoutTests/ChangeLog (115486 => 115487)
--- trunk/LayoutTests/ChangeLog 2012-04-27 20:29:31 UTC (rev 115486)
+++ trunk/LayoutTests/ChangeLog 2012-04-27 20:30:40 UTC (rev 115487)
@@ -1,3 +1,17 @@
+2012-04-27 Alexandru Chiculita <[email protected]>
+
+ [CSS Shaders] Implement CSS Animations and Transitions for CSS Shaders
+ https://bugs.webkit.org/show_bug.cgi?id=71406
+
+ Reviewed by Dean Jackson.
+
+ * animations/resources/animation-test-helpers.js: Added a check for the "custom" function and used the parser in custom-filter-parser.js instead.
+ (getFilterParameters):
+ (filterParametersMatch):
+ * css3/filters/custom/custom-filter-animation-expected.txt: Added.
+ * css3/filters/custom/custom-filter-animation.html: Added.
+ * css3/filters/resources/custom-filter-parser.js: Added a simple parser for the "custom" function, so that multiple types can be checked correctly.
+
2012-04-26 Sam Weinig <[email protected]>
Add support for the Blob constructor
Modified: trunk/LayoutTests/animations/resources/animation-test-helpers.js (115486 => 115487)
--- trunk/LayoutTests/animations/resources/animation-test-helpers.js 2012-04-27 20:29:31 UTC (rev 115486)
+++ trunk/LayoutTests/animations/resources/animation-test-helpers.js 2012-04-27 20:30:40 UTC (rev 115487)
@@ -62,7 +62,15 @@
// Return an array of numeric filter params in 0-1.
function getFilterParameters(s)
{
- var filterParams = s.match(/\((.+)\)/)[1];
+ var filterResult = s.match(/(\w+)\((.+)\)/);
+ if (!filterResult)
+ throw new Error("There's no filter in \"" + s + "\"");
+ var filterParams = filterResult[2];
+ if (filterResult[1] == "custom") {
+ if (!window.getCustomFilterParameters)
+ throw new Error("getCustomFilterParameters not found. Did you include custom-filter-parser.js?");
+ return getCustomFilterParameters(filterParams);
+ }
var paramList = filterParams.split(' '); // FIXME: the spec may allow comma separation at some point.
// Normalize percentage values.
@@ -80,9 +88,29 @@
{
if (paramList1.length != paramList2.length)
return false;
-
for (var i = 0; i < paramList1.length; ++i) {
- var match = isCloseEnough(paramList1[i], paramList2[i], tolerance);
+ var param1 = paramList1[i],
+ param2 = paramList2[i];
+ if (typeof param1 == "object") {
+ // This is a custom filter parameter.
+ if (param1.type != "parameter") {
+ // Checking for shader uris and other keywords. They need to be exactly the same.
+ if (param1.type != param2.type
+ || param1.value != param2.value)
+ return false;
+ continue;
+ }
+ if (param1.name != param2.name
+ || param1.value.length != param2.value.length)
+ return false;
+ // For now we only support floats.
+ for (var j = 0; j < param1.value.length; ++j) {
+ if (!isCloseEnough(param1.value[j].value, param2.value[j].value, tolerance))
+ return false;
+ }
+ continue;
+ }
+ var match = isCloseEnough(param1, param2, tolerance);
if (!match)
return false;
}
Added: trunk/LayoutTests/css3/filters/custom/custom-filter-animation-expected.txt (0 => 115487)
--- trunk/LayoutTests/css3/filters/custom/custom-filter-animation-expected.txt (rev 0)
+++ trunk/LayoutTests/css3/filters/custom/custom-filter-animation-expected.txt 2012-04-27 20:30:40 UTC (rev 115487)
@@ -0,0 +1,11 @@
+
+PASS - "webkitFilter" property for "custom-from-none-box" element at 1s saw something close to: custom(url(vertex-rotate.vs) none, 1 1 filter-box, rotateBy 30, offset 0)
+PASS - "webkitFilter" property for "custom-to-none-box" element at 1s saw something close to: custom(url(vertex-rotate.vs) none, 1 1 filter-box, rotateBy 30, offset 0)
+PASS - "webkitFilter" property for "custom-from-no-params-box" element at 1s saw something close to: custom(url(vertex-rotate.vs) none, 1 1 filter-box, rotateBy 30, offset 0)
+PASS - "webkitFilter" property for "custom-to-no-params-box" element at 1s saw something close to: custom(url(vertex-rotate.vs) none, 1 1 filter-box, rotateBy 30, offset 0)
+PASS - "webkitFilter" property for "custom-mix-attributes-box" element at 1s saw something close to: custom(url(vertex-rotate.vs) none, 5 5 border-box, rotateBy 30, offset 0)
+PASS - "webkitFilter" property for "custom-from-diff-params-box" element at 1s saw something close to: custom(url(vertex-rotate.vs) none, 1 1 filter-box, param 10, rotateBy 60, offset 10, another_param 5)
+PASS - "webkitFilter" property for "custom-to-diff-params-box" element at 1s saw something close to: custom(url(vertex-rotate.vs) none, 1 1 filter-box, param 10, rotateBy 60, offset 10, another_param 5)
+PASS - "webkitFilter" property for "custom-mix-params-box" element at 1s saw something close to: custom(url(vertex-rotate.vs) none, 1 1 filter-box, param 10, another_param 5, first_param 6, rotateBy 60, offset 10, last_param 4)
+PASS - "webkitFilter" property for "custom-mix-numbers-box" element at 1s saw something close to: custom(url(vertex-rotate.vs) none, 1 1 filter-box, rotateBy 45, a 5.5, b 11 16.5, c 22 27.5 33, d 38.5 44 49.5)
+
Added: trunk/LayoutTests/css3/filters/custom/custom-filter-animation.html (0 => 115487)
--- trunk/LayoutTests/css3/filters/custom/custom-filter-animation.html (rev 0)
+++ trunk/LayoutTests/css3/filters/custom/custom-filter-animation.html 2012-04-27 20:30:40 UTC (rev 115487)
@@ -0,0 +1,139 @@
+<!DOCTYPE html>
+
+<html>
+<head>
+ <script>
+ if (window.layoutTestController) {
+ window.layoutTestController.overridePreference("WebKitCSSCustomFilterEnabled", "1");
+ window.layoutTestController.overridePreference("WebKitWebGLEnabled", "1");
+ }
+ </script>
+ <style>
+ .box {
+ height: 100px;
+ width: 100px;
+ margin: 10px;
+ background-color: blue;
+ display: inline-block;
+ }
+
+ #custom-from-none-box {
+ -webkit-animation: custom-from-none-anim 2s linear;
+ }
+
+ #custom-to-none-box {
+ -webkit-animation: custom-to-none-anim 2s linear;
+ }
+
+ #custom-from-no-params-box {
+ -webkit-animation: custom-from-no-params-anim 2s linear;
+ }
+
+ #custom-to-no-params-box {
+ -webkit-animation: custom-to-no-params-anim 2s linear;
+ }
+
+ #custom-mix-attributes-box {
+ -webkit-animation: custom-mix-attributes-anim 2s linear;
+ }
+
+ #custom-from-diff-params-box {
+ -webkit-animation: custom-from-diff-params-anim 2s linear;
+ }
+
+ #custom-to-diff-params-box {
+ -webkit-animation: custom-to-diff-params-anim 2s linear;
+ }
+
+ #custom-mix-params-box {
+ -webkit-animation: custom-mix-params-anim 2s linear;
+ }
+
+ #custom-mix-numbers-box {
+ -webkit-animation: custom-mix-numbers-anim 2s linear;
+ }
+
+ @-webkit-keyframes custom-from-none-anim {
+ from { -webkit-filter: none; }
+ to { -webkit-filter: custom(url(../resources/vertex-rotate.vs), rotateBy 30, offset 0); }
+ }
+
+ @-webkit-keyframes custom-to-none-anim {
+ from { -webkit-filter: custom(url(../resources/vertex-rotate.vs), rotateBy 30, offset 0); }
+ to { -webkit-filter: none; }
+ }
+
+ @-webkit-keyframes custom-from-no-params-anim {
+ from { -webkit-filter: custom(url(../resources/vertex-rotate.vs)); }
+ to { -webkit-filter: custom(url(../resources/vertex-rotate.vs), rotateBy 30, offset 0); }
+ }
+
+ @-webkit-keyframes custom-to-no-params-anim {
+ from { -webkit-filter: custom(url(../resources/vertex-rotate.vs), rotateBy 30, offset 0); }
+ to { -webkit-filter: custom(url(../resources/vertex-rotate.vs)); }
+ }
+
+ @-webkit-keyframes custom-mix-attributes-anim {
+ from { -webkit-filter: custom(url(../resources/vertex-offset.vs), rotateBy_a 30, offset_a 0); }
+ to { -webkit-filter: custom(url(../resources/vertex-rotate.vs), 5 5 border-box, rotateBy 30, offset 0); }
+ }
+
+ @-webkit-keyframes custom-from-diff-params-anim {
+ from { -webkit-filter: custom(url(../resources/vertex-rotate.vs), param 10, rotateBy 30, offset 0, another_param 5); }
+ to { -webkit-filter: custom(url(../resources/vertex-rotate.vs), rotateBy 90, offset 20); }
+ }
+
+ @-webkit-keyframes custom-to-diff-params-anim {
+ from { -webkit-filter: custom(url(../resources/vertex-rotate.vs), rotateBy 90, offset 20); }
+ to { -webkit-filter: custom(url(../resources/vertex-rotate.vs), param 10, rotateBy 30, offset 0, another_param 5); }
+ }
+
+ @-webkit-keyframes custom-mix-params-anim {
+ from { -webkit-filter: custom(url(../resources/vertex-rotate.vs), first_param 6, rotateBy 90, offset 20, last_param 4); }
+ to { -webkit-filter: custom(url(../resources/vertex-rotate.vs), param 10, rotateBy 30, offset 0, another_param 5); }
+ }
+
+ @-webkit-keyframes custom-mix-numbers-anim {
+ from { -webkit-filter: custom(url(../resources/vertex-rotate.vs), rotateBy 0, a 1, b 2 3, c 4 5 6, d 7 8 9); }
+ to { -webkit-filter: custom(url(../resources/vertex-rotate.vs), rotateBy 90, a 10, b 20 30, c 40 50 60, d 70 80 90); }
+ }
+ </style>
+ <script src=""
+ <script src=""
+ <script type="text/_javascript_">
+ const expectedValues = [
+ // [animation-name, time, element-id, property, expected-value, tolerance]
+ ["custom-from-none-anim", 1, "custom-from-none-box", "webkitFilter", 'custom(url(vertex-rotate.vs) none, 1 1 filter-box, rotateBy 30, offset 0)', 0],
+ ["custom-to-none-anim", 1, "custom-to-none-box", "webkitFilter", 'custom(url(vertex-rotate.vs) none, 1 1 filter-box, rotateBy 30, offset 0)', 0],
+
+ ["custom-from-no-params-anim", 1, "custom-from-no-params-box", "webkitFilter", 'custom(url(vertex-rotate.vs) none, 1 1 filter-box, rotateBy 30, offset 0)', 0],
+ ["custom-to-no-params-anim", 1, "custom-to-no-params-box", "webkitFilter", 'custom(url(vertex-rotate.vs) none, 1 1 filter-box, rotateBy 30, offset 0)', 0],
+
+ ["custom-mix-attributes-anim", 1, "custom-mix-attributes-box", "webkitFilter", 'custom(url(vertex-rotate.vs) none, 5 5 border-box, rotateBy 30, offset 0)', 0],
+
+ // FIXME: CSS Shaders do not get good FPS in debug mode, so the tolerance needs to be higher.
+ // https://bugs.webkit.org/show_bug.cgi?id=85086
+ ["custom-from-diff-params-anim", 1, "custom-from-diff-params-box", "webkitFilter", 'custom(url(vertex-rotate.vs) none, 1 1 filter-box, param 10, rotateBy 60, offset 10, another_param 5)', 5],
+ ["custom-to-diff-params-anim", 1, "custom-to-diff-params-box", "webkitFilter", 'custom(url(vertex-rotate.vs) none, 1 1 filter-box, param 10, rotateBy 60, offset 10, another_param 5)', 5],
+
+ ["custom-mix-params-anim", 1, "custom-mix-params-box", "webkitFilter", 'custom(url(vertex-rotate.vs) none, 1 1 filter-box, param 10, another_param 5, first_param 6, rotateBy 60, offset 10, last_param 4)', 5],
+ ["custom-mix-numbers-anim", 1, "custom-mix-numbers-box", "webkitFilter", 'custom(url(vertex-rotate.vs) none, 1 1 filter-box, rotateBy 45, a 5.5, b 11 16.5, c 22 27.5 33, d 38.5 44 49.5)', 10]
+ ];
+ runAnimationTest(expectedValues);
+ </script>
+</head>
+<body>
+ <div class="box" id="custom-from-none-box"></div>
+ <div class="box" id="custom-to-none-box"></div>
+ <div class="box" id="custom-from-no-params-box"></div>
+ <div class="box" id="custom-to-no-params-box"></div>
+ <div class="box" id="custom-mix-attributes-box"></div>
+ <div class="box" id="custom-from-diff-params-box"></div>
+ <div class="box" id="custom-to-diff-params-box"></div>
+ <div class="box" id="custom-mix-params-box"></div>
+ <div class="box" id="custom-mix-numbers-box"></div>
+
+ <div id="result">
+ </div>
+</body>
+</html>
Added: trunk/LayoutTests/css3/filters/resources/custom-filter-parser.js (0 => 115487)
--- trunk/LayoutTests/css3/filters/resources/custom-filter-parser.js (rev 0)
+++ trunk/LayoutTests/css3/filters/resources/custom-filter-parser.js 2012-04-27 20:30:40 UTC (rev 115487)
@@ -0,0 +1,202 @@
+// This is a helper script designed to parse the computed syntax of the custom filter.
+// Note that it is generic enough so that it can be used for other properties in the future.
+
+function Token(type)
+{
+ this.type = type;
+}
+
+// Checks if the type of the token is in the list of arguments passed to the function.
+// It also accepts arrays and other type checking functions.
+Token.prototype.isA = function()
+{
+ for (var i = 0; i < arguments.length; ++i) {
+ var type = arguments[i];
+ if ((typeof type == "object" && type.length && this.isA.apply(this, type))
+ || (typeof type == "function" && type(this))
+ || type == this.type)
+ return true;
+ }
+ return false;
+}
+
+// Creates a new token object and copies all the properties in "value" to the new token.
+function createToken(type, value) {
+ var token = new Token(type);
+ if (value) {
+ for (var i in value)
+ if (value.hasOwnProperty(i))
+ token[i] = value[i];
+ }
+ return token;
+}
+
+// Tokenizes the string into Tokens of types [urls, floats, integers, keywords, ",", "(", ")" and "."].
+function tokenizeString(s)
+{
+ var tokenizer = new RegExp([
+ "url\\(\\s*(.*?)\\s*\\)", // url() - 1
+ "((?:[\\+-]?)\\d*\\.\\d+)", // floats - 2
+ "((?:[\\+-]?)\\d+)", // integers - 3
+ "([\\w-][\\w\\d-]*)", // keywords - 4
+ "([,\\.\\(\\)])" // punctuation - 5
+ ].join("|"), "g");
+
+ var match, tokens = [];
+ while (match = tokenizer.exec(s)) {
+ if (match[1] !== undefined)
+ tokens.push(createToken("url", {value: match[1]}));
+ else if (match[2] !== undefined)
+ tokens.push(createToken("float", {value: parseFloat(match[2])}));
+ else if (match[3] !== undefined)
+ tokens.push(createToken("integer", {value: parseInt(match[3])}));
+ else if (match[4] !== undefined)
+ tokens.push(createToken("keyword", {value: match[4]}));
+ else if (match[5] !== undefined)
+ tokens.push(createToken(match[5]));
+ }
+ return tokens;
+}
+
+// Checks if the token is a number. Can be used in combination with the "Token.isA" method.
+function number(token)
+{
+ return token.type == "float" || token.type == "integer";
+}
+
+// Helper class to iterate on the token stream. It will add an "end"
+// token at the end to make it easier to use the "ahead" function
+// without checking if it's the last token in the stream.
+function TokenStream(tokens) {
+ this.tokens = tokens;
+ this.tokens.push(new Token("end"));
+ this.tokenIndex = 0;
+}
+
+TokenStream.prototype.current = function()
+{
+ return this.tokens[this.tokenIndex];
+}
+
+TokenStream.prototype.ahead = function()
+{
+ return this.tokens[this.tokenIndex + 1];
+}
+
+// Skips the current token only if it matches the "typeMatcher". Otherwise it throws an error.
+TokenStream.prototype.skip = function(typeMatcher)
+{
+ if (!typeMatcher || this.ahead().isA(typeMatcher)) {
+ var token = this.current();
+ ++this.tokenIndex;
+ return token;
+ }
+ throw new Error("Cannot use " + JSON.stringify(typeMatcher) + " to skip over " + JSON.stringify(this.ahead()));
+}
+
+// Skips the current token, only if it matches the "typeMatcher". Makes it easy to skip over comma tokens.
+TokenStream.prototype.skipIfNeeded = function(typeMatcher)
+{
+ if (this.ahead() && this.ahead().isA(typeMatcher))
+ ++this.tokenIndex;
+}
+
+// Creates a new "function" node. It expects that the current token is the function name.
+function parseFunction(m)
+{
+ var functionObject = {
+ type: "function",
+ name: m.skip().value
+ };
+ m.skip("(");
+ functionObject.arguments = parseList(m, [")", "end"]);
+ m.skip(")");
+ return functionObject;
+}
+
+// Creates a new "parameter" node. It expects that the current token is the parameter name.
+// It consumes everything before the following comma.
+function parseParameter(m)
+{
+ var functionObject = {
+ type: "parameter",
+ name: m.skip().value
+ };
+ functionObject.value = parseList(m, [",", "end"]);
+ m.skipIfNeeded(",");
+ return functionObject;
+}
+
+// Consumes a list of tokens before reaching the "endToken" and returns an array with all the parsed items.
+// Makes the following assumptions:
+// - if a keyword is followed by "(" then it is a start of function
+// - if a keyword is not followed by "," it is a parameter
+// Keywords that do not match either of the previous rules and tokens like number and url are just cloned.
+function parseList(m, endToken)
+{
+ var result = [], token;
+ while ((token = m.current()) && !token.isA(endToken)) {
+ if (token.isA("keyword")) {
+ if (m.ahead().isA("("))
+ result.push(parseFunction(m));
+ else if (m.ahead().isA(",", endToken)) {
+ result.push({
+ type: "keyword",
+ value: m.skip().value
+ });
+ } else
+ result.push(parseParameter(m));
+ } else if (token.isA(number)) {
+ result.push({
+ type: "number",
+ value: m.skip().value
+ });
+ } else if (token.isA("url")) {
+ result.push({
+ type: "url",
+ value: m.skip().value
+ });
+ } else if (token.isA(","))
+ m.skip();
+ else
+ throw "Unexpected token " + JSON.stringify(token) + " in a list.";
+ }
+ return result;
+}
+
+function tokensToValues(tokens)
+{
+ var m = new TokenStream(tokens);
+ return parseList(m, "end");
+}
+
+// Extracts a parameters array from the parameters string of the custom filter function.
+function parseCustomFilterParameters(s)
+{
+ return tokensToValues(tokenizeString(s));
+}
+
+// Need to remove the base URL to avoid having local paths in the expected results.
+function removeBaseURL(src) {
+ var urlRegexp = /url\(([^\)]*)\)/g;
+ return src.replace(urlRegexp, function(match, url) {
+ return "url(" + url.substr(url.lastIndexOf("/") + 1) + ")";
+ });
+}
+
+// Parses the parameters of the custom filter function and returns it using the following order:
+// - If parameters have different types (ie. url, number, named parameter), the alphabetical order of the "type" is used.
+// - If parameters are of type "parameter" the alphabetical order of the parameter names is used.
+// - If parameters are of other types, then the value is used to order them alphabetical.
+// The order is important to make it easy to compare two custom filters, that have exactly the same parameters,
+// but with potentially different "named parameter" values.
+function getCustomFilterParameters(s)
+{
+ return parseCustomFilterParameters(removeBaseURL(s)).sort(function(a, b) {
+ if (a.type != b.type)
+ return a.type.localeCompare(b.type);
+ if (a.type == "parameter")
+ return a.name.localeCompare(b.name);
+ return a.value.toString().localeCompare(b.value.toString());
+ });
+}
Modified: trunk/Source/WebCore/ChangeLog (115486 => 115487)
--- trunk/Source/WebCore/ChangeLog 2012-04-27 20:29:31 UTC (rev 115486)
+++ trunk/Source/WebCore/ChangeLog 2012-04-27 20:30:40 UTC (rev 115487)
@@ -1,3 +1,45 @@
+2012-04-27 Alexandru Chiculita <[email protected]>
+
+ [CSS Shaders] Implement CSS Animations and Transitions for CSS Shaders
+ https://bugs.webkit.org/show_bug.cgi?id=71406
+
+ Reviewed by Dean Jackson.
+
+ I've implemented the blend function for the CustomFilterOperation. This should enable animations for CSS Shaders.
+ Currently, just floats are implemented. If any of the filter attributes like shader, mesh size or box mode are different,
+ the fallback is to use the "to" part of the animation instead. If other shader parameters do not match, it will merge the parameter values
+ between the "from" and "to" states.
+
+ Test: css3/filters/custom/custom-filter-animation.html
+
+ * platform/graphics/filters/CustomFilterNumberParameter.h:
+ (WebCore::CustomFilterNumberParameter::blend):
+ (CustomFilterNumberParameter):
+ (WebCore::CustomFilterNumberParameter::operator==):
+ * platform/graphics/filters/CustomFilterOperation.cpp:
+ (WebCore::equalCustomFilterParameters):
+ (WebCore):
+ (WebCore::checkCustomFilterParametersOrder):
+ (WebCore::blendCustomFilterParameters):
+ (WebCore::CustomFilterOperation::CustomFilterOperation):
+ (WebCore::CustomFilterOperation::blend):
+ * platform/graphics/filters/CustomFilterOperation.h:
+ (WebCore):
+ (CustomFilterOperation):
+ (WebCore::CustomFilterOperation::operator==):
+ (WebCore::CustomFilterOperation::operator!=):
+ * platform/graphics/filters/CustomFilterParameter.h:
+ (CustomFilterParameter):
+ (WebCore::CustomFilterParameter::isSameType):
+ (WebCore::CustomFilterParameter::operator==):
+ (WebCore::CustomFilterParameter::operator!=):
+ * platform/graphics/filters/CustomFilterProgram.h:
+ * rendering/style/StyleCustomFilterProgram.h:
+ (StyleCustomFilterProgram):
+ (WebCore::StyleCustomFilterProgram::cachedVertexShader):
+ (WebCore::StyleCustomFilterProgram::cachedFragmentShader):
+ (WebCore::StyleCustomFilterProgram::operator==):
+
2012-04-27 Chris Rogers <[email protected]>
Re-factor scheduling logic from AudioBufferSourceNode into AudioScheduledSourceNode
Modified: trunk/Source/WebCore/platform/graphics/filters/CustomFilterNumberParameter.h (115486 => 115487)
--- trunk/Source/WebCore/platform/graphics/filters/CustomFilterNumberParameter.h 2012-04-27 20:29:31 UTC (rev 115486)
+++ trunk/Source/WebCore/platform/graphics/filters/CustomFilterNumberParameter.h 2012-04-27 20:30:40 UTC (rev 115487)
@@ -48,6 +48,27 @@
void addValue(double value) { m_data.append(value); }
+ virtual PassRefPtr<CustomFilterParameter> blend(const CustomFilterParameter* from, double progress)
+ {
+ if (!from || !isSameType(*from))
+ return this;
+ const CustomFilterNumberParameter* fromNumber = static_cast<const CustomFilterNumberParameter*>(from);
+ if (size() != fromNumber->size())
+ return this;
+ RefPtr<CustomFilterNumberParameter> result = CustomFilterNumberParameter::create(name());
+ for (size_t i = 0; i < size(); ++i)
+ result->addValue(WebCore::blend(fromNumber->valueAt(i), valueAt(i), progress));
+ return result.release();
+ }
+
+ virtual bool operator==(const CustomFilterParameter& o) const
+ {
+ if (!isSameType(o))
+ return false;
+ const CustomFilterNumberParameter* other = static_cast<const CustomFilterNumberParameter*>(&o);
+ return m_data == other->m_data;
+ }
+
private:
CustomFilterNumberParameter(const String& name)
: CustomFilterParameter(NUMBER, name)
Modified: trunk/Source/WebCore/platform/graphics/filters/CustomFilterOperation.cpp (115486 => 115487)
--- trunk/Source/WebCore/platform/graphics/filters/CustomFilterOperation.cpp 2012-04-27 20:29:31 UTC (rev 115486)
+++ trunk/Source/WebCore/platform/graphics/filters/CustomFilterOperation.cpp 2012-04-27 20:30:40 UTC (rev 115487)
@@ -40,6 +40,60 @@
namespace WebCore {
+bool customFilterParametersEqual(const CustomFilterParameterList& listA, const CustomFilterParameterList& listB)
+{
+ if (listA.size() != listB.size())
+ return false;
+ for (size_t i = 0; i < listA.size(); ++i) {
+ if (listA.at(i).get() != listB.at(i).get()
+ && *listA.at(i).get() != *listB.at(i).get())
+ return false;
+ }
+ return true;
+}
+
+#if !ASSERT_DISABLED
+static bool checkCustomFilterParametersOrder(const CustomFilterParameterList& parameters)
+{
+ for (unsigned i = 1; i < parameters.size(); ++i) {
+ // Break for equal or not-sorted parameters.
+ if (!codePointCompareLessThan(parameters.at(i - 1)->name(), parameters.at(i)->name()))
+ return false;
+ }
+ return true;
+}
+#endif
+
+void blendCustomFilterParameters(const CustomFilterParameterList& fromList, const CustomFilterParameterList& toList, double progress, CustomFilterParameterList& resultList)
+{
+ // This method expects both lists to be sorted by parameter name and the result list is also sorted.
+ ASSERT(checkCustomFilterParametersOrder(fromList));
+ ASSERT(checkCustomFilterParametersOrder(toList));
+ size_t fromListIndex = 0, toListIndex = 0;
+ while (fromListIndex < fromList.size() && toListIndex < toList.size()) {
+ CustomFilterParameter* paramFrom = fromList.at(fromListIndex).get();
+ CustomFilterParameter* paramTo = toList.at(toListIndex).get();
+ if (paramFrom->name() == paramTo->name()) {
+ resultList.append(paramTo->blend(paramFrom, progress));
+ ++fromListIndex;
+ ++toListIndex;
+ continue;
+ }
+ if (codePointCompareLessThan(paramFrom->name(), paramTo->name())) {
+ resultList.append(paramFrom);
+ ++fromListIndex;
+ continue;
+ }
+ resultList.append(paramTo);
+ ++toListIndex;
+ }
+ for (; fromListIndex < fromList.size(); ++fromListIndex)
+ resultList.append(fromList.at(fromListIndex));
+ for (; toListIndex < toList.size(); ++toListIndex)
+ resultList.append(toList.at(toListIndex));
+ ASSERT(checkCustomFilterParametersOrder(resultList));
+}
+
CustomFilterOperation::CustomFilterOperation(PassRefPtr<CustomFilterProgram> program, const CustomFilterParameterList& sortedParameters, unsigned meshRows, unsigned meshColumns, MeshBoxType meshBoxType, MeshType meshType)
: FilterOperation(CUSTOM)
, m_program(program)
@@ -50,24 +104,33 @@
, m_meshType(meshType)
{
// Make sure that the parameters are alwyas sorted by name. We use that to merge two CustomFilterOperations in animations.
- ASSERT(hasSortedParameterList());
+ ASSERT(checkCustomFilterParametersOrder(m_parameters));
}
CustomFilterOperation::~CustomFilterOperation()
{
}
-#ifndef NDEBUG
-bool CustomFilterOperation::hasSortedParameterList()
+PassRefPtr<FilterOperation> CustomFilterOperation::blend(const FilterOperation* from, double progress, bool blendToPassthrough)
{
- for (unsigned i = 1; i < m_parameters.size(); ++i) {
- // Break for equal or not-sorted parameters.
- if (!codePointCompareLessThan(m_parameters.at(i - i)->name(), m_parameters.at(i)->name()))
- return false;
- }
- return true;
+ // FIXME: There's no way to decide what is the "passthrough filter" for shaders using the current CSS Syntax.
+ // https://bugs.webkit.org/show_bug.cgi?id=84903
+ // https://www.w3.org/Bugs/Public/show_bug.cgi?id=16861
+ if (blendToPassthrough || !from || !from->isSameType(*this))
+ return this;
+
+ const CustomFilterOperation* fromOp = static_cast<const CustomFilterOperation*>(from);
+ if (*m_program.get() != *fromOp->m_program.get()
+ || m_meshRows != fromOp->m_meshRows
+ || m_meshColumns != fromOp->m_meshColumns
+ || m_meshBoxType != fromOp->m_meshBoxType
+ || m_meshType != fromOp->m_meshType)
+ return this;
+
+ CustomFilterParameterList animatedParameters;
+ blendCustomFilterParameters(fromOp->m_parameters, m_parameters, progress, animatedParameters);
+ return CustomFilterOperation::create(m_program, animatedParameters, m_meshRows, m_meshColumns, m_meshBoxType, m_meshType);
}
-#endif
} // namespace WebCore
Modified: trunk/Source/WebCore/platform/graphics/filters/CustomFilterOperation.h (115486 => 115487)
--- trunk/Source/WebCore/platform/graphics/filters/CustomFilterOperation.h 2012-04-27 20:29:31 UTC (rev 115486)
+++ trunk/Source/WebCore/platform/graphics/filters/CustomFilterOperation.h 2012-04-27 20:30:40 UTC (rev 115487)
@@ -43,6 +43,9 @@
class CustomFilterParameter;
typedef Vector<RefPtr<CustomFilterParameter> > CustomFilterParameterList;
+bool customFilterParametersEqual(const CustomFilterParameterList&, const CustomFilterParameterList&);
+void blendCustomFilterParameters(const CustomFilterParameterList& listFrom, const CustomFilterParameterList& listTo, double progress, CustomFilterParameterList& resultList);
+
class CustomFilterOperation : public FilterOperation {
public:
enum MeshBoxType {
@@ -83,6 +86,8 @@
virtual bool affectsOpacity() const { return true; }
virtual bool movesPixels() const { return true; }
+
+ virtual PassRefPtr<FilterOperation> blend(const FilterOperation* from, double progress, bool blendToPassthrough = false);
private:
virtual bool operator==(const FilterOperation& o) const
{
@@ -90,18 +95,15 @@
return false;
const CustomFilterOperation* other = static_cast<const CustomFilterOperation*>(&o);
- return m_program.get() == other->m_program.get()
+ return *m_program.get() == *other->m_program.get()
&& m_meshRows == other->m_meshRows
&& m_meshColumns == other->m_meshColumns
&& m_meshBoxType == other->m_meshBoxType
- && m_meshType == other->m_meshType;
+ && m_meshType == other->m_meshType
+ && customFilterParametersEqual(m_parameters, other->m_parameters);
}
CustomFilterOperation(PassRefPtr<CustomFilterProgram>, const CustomFilterParameterList&, unsigned meshRows, unsigned meshColumns, MeshBoxType, MeshType);
-
-#ifndef NDEBUG
- bool hasSortedParameterList();
-#endif
RefPtr<CustomFilterProgram> m_program;
CustomFilterParameterList m_parameters;
Modified: trunk/Source/WebCore/platform/graphics/filters/CustomFilterParameter.h (115486 => 115487)
--- trunk/Source/WebCore/platform/graphics/filters/CustomFilterParameter.h 2012-04-27 20:29:31 UTC (rev 115486)
+++ trunk/Source/WebCore/platform/graphics/filters/CustomFilterParameter.h 2012-04-27 20:30:40 UTC (rev 115487)
@@ -52,7 +52,12 @@
ParameterType parameterType() const { return m_type; }
const String& name() const { return m_name; }
-
+
+ bool isSameType(const CustomFilterParameter& other) const { return parameterType() == other.parameterType(); }
+
+ virtual PassRefPtr<CustomFilterParameter> blend(const CustomFilterParameter*, double progress) = 0;
+ virtual bool operator==(const CustomFilterParameter&) const = 0;
+ bool operator!=(const CustomFilterParameter& o) const { return !(*this == o); }
protected:
CustomFilterParameter(ParameterType type, const String& name)
: m_name(name)
Modified: trunk/Source/WebCore/platform/graphics/filters/CustomFilterProgram.h (115486 => 115487)
--- trunk/Source/WebCore/platform/graphics/filters/CustomFilterProgram.h 2012-04-27 20:29:31 UTC (rev 115486)
+++ trunk/Source/WebCore/platform/graphics/filters/CustomFilterProgram.h 2012-04-27 20:30:40 UTC (rev 115487)
@@ -57,6 +57,10 @@
PassRefPtr<CustomFilterShader> createShaderWithContext(GraphicsContext3D*);
#endif
+ // StyleCustomFilterProgram has the only implementation for the following method. That means, it casts to StyleCustomFilterProgram
+ // withouth checking the type. If you add another implementation, also add a mechanism to check for the correct type.
+ virtual bool operator==(const CustomFilterProgram&) const = 0;
+ bool operator!=(const CustomFilterProgram& o) const { return !(*this == o); }
protected:
// StyleCustomFilterProgram can notify the clients that the cached resources are
// loaded and it is ready to create CustomFilterShader objects.
Modified: trunk/Source/WebCore/rendering/style/StyleCustomFilterProgram.h (115486 => 115487)
--- trunk/Source/WebCore/rendering/style/StyleCustomFilterProgram.h 2012-04-27 20:29:31 UTC (rev 115486)
+++ trunk/Source/WebCore/rendering/style/StyleCustomFilterProgram.h 2012-04-27 20:30:40 UTC (rev 115487)
@@ -113,6 +113,16 @@
if (isLoaded())
notifyClients();
}
+
+ CachedShader* cachedVertexShader() const { return m_vertexShader ? m_vertexShader->cachedShader() : 0; }
+ CachedShader* cachedFragmentShader() const { return m_fragmentShader ? m_fragmentShader->cachedShader() : 0; }
+
+ virtual bool operator==(const CustomFilterProgram& o) const
+ {
+ // The following cast is ugly, but StyleCustomFilterProgram is the single implementation of CustomFilterProgram.
+ const StyleCustomFilterProgram* other = static_cast<const StyleCustomFilterProgram*>(&o);
+ return cachedVertexShader() == other->cachedVertexShader() && cachedFragmentShader() == other->cachedFragmentShader();
+ }
private:
StyleCustomFilterProgram(PassRefPtr<StyleShader> vertexShader, PassRefPtr<StyleShader> fragmentShader)