diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
commit | 1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch) | |
tree | 46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WebInspectorUI/UserInterface/Models/Gradient.js | |
parent | 32761a6cee1d0dee366b885b7b9c777e67885688 (diff) | |
download | WebKitGtk-tarball-master.tar.gz |
webkitgtk-2.16.5HEADwebkitgtk-2.16.5master
Diffstat (limited to 'Source/WebInspectorUI/UserInterface/Models/Gradient.js')
-rw-r--r-- | Source/WebInspectorUI/UserInterface/Models/Gradient.js | 392 |
1 files changed, 392 insertions, 0 deletions
diff --git a/Source/WebInspectorUI/UserInterface/Models/Gradient.js b/Source/WebInspectorUI/UserInterface/Models/Gradient.js new file mode 100644 index 000000000..f9b1c238c --- /dev/null +++ b/Source/WebInspectorUI/UserInterface/Models/Gradient.js @@ -0,0 +1,392 @@ +/* + * Copyright (C) 2014 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +WebInspector.Gradient = class Gradient +{ + constructor(type, stops) + { + this.type = type; + this.stops = stops; + } + + // Static + + static fromString(cssString) + { + var type; + var openingParenthesisIndex = cssString.indexOf("("); + var typeString = cssString.substring(0, openingParenthesisIndex); + if (typeString.indexOf(WebInspector.Gradient.Types.Linear) !== -1) + type = WebInspector.Gradient.Types.Linear; + else if (typeString.indexOf(WebInspector.Gradient.Types.Radial) !== -1) + type = WebInspector.Gradient.Types.Radial; + else + return null; + + var components = []; + var currentParams = []; + var currentParam = ""; + var openParentheses = 0; + var ch = openingParenthesisIndex + 1; + var c = null; + while (c = cssString[ch]) { + if (c === "(") + openParentheses++; + if (c === ")") + openParentheses--; + + var isComma = c === ","; + var isSpace = /\s/.test(c); + + if (openParentheses === 0) { + if (isSpace) { + if (currentParam !== "") + currentParams.push(currentParam); + currentParam = ""; + } else if (isComma) { + currentParams.push(currentParam); + components.push(currentParams); + currentParams = []; + currentParam = ""; + } + } + + if (openParentheses === -1) { + currentParams.push(currentParam); + components.push(currentParams); + break; + } + + if (openParentheses > 0 || (!isComma && !isSpace)) + currentParam += c; + + ch++; + } + + if (openParentheses !== -1) + return null; + + var gradient; + if (type === WebInspector.Gradient.Types.Linear) + gradient = WebInspector.LinearGradient.fromComponents(components); + else + gradient = WebInspector.RadialGradient.fromComponents(components); + + if (gradient) + gradient.repeats = typeString.startsWith("repeating"); + + return gradient; + } + + static stopsWithComponents(components) + { + // FIXME: handle lengths. + var stops = components.map(function(component) { + while (component.length) { + var color = WebInspector.Color.fromString(component.shift()); + if (!color) + continue; + + var stop = {color}; + if (component.length && component[0].substr(-1) === "%") + stop.offset = parseFloat(component.shift()) / 100; + return stop; + } + }); + + if (!stops.length) + return null; + + for (var i = 0, count = stops.length; i < count; ++i) { + var stop = stops[i]; + + // If one of the stops failed to parse, then this is not a valid + // set of components for a gradient. So the whole thing is invalid. + if (!stop) + return null; + + if (!stop.offset) + stop.offset = i / (count - 1); + } + + return stops; + } + + // Public + + stringFromStops(stops) + { + var count = stops.length - 1; + return stops.map(function(stop, index) { + var str = stop.color; + if (stop.offset !== index / count) + str += " " + Math.round(stop.offset * 10000) / 100 + "%"; + return str; + }).join(", "); + } + + // Public + + copy() + { + // Implemented by subclasses. + } + + toString() + { + // Implemented by subclasses. + } +}; + +WebInspector.Gradient.Types = { + Linear: "linear-gradient", + Radial: "radial-gradient" +}; + +WebInspector.LinearGradient = class LinearGradient extends WebInspector.Gradient +{ + constructor(angle, stops) + { + super(WebInspector.Gradient.Types.Linear, stops); + this._angle = angle; + } + + // Static + + static fromComponents(components) + { + let angle = {value: 180, units: WebInspector.LinearGradient.AngleUnits.DEG}; + + if (components[0].length === 1 && !WebInspector.Color.fromString(components[0][0])) { + let match = components[0][0].match(/([-\d\.]+)(\w+)/); + if (!match || !Object.values(WebInspector.LinearGradient.AngleUnits).includes(match[2])) + return null; + + angle.value = parseFloat(match[1]); + angle.units = match[2]; + + components.shift(); + } else if (components[0][0] === "to") { + components[0].shift(); + switch (components[0].sort().join(" ")) { + case "top": + angle.value = 0; + break; + case "right top": + angle.value = 45; + break; + case "right": + angle.value = 90; + break; + case "bottom right": + angle.value = 135; + break; + case "bottom": + angle.value = 180; + break; + case "bottom left": + angle.value = 225; + break; + case "left": + angle.value = 270; + break; + case "left top": + angle.value = 315; + break; + default: + return null; + } + + components.shift(); + } else if (components[0].length !== 1 && !WebInspector.Color.fromString(components[0][0])) { + // If the first component is not a color, then we're dealing with a + // legacy linear gradient format that we don't support. + return null; + } + + var stops = WebInspector.Gradient.stopsWithComponents(components); + if (!stops) + return null; + + return new WebInspector.LinearGradient(angle, stops); + } + + // Public + + set angleValue(value) { this._angle.value = value; } + + get angleValue() + { + return this._angle.value.maxDecimals(2); + } + + set angleUnits(units) + { + if (units === this._angle.units) + return; + + this._angle.value = this._angleValueForUnits(units); + this._angle.units = units; + } + + get angleUnits() { return this._angle.units; } + + copy() + { + return new WebInspector.LinearGradient(this._angle, this.stops.concat()); + } + + toString() + { + let str = ""; + + let deg = this._angleValueForUnits(WebInspector.LinearGradient.AngleUnits.DEG); + if (deg === 0) + str += "to top"; + else if (deg === 45) + str += "to top right"; + else if (deg === 90) + str += "to right"; + else if (deg === 135) + str += "to bottom right"; + else if (deg === 225) + str += "to bottom left"; + else if (deg === 270) + str += "to left"; + else if (deg === 315) + str += "to top left"; + else if (deg !== 180) + str += this.angleValue + this.angleUnits; + + if (str !== "") + str += ", "; + + str += this.stringFromStops(this.stops); + + return (this.repeats ? "repeating-" : "") + this.type + "(" + str + ")"; + } + + // Private + + _angleValueForUnits(units) + { + if (units === this._angle.units) + return this._angle.value; + + let deg = 0; + + switch (this._angle.units) { + case WebInspector.LinearGradient.AngleUnits.DEG: + deg = this._angle.value; + break; + + case WebInspector.LinearGradient.AngleUnits.RAD: + deg = this._angle.value * 180 / Math.PI; + break; + + case WebInspector.LinearGradient.AngleUnits.GRAD: + deg = this._angle.value / 400 * 360; + break; + + case WebInspector.LinearGradient.AngleUnits.TURN: + deg = this._angle.value * 360; + break; + + default: + WebInspector.reportInternalError(`Unknown angle units "${this._angle.units}"`); + return 0; + } + + let value = 0; + + switch (units) { + case WebInspector.LinearGradient.AngleUnits.DEG: + value = deg; + break; + + case WebInspector.LinearGradient.AngleUnits.RAD: + value = deg * Math.PI / 180; + break; + + case WebInspector.LinearGradient.AngleUnits.GRAD: + value = deg / 360 * 400; + break; + + case WebInspector.LinearGradient.AngleUnits.TURN: + value = deg / 360; + break; + } + + return value; + } +}; + +WebInspector.LinearGradient.AngleUnits = { + DEG: "deg", + RAD: "rad", + GRAD: "grad", + TURN: "turn", +}; + +WebInspector.RadialGradient = class RadialGradient extends WebInspector.Gradient +{ + constructor(sizing, stops) + { + super(WebInspector.Gradient.Types.Radial, stops); + this.sizing = sizing; + } + + // Static + + static fromComponents(components) + { + var sizing = !WebInspector.Color.fromString(components[0].join(" ")) ? components.shift().join(" ") : ""; + + var stops = WebInspector.Gradient.stopsWithComponents(components); + if (!stops) + return null; + + return new WebInspector.RadialGradient(sizing, stops); + } + + // Public + + copy() + { + return new WebInspector.RadialGradient(this.sizing, this.stops.concat()); + } + + toString() + { + var str = this.sizing; + + if (str !== "") + str += ", "; + + str += this.stringFromStops(this.stops); + + return (this.repeats ? "repeating-" : "") + this.type + "(" + str + ")"; + } +}; |