mirror of
https://github.com/zoriya/react-native-svg.git
synced 2026-06-03 15:14:18 +00:00
Allow int32ARGBColor and use it to represent colors instead of rgbaArray
int32ARGBColor is 0xaarrggbb format to allow no processing Optimize default fill handling Improve gradient input validation Simplify gradient extraction Use a single array to represent gradient, with two numbers per stop Reuse transform props in extractProps, short circuit identity transform. [android] Refactor ImageView, fix mLoading
This commit is contained in:
+17
-7
@@ -69,13 +69,14 @@ export default class Matrix2D {
|
||||
/**
|
||||
* Reset current matrix to an identity matrix.
|
||||
* @method reset
|
||||
* @return {Matrix2D} This matrix. Useful for chaining method calls.
|
||||
**/
|
||||
reset = function() {
|
||||
if (this.hasInitialState) {
|
||||
return;
|
||||
}
|
||||
this.a = this.d = 1;
|
||||
this.b = this.c = this.tx = this.ty = 0;
|
||||
this.hasInitialState = true;
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -97,7 +98,6 @@ export default class Matrix2D {
|
||||
* @param {Number} d
|
||||
* @param {Number} tx
|
||||
* @param {Number} ty
|
||||
* @return {Matrix2D} This matrix. Useful for chaining method calls.
|
||||
**/
|
||||
append = function(a, b, c, d, tx, ty) {
|
||||
if (this.hasInitialState) {
|
||||
@@ -108,7 +108,7 @@ export default class Matrix2D {
|
||||
this.d = d;
|
||||
this.tx = tx;
|
||||
this.ty = ty;
|
||||
return this;
|
||||
return;
|
||||
}
|
||||
const a1 = this.a;
|
||||
const b1 = this.b;
|
||||
@@ -122,7 +122,6 @@ export default class Matrix2D {
|
||||
}
|
||||
this.tx = a1 * tx + c1 * ty + this.tx;
|
||||
this.ty = b1 * tx + d1 * ty + this.ty;
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -141,7 +140,6 @@ export default class Matrix2D {
|
||||
* @param {Number} skewY
|
||||
* @param {Number} regX Optional.
|
||||
* @param {Number} regY Optional.
|
||||
* @return {Matrix2D} This matrix. Useful for chaining method calls.
|
||||
**/
|
||||
appendTransform = function(
|
||||
x,
|
||||
@@ -154,6 +152,19 @@ export default class Matrix2D {
|
||||
regX,
|
||||
regY,
|
||||
) {
|
||||
if (
|
||||
x === 0 &&
|
||||
y === 0 &&
|
||||
scaleX === 1 &&
|
||||
scaleY === 1 &&
|
||||
rotation === 0 &&
|
||||
skewX === 0 &&
|
||||
skewY === 0 &&
|
||||
regX === 0 &&
|
||||
regY === 0
|
||||
) {
|
||||
return;
|
||||
}
|
||||
let cos, sin;
|
||||
if (rotation % 360) {
|
||||
const r = rotation * DEG_TO_RAD;
|
||||
@@ -182,6 +193,5 @@ export default class Matrix2D {
|
||||
this.tx -= regX * this.a + regY * this.c;
|
||||
this.ty -= regX * this.b + regY * this.d;
|
||||
}
|
||||
return this;
|
||||
};
|
||||
}
|
||||
|
||||
+24
-21
@@ -2,30 +2,33 @@ import extractColor from './extractColor';
|
||||
|
||||
const urlIdPattern = /^url\(#(.+?)\)$/;
|
||||
|
||||
export default function extractBrush(colorOrBrush) {
|
||||
if (!colorOrBrush || colorOrBrush === 'none') {
|
||||
const currentColorBrush = [2];
|
||||
|
||||
export default function extractBrush(color) {
|
||||
if (typeof color === 'number') {
|
||||
if (color >>> 0 === color && color >= 0 && color <= 0xffffffff) {
|
||||
return [0, color];
|
||||
}
|
||||
}
|
||||
|
||||
if (!color || color === 'none') {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (colorOrBrush === 'currentColor') {
|
||||
return [2];
|
||||
if (color === 'currentColor') {
|
||||
return currentColorBrush;
|
||||
}
|
||||
try {
|
||||
const matched = typeof colorOrBrush === 'string' && colorOrBrush.match(urlIdPattern);
|
||||
// brush
|
||||
if (matched) {
|
||||
return [1, matched[1]];
|
||||
} else {
|
||||
// solid color
|
||||
const color = extractColor(colorOrBrush);
|
||||
const r = color[0];
|
||||
const g = color[1];
|
||||
const b = color[2];
|
||||
const a = color[3];
|
||||
return [0, r, g, b, a === undefined ? 1 : a];
|
||||
}
|
||||
} catch (err) {
|
||||
console.warn(`"${colorOrBrush}" is not a valid color or brush`);
|
||||
return null;
|
||||
|
||||
const brush = typeof color === 'string' && color.match(urlIdPattern);
|
||||
if (brush) {
|
||||
return [1, brush[1]];
|
||||
}
|
||||
|
||||
const int32ARGBColor = extractColor(color);
|
||||
if (typeof int32ARGBColor === 'number') {
|
||||
return [0, int32ARGBColor];
|
||||
}
|
||||
|
||||
console.warn(`"${color}" is not a valid color or brush`);
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { Platform } from 'react-native';
|
||||
|
||||
export const colorNames = {
|
||||
aliceblue: [240, 248, 255],
|
||||
antiquewhite: [250, 235, 215],
|
||||
@@ -151,10 +153,20 @@ export const colorNames = {
|
||||
for (const name in colorNames) {
|
||||
if (colorNames.hasOwnProperty(name)) {
|
||||
const color = colorNames[name];
|
||||
for (let i = 0; i < 3; i++) {
|
||||
color[i] = color[i] / 255;
|
||||
const r = color[0];
|
||||
const g = color[1];
|
||||
const b = color[2];
|
||||
|
||||
let int32Color = (0xff000000 | (r << 16) | (g << 8) | b) >>> 0;
|
||||
|
||||
if (Platform.OS === 'android') {
|
||||
// Android use 32 bit *signed* integer to represent the color
|
||||
// We utilize the fact that bitwise operations in JS also operates on
|
||||
// signed 32 bit integers, so that we can use those to convert from
|
||||
// *unsigned* to *signed* 32bit int that way.
|
||||
int32Color = int32Color | 0x0;
|
||||
}
|
||||
Object.freeze(color);
|
||||
colorNames[name] = int32Color;
|
||||
}
|
||||
}
|
||||
Object.freeze(colorNames);
|
||||
@@ -390,11 +402,7 @@ function rgbFromHwbString(string) {
|
||||
return hwbToRgb([h, w, b, a]);
|
||||
}
|
||||
|
||||
export default function extractColor(string) {
|
||||
if (typeof string !== 'string') {
|
||||
return string;
|
||||
}
|
||||
|
||||
function colorFromString(string) {
|
||||
const prefix = string.substring(0, 3).toLowerCase();
|
||||
|
||||
switch (prefix) {
|
||||
@@ -406,3 +414,40 @@ export default function extractColor(string) {
|
||||
return rgbFromString(string);
|
||||
}
|
||||
}
|
||||
|
||||
// Returns 0xaarrggbb or null
|
||||
export default function extractColor(color) {
|
||||
if (typeof color === 'number') {
|
||||
if (color >>> 0 === color && color >= 0 && color <= 0xffffffff) {
|
||||
return color;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
const parsedColor =
|
||||
typeof color === 'string' ? colorFromString(color) : color;
|
||||
if (!Array.isArray(parsedColor)) {
|
||||
return parsedColor;
|
||||
}
|
||||
|
||||
const r = parsedColor[0];
|
||||
const g = parsedColor[1];
|
||||
const b = parsedColor[2];
|
||||
const a = parsedColor[3];
|
||||
|
||||
let int32Color =
|
||||
((a === undefined ? 0xff000000 : Math.round(a * 255) << 24) |
|
||||
(Math.round(r * 255) << 16) |
|
||||
(Math.round(g * 255) << 8) |
|
||||
Math.round(b * 255)) >>>
|
||||
0;
|
||||
|
||||
if (Platform.OS === 'android') {
|
||||
// Android use 32 bit *signed* integer to represent the color
|
||||
// We utilize the fact that bitwise operations in JS also operates on
|
||||
// signed 32 bit integers, so that we can use those to convert from
|
||||
// *unsigned* to *signed* 32bit int that way.
|
||||
int32Color = int32Color | 0x0;
|
||||
}
|
||||
return int32Color;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import extractBrush from './extractBrush';
|
||||
import extractOpacity from './extractOpacity';
|
||||
import { colorNames } from './extractColor';
|
||||
|
||||
const fillRules = {
|
||||
evenodd: 0,
|
||||
@@ -9,6 +10,9 @@ const fillRules = {
|
||||
const fillProps = ['fill', 'fillOpacity', 'fillRule'];
|
||||
const numFillProps = fillProps.length;
|
||||
|
||||
// default fill is black
|
||||
const defaultFill = [0, colorNames.black];
|
||||
|
||||
export default function extractFill(props, styleProperties) {
|
||||
for (let i = 0; i < numFillProps; i++) {
|
||||
const name = fillProps[i];
|
||||
@@ -17,10 +21,10 @@ export default function extractFill(props, styleProperties) {
|
||||
}
|
||||
}
|
||||
|
||||
const { fill, fillRule, fillOpacity } = props;
|
||||
return {
|
||||
// default fill is black
|
||||
fill: extractBrush(props.fill || '#000'),
|
||||
fillOpacity: extractOpacity(props.fillOpacity),
|
||||
fillRule: fillRules[props.fillRule] === 0 ? 0 : 1,
|
||||
fill: !fill && typeof fill !== 'number' ? defaultFill : extractBrush(fill),
|
||||
fillRule: fillRules[fillRule] === 0 ? 0 : 1,
|
||||
fillOpacity: extractOpacity(fillOpacity),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -46,34 +46,29 @@ export default function extractGradient(props, parent) {
|
||||
props: { offset, stopColor, stopOpacity },
|
||||
} = childArray[i];
|
||||
const offsetNumber = percentToFloat(offset);
|
||||
if (stopColor && !isNaN(offsetNumber)) {
|
||||
const color = extractColor(stopColor);
|
||||
if (!color) {
|
||||
console.warn(`"${stopColor}" is not a valid color`);
|
||||
continue;
|
||||
}
|
||||
const r = color[0];
|
||||
const g = color[1];
|
||||
const b = color[2];
|
||||
const a = extractOpacity(stopOpacity);
|
||||
stops.push([offsetNumber, r, g, b, a]);
|
||||
const color = stopColor && extractColor(stopColor);
|
||||
if (typeof color !== 'number' || isNaN(offsetNumber)) {
|
||||
console.warn(
|
||||
`"${stopColor}" is not a valid color or "${offset}" is not a valid offset`,
|
||||
);
|
||||
continue;
|
||||
}
|
||||
const alpha = Math.round(extractOpacity(stopOpacity) * 255);
|
||||
stops.push([offsetNumber, (color & 0x00ffffff) | (alpha << 24)]);
|
||||
}
|
||||
stops.sort(offsetComparator);
|
||||
|
||||
const colors = [];
|
||||
const offsets = [];
|
||||
const gradient = [];
|
||||
const k = stops.length;
|
||||
for (let j = 0; j < k; j++) {
|
||||
const s = stops[j];
|
||||
offsets.push(s[0]);
|
||||
colors.push(s[1], s[2], s[3], s[4]);
|
||||
gradient.push(s[0], s[1]);
|
||||
}
|
||||
|
||||
return {
|
||||
name: id,
|
||||
gradient,
|
||||
children: childArray,
|
||||
gradient: colors.concat(offsets),
|
||||
gradientUnits: units[gradientUnits] || 0,
|
||||
gradientTransform: extractTransform(
|
||||
gradientTransform || transform || props,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import extractFill from './extractFill';
|
||||
import extractStroke from './extractStroke';
|
||||
import extractTransform, { props2transform } from './extractTransform';
|
||||
import { transformToMatrix, props2transform } from './extractTransform';
|
||||
import extractClipPath from './extractClipPath';
|
||||
import extractResponder from './extractResponder';
|
||||
import extractOpacity from './extractOpacity';
|
||||
@@ -17,13 +17,14 @@ export function propsAndStyles(props) {
|
||||
export default function extractProps(props, ref) {
|
||||
const { opacity, onLayout, id, clipPath, mask } = props;
|
||||
const styleProperties = [];
|
||||
|
||||
const transformProps = props2transform(props);
|
||||
const matrix = transformToMatrix(transformProps, props.transform);
|
||||
const extractedProps = {
|
||||
matrix,
|
||||
onLayout,
|
||||
...transformProps,
|
||||
propList: styleProperties,
|
||||
opacity: extractOpacity(opacity),
|
||||
matrix: extractTransform(props),
|
||||
...props2transform(props),
|
||||
...extractResponder(props, ref),
|
||||
...extractFill(props, styleProperties),
|
||||
...extractStroke(props, styleProperties),
|
||||
|
||||
@@ -17,7 +17,7 @@ function appendTransform(props) {
|
||||
);
|
||||
}
|
||||
|
||||
function transformToMatrix(props, transform) {
|
||||
export function transformToMatrix(props, transform) {
|
||||
pooledMatrix.reset();
|
||||
appendTransform(props);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user