summaryrefslogtreecommitdiff
path: root/Source/WebInspectorUI/UserInterface/Models/Gradient.js
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
commit1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch)
tree46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WebInspectorUI/UserInterface/Models/Gradient.js
parent32761a6cee1d0dee366b885b7b9c777e67885688 (diff)
downloadWebKitGtk-tarball-master.tar.gz
Diffstat (limited to 'Source/WebInspectorUI/UserInterface/Models/Gradient.js')
-rw-r--r--Source/WebInspectorUI/UserInterface/Models/Gradient.js392
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 + ")";
+ }
+};