Chromium Code Reviews| Index: third_party/WebKit/Source/devtools/front_end/common/CSSShadowModel.js |
| diff --git a/third_party/WebKit/Source/devtools/front_end/common/CSSShadowModel.js b/third_party/WebKit/Source/devtools/front_end/common/CSSShadowModel.js |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..c0099b3474020cd75e038795b5126e56fe9633fe |
| --- /dev/null |
| +++ b/third_party/WebKit/Source/devtools/front_end/common/CSSShadowModel.js |
| @@ -0,0 +1,343 @@ |
| +// Copyright 2016 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +/** |
| + * @constructor |
| + * @param {boolean} inset |
| + * @param {!WebInspector.CSSLength} offsetX |
| + * @param {!WebInspector.CSSLength} offsetY |
| + * @param {!WebInspector.CSSLength} blurRadius |
| + * @param {!WebInspector.CSSLength} spreadRadius |
| + * @param {!WebInspector.Color} color |
| + */ |
| +WebInspector.CSSShadowModel = function(inset, offsetX, offsetY, blurRadius, spreadRadius, color) |
| +{ |
| + this._inset = inset; |
| + this._offsetX = offsetX; |
| + this._offsetY = offsetY; |
| + this._blurRadius = blurRadius; |
| + this._spreadRadius = spreadRadius; |
| + this._color = color; |
| + this._format = "XYB"; |
| +} |
| + |
| +/** |
| + * @enum {string} |
| + */ |
| +WebInspector.CSSShadowModel.FormatParts = { |
| + Inset: "I", |
| + OffsetX: "X", |
| + OffsetY: "Y", |
| + BlurRadius: "B", |
| + SpreadRadius: "S", |
| + Color: "C" |
| +} |
| + |
| +/** |
| + * @param {string} text |
| + * @return {!Array<!WebInspector.CSSShadowModel>} |
| + */ |
| +WebInspector.CSSShadowModel.parseTextShadow = function(text) |
| +{ |
| + return WebInspector.CSSShadowModel._parseShadow(text, false); |
| +} |
| + |
| +/** |
| + * @param {string} text |
| + * @return {!Array<!WebInspector.CSSShadowModel>} |
| + */ |
| +WebInspector.CSSShadowModel.parseBoxShadow = function(text) |
| +{ |
| + return WebInspector.CSSShadowModel._parseShadow(text, true); |
| +} |
| + |
| +WebInspector.CSSShadowModel.prototype = { |
| + /** |
| + * @param {boolean} inset |
| + */ |
| + setInset: function(inset) |
| + { |
| + this._inset = inset; |
| + }, |
| + |
| + /** |
| + * @param {!WebInspector.CSSLength} offsetX |
| + * @param {!WebInspector.CSSLength} offsetY |
| + */ |
| + setOffset: function(offsetX, offsetY) |
| + { |
| + this._offsetX = offsetX; |
| + this._offsetY = offsetY; |
| + }, |
| + |
| + /** |
| + * @param {!WebInspector.CSSLength} blurRadius |
| + */ |
| + setBlurRadius: function(blurRadius) |
| + { |
| + this._blurRadius = blurRadius; |
| + }, |
| + |
| + /** |
| + * @param {!WebInspector.CSSLength} spreadRadius |
| + */ |
| + setSpreadRadius: function(spreadRadius) |
| + { |
| + this._spreadRadius = spreadRadius; |
|
dgozman
2016/08/22 16:56:41
Don't you want to add "S" to format here?
flandy
2016/08/22 19:42:20
Yes, if it is not included in the format already,
|
| + }, |
| + |
| + /** |
| + * @param {!WebInspector.Color} color |
| + */ |
| + setColor: function(color) |
| + { |
| + this._color = color; |
| + }, |
| + |
| + /** |
| + * @param {string} format |
| + */ |
| + setFormat: function(format) |
| + { |
| + this._format = format; |
|
dgozman
2016/08/22 16:56:41
Do we intend to switch between formats?
flandy
2016/08/22 19:42:20
No. Removed
|
| + }, |
| + |
| + /** |
| + * @return {!WebInspector.CSSLength} |
| + */ |
| + offsetX: function() |
| + { |
| + return this._offsetX; |
| + }, |
| + |
| + /** |
| + * @return {!WebInspector.CSSLength} |
| + */ |
| + offsetY: function() |
| + { |
| + return this._offsetY; |
| + }, |
| + |
| + /** |
| + * @return {string} |
| + */ |
| + asCSSText: function() |
| + { |
| + var parts = []; |
| + for (var i = 0; i < this._format.length; i++) { |
| + var part = this._format.charAt(i); |
| + if (part === WebInspector.CSSShadowModel.FormatParts.Inset && this._inset) |
| + parts.push("inset"); |
| + else if (part === WebInspector.CSSShadowModel.FormatParts.OffsetX) |
| + parts.push(this._offsetX.asCSSText()); |
| + else if (part === WebInspector.CSSShadowModel.FormatParts.OffsetY) |
| + parts.push(this._offsetY.asCSSText()); |
| + else if (part === WebInspector.CSSShadowModel.FormatParts.BlurRadius) |
| + parts.push(this._blurRadius.asCSSText()); |
| + else if (part === WebInspector.CSSShadowModel.FormatParts.SpreadRadius) |
| + parts.push(this._spreadRadius.asCSSText()); |
| + else if (part === WebInspector.CSSShadowModel.FormatParts.Color) |
| + parts.push(this._color.asString(this._color.format())); |
| + } |
| + return parts.join(" "); |
| + } |
| +} |
| + |
| +/** |
| + * @param {string} text |
| + * @param {boolean} isBoxShadow |
| + * @return {!Array<!WebInspector.CSSShadowModel>} |
| + */ |
| +WebInspector.CSSShadowModel._parseShadow = function(text, isBoxShadow) |
| +{ |
| + var shadowTexts = []; |
| + // Split by commas that aren't inside of color values to get the individual shadow values. |
| + var splits = WebInspector.TextUtils.splitStringByRegexes(text, [WebInspector.Color.Regex, /,/g]); |
| + var currentIndex = 0; |
| + for (var i = 0; i < splits.length; i++) { |
| + if (splits[i].regexIndex === 1) { |
| + var comma = splits[i]; |
| + shadowTexts.push(text.substring(currentIndex, comma.position)); |
| + currentIndex = comma.position + 1; |
| + } |
| + } |
| + shadowTexts.push(text.substring(currentIndex, text.length)); |
| + |
| + var shadows = []; |
| + for (var i = 0; i < shadowTexts.length; i++) { |
| + var shadow = new WebInspector.CSSShadowModel(false, WebInspector.CSSLength.zero(), WebInspector.CSSLength.zero(), |
|
dgozman
2016/08/22 16:56:41
If you never create with meaningful parameters, ju
flandy
2016/08/22 19:42:20
Done.
|
| + WebInspector.CSSLength.zero(), WebInspector.CSSLength.zero(), /** @type {!WebInspector.Color} */ (WebInspector.Color.parse("black"))); |
| + var format = ""; |
| + var nextPartAllowed = true; |
| + var regexes = [/inset/gi, WebInspector.Color.Regex, WebInspector.CSSLength.regex()]; |
| + var results = WebInspector.TextUtils.splitStringByRegexes(shadowTexts[i], regexes); |
| + for (var j = 0; j < results.length; j++) { |
| + var result = results[j]; |
| + if (result.regexIndex === -1) { |
| + // Don't allow anything other than inset, color, length values, and whitespace. |
| + if (/\S/.test(result.value)) |
| + return []; |
| + // All parts must be separated by whitespace. |
| + nextPartAllowed = true; |
| + } else { |
| + if (!nextPartAllowed) |
| + return []; |
| + nextPartAllowed = false; |
| + |
| + if (result.regexIndex === 0) { |
| + shadow.setInset(true); |
| + format += WebInspector.CSSShadowModel.FormatParts.Inset; |
| + } else if (result.regexIndex === 1) { |
| + var color = WebInspector.Color.parse(result.value); |
| + if (!color) |
| + return []; |
| + shadow.setColor(color); |
| + format += WebInspector.CSSShadowModel.FormatParts.Color; |
| + } else if (result.regexIndex === 2) { |
| + var length = WebInspector.CSSLength.parse(result.value); |
| + if (!length) |
| + return []; |
| + var previousPart = format.length > 0 ? format.charAt(format.length - 1) : ""; |
| + if (previousPart === WebInspector.CSSShadowModel.FormatParts.OffsetX) { |
| + shadow.setOffset(shadow.offsetX(), length); |
|
dgozman
2016/08/22 16:56:41
Use fields, not setters.
flandy
2016/08/22 19:42:20
Done.
|
| + format += WebInspector.CSSShadowModel.FormatParts.OffsetY; |
| + } else if (previousPart === WebInspector.CSSShadowModel.FormatParts.OffsetY) { |
| + shadow.setBlurRadius(length); |
| + format += WebInspector.CSSShadowModel.FormatParts.BlurRadius; |
| + } else if (previousPart === WebInspector.CSSShadowModel.FormatParts.BlurRadius) { |
| + shadow.setSpreadRadius(length); |
| + format += WebInspector.CSSShadowModel.FormatParts.SpreadRadius; |
| + } else { |
| + shadow.setOffset(length, shadow.offsetY()); |
| + format += WebInspector.CSSShadowModel.FormatParts.OffsetX; |
| + } |
| + } |
| + } |
| + } |
| + if (invalidCount(WebInspector.CSSShadowModel.FormatParts.OffsetX, 1, 1) |
| + || invalidCount(WebInspector.CSSShadowModel.FormatParts.OffsetY, 1, 1) |
| + || invalidCount(WebInspector.CSSShadowModel.FormatParts.Color, 0, 1) |
| + || invalidCount(WebInspector.CSSShadowModel.FormatParts.BlurRadius, 0, 1) |
| + || invalidCount(WebInspector.CSSShadowModel.FormatParts.Inset, 0, isBoxShadow ? 1 : 0) |
| + || invalidCount(WebInspector.CSSShadowModel.FormatParts.SpreadRadius, 0, isBoxShadow ? 1 : 0)) |
| + return []; |
| + shadow.setFormat(format); |
|
dgozman
2016/08/22 16:56:41
We can set fields here directly, and not expose se
flandy
2016/08/22 19:42:20
Setters will still be used by the Shadow Editor to
|
| + shadows.push(shadow); |
| + } |
| + return shadows; |
| + |
| + /** |
| + * @param {string} character |
| + * @param {number} min |
| + * @param {number} max |
| + * @return {boolean} |
| + */ |
| + function invalidCount(character, min, max) |
| + { |
| + var count = 0; |
| + for (var i = 0; i < format.length; i++) { |
| + if (format.charAt(i) === character) |
| + count++; |
| + } |
| + return count < min || count > max; |
| + } |
| +} |
| + |
| +/** |
| + * @constructor |
| + * @param {number} amount |
| + * @param {!WebInspector.CSSLengthUnit} unit |
| + */ |
| +WebInspector.CSSLength = function(amount, unit) |
| +{ |
| + this.amount = amount; |
| + this.unit = unit; |
| +} |
| + |
| +/** @type {!RegExp} */ |
| +WebInspector.CSSNumberRegex = /[+-]?(?:[0-9]*[.])?[0-9]+/; |
| +/** @type {!RegExp} */ |
| +WebInspector.CSSZeroRegex = /[+-]?(?:0*[.])?0+/; |
| +/** @type {!RegExp} */ |
| +WebInspector.CSSExponentRegex = /(?:[eE][+-]?[0-9]+)?/; |
| + |
| +/** |
| + * @return {!RegExp} |
| + */ |
| +WebInspector.CSSLength.regex = function() |
| +{ |
| + var number = WebInspector.CSSNumberRegex.source + WebInspector.CSSExponentRegex.source; |
| + var unit = WebInspector.CSSLengthUnit.regex().source; |
| + var zero = WebInspector.CSSZeroRegex.source + WebInspector.CSSExponentRegex.source; |
| + return new RegExp("(" + number + ")(" + unit + ")|" + zero, "gi"); |
|
dgozman
2016/08/22 16:56:41
All this regexp magic is hard to understand. Can w
flandy
2016/08/22 19:42:21
I've now inlined the regexes.
|
| +} |
| + |
| +/** |
| + * @enum {string} |
| + */ |
| +WebInspector.CSSLengthUnit = { |
| + Ch: "ch", |
| + Cm: "cm", |
| + Em: "em", |
| + Ex: "ex", |
| + In: "in", |
| + Mm: "mm", |
| + Pc: "pc", |
| + Pt: "pt", |
| + Px: "px", |
| + Rem: "rem", |
| + Vh: "vh", |
| + Vmax: "vmax", |
| + Vmin: "vmin", |
| + Vw: "vw", |
| + None: "" |
| +} |
| + |
| +/** |
| + * @return {!RegExp} |
| + */ |
| +WebInspector.CSSLengthUnit.regex = function() |
| +{ |
| + var units = []; |
| + var keys = Object.keys(WebInspector.CSSLengthUnit); |
| + for (var i = 0; i < keys.length; i++) { |
| + var unit = WebInspector.CSSLengthUnit[keys[i]]; |
| + if (unit && typeof unit === "string") |
|
dgozman
2016/08/22 16:56:41
How could it be not string?
flandy
2016/08/22 19:42:20
Removed.
|
| + units.push(unit); |
| + } |
| + return new RegExp(units.join("|"), "i"); |
|
dgozman
2016/08/22 16:56:41
Let's cache this one.
flandy
2016/08/22 19:42:20
Removed.
|
| +} |
| + |
| +/** |
| + * @param {string} text |
| + * @return {?WebInspector.CSSLength} |
| + */ |
| +WebInspector.CSSLength.parse = function(text) |
| +{ |
| + var lengthRegex = new RegExp("^(?:" + WebInspector.CSSLength.regex().source + ")$", "i"); |
|
dgozman
2016/08/22 16:56:41
Let's cache this one as well. Why don't we inline
flandy
2016/08/22 19:42:20
I use WI.CSSLength.Regex in the parse function as
|
| + var match = text.match(lengthRegex) || []; |
| + if (match.length > 2 && match[2]) |
| + return new WebInspector.CSSLength(parseFloat(match[1]), match[2]); |
| + else if (match.length > 0) |
| + return WebInspector.CSSLength.zero(); |
| + return null; |
| +} |
| + |
| +/** |
| + * @return {!WebInspector.CSSLength} |
| + */ |
| +WebInspector.CSSLength.zero = function() |
| +{ |
| + return new WebInspector.CSSLength(0, WebInspector.CSSLengthUnit.None); |
| +} |
| + |
| +WebInspector.CSSLength.prototype = { |
| + /** |
| + * @return {string} |
| + */ |
| + asCSSText: function() |
| + { |
| + return this.amount + this.unit; |
| + } |
| +} |