/javafx-ui-common/src/com/sun/javafx/scene/paint/GradientUtils.java
Java | 306 lines | 229 code | 40 blank | 37 comment | 61 complexity | c9afeb3e7afa91266b895ab06837dcdc MD5 | raw file
Possible License(s): BSD-3-Clause, LGPL-2.1, GPL-2.0, LGPL-2.0
- /*
- * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
- package com.sun.javafx.scene.paint;
- import java.util.LinkedList;
- import java.util.List;
- import javafx.scene.paint.Color;
- import javafx.scene.paint.Stop;
- public class GradientUtils {
- public static String lengthToString(double value, boolean proportional) {
- if (proportional) {
- return (value * 100) + "%";
- } else {
- return value + "px";
- }
- }
- public static class Point {
- public static final Point MIN = new Point(0, true);
- public static final Point MAX = new Point(1, true);
- public double value;
- public boolean proportional;
- @Override
- public String toString() {
- return "value = " + value + ", proportional = " + proportional;
- }
- public Point(double value, boolean proportional) {
- this.value = value;
- this.proportional = proportional;
- }
- public Point() {
- }
- }
- public static class Parser {
- private int index;
- private String[] tokens;
- private boolean proportional;
- private boolean proportionalSet = false;
- private interface Delimiter {
- public boolean isDelimiter(char value);
- }
- private String[] splitString(String string, Delimiter delimiter, boolean canRepeat) {
- List<String> tokenList = new LinkedList<String>();
- StringBuilder token = new StringBuilder();
- int i = 0;
- char[] input = string.toCharArray();
- while (i < input.length) {
- char currentChar = input[i];
- if (delimiter.isDelimiter(currentChar)) {
- if (!canRepeat || token.length() > 0) {
- tokenList.add(token.toString());
- }
- token.setLength(0);
- } else if (currentChar == '(') {
- while (i < input.length) {
- token.append(input[i]);
- if (input[i] == ')') {
- break;
- }
- i++;
- }
- } else {
- token.append(input[i]);
- }
- i++;
- }
- if (!canRepeat || token.length() > 0) {
- tokenList.add(token.toString());
- }
- return tokenList.toArray(new String[tokenList.size()]);
- }
- public Parser(String content) {
- tokens = splitString(content, new Delimiter() {
- @Override
- public boolean isDelimiter(char value) {
- return (value == ',');
- }
- }, false);
- index = 0;
- }
- public int getSize() {
- return tokens.length;
- }
- public void shift() {
- index++;
- }
- public String getCurrentToken() {
- String currentToken = tokens[index].trim();
- if (currentToken.isEmpty()) {
- throw new IllegalArgumentException("Invalid gradient specification: "
- + "found empty token.");
- }
- return currentToken;
- }
- public String[] splitCurrentToken() {
- return getCurrentToken().split("\\s");
- }
- public static void checkNumberOfArguments(String[] tokens, int count) {
- if (tokens.length < count + 1) {
- throw new IllegalArgumentException("Invalid gradient specification: "
- + "parameter '"+ tokens[0] + "' needs " + count + " argument(s).");
- }
- }
- public static double parseAngle(String value) {
- double angle = 0;
- if (value.endsWith("deg")) {
- value = value.substring(0, value.length() - 3);
- angle = Double.parseDouble(value);
- } else if (value.endsWith("grad")) {
- value = value.substring(0, value.length() - 4);
- angle = Double.parseDouble(value);
- angle = angle * 9 / 10;
- } else if (value.endsWith("rad")) {
- value = value.substring(0, value.length() - 3);
- angle = Double.parseDouble(value);
- angle = angle * 180 / Math.PI;
- } else if (value.endsWith("turn")) {
- value = value.substring(0, value.length() - 4);
- angle = Double.parseDouble(value);
- angle = angle * 360;
- } else {
- throw new IllegalArgumentException("Invalid gradient specification:"
- + "angle must end in deg, rad, grad, or turn");
- }
- return angle;
- }
- public static double parsePercentage(String value) {
- double percentage;
- if (value.endsWith("%")) {
- value = value.substring(0, value.length() - 1);
- percentage = Double.parseDouble(value) / 100;
- } else {
- throw new IllegalArgumentException("Invalid gradient specification: "
- + "focus-distance must be specified as percentage");
- }
- return percentage;
- }
- public Point parsePoint(String value) {
- Point p = new Point();
- if (value.endsWith("%")) {
- p.proportional = true;
- value = value.substring(0, value.length() - 1);
- } else if (value.endsWith("px")) {
- value = value.substring(0, value.length() - 2);
- }
- p.value = Double.parseDouble(value);
- if (p.proportional) {
- p.value /= 100;
- }
- if (proportionalSet && proportional != p.proportional) {
- throw new IllegalArgumentException("Invalid gradient specification:"
- + "cannot mix proportional and non-proportional values");
- }
- proportionalSet = true;
- proportional = p.proportional;
- return p;
- }
- // length specifies the length of gradient line used when recalculating
- // non-proportional color-stops
- public Stop[] parseStops(boolean proportional, double length) {
- int stopsCount = tokens.length - index;
- Color[] colors = new Color[stopsCount];
- double[] offsets = new double[stopsCount];
- Stop[] stops = new Stop[stopsCount];
- for (int i = 0; i < stopsCount; i++) {
- String stopString = tokens[i + index].trim();
- String[] stopTokens = splitString(stopString, new Delimiter() {
- @Override
- public boolean isDelimiter(char value) {
- return Character.isWhitespace(value);
- }
- }, true);
- if (stopTokens.length == 0) {
- throw new IllegalArgumentException("Invalid gradient specification, "
- + "empty stop found");
- }
- String currentToken = stopTokens[0];
- double offset = -1;
- Color c = Color.web(currentToken);
- if (stopTokens.length == 2) {
- // parsing offset
- String o = stopTokens[1];
- if (o.endsWith("%")) {
- o = o.substring(0, o.length() - 1);
- offset = Double.parseDouble(o) / 100;
- } else if (!proportional) {
- if (o.endsWith("px")) {
- o = o.substring(0, o.length() - 2);
- }
- offset = Double.parseDouble(o) / length;
- } else {
- throw new IllegalArgumentException("Invalid gradient specification, "
- + "non-proportional stops not permited in proportional gradient: " + o);
- }
- } else if (stopTokens.length > 2) {
- throw new IllegalArgumentException("Invalid gradient specification, "
- + "unexpected content in stop specification: " + stopTokens[2]);
- }
- colors[i] = c;
- offsets[i] = offset;
- }
- // normalize based on CSS specification
- // If the first color-stop does not have a position, set its position to 0%.
- // If the last color-stop does not have a position, set its position to 100%.
- if (offsets[0] < 0) {
- offsets[0] = 0;
- }
- if (offsets[offsets.length - 1] < 0) {
- offsets[offsets.length - 1] = 1;
- }
- // If a color-stop has a position that is less than the specified position
- // of any color-stop before it in the list, set its position to be equal
- // to the largest specified position of any color-stop before it.
- double max = offsets[0];
- for (int i = 1; i < offsets.length; i++) {
- if (offsets[i] < max && offsets[i] > 0) {
- offsets[i] = max;
- } else {
- max = offsets[i];
- }
- }
- // If any color-stop still does not have a position, then,
- // for each run of adjacent color-stops without positions,
- // set their positions so that they are evenly spaced
- // between the preceding and following color-stops with positions.
- int firstIndex = -1;
- for (int i = 1; i < offsets.length; i++) {
- double offset = offsets[i];
- if (offset < 0 && firstIndex < 0) {
- firstIndex = i;
- } else if (offset >= 0 && firstIndex > 0) {
- int n = i - firstIndex + 1;
- double part = (offsets[i] - offsets[firstIndex - 1]) / n;
- for (int j = 0; j < n - 1; j++) {
- offsets[firstIndex + j] = offsets[firstIndex - 1] + part * (j + 1);
- }
- }
- }
- for (int i = 0; i < stops.length; i++) {
- Stop stop = new Stop(offsets[i], colors[i]);
- stops[i] = stop;
- }
- return stops;
- }
- }
- }