mirror of
https://github.com/zoriya/react-native-svg.git
synced 2025-12-05 22:56:11 +00:00
chore: add CI for JS, iOS and Android formatting (#1782)
Added CI workflow and local pre-commit hook for formatting and linting the newly added JS, iOS and Android code.
This commit is contained in:
91
.clang-format
Normal file
91
.clang-format
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
---
|
||||||
|
AccessModifierOffset: -1
|
||||||
|
AlignAfterOpenBracket: AlwaysBreak
|
||||||
|
AlignConsecutiveAssignments: false
|
||||||
|
AlignConsecutiveDeclarations: false
|
||||||
|
AlignEscapedNewlinesLeft: true
|
||||||
|
AlignOperands: false
|
||||||
|
AlignTrailingComments: false
|
||||||
|
AllowAllParametersOfDeclarationOnNextLine: false
|
||||||
|
AllowShortBlocksOnASingleLine: false
|
||||||
|
AllowShortCaseLabelsOnASingleLine: false
|
||||||
|
AllowShortFunctionsOnASingleLine: Empty
|
||||||
|
AllowShortIfStatementsOnASingleLine: false
|
||||||
|
AllowShortLoopsOnASingleLine: false
|
||||||
|
AlwaysBreakAfterReturnType: None
|
||||||
|
AlwaysBreakBeforeMultilineStrings: true
|
||||||
|
AlwaysBreakTemplateDeclarations: true
|
||||||
|
BinPackArguments: false
|
||||||
|
BinPackParameters: false
|
||||||
|
BraceWrapping:
|
||||||
|
AfterClass: false
|
||||||
|
AfterControlStatement: false
|
||||||
|
AfterEnum: false
|
||||||
|
AfterFunction: false
|
||||||
|
AfterNamespace: false
|
||||||
|
AfterObjCDeclaration: false
|
||||||
|
AfterStruct: false
|
||||||
|
AfterUnion: false
|
||||||
|
BeforeCatch: false
|
||||||
|
BeforeElse: false
|
||||||
|
IndentBraces: false
|
||||||
|
BreakBeforeBinaryOperators: None
|
||||||
|
BreakBeforeBraces: Attach
|
||||||
|
BreakBeforeTernaryOperators: true
|
||||||
|
BreakConstructorInitializersBeforeComma: false
|
||||||
|
BreakAfterJavaFieldAnnotations: false
|
||||||
|
BreakStringLiterals: false
|
||||||
|
ColumnLimit: 80
|
||||||
|
CommentPragmas: '^ IWYU pragma:'
|
||||||
|
ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
||||||
|
ConstructorInitializerIndentWidth: 4
|
||||||
|
ContinuationIndentWidth: 4
|
||||||
|
Cpp11BracedListStyle: true
|
||||||
|
DerivePointerAlignment: false
|
||||||
|
DisableFormat: false
|
||||||
|
ForEachMacros: [ FOR_EACH_RANGE, FOR_EACH, ]
|
||||||
|
IncludeCategories:
|
||||||
|
- Regex: '^<.*\.h(pp)?>'
|
||||||
|
Priority: 1
|
||||||
|
- Regex: '^<.*'
|
||||||
|
Priority: 2
|
||||||
|
- Regex: '.*'
|
||||||
|
Priority: 3
|
||||||
|
IndentCaseLabels: true
|
||||||
|
IndentWidth: 2
|
||||||
|
IndentWrappedFunctionNames: false
|
||||||
|
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||||
|
MacroBlockBegin: ''
|
||||||
|
MacroBlockEnd: ''
|
||||||
|
MaxEmptyLinesToKeep: 1
|
||||||
|
NamespaceIndentation: None
|
||||||
|
ObjCBlockIndentWidth: 2
|
||||||
|
ObjCSpaceAfterProperty: true
|
||||||
|
ObjCSpaceBeforeProtocolList: true
|
||||||
|
PenaltyBreakBeforeFirstCallParameter: 1
|
||||||
|
PenaltyBreakComment: 300
|
||||||
|
PenaltyBreakFirstLessLess: 120
|
||||||
|
PenaltyBreakString: 1000
|
||||||
|
PenaltyExcessCharacter: 1000000
|
||||||
|
PenaltyReturnTypeOnItsOwnLine: 200
|
||||||
|
PointerAlignment: Right
|
||||||
|
ReflowComments: true
|
||||||
|
SortIncludes: true
|
||||||
|
SpaceAfterCStyleCast: false
|
||||||
|
SpaceBeforeAssignmentOperators: true
|
||||||
|
SpaceBeforeParens: ControlStatements
|
||||||
|
SpaceInEmptyParentheses: false
|
||||||
|
SpacesBeforeTrailingComments: 1
|
||||||
|
SpacesInAngles: false
|
||||||
|
SpacesInContainerLiterals: true
|
||||||
|
SpacesInCStyleCastParentheses: false
|
||||||
|
SpacesInParentheses: false
|
||||||
|
SpacesInSquareBrackets: false
|
||||||
|
Standard: Cpp11
|
||||||
|
TabWidth: 8
|
||||||
|
UseTab: Never
|
||||||
|
---
|
||||||
|
Language: ObjC
|
||||||
|
ColumnLimit: 120
|
||||||
|
BreakBeforeBraces: WebKit
|
||||||
|
...
|
||||||
6
.github/workflows/js-build-test.yml
vendored
6
.github/workflows/js-build-test.yml
vendored
@@ -25,10 +25,8 @@ jobs:
|
|||||||
run: yarn
|
run: yarn
|
||||||
- name: Build
|
- name: Build
|
||||||
run: yarn bob
|
run: yarn bob
|
||||||
- name: Lint
|
- name: Test and lint
|
||||||
run: yarn lint
|
run: yarn test
|
||||||
- name: Tests
|
|
||||||
run: yarn jest
|
|
||||||
- name: Build Example App
|
- name: Build Example App
|
||||||
working-directory: Example/
|
working-directory: Example/
|
||||||
run: yarn && yarn tsc
|
run: yarn && yarn tsc
|
||||||
|
|||||||
4
.husky/pre-commit
Executable file
4
.husky/pre-commit
Executable file
@@ -0,0 +1,4 @@
|
|||||||
|
#!/usr/bin/env sh
|
||||||
|
. "$(dirname -- "$0")/_/husky.sh"
|
||||||
|
|
||||||
|
yarn lint-staged
|
||||||
@@ -501,7 +501,7 @@ SPEC CHECKSUMS:
|
|||||||
CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99
|
CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99
|
||||||
DoubleConversion: 831926d9b8bf8166fd87886c4abab286c2422662
|
DoubleConversion: 831926d9b8bf8166fd87886c4abab286c2422662
|
||||||
FBLazyVector: bcdeff523be9f87a135b7c6fde8736db94904716
|
FBLazyVector: bcdeff523be9f87a135b7c6fde8736db94904716
|
||||||
FBReactNativeSpec: 226f8b0f1a2e736a49301883ee34bca88cdc24f6
|
FBReactNativeSpec: 0c3f104f594b34d7b3a923cd12e03b0d4e12eaf5
|
||||||
Flipper: 26fc4b7382499f1281eb8cb921e5c3ad6de91fe0
|
Flipper: 26fc4b7382499f1281eb8cb921e5c3ad6de91fe0
|
||||||
Flipper-Boost-iOSX: fd1e2b8cbef7e662a122412d7ac5f5bea715403c
|
Flipper-Boost-iOSX: fd1e2b8cbef7e662a122412d7ac5f5bea715403c
|
||||||
Flipper-DoubleConversion: 57ffbe81ef95306cc9e69c4aa3aeeeeb58a6a28c
|
Flipper-DoubleConversion: 57ffbe81ef95306cc9e69c4aa3aeeeeb58a6a28c
|
||||||
|
|||||||
26
USAGE.md
26
USAGE.md
@@ -105,14 +105,14 @@ export default function TestComponent() {
|
|||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<SvgUri
|
<SvgUri
|
||||||
width="100"
|
width="100"
|
||||||
height="100"
|
height="100"
|
||||||
uri="https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/ruby.svg"
|
uri="https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/ruby.svg"
|
||||||
onError={onError}
|
onError={onError}
|
||||||
onLoad={onLoad}
|
onLoad={onLoad}
|
||||||
/>
|
/>
|
||||||
{loading && <ActivityIndicator size="large" color="#0000ff"/>}
|
{loading && <ActivityIndicator size="large" color="#0000ff" />}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -129,16 +129,20 @@ import * as React from 'react';
|
|||||||
import { SvgUri } from 'react-native-svg';
|
import { SvgUri } from 'react-native-svg';
|
||||||
|
|
||||||
export default () => {
|
export default () => {
|
||||||
const [uri, setUri] = React.useState('https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/not_existing.svg')
|
const [uri, setUri] = React.useState(
|
||||||
|
'https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/not_existing.svg',
|
||||||
|
);
|
||||||
return (
|
return (
|
||||||
<SvgUri
|
<SvgUri
|
||||||
onError={() => setUri('https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/ruby.svg')}
|
onError={() =>
|
||||||
|
setUri('https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/ruby.svg')
|
||||||
|
}
|
||||||
width="100%"
|
width="100%"
|
||||||
height="100%"
|
height="100%"
|
||||||
uri={uri}
|
uri={uri}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
# Use with svg files
|
# Use with svg files
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ buildscript {
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath("com.android.tools.build:gradle:3.6.1")
|
classpath("com.android.tools.build:gradle:3.6.1")
|
||||||
|
classpath "com.diffplug.spotless:spotless-plugin-gradle:5.15.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -26,6 +27,10 @@ if (isNewArchitectureEnabled()) {
|
|||||||
apply plugin: "com.facebook.react"
|
apply plugin: "com.facebook.react"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (project == rootProject) {
|
||||||
|
apply from: 'spotless.gradle'
|
||||||
|
}
|
||||||
|
|
||||||
apply plugin: 'com.android.library'
|
apply plugin: 'com.android.library'
|
||||||
|
|
||||||
def safeExtGet(prop, fallback) {
|
def safeExtGet(prop, fallback) {
|
||||||
|
|||||||
BIN
android/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
android/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
5
android/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
5
android/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
distributionBase=GRADLE_USER_HOME
|
||||||
|
distributionPath=wrapper/dists
|
||||||
|
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip
|
||||||
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
zipStorePath=wrapper/dists
|
||||||
240
android/gradlew
vendored
Executable file
240
android/gradlew
vendored
Executable file
@@ -0,0 +1,240 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
#
|
||||||
|
# Copyright © 2015-2021 the original authors.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
#
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
#
|
||||||
|
# Gradle start up script for POSIX generated by Gradle.
|
||||||
|
#
|
||||||
|
# Important for running:
|
||||||
|
#
|
||||||
|
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
|
||||||
|
# noncompliant, but you have some other compliant shell such as ksh or
|
||||||
|
# bash, then to run this script, type that shell name before the whole
|
||||||
|
# command line, like:
|
||||||
|
#
|
||||||
|
# ksh Gradle
|
||||||
|
#
|
||||||
|
# Busybox and similar reduced shells will NOT work, because this script
|
||||||
|
# requires all of these POSIX shell features:
|
||||||
|
# * functions;
|
||||||
|
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
|
||||||
|
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
|
||||||
|
# * compound commands having a testable exit status, especially «case»;
|
||||||
|
# * various built-in commands including «command», «set», and «ulimit».
|
||||||
|
#
|
||||||
|
# Important for patching:
|
||||||
|
#
|
||||||
|
# (2) This script targets any POSIX shell, so it avoids extensions provided
|
||||||
|
# by Bash, Ksh, etc; in particular arrays are avoided.
|
||||||
|
#
|
||||||
|
# The "traditional" practice of packing multiple parameters into a
|
||||||
|
# space-separated string is a well documented source of bugs and security
|
||||||
|
# problems, so this is (mostly) avoided, by progressively accumulating
|
||||||
|
# options in "$@", and eventually passing that to Java.
|
||||||
|
#
|
||||||
|
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
|
||||||
|
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
|
||||||
|
# see the in-line comments for details.
|
||||||
|
#
|
||||||
|
# There are tweaks for specific operating systems such as AIX, CygWin,
|
||||||
|
# Darwin, MinGW, and NonStop.
|
||||||
|
#
|
||||||
|
# (3) This script is generated from the Groovy template
|
||||||
|
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||||
|
# within the Gradle project.
|
||||||
|
#
|
||||||
|
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||||
|
#
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
# Attempt to set APP_HOME
|
||||||
|
|
||||||
|
# Resolve links: $0 may be a link
|
||||||
|
app_path=$0
|
||||||
|
|
||||||
|
# Need this for daisy-chained symlinks.
|
||||||
|
while
|
||||||
|
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
|
||||||
|
[ -h "$app_path" ]
|
||||||
|
do
|
||||||
|
ls=$( ls -ld "$app_path" )
|
||||||
|
link=${ls#*' -> '}
|
||||||
|
case $link in #(
|
||||||
|
/*) app_path=$link ;; #(
|
||||||
|
*) app_path=$APP_HOME$link ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
||||||
|
|
||||||
|
APP_NAME="Gradle"
|
||||||
|
APP_BASE_NAME=${0##*/}
|
||||||
|
|
||||||
|
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
|
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||||
|
|
||||||
|
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||||
|
MAX_FD=maximum
|
||||||
|
|
||||||
|
warn () {
|
||||||
|
echo "$*"
|
||||||
|
} >&2
|
||||||
|
|
||||||
|
die () {
|
||||||
|
echo
|
||||||
|
echo "$*"
|
||||||
|
echo
|
||||||
|
exit 1
|
||||||
|
} >&2
|
||||||
|
|
||||||
|
# OS specific support (must be 'true' or 'false').
|
||||||
|
cygwin=false
|
||||||
|
msys=false
|
||||||
|
darwin=false
|
||||||
|
nonstop=false
|
||||||
|
case "$( uname )" in #(
|
||||||
|
CYGWIN* ) cygwin=true ;; #(
|
||||||
|
Darwin* ) darwin=true ;; #(
|
||||||
|
MSYS* | MINGW* ) msys=true ;; #(
|
||||||
|
NONSTOP* ) nonstop=true ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||||
|
|
||||||
|
|
||||||
|
# Determine the Java command to use to start the JVM.
|
||||||
|
if [ -n "$JAVA_HOME" ] ; then
|
||||||
|
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||||
|
# IBM's JDK on AIX uses strange locations for the executables
|
||||||
|
JAVACMD=$JAVA_HOME/jre/sh/java
|
||||||
|
else
|
||||||
|
JAVACMD=$JAVA_HOME/bin/java
|
||||||
|
fi
|
||||||
|
if [ ! -x "$JAVACMD" ] ; then
|
||||||
|
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||||
|
|
||||||
|
Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
location of your Java installation."
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
JAVACMD=java
|
||||||
|
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||||
|
|
||||||
|
Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
location of your Java installation."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Increase the maximum file descriptors if we can.
|
||||||
|
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||||
|
case $MAX_FD in #(
|
||||||
|
max*)
|
||||||
|
MAX_FD=$( ulimit -H -n ) ||
|
||||||
|
warn "Could not query maximum file descriptor limit"
|
||||||
|
esac
|
||||||
|
case $MAX_FD in #(
|
||||||
|
'' | soft) :;; #(
|
||||||
|
*)
|
||||||
|
ulimit -n "$MAX_FD" ||
|
||||||
|
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Collect all arguments for the java command, stacking in reverse order:
|
||||||
|
# * args from the command line
|
||||||
|
# * the main class name
|
||||||
|
# * -classpath
|
||||||
|
# * -D...appname settings
|
||||||
|
# * --module-path (only if needed)
|
||||||
|
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
|
||||||
|
|
||||||
|
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||||
|
if "$cygwin" || "$msys" ; then
|
||||||
|
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||||
|
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
||||||
|
|
||||||
|
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||||
|
|
||||||
|
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||||
|
for arg do
|
||||||
|
if
|
||||||
|
case $arg in #(
|
||||||
|
-*) false ;; # don't mess with options #(
|
||||||
|
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
|
||||||
|
[ -e "$t" ] ;; #(
|
||||||
|
*) false ;;
|
||||||
|
esac
|
||||||
|
then
|
||||||
|
arg=$( cygpath --path --ignore --mixed "$arg" )
|
||||||
|
fi
|
||||||
|
# Roll the args list around exactly as many times as the number of
|
||||||
|
# args, so each arg winds up back in the position where it started, but
|
||||||
|
# possibly modified.
|
||||||
|
#
|
||||||
|
# NB: a `for` loop captures its iteration list before it begins, so
|
||||||
|
# changing the positional parameters here affects neither the number of
|
||||||
|
# iterations, nor the values presented in `arg`.
|
||||||
|
shift # remove old arg
|
||||||
|
set -- "$@" "$arg" # push replacement arg
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Collect all arguments for the java command;
|
||||||
|
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
|
||||||
|
# shell script including quotes and variable substitutions, so put them in
|
||||||
|
# double quotes to make sure that they get re-expanded; and
|
||||||
|
# * put everything else in single quotes, so that it's not re-expanded.
|
||||||
|
|
||||||
|
set -- \
|
||||||
|
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||||
|
-classpath "$CLASSPATH" \
|
||||||
|
org.gradle.wrapper.GradleWrapperMain \
|
||||||
|
"$@"
|
||||||
|
|
||||||
|
# Stop when "xargs" is not available.
|
||||||
|
if ! command -v xargs >/dev/null 2>&1
|
||||||
|
then
|
||||||
|
die "xargs is not available"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Use "xargs" to parse quoted args.
|
||||||
|
#
|
||||||
|
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||||
|
#
|
||||||
|
# In Bash we could simply go:
|
||||||
|
#
|
||||||
|
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
|
||||||
|
# set -- "${ARGS[@]}" "$@"
|
||||||
|
#
|
||||||
|
# but POSIX shell has neither arrays nor command substitution, so instead we
|
||||||
|
# post-process each arg (as a line of input to sed) to backslash-escape any
|
||||||
|
# character that might be a shell metacharacter, then use eval to reverse
|
||||||
|
# that process (while maintaining the separation between arguments), and wrap
|
||||||
|
# the whole thing up as a single "set" statement.
|
||||||
|
#
|
||||||
|
# This will of course break if any of these variables contains a newline or
|
||||||
|
# an unmatched quote.
|
||||||
|
#
|
||||||
|
|
||||||
|
eval "set -- $(
|
||||||
|
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
|
||||||
|
xargs -n1 |
|
||||||
|
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
|
||||||
|
tr '\n' ' '
|
||||||
|
)" '"$@"'
|
||||||
|
|
||||||
|
exec "$JAVACMD" "$@"
|
||||||
91
android/gradlew.bat
vendored
Normal file
91
android/gradlew.bat
vendored
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
@rem
|
||||||
|
@rem Copyright 2015 the original author or authors.
|
||||||
|
@rem
|
||||||
|
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
@rem you may not use this file except in compliance with the License.
|
||||||
|
@rem You may obtain a copy of the License at
|
||||||
|
@rem
|
||||||
|
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
@rem
|
||||||
|
@rem Unless required by applicable law or agreed to in writing, software
|
||||||
|
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@rem See the License for the specific language governing permissions and
|
||||||
|
@rem limitations under the License.
|
||||||
|
@rem
|
||||||
|
|
||||||
|
@if "%DEBUG%"=="" @echo off
|
||||||
|
@rem ##########################################################################
|
||||||
|
@rem
|
||||||
|
@rem Gradle startup script for Windows
|
||||||
|
@rem
|
||||||
|
@rem ##########################################################################
|
||||||
|
|
||||||
|
@rem Set local scope for the variables with windows NT shell
|
||||||
|
if "%OS%"=="Windows_NT" setlocal
|
||||||
|
|
||||||
|
set DIRNAME=%~dp0
|
||||||
|
if "%DIRNAME%"=="" set DIRNAME=.
|
||||||
|
set APP_BASE_NAME=%~n0
|
||||||
|
set APP_HOME=%DIRNAME%
|
||||||
|
|
||||||
|
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||||
|
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||||
|
|
||||||
|
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
|
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||||
|
|
||||||
|
@rem Find java.exe
|
||||||
|
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||||
|
|
||||||
|
set JAVA_EXE=java.exe
|
||||||
|
%JAVA_EXE% -version >NUL 2>&1
|
||||||
|
if %ERRORLEVEL% equ 0 goto execute
|
||||||
|
|
||||||
|
echo.
|
||||||
|
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||||
|
echo.
|
||||||
|
echo Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
echo location of your Java installation.
|
||||||
|
|
||||||
|
goto fail
|
||||||
|
|
||||||
|
:findJavaFromJavaHome
|
||||||
|
set JAVA_HOME=%JAVA_HOME:"=%
|
||||||
|
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||||
|
|
||||||
|
if exist "%JAVA_EXE%" goto execute
|
||||||
|
|
||||||
|
echo.
|
||||||
|
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||||
|
echo.
|
||||||
|
echo Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
echo location of your Java installation.
|
||||||
|
|
||||||
|
goto fail
|
||||||
|
|
||||||
|
:execute
|
||||||
|
@rem Setup the command line
|
||||||
|
|
||||||
|
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||||
|
|
||||||
|
|
||||||
|
@rem Execute Gradle
|
||||||
|
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||||
|
|
||||||
|
:end
|
||||||
|
@rem End local scope for the variables with windows NT shell
|
||||||
|
if %ERRORLEVEL% equ 0 goto mainEnd
|
||||||
|
|
||||||
|
:fail
|
||||||
|
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||||
|
rem the _cmd.exe /c_ return code!
|
||||||
|
set EXIT_CODE=%ERRORLEVEL%
|
||||||
|
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
||||||
|
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
||||||
|
exit /b %EXIT_CODE%
|
||||||
|
|
||||||
|
:mainEnd
|
||||||
|
if "%OS%"=="Windows_NT" endlocal
|
||||||
|
|
||||||
|
:omega
|
||||||
9
android/spotless.gradle
Normal file
9
android/spotless.gradle
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
// formatter & linter configuration for java
|
||||||
|
apply plugin: 'com.diffplug.spotless'
|
||||||
|
|
||||||
|
spotless {
|
||||||
|
java {
|
||||||
|
target 'src/fabric/**/*.java', 'src/main/java/**/*.java', 'src/paper/java/com/horcrux/svg/**/*.java'
|
||||||
|
googleJavaFormat()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,59 +1,62 @@
|
|||||||
package com.horcrux.svg;
|
package com.horcrux.svg;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.view.ViewGroup;
|
|
||||||
import androidx.annotation.UiThread;
|
import androidx.annotation.UiThread;
|
||||||
import com.facebook.react.bridge.ReactContext;
|
import com.facebook.react.bridge.ReactContext;
|
||||||
import com.facebook.react.bridge.ReadableMap;
|
import com.facebook.react.bridge.ReadableMap;
|
||||||
import com.facebook.react.bridge.WritableMap;
|
import com.facebook.react.bridge.WritableMap;
|
||||||
import com.facebook.react.bridge.WritableNativeMap;
|
import com.facebook.react.bridge.WritableNativeMap;
|
||||||
import com.facebook.react.uimanager.FabricViewStateManager;
|
import com.facebook.react.uimanager.FabricViewStateManager;
|
||||||
import com.facebook.react.uimanager.PixelUtil;
|
|
||||||
import com.facebook.react.uimanager.FabricViewStateManager.HasFabricViewStateManager;
|
import com.facebook.react.uimanager.FabricViewStateManager.HasFabricViewStateManager;
|
||||||
import com.facebook.react.uimanager.FabricViewStateManager.StateUpdateCallback;
|
import com.facebook.react.uimanager.FabricViewStateManager.StateUpdateCallback;
|
||||||
|
import com.facebook.react.uimanager.PixelUtil;
|
||||||
import com.facebook.react.views.view.ReactViewGroup;
|
import com.facebook.react.views.view.ReactViewGroup;
|
||||||
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
public abstract class FabricEnabledViewGroup extends ReactViewGroup implements HasFabricViewStateManager {
|
public abstract class FabricEnabledViewGroup extends ReactViewGroup
|
||||||
private final FabricViewStateManager mFabricViewStateManager = new FabricViewStateManager();
|
implements HasFabricViewStateManager {
|
||||||
|
private final FabricViewStateManager mFabricViewStateManager = new FabricViewStateManager();
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public FabricViewStateManager getFabricViewStateManager() {
|
public FabricViewStateManager getFabricViewStateManager() {
|
||||||
return this.mFabricViewStateManager;
|
return this.mFabricViewStateManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected final void updateScreenSizeFabric(int width, int height) {
|
protected final void updateScreenSizeFabric(int width, int height) {
|
||||||
this.updateState(width, height);
|
this.updateState(width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
@UiThread
|
@UiThread
|
||||||
public final void updateState(int width, int height) {
|
public final void updateState(int width, int height) {
|
||||||
final float realWidth = PixelUtil.toDIPFromPixel((float)width);
|
final float realWidth = PixelUtil.toDIPFromPixel((float) width);
|
||||||
final float realHeight = PixelUtil.toDIPFromPixel((float)height);
|
final float realHeight = PixelUtil.toDIPFromPixel((float) height);
|
||||||
ReadableMap currentState = this.mFabricViewStateManager.getStateData();
|
ReadableMap currentState = this.mFabricViewStateManager.getStateData();
|
||||||
if (currentState != null) {
|
if (currentState != null) {
|
||||||
float delta = 0.9F;
|
float delta = 0.9F;
|
||||||
float stateFrameHeight = currentState.hasKey("frameHeight") ? (float)currentState.getDouble("frameHeight") : 0.0F;
|
float stateFrameHeight =
|
||||||
float stateFrameWidth = currentState.hasKey("frameWidth") ? (float)currentState.getDouble("frameWidth") : 0.0F;
|
currentState.hasKey("frameHeight") ? (float) currentState.getDouble("frameHeight") : 0.0F;
|
||||||
if (Math.abs(stateFrameWidth - realWidth) < delta &&
|
float stateFrameWidth =
|
||||||
Math.abs(stateFrameHeight - realHeight) < delta) {
|
currentState.hasKey("frameWidth") ? (float) currentState.getDouble("frameWidth") : 0.0F;
|
||||||
return;
|
if (Math.abs(stateFrameWidth - realWidth) < delta
|
||||||
}
|
&& Math.abs(stateFrameHeight - realHeight) < delta) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this.mFabricViewStateManager.setState((StateUpdateCallback)(new StateUpdateCallback() {
|
this.mFabricViewStateManager.setState(
|
||||||
public final WritableMap getStateUpdate() {
|
(StateUpdateCallback)
|
||||||
WritableMap map = (WritableMap)(new WritableNativeMap());
|
(new StateUpdateCallback() {
|
||||||
map.putDouble("frameWidth", (double)realWidth);
|
public final WritableMap getStateUpdate() {
|
||||||
map.putDouble("frameHeight", (double)realHeight);
|
WritableMap map = (WritableMap) (new WritableNativeMap());
|
||||||
return map;
|
map.putDouble("frameWidth", (double) realWidth);
|
||||||
}
|
map.putDouble("frameHeight", (double) realHeight);
|
||||||
}));
|
return map;
|
||||||
}
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
public FabricEnabledViewGroup(@Nullable ReactContext context) {
|
public FabricEnabledViewGroup(@Nullable ReactContext context) {
|
||||||
super((Context)context);
|
super((Context) context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,6 @@
|
|||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
package com.horcrux.svg;
|
package com.horcrux.svg;
|
||||||
|
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
@@ -19,215 +18,214 @@ import android.graphics.RadialGradient;
|
|||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.graphics.RectF;
|
import android.graphics.RectF;
|
||||||
import android.graphics.Shader;
|
import android.graphics.Shader;
|
||||||
|
|
||||||
import com.facebook.common.logging.FLog;
|
import com.facebook.common.logging.FLog;
|
||||||
import com.facebook.react.bridge.ReadableArray;
|
import com.facebook.react.bridge.ReadableArray;
|
||||||
import com.facebook.react.common.ReactConstants;
|
import com.facebook.react.common.ReactConstants;
|
||||||
|
|
||||||
class Brush {
|
class Brush {
|
||||||
private final BrushType mType;
|
private final BrushType mType;
|
||||||
private final SVGLength[] mPoints;
|
private final SVGLength[] mPoints;
|
||||||
private ReadableArray mColors;
|
private ReadableArray mColors;
|
||||||
private final boolean mUseObjectBoundingBox;
|
private final boolean mUseObjectBoundingBox;
|
||||||
|
|
||||||
// TODO implement pattern units
|
// TODO implement pattern units
|
||||||
@SuppressWarnings({"unused"})
|
@SuppressWarnings({"unused"})
|
||||||
private boolean mUseContentObjectBoundingBoxUnits;
|
private boolean mUseContentObjectBoundingBoxUnits;
|
||||||
|
|
||||||
private Matrix mMatrix;
|
private Matrix mMatrix;
|
||||||
private Rect mUserSpaceBoundingBox;
|
private Rect mUserSpaceBoundingBox;
|
||||||
private PatternView mPattern;
|
private PatternView mPattern;
|
||||||
|
|
||||||
Brush(BrushType type, SVGLength[] points, BrushUnits units) {
|
Brush(BrushType type, SVGLength[] points, BrushUnits units) {
|
||||||
mType = type;
|
mType = type;
|
||||||
mPoints = points;
|
mPoints = points;
|
||||||
mUseObjectBoundingBox = units == BrushUnits.OBJECT_BOUNDING_BOX;
|
mUseObjectBoundingBox = units == BrushUnits.OBJECT_BOUNDING_BOX;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setContentUnits(BrushUnits units) {
|
||||||
|
mUseContentObjectBoundingBoxUnits = units == BrushUnits.OBJECT_BOUNDING_BOX;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setPattern(PatternView pattern) {
|
||||||
|
mPattern = pattern;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum BrushType {
|
||||||
|
LINEAR_GRADIENT,
|
||||||
|
RADIAL_GRADIENT,
|
||||||
|
PATTERN
|
||||||
|
}
|
||||||
|
|
||||||
|
enum BrushUnits {
|
||||||
|
OBJECT_BOUNDING_BOX,
|
||||||
|
USER_SPACE_ON_USE
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void parseGradientStops(
|
||||||
|
ReadableArray value, int stopsCount, float[] stops, int[] stopsColors, float opacity) {
|
||||||
|
for (int i = 0; i < stopsCount; i++) {
|
||||||
|
int stopIndex = i * 2;
|
||||||
|
stops[i] = (float) value.getDouble(stopIndex);
|
||||||
|
int color = value.getInt(stopIndex + 1);
|
||||||
|
int alpha = color >>> 24;
|
||||||
|
int combined = Math.round((float) alpha * opacity);
|
||||||
|
stopsColors[i] = combined << 24 | (color & 0x00ffffff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setUserSpaceBoundingBox(Rect userSpaceBoundingBox) {
|
||||||
|
mUserSpaceBoundingBox = userSpaceBoundingBox;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setGradientColors(ReadableArray colors) {
|
||||||
|
mColors = colors;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setGradientTransform(Matrix matrix) {
|
||||||
|
mMatrix = matrix;
|
||||||
|
}
|
||||||
|
|
||||||
|
private RectF getPaintRect(RectF pathBoundingBox) {
|
||||||
|
RectF rect = mUseObjectBoundingBox ? pathBoundingBox : new RectF(mUserSpaceBoundingBox);
|
||||||
|
float width = rect.width();
|
||||||
|
float height = rect.height();
|
||||||
|
float x = 0f;
|
||||||
|
float y = 0f;
|
||||||
|
|
||||||
|
if (mUseObjectBoundingBox) {
|
||||||
|
x = rect.left;
|
||||||
|
y = rect.top;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setContentUnits(BrushUnits units) {
|
return new RectF(x, y, x + width, y + height);
|
||||||
mUseContentObjectBoundingBoxUnits = units == BrushUnits.OBJECT_BOUNDING_BOX;
|
}
|
||||||
|
|
||||||
|
private double getVal(SVGLength length, double relative, float scale, float textSize) {
|
||||||
|
return PropHelper.fromRelative(
|
||||||
|
length,
|
||||||
|
relative,
|
||||||
|
0,
|
||||||
|
mUseObjectBoundingBox && length.unit == SVGLength.UnitType.NUMBER ? relative : scale,
|
||||||
|
textSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setupPaint(Paint paint, RectF pathBoundingBox, float scale, float opacity) {
|
||||||
|
RectF rect = getPaintRect(pathBoundingBox);
|
||||||
|
float width = rect.width();
|
||||||
|
float height = rect.height();
|
||||||
|
float offsetX = rect.left;
|
||||||
|
float offsetY = rect.top;
|
||||||
|
|
||||||
|
float textSize = paint.getTextSize();
|
||||||
|
if (mType == BrushType.PATTERN) {
|
||||||
|
double x = getVal(mPoints[0], width, scale, textSize);
|
||||||
|
double y = getVal(mPoints[1], height, scale, textSize);
|
||||||
|
double w = getVal(mPoints[2], width, scale, textSize);
|
||||||
|
double h = getVal(mPoints[3], height, scale, textSize);
|
||||||
|
|
||||||
|
if (!(w > 1 && h > 1)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Bitmap bitmap = Bitmap.createBitmap((int) w, (int) h, Bitmap.Config.ARGB_8888);
|
||||||
|
Canvas canvas = new Canvas(bitmap);
|
||||||
|
|
||||||
|
RectF vbRect = mPattern.getViewBox();
|
||||||
|
if (vbRect != null && vbRect.width() > 0 && vbRect.height() > 0) {
|
||||||
|
RectF eRect = new RectF((float) x, (float) y, (float) w, (float) h);
|
||||||
|
Matrix mViewBoxMatrix =
|
||||||
|
ViewBox.getTransform(vbRect, eRect, mPattern.mAlign, mPattern.mMeetOrSlice);
|
||||||
|
canvas.concat(mViewBoxMatrix);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mUseContentObjectBoundingBoxUnits) {
|
||||||
|
canvas.scale(width / scale, height / scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
mPattern.draw(canvas, new Paint(), opacity);
|
||||||
|
|
||||||
|
Matrix patternMatrix = new Matrix();
|
||||||
|
if (mMatrix != null) {
|
||||||
|
patternMatrix.preConcat(mMatrix);
|
||||||
|
}
|
||||||
|
|
||||||
|
BitmapShader bitmapShader =
|
||||||
|
new BitmapShader(bitmap, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);
|
||||||
|
bitmapShader.setLocalMatrix(patternMatrix);
|
||||||
|
paint.setShader(bitmapShader);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setPattern(PatternView pattern) {
|
int size = mColors.size();
|
||||||
mPattern = pattern;
|
if (size == 0) {
|
||||||
|
FLog.w(ReactConstants.TAG, "Gradient contains no stops");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int stopsCount = size / 2;
|
||||||
|
int[] stopsColors = new int[stopsCount];
|
||||||
|
float[] stops = new float[stopsCount];
|
||||||
|
parseGradientStops(mColors, stopsCount, stops, stopsColors, opacity);
|
||||||
|
|
||||||
|
if (stops.length == 1) {
|
||||||
|
// Gradient with only one stop will make LinearGradient/RadialGradient
|
||||||
|
// throw. It may happen when source SVG contains only one stop or
|
||||||
|
// two stops at the same spot (see lib/extract/extractGradient.js).
|
||||||
|
// Although it's mistake SVGs like this can be produced by vector
|
||||||
|
// editors or other tools, so let's handle that gracefully.
|
||||||
|
stopsColors = new int[] {stopsColors[0], stopsColors[0]};
|
||||||
|
stops = new float[] {stops[0], stops[0]};
|
||||||
|
FLog.w(ReactConstants.TAG, "Gradient contains only one stop");
|
||||||
}
|
}
|
||||||
|
|
||||||
enum BrushType {
|
if (mType == BrushType.LINEAR_GRADIENT) {
|
||||||
LINEAR_GRADIENT,
|
double x1 = getVal(mPoints[0], width, scale, textSize) + offsetX;
|
||||||
RADIAL_GRADIENT,
|
double y1 = getVal(mPoints[1], height, scale, textSize) + offsetY;
|
||||||
PATTERN
|
double x2 = getVal(mPoints[2], width, scale, textSize) + offsetX;
|
||||||
}
|
double y2 = getVal(mPoints[3], height, scale, textSize) + offsetY;
|
||||||
|
|
||||||
enum BrushUnits {
|
Shader linearGradient =
|
||||||
OBJECT_BOUNDING_BOX,
|
new LinearGradient(
|
||||||
USER_SPACE_ON_USE
|
(float) x1,
|
||||||
}
|
(float) y1,
|
||||||
|
(float) x2,
|
||||||
private static void parseGradientStops(ReadableArray value, int stopsCount, float[] stops, int[] stopsColors, float opacity) {
|
(float) y2,
|
||||||
for (int i = 0; i < stopsCount; i++) {
|
stopsColors,
|
||||||
int stopIndex = i * 2;
|
stops,
|
||||||
stops[i] = (float) value.getDouble(stopIndex);
|
Shader.TileMode.CLAMP);
|
||||||
int color = value.getInt(stopIndex + 1);
|
|
||||||
int alpha = color >>> 24;
|
if (mMatrix != null) {
|
||||||
int combined = Math.round((float)alpha * opacity);
|
Matrix m = new Matrix();
|
||||||
stopsColors[i] = combined << 24 | (color & 0x00ffffff);
|
m.preConcat(mMatrix);
|
||||||
}
|
linearGradient.setLocalMatrix(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setUserSpaceBoundingBox(Rect userSpaceBoundingBox) {
|
paint.setShader(linearGradient);
|
||||||
mUserSpaceBoundingBox = userSpaceBoundingBox;
|
} else if (mType == BrushType.RADIAL_GRADIENT) {
|
||||||
}
|
double rx = getVal(mPoints[2], width, scale, textSize);
|
||||||
|
double ry = getVal(mPoints[3], height, scale, textSize);
|
||||||
void setGradientColors(ReadableArray colors) {
|
|
||||||
mColors = colors;
|
double ratio = ry / rx;
|
||||||
}
|
|
||||||
|
double cx = getVal(mPoints[4], width, scale, textSize) + offsetX;
|
||||||
void setGradientTransform(Matrix matrix) {
|
double cy = getVal(mPoints[5], height / ratio, scale, textSize) + offsetY / ratio;
|
||||||
mMatrix = matrix;
|
|
||||||
}
|
// TODO: support focus point.
|
||||||
|
// double fx = PropHelper.fromRelative(mPoints[0], width, offsetX, scale);
|
||||||
private RectF getPaintRect(RectF pathBoundingBox) {
|
// double fy = PropHelper.fromRelative(mPoints[1], height, offsetY, scale) / (ry / rx);
|
||||||
RectF rect = mUseObjectBoundingBox ? pathBoundingBox : new RectF(mUserSpaceBoundingBox);
|
|
||||||
float width = rect.width();
|
Shader radialGradient =
|
||||||
float height = rect.height();
|
new RadialGradient(
|
||||||
float x = 0f;
|
(float) cx, (float) cy, (float) rx, stopsColors, stops, Shader.TileMode.CLAMP);
|
||||||
float y = 0f;
|
|
||||||
|
Matrix radialMatrix = new Matrix();
|
||||||
if (mUseObjectBoundingBox) {
|
radialMatrix.preScale(1f, (float) ratio);
|
||||||
x = rect.left;
|
|
||||||
y = rect.top;
|
if (mMatrix != null) {
|
||||||
}
|
radialMatrix.preConcat(mMatrix);
|
||||||
|
}
|
||||||
return new RectF(x, y, x + width, y + height);
|
|
||||||
}
|
radialGradient.setLocalMatrix(radialMatrix);
|
||||||
|
paint.setShader(radialGradient);
|
||||||
private double getVal(SVGLength length, double relative, float scale, float textSize) {
|
|
||||||
return PropHelper.fromRelative(length, relative, 0, mUseObjectBoundingBox &&
|
|
||||||
length.unit == SVGLength.UnitType.NUMBER ? relative : scale, textSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setupPaint(Paint paint, RectF pathBoundingBox, float scale, float opacity) {
|
|
||||||
RectF rect = getPaintRect(pathBoundingBox);
|
|
||||||
float width = rect.width();
|
|
||||||
float height = rect.height();
|
|
||||||
float offsetX = rect.left;
|
|
||||||
float offsetY = rect.top;
|
|
||||||
|
|
||||||
float textSize = paint.getTextSize();
|
|
||||||
if (mType == BrushType.PATTERN) {
|
|
||||||
double x = getVal(mPoints[0], width, scale, textSize);
|
|
||||||
double y = getVal(mPoints[1], height, scale, textSize);
|
|
||||||
double w = getVal(mPoints[2], width, scale, textSize);
|
|
||||||
double h = getVal(mPoints[3], height, scale, textSize);
|
|
||||||
|
|
||||||
if (!(w > 1 && h > 1)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Bitmap bitmap = Bitmap.createBitmap(
|
|
||||||
(int) w,
|
|
||||||
(int) h,
|
|
||||||
Bitmap.Config.ARGB_8888);
|
|
||||||
Canvas canvas = new Canvas(bitmap);
|
|
||||||
|
|
||||||
RectF vbRect = mPattern.getViewBox();
|
|
||||||
if (vbRect != null && vbRect.width() > 0 && vbRect.height() > 0) {
|
|
||||||
RectF eRect = new RectF((float) x, (float) y, (float) w, (float) h);
|
|
||||||
Matrix mViewBoxMatrix = ViewBox.getTransform(vbRect, eRect, mPattern.mAlign, mPattern.mMeetOrSlice);
|
|
||||||
canvas.concat(mViewBoxMatrix);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mUseContentObjectBoundingBoxUnits) {
|
|
||||||
canvas.scale(width / scale, height / scale);
|
|
||||||
}
|
|
||||||
|
|
||||||
mPattern.draw(canvas, new Paint(), opacity);
|
|
||||||
|
|
||||||
Matrix patternMatrix = new Matrix();
|
|
||||||
if (mMatrix != null) {
|
|
||||||
patternMatrix.preConcat(mMatrix);
|
|
||||||
}
|
|
||||||
|
|
||||||
BitmapShader bitmapShader = new BitmapShader(bitmap, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);
|
|
||||||
bitmapShader.setLocalMatrix(patternMatrix);
|
|
||||||
paint.setShader(bitmapShader);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int size = mColors.size();
|
|
||||||
if (size == 0) {
|
|
||||||
FLog.w(ReactConstants.TAG, "Gradient contains no stops");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
int stopsCount = size / 2;
|
|
||||||
int[] stopsColors = new int[stopsCount];
|
|
||||||
float[] stops = new float[stopsCount];
|
|
||||||
parseGradientStops(mColors, stopsCount, stops, stopsColors, opacity);
|
|
||||||
|
|
||||||
if (stops.length == 1) {
|
|
||||||
// Gradient with only one stop will make LinearGradient/RadialGradient
|
|
||||||
// throw. It may happen when source SVG contains only one stop or
|
|
||||||
// two stops at the same spot (see lib/extract/extractGradient.js).
|
|
||||||
// Although it's mistake SVGs like this can be produced by vector
|
|
||||||
// editors or other tools, so let's handle that gracefully.
|
|
||||||
stopsColors = new int[] { stopsColors[0], stopsColors[0] };
|
|
||||||
stops = new float[] { stops[0], stops[0] };
|
|
||||||
FLog.w(ReactConstants.TAG, "Gradient contains only one stop");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mType == BrushType.LINEAR_GRADIENT) {
|
|
||||||
double x1 = getVal(mPoints[0], width, scale, textSize) + offsetX;
|
|
||||||
double y1 = getVal(mPoints[1], height, scale, textSize) + offsetY;
|
|
||||||
double x2 = getVal(mPoints[2], width, scale, textSize) + offsetX;
|
|
||||||
double y2 = getVal(mPoints[3], height, scale, textSize) + offsetY;
|
|
||||||
|
|
||||||
Shader linearGradient = new LinearGradient(
|
|
||||||
(float) x1,
|
|
||||||
(float) y1,
|
|
||||||
(float) x2,
|
|
||||||
(float) y2,
|
|
||||||
stopsColors,
|
|
||||||
stops,
|
|
||||||
Shader.TileMode.CLAMP);
|
|
||||||
|
|
||||||
if (mMatrix != null) {
|
|
||||||
Matrix m = new Matrix();
|
|
||||||
m.preConcat(mMatrix);
|
|
||||||
linearGradient.setLocalMatrix(m);
|
|
||||||
}
|
|
||||||
|
|
||||||
paint.setShader(linearGradient);
|
|
||||||
} else if (mType == BrushType.RADIAL_GRADIENT) {
|
|
||||||
double rx = getVal(mPoints[2], width, scale, textSize);
|
|
||||||
double ry = getVal(mPoints[3], height, scale, textSize);
|
|
||||||
|
|
||||||
double ratio = ry / rx;
|
|
||||||
|
|
||||||
double cx = getVal(mPoints[4], width, scale, textSize) + offsetX;
|
|
||||||
double cy = getVal(mPoints[5], height / ratio, scale, textSize) + offsetY / ratio;
|
|
||||||
|
|
||||||
// TODO: support focus point.
|
|
||||||
//double fx = PropHelper.fromRelative(mPoints[0], width, offsetX, scale);
|
|
||||||
//double fy = PropHelper.fromRelative(mPoints[1], height, offsetY, scale) / (ry / rx);
|
|
||||||
|
|
||||||
Shader radialGradient = new RadialGradient(
|
|
||||||
(float) cx,
|
|
||||||
(float) cy,
|
|
||||||
(float) rx,
|
|
||||||
stopsColors,
|
|
||||||
stops,
|
|
||||||
Shader.TileMode.CLAMP
|
|
||||||
);
|
|
||||||
|
|
||||||
Matrix radialMatrix = new Matrix();
|
|
||||||
radialMatrix.preScale(1f, (float) ratio);
|
|
||||||
|
|
||||||
if (mMatrix != null) {
|
|
||||||
radialMatrix.preConcat(mMatrix);
|
|
||||||
}
|
|
||||||
|
|
||||||
radialGradient.setLocalMatrix(radialMatrix);
|
|
||||||
paint.setShader(radialGradient);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,71 +6,68 @@
|
|||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
package com.horcrux.svg;
|
package com.horcrux.svg;
|
||||||
|
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.graphics.Canvas;
|
import android.graphics.Canvas;
|
||||||
import android.graphics.Paint;
|
import android.graphics.Paint;
|
||||||
import android.graphics.Path;
|
import android.graphics.Path;
|
||||||
|
|
||||||
import com.facebook.react.bridge.Dynamic;
|
import com.facebook.react.bridge.Dynamic;
|
||||||
import com.facebook.react.bridge.ReactContext;
|
import com.facebook.react.bridge.ReactContext;
|
||||||
import com.facebook.react.uimanager.annotations.ReactProp;
|
import com.facebook.react.uimanager.annotations.ReactProp;
|
||||||
|
|
||||||
@SuppressLint("ViewConstructor")
|
@SuppressLint("ViewConstructor")
|
||||||
class CircleView extends RenderableView {
|
class CircleView extends RenderableView {
|
||||||
private SVGLength mCx;
|
private SVGLength mCx;
|
||||||
private SVGLength mCy;
|
private SVGLength mCy;
|
||||||
private SVGLength mR;
|
private SVGLength mR;
|
||||||
|
|
||||||
public CircleView(ReactContext reactContext) {
|
public CircleView(ReactContext reactContext) {
|
||||||
super(reactContext);
|
super(reactContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "cx")
|
@ReactProp(name = "cx")
|
||||||
public void setCx(Dynamic cx) {
|
public void setCx(Dynamic cx) {
|
||||||
mCx = SVGLength.from(cx);
|
mCx = SVGLength.from(cx);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCx(String cx) {
|
public void setCx(String cx) {
|
||||||
mCx = SVGLength.from(cx);
|
mCx = SVGLength.from(cx);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "cy")
|
@ReactProp(name = "cy")
|
||||||
public void setCy(Dynamic cy) {
|
public void setCy(Dynamic cy) {
|
||||||
mCy = SVGLength.from(cy);
|
mCy = SVGLength.from(cy);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCy(String cy) {
|
public void setCy(String cy) {
|
||||||
mCy = SVGLength.from(cy);
|
mCy = SVGLength.from(cy);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "r")
|
@ReactProp(name = "r")
|
||||||
public void setR(Dynamic r) {
|
public void setR(Dynamic r) {
|
||||||
mR = SVGLength.from(r);
|
mR = SVGLength.from(r);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setR(String r) {
|
public void setR(String r) {
|
||||||
mR = SVGLength.from(r);
|
mR = SVGLength.from(r);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
Path getPath(Canvas canvas, Paint paint) {
|
Path getPath(Canvas canvas, Paint paint) {
|
||||||
Path path = new Path();
|
Path path = new Path();
|
||||||
|
|
||||||
double cx = relativeOnWidth(mCx);
|
double cx = relativeOnWidth(mCx);
|
||||||
double cy = relativeOnHeight(mCy);
|
double cy = relativeOnHeight(mCy);
|
||||||
double r = relativeOnOther(mR);
|
double r = relativeOnOther(mR);
|
||||||
|
|
||||||
path.addCircle((float) cx, (float) cy, (float) r, Path.Direction.CW);
|
path.addCircle((float) cx, (float) cy, (float) r, Path.Direction.CW);
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,13 +6,11 @@
|
|||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
package com.horcrux.svg;
|
package com.horcrux.svg;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.graphics.Canvas;
|
import android.graphics.Canvas;
|
||||||
import android.graphics.Paint;
|
import android.graphics.Paint;
|
||||||
|
|
||||||
import com.facebook.common.logging.FLog;
|
import com.facebook.common.logging.FLog;
|
||||||
import com.facebook.react.bridge.ReactContext;
|
import com.facebook.react.bridge.ReactContext;
|
||||||
import com.facebook.react.common.ReactConstants;
|
import com.facebook.react.common.ReactConstants;
|
||||||
@@ -20,33 +18,35 @@ import com.facebook.react.common.ReactConstants;
|
|||||||
@SuppressLint("ViewConstructor")
|
@SuppressLint("ViewConstructor")
|
||||||
class ClipPathView extends GroupView {
|
class ClipPathView extends GroupView {
|
||||||
|
|
||||||
public ClipPathView(ReactContext reactContext) {
|
public ClipPathView(ReactContext reactContext) {
|
||||||
super(reactContext);
|
super(reactContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
void draw(Canvas canvas, Paint paint, float opacity) {
|
void draw(Canvas canvas, Paint paint, float opacity) {
|
||||||
FLog.w(ReactConstants.TAG, "RNSVG: ClipPath can't be drawn, it should be defined as a child component for `Defs` ");
|
FLog.w(
|
||||||
}
|
ReactConstants.TAG,
|
||||||
|
"RNSVG: ClipPath can't be drawn, it should be defined as a child component for `Defs` ");
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
void saveDefinition() {
|
void saveDefinition() {
|
||||||
getSvgView().defineClipPath(this, mName);
|
getSvgView().defineClipPath(this, mName);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
boolean isResponsible() {
|
boolean isResponsible() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
int hitTest(float[] src) {
|
int hitTest(float[] src) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
void mergeProperties(RenderableView target) {}
|
void mergeProperties(RenderableView target) {}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
void resetProperties() {}
|
void resetProperties() {}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,38 +6,36 @@
|
|||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
package com.horcrux.svg;
|
package com.horcrux.svg;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.graphics.Canvas;
|
import android.graphics.Canvas;
|
||||||
import android.graphics.Paint;
|
import android.graphics.Paint;
|
||||||
import android.graphics.Path;
|
import android.graphics.Path;
|
||||||
|
|
||||||
import com.facebook.react.bridge.ReactContext;
|
import com.facebook.react.bridge.ReactContext;
|
||||||
|
|
||||||
@SuppressLint("ViewConstructor")
|
@SuppressLint("ViewConstructor")
|
||||||
class DefinitionView extends VirtualView {
|
class DefinitionView extends VirtualView {
|
||||||
|
|
||||||
DefinitionView(ReactContext reactContext) {
|
DefinitionView(ReactContext reactContext) {
|
||||||
super(reactContext);
|
super(reactContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("EmptyMethod")
|
@SuppressWarnings("EmptyMethod")
|
||||||
void draw(Canvas canvas, Paint paint, float opacity) {}
|
void draw(Canvas canvas, Paint paint, float opacity) {}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
boolean isResponsible() {
|
boolean isResponsible() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
Path getPath(Canvas canvas, Paint paint) {
|
Path getPath(Canvas canvas, Paint paint) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
int hitTest(float[] src) {
|
int hitTest(float[] src) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,32 +6,30 @@
|
|||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
package com.horcrux.svg;
|
package com.horcrux.svg;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.graphics.Canvas;
|
import android.graphics.Canvas;
|
||||||
import android.graphics.Paint;
|
import android.graphics.Paint;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
import com.facebook.react.bridge.ReactContext;
|
import com.facebook.react.bridge.ReactContext;
|
||||||
|
|
||||||
@SuppressLint("ViewConstructor")
|
@SuppressLint("ViewConstructor")
|
||||||
class DefsView extends DefinitionView {
|
class DefsView extends DefinitionView {
|
||||||
|
|
||||||
public DefsView(ReactContext reactContext) {
|
public DefsView(ReactContext reactContext) {
|
||||||
super(reactContext);
|
super(reactContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
void draw(Canvas canvas, Paint paint, float opacity) {}
|
void draw(Canvas canvas, Paint paint, float opacity) {}
|
||||||
|
|
||||||
void saveDefinition() {
|
void saveDefinition() {
|
||||||
for (int i = 0; i < getChildCount(); i++) {
|
for (int i = 0; i < getChildCount(); i++) {
|
||||||
View child = getChildAt(i);
|
View child = getChildAt(i);
|
||||||
if (child instanceof VirtualView) {
|
if (child instanceof VirtualView) {
|
||||||
((VirtualView)child).saveDefinition();
|
((VirtualView) child).saveDefinition();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,6 @@
|
|||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
package com.horcrux.svg;
|
package com.horcrux.svg;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
@@ -14,76 +13,76 @@ import android.graphics.Canvas;
|
|||||||
import android.graphics.Paint;
|
import android.graphics.Paint;
|
||||||
import android.graphics.Path;
|
import android.graphics.Path;
|
||||||
import android.graphics.RectF;
|
import android.graphics.RectF;
|
||||||
|
|
||||||
import com.facebook.react.bridge.Dynamic;
|
import com.facebook.react.bridge.Dynamic;
|
||||||
import com.facebook.react.bridge.ReactContext;
|
import com.facebook.react.bridge.ReactContext;
|
||||||
import com.facebook.react.uimanager.annotations.ReactProp;
|
import com.facebook.react.uimanager.annotations.ReactProp;
|
||||||
|
|
||||||
@SuppressLint("ViewConstructor")
|
@SuppressLint("ViewConstructor")
|
||||||
class EllipseView extends RenderableView {
|
class EllipseView extends RenderableView {
|
||||||
private SVGLength mCx;
|
private SVGLength mCx;
|
||||||
private SVGLength mCy;
|
private SVGLength mCy;
|
||||||
private SVGLength mRx;
|
private SVGLength mRx;
|
||||||
private SVGLength mRy;
|
private SVGLength mRy;
|
||||||
|
|
||||||
public EllipseView(ReactContext reactContext) {
|
public EllipseView(ReactContext reactContext) {
|
||||||
super(reactContext);
|
super(reactContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "cx")
|
@ReactProp(name = "cx")
|
||||||
public void setCx(Dynamic cx) {
|
public void setCx(Dynamic cx) {
|
||||||
mCx = SVGLength.from(cx);
|
mCx = SVGLength.from(cx);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCx(String cx) {
|
public void setCx(String cx) {
|
||||||
mCx = SVGLength.from(cx);
|
mCx = SVGLength.from(cx);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "cy")
|
@ReactProp(name = "cy")
|
||||||
public void setCy(Dynamic cy) {
|
public void setCy(Dynamic cy) {
|
||||||
mCy = SVGLength.from(cy);
|
mCy = SVGLength.from(cy);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCy(String cy) {
|
public void setCy(String cy) {
|
||||||
mCy = SVGLength.from(cy);
|
mCy = SVGLength.from(cy);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "rx")
|
@ReactProp(name = "rx")
|
||||||
public void setRx(Dynamic rx) {
|
public void setRx(Dynamic rx) {
|
||||||
mRx = SVGLength.from(rx);
|
mRx = SVGLength.from(rx);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setRx(String rx) {
|
public void setRx(String rx) {
|
||||||
mRx = SVGLength.from(rx);
|
mRx = SVGLength.from(rx);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "ry")
|
@ReactProp(name = "ry")
|
||||||
public void setRy(Dynamic ry) {
|
public void setRy(Dynamic ry) {
|
||||||
mRy = SVGLength.from(ry);
|
mRy = SVGLength.from(ry);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setRy(String ry) {
|
public void setRy(String ry) {
|
||||||
mRy = SVGLength.from(ry);
|
mRy = SVGLength.from(ry);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
Path getPath(Canvas canvas, Paint paint) {
|
Path getPath(Canvas canvas, Paint paint) {
|
||||||
Path path = new Path();
|
Path path = new Path();
|
||||||
double cx = relativeOnWidth(mCx);
|
double cx = relativeOnWidth(mCx);
|
||||||
double cy = relativeOnHeight(mCy);
|
double cy = relativeOnHeight(mCy);
|
||||||
double rx = relativeOnWidth(mRx);
|
double rx = relativeOnWidth(mRx);
|
||||||
double ry = relativeOnHeight(mRy);
|
double ry = relativeOnHeight(mRy);
|
||||||
RectF oval = new RectF((float) (cx - rx), (float) (cy - ry), (float) (cx + rx), (float) (cy + ry));
|
RectF oval =
|
||||||
path.addOval(oval, Path.Direction.CW);
|
new RectF((float) (cx - rx), (float) (cy - ry), (float) (cx + rx), (float) (cy + ry));
|
||||||
|
path.addOval(oval, Path.Direction.CW);
|
||||||
|
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,214 +1,232 @@
|
|||||||
package com.horcrux.svg;
|
package com.horcrux.svg;
|
||||||
|
|
||||||
import com.facebook.react.bridge.ReadableMap;
|
|
||||||
import com.facebook.react.bridge.ReadableType;
|
|
||||||
|
|
||||||
import static com.facebook.react.uimanager.ViewProps.FONT_FAMILY;
|
import static com.facebook.react.uimanager.ViewProps.FONT_FAMILY;
|
||||||
import static com.facebook.react.uimanager.ViewProps.FONT_SIZE;
|
import static com.facebook.react.uimanager.ViewProps.FONT_SIZE;
|
||||||
import static com.facebook.react.uimanager.ViewProps.FONT_STYLE;
|
import static com.facebook.react.uimanager.ViewProps.FONT_STYLE;
|
||||||
import static com.facebook.react.uimanager.ViewProps.FONT_WEIGHT;
|
import static com.facebook.react.uimanager.ViewProps.FONT_WEIGHT;
|
||||||
import static com.horcrux.svg.TextProperties.*;
|
import static com.horcrux.svg.TextProperties.*;
|
||||||
|
|
||||||
|
import com.facebook.react.bridge.ReadableMap;
|
||||||
|
import com.facebook.react.bridge.ReadableType;
|
||||||
|
|
||||||
class FontData {
|
class FontData {
|
||||||
|
|
||||||
static class AbsoluteFontWeight {
|
static class AbsoluteFontWeight {
|
||||||
|
|
||||||
static final int normal = 400;
|
static final int normal = 400;
|
||||||
|
|
||||||
private static final FontWeight[] WEIGHTS = new FontWeight[]{
|
private static final FontWeight[] WEIGHTS =
|
||||||
FontWeight.w100,
|
new FontWeight[] {
|
||||||
FontWeight.w100,
|
FontWeight.w100,
|
||||||
FontWeight.w200,
|
FontWeight.w100,
|
||||||
FontWeight.w300,
|
FontWeight.w200,
|
||||||
FontWeight.Normal,
|
FontWeight.w300,
|
||||||
FontWeight.w500,
|
FontWeight.Normal,
|
||||||
FontWeight.w600,
|
FontWeight.w500,
|
||||||
FontWeight.Bold,
|
FontWeight.w600,
|
||||||
FontWeight.w800,
|
FontWeight.Bold,
|
||||||
FontWeight.w900,
|
FontWeight.w800,
|
||||||
FontWeight.w900,
|
FontWeight.w900,
|
||||||
|
FontWeight.w900,
|
||||||
};
|
};
|
||||||
|
|
||||||
static FontWeight nearestFontWeight(int absoluteFontWeight) {
|
static FontWeight nearestFontWeight(int absoluteFontWeight) {
|
||||||
return WEIGHTS[Math.round(absoluteFontWeight / 100f)];
|
return WEIGHTS[Math.round(absoluteFontWeight / 100f)];
|
||||||
}
|
|
||||||
|
|
||||||
private static final int[] absoluteFontWeights = new int[]{
|
|
||||||
400, 700, 100, 200, 300, 400, 500, 600, 700, 800, 900
|
|
||||||
};
|
|
||||||
|
|
||||||
// https://drafts.csswg.org/css-fonts-4/#relative-weights
|
|
||||||
static int from(FontWeight fontWeight, FontData parent) {
|
|
||||||
if (fontWeight == FontWeight.Bolder) {
|
|
||||||
return bolder(parent.absoluteFontWeight);
|
|
||||||
} else if (fontWeight == FontWeight.Lighter) {
|
|
||||||
return lighter(parent.absoluteFontWeight);
|
|
||||||
} else {
|
|
||||||
return absoluteFontWeights[fontWeight.ordinal()];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int bolder(int inherited) {
|
|
||||||
if (inherited < 350) {
|
|
||||||
return 400;
|
|
||||||
} else if (inherited < 550) {
|
|
||||||
return 700;
|
|
||||||
} else if (inherited < 900) {
|
|
||||||
return 900;
|
|
||||||
} else {
|
|
||||||
return inherited;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int lighter(int inherited) {
|
|
||||||
if (inherited < 100) {
|
|
||||||
return inherited;
|
|
||||||
} else if (inherited < 550) {
|
|
||||||
return 100;
|
|
||||||
} else if (inherited < 750) {
|
|
||||||
return 400;
|
|
||||||
} else {
|
|
||||||
return 700;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static final double DEFAULT_FONT_SIZE = 12d;
|
private static final int[] absoluteFontWeights =
|
||||||
|
new int[] {400, 700, 100, 200, 300, 400, 500, 600, 700, 800, 900};
|
||||||
|
|
||||||
private static final double DEFAULT_KERNING = 0d;
|
// https://drafts.csswg.org/css-fonts-4/#relative-weights
|
||||||
private static final double DEFAULT_WORD_SPACING = 0d;
|
static int from(FontWeight fontWeight, FontData parent) {
|
||||||
private static final double DEFAULT_LETTER_SPACING = 0d;
|
if (fontWeight == FontWeight.Bolder) {
|
||||||
|
return bolder(parent.absoluteFontWeight);
|
||||||
private static final String KERNING = "kerning";
|
} else if (fontWeight == FontWeight.Lighter) {
|
||||||
private static final String FONT_DATA = "fontData";
|
return lighter(parent.absoluteFontWeight);
|
||||||
private static final String TEXT_ANCHOR = "textAnchor";
|
} else {
|
||||||
private static final String WORD_SPACING = "wordSpacing";
|
return absoluteFontWeights[fontWeight.ordinal()];
|
||||||
private static final String LETTER_SPACING = "letterSpacing";
|
}
|
||||||
private static final String TEXT_DECORATION = "textDecoration";
|
|
||||||
private static final String FONT_FEATURE_SETTINGS = "fontFeatureSettings";
|
|
||||||
private static final String FONT_VARIATION_SETTINGS = "fontVariationSettings";
|
|
||||||
private static final String FONT_VARIANT_LIGATURES = "fontVariantLigatures";
|
|
||||||
|
|
||||||
final double fontSize;
|
|
||||||
final String fontFamily;
|
|
||||||
final FontStyle fontStyle;
|
|
||||||
final ReadableMap fontData;
|
|
||||||
|
|
||||||
FontWeight fontWeight;
|
|
||||||
int absoluteFontWeight;
|
|
||||||
|
|
||||||
final String fontFeatureSettings;
|
|
||||||
final String fontVariationSettings;
|
|
||||||
final FontVariantLigatures fontVariantLigatures;
|
|
||||||
|
|
||||||
final TextAnchor textAnchor;
|
|
||||||
private final TextDecoration textDecoration;
|
|
||||||
|
|
||||||
final double kerning;
|
|
||||||
final double wordSpacing;
|
|
||||||
final double letterSpacing;
|
|
||||||
|
|
||||||
final boolean manualKerning;
|
|
||||||
|
|
||||||
static final FontData Defaults = new FontData();
|
|
||||||
|
|
||||||
private FontData() {
|
|
||||||
fontData = null;
|
|
||||||
fontFamily = "";
|
|
||||||
fontStyle = FontStyle.normal;
|
|
||||||
fontWeight = FontWeight.Normal;
|
|
||||||
absoluteFontWeight = AbsoluteFontWeight.normal;
|
|
||||||
fontFeatureSettings = "";
|
|
||||||
fontVariationSettings = "";
|
|
||||||
fontVariantLigatures = FontVariantLigatures.normal;
|
|
||||||
|
|
||||||
textAnchor = TextAnchor.start;
|
|
||||||
textDecoration = TextDecoration.None;
|
|
||||||
|
|
||||||
manualKerning = false;
|
|
||||||
kerning = DEFAULT_KERNING;
|
|
||||||
fontSize = DEFAULT_FONT_SIZE;
|
|
||||||
wordSpacing = DEFAULT_WORD_SPACING;
|
|
||||||
letterSpacing = DEFAULT_LETTER_SPACING;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private double toAbsolute(ReadableMap font, String prop, double scale, double fontSize, double relative) {
|
private static int bolder(int inherited) {
|
||||||
ReadableType propType = font.getType(prop);
|
if (inherited < 350) {
|
||||||
if (propType == ReadableType.Number) {
|
return 400;
|
||||||
return font.getDouble(prop);
|
} else if (inherited < 550) {
|
||||||
|
return 700;
|
||||||
|
} else if (inherited < 900) {
|
||||||
|
return 900;
|
||||||
|
} else {
|
||||||
|
return inherited;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int lighter(int inherited) {
|
||||||
|
if (inherited < 100) {
|
||||||
|
return inherited;
|
||||||
|
} else if (inherited < 550) {
|
||||||
|
return 100;
|
||||||
|
} else if (inherited < 750) {
|
||||||
|
return 400;
|
||||||
|
} else {
|
||||||
|
return 700;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static final double DEFAULT_FONT_SIZE = 12d;
|
||||||
|
|
||||||
|
private static final double DEFAULT_KERNING = 0d;
|
||||||
|
private static final double DEFAULT_WORD_SPACING = 0d;
|
||||||
|
private static final double DEFAULT_LETTER_SPACING = 0d;
|
||||||
|
|
||||||
|
private static final String KERNING = "kerning";
|
||||||
|
private static final String FONT_DATA = "fontData";
|
||||||
|
private static final String TEXT_ANCHOR = "textAnchor";
|
||||||
|
private static final String WORD_SPACING = "wordSpacing";
|
||||||
|
private static final String LETTER_SPACING = "letterSpacing";
|
||||||
|
private static final String TEXT_DECORATION = "textDecoration";
|
||||||
|
private static final String FONT_FEATURE_SETTINGS = "fontFeatureSettings";
|
||||||
|
private static final String FONT_VARIATION_SETTINGS = "fontVariationSettings";
|
||||||
|
private static final String FONT_VARIANT_LIGATURES = "fontVariantLigatures";
|
||||||
|
|
||||||
|
final double fontSize;
|
||||||
|
final String fontFamily;
|
||||||
|
final FontStyle fontStyle;
|
||||||
|
final ReadableMap fontData;
|
||||||
|
|
||||||
|
FontWeight fontWeight;
|
||||||
|
int absoluteFontWeight;
|
||||||
|
|
||||||
|
final String fontFeatureSettings;
|
||||||
|
final String fontVariationSettings;
|
||||||
|
final FontVariantLigatures fontVariantLigatures;
|
||||||
|
|
||||||
|
final TextAnchor textAnchor;
|
||||||
|
private final TextDecoration textDecoration;
|
||||||
|
|
||||||
|
final double kerning;
|
||||||
|
final double wordSpacing;
|
||||||
|
final double letterSpacing;
|
||||||
|
|
||||||
|
final boolean manualKerning;
|
||||||
|
|
||||||
|
static final FontData Defaults = new FontData();
|
||||||
|
|
||||||
|
private FontData() {
|
||||||
|
fontData = null;
|
||||||
|
fontFamily = "";
|
||||||
|
fontStyle = FontStyle.normal;
|
||||||
|
fontWeight = FontWeight.Normal;
|
||||||
|
absoluteFontWeight = AbsoluteFontWeight.normal;
|
||||||
|
fontFeatureSettings = "";
|
||||||
|
fontVariationSettings = "";
|
||||||
|
fontVariantLigatures = FontVariantLigatures.normal;
|
||||||
|
|
||||||
|
textAnchor = TextAnchor.start;
|
||||||
|
textDecoration = TextDecoration.None;
|
||||||
|
|
||||||
|
manualKerning = false;
|
||||||
|
kerning = DEFAULT_KERNING;
|
||||||
|
fontSize = DEFAULT_FONT_SIZE;
|
||||||
|
wordSpacing = DEFAULT_WORD_SPACING;
|
||||||
|
letterSpacing = DEFAULT_LETTER_SPACING;
|
||||||
|
}
|
||||||
|
|
||||||
|
private double toAbsolute(
|
||||||
|
ReadableMap font, String prop, double scale, double fontSize, double relative) {
|
||||||
|
ReadableType propType = font.getType(prop);
|
||||||
|
if (propType == ReadableType.Number) {
|
||||||
|
return font.getDouble(prop);
|
||||||
|
} else {
|
||||||
|
String string = font.getString(prop);
|
||||||
|
return PropHelper.fromRelative(string, relative, scale, fontSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setInheritedWeight(FontData parent) {
|
||||||
|
absoluteFontWeight = parent.absoluteFontWeight;
|
||||||
|
fontWeight = parent.fontWeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleNumericWeight(FontData parent, double number) {
|
||||||
|
long weight = Math.round(number);
|
||||||
|
if (weight >= 1 && weight <= 1000) {
|
||||||
|
absoluteFontWeight = (int) weight;
|
||||||
|
fontWeight = AbsoluteFontWeight.nearestFontWeight(absoluteFontWeight);
|
||||||
|
} else {
|
||||||
|
setInheritedWeight(parent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FontData(ReadableMap font, FontData parent, double scale) {
|
||||||
|
double parentFontSize = parent.fontSize;
|
||||||
|
|
||||||
|
if (font.hasKey(FONT_SIZE)) {
|
||||||
|
fontSize = toAbsolute(font, FONT_SIZE, 1, parentFontSize, parentFontSize);
|
||||||
|
} else {
|
||||||
|
fontSize = parentFontSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (font.hasKey(FONT_WEIGHT)) {
|
||||||
|
ReadableType fontWeightType = font.getType(FONT_WEIGHT);
|
||||||
|
if (fontWeightType == ReadableType.Number) {
|
||||||
|
handleNumericWeight(parent, font.getDouble(FONT_WEIGHT));
|
||||||
|
} else {
|
||||||
|
String string = font.getString(FONT_WEIGHT);
|
||||||
|
if (FontWeight.hasEnum(string)) {
|
||||||
|
absoluteFontWeight = AbsoluteFontWeight.from(FontWeight.get(string), parent);
|
||||||
|
fontWeight = AbsoluteFontWeight.nearestFontWeight(absoluteFontWeight);
|
||||||
|
} else if (string != null) {
|
||||||
|
handleNumericWeight(parent, Double.parseDouble(string));
|
||||||
} else {
|
} else {
|
||||||
String string = font.getString(prop);
|
setInheritedWeight(parent);
|
||||||
return PropHelper.fromRelative(
|
|
||||||
string,
|
|
||||||
relative,
|
|
||||||
scale,
|
|
||||||
fontSize
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setInheritedWeight(parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setInheritedWeight(FontData parent) {
|
fontData = font.hasKey(FONT_DATA) ? font.getMap(FONT_DATA) : parent.fontData;
|
||||||
absoluteFontWeight = parent.absoluteFontWeight;
|
|
||||||
fontWeight = parent.fontWeight;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void handleNumericWeight(FontData parent, double number) {
|
fontFamily = font.hasKey(FONT_FAMILY) ? font.getString(FONT_FAMILY) : parent.fontFamily;
|
||||||
long weight = Math.round(number);
|
fontStyle =
|
||||||
if (weight >= 1 && weight <= 1000) {
|
font.hasKey(FONT_STYLE) ? FontStyle.valueOf(font.getString(FONT_STYLE)) : parent.fontStyle;
|
||||||
absoluteFontWeight = (int)weight;
|
fontFeatureSettings =
|
||||||
fontWeight = AbsoluteFontWeight.nearestFontWeight(absoluteFontWeight);
|
font.hasKey(FONT_FEATURE_SETTINGS)
|
||||||
} else {
|
? font.getString(FONT_FEATURE_SETTINGS)
|
||||||
setInheritedWeight(parent);
|
: parent.fontFeatureSettings;
|
||||||
}
|
fontVariationSettings =
|
||||||
}
|
font.hasKey(FONT_VARIATION_SETTINGS)
|
||||||
|
? font.getString(FONT_VARIATION_SETTINGS)
|
||||||
|
: parent.fontVariationSettings;
|
||||||
|
fontVariantLigatures =
|
||||||
|
font.hasKey(FONT_VARIANT_LIGATURES)
|
||||||
|
? FontVariantLigatures.valueOf(font.getString(FONT_VARIANT_LIGATURES))
|
||||||
|
: parent.fontVariantLigatures;
|
||||||
|
|
||||||
FontData(ReadableMap font, FontData parent, double scale) {
|
textAnchor =
|
||||||
double parentFontSize = parent.fontSize;
|
font.hasKey(TEXT_ANCHOR)
|
||||||
|
? TextAnchor.valueOf(font.getString(TEXT_ANCHOR))
|
||||||
|
: parent.textAnchor;
|
||||||
|
textDecoration =
|
||||||
|
font.hasKey(TEXT_DECORATION)
|
||||||
|
? TextDecoration.getEnum(font.getString(TEXT_DECORATION))
|
||||||
|
: parent.textDecoration;
|
||||||
|
|
||||||
if (font.hasKey(FONT_SIZE)) {
|
final boolean hasKerning = font.hasKey(KERNING);
|
||||||
fontSize = toAbsolute(font, FONT_SIZE, 1, parentFontSize, parentFontSize);
|
manualKerning = hasKerning || parent.manualKerning;
|
||||||
} else {
|
|
||||||
fontSize = parentFontSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (font.hasKey(FONT_WEIGHT)) {
|
// https://www.w3.org/TR/SVG11/text.html#SpacingProperties
|
||||||
ReadableType fontWeightType = font.getType(FONT_WEIGHT);
|
// https://drafts.csswg.org/css-text-3/#spacing
|
||||||
if (fontWeightType == ReadableType.Number) {
|
// calculated values for units in: kerning, word-spacing, and, letter-spacing.
|
||||||
handleNumericWeight(parent, font.getDouble(FONT_WEIGHT));
|
kerning = hasKerning ? toAbsolute(font, KERNING, scale, fontSize, 0) : parent.kerning;
|
||||||
} else {
|
wordSpacing =
|
||||||
String string = font.getString(FONT_WEIGHT);
|
font.hasKey(WORD_SPACING)
|
||||||
if (FontWeight.hasEnum(string)) {
|
? toAbsolute(font, WORD_SPACING, scale, fontSize, 0)
|
||||||
absoluteFontWeight = AbsoluteFontWeight.from(FontWeight.get(string), parent);
|
: parent.wordSpacing;
|
||||||
fontWeight = AbsoluteFontWeight.nearestFontWeight(absoluteFontWeight);
|
letterSpacing =
|
||||||
} else if (string != null) {
|
font.hasKey(LETTER_SPACING)
|
||||||
handleNumericWeight(parent, Double.parseDouble(string));
|
? toAbsolute(font, LETTER_SPACING, scale, fontSize, 0)
|
||||||
} else {
|
: parent.letterSpacing;
|
||||||
setInheritedWeight(parent);
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
setInheritedWeight(parent);
|
|
||||||
}
|
|
||||||
|
|
||||||
fontData = font.hasKey(FONT_DATA) ? font.getMap(FONT_DATA) : parent.fontData;
|
|
||||||
|
|
||||||
fontFamily = font.hasKey(FONT_FAMILY) ? font.getString(FONT_FAMILY) : parent.fontFamily;
|
|
||||||
fontStyle = font.hasKey(FONT_STYLE) ? FontStyle.valueOf(font.getString(FONT_STYLE)) : parent.fontStyle;
|
|
||||||
fontFeatureSettings = font.hasKey(FONT_FEATURE_SETTINGS) ? font.getString(FONT_FEATURE_SETTINGS) : parent.fontFeatureSettings;
|
|
||||||
fontVariationSettings = font.hasKey(FONT_VARIATION_SETTINGS) ? font.getString(FONT_VARIATION_SETTINGS) : parent.fontVariationSettings;
|
|
||||||
fontVariantLigatures = font.hasKey(FONT_VARIANT_LIGATURES) ? FontVariantLigatures.valueOf(font.getString(FONT_VARIANT_LIGATURES)) : parent.fontVariantLigatures;
|
|
||||||
|
|
||||||
textAnchor = font.hasKey(TEXT_ANCHOR) ? TextAnchor.valueOf(font.getString(TEXT_ANCHOR)) : parent.textAnchor;
|
|
||||||
textDecoration = font.hasKey(TEXT_DECORATION) ? TextDecoration.getEnum(font.getString(TEXT_DECORATION)) : parent.textDecoration;
|
|
||||||
|
|
||||||
final boolean hasKerning = font.hasKey(KERNING);
|
|
||||||
manualKerning = hasKerning || parent.manualKerning;
|
|
||||||
|
|
||||||
// https://www.w3.org/TR/SVG11/text.html#SpacingProperties
|
|
||||||
// https://drafts.csswg.org/css-text-3/#spacing
|
|
||||||
// calculated values for units in: kerning, word-spacing, and, letter-spacing.
|
|
||||||
kerning = hasKerning ? toAbsolute(font, KERNING, scale, fontSize, 0) : parent.kerning;
|
|
||||||
wordSpacing = font.hasKey(WORD_SPACING) ? toAbsolute(font, WORD_SPACING, scale, fontSize, 0) : parent.wordSpacing;
|
|
||||||
letterSpacing = font.hasKey(LETTER_SPACING) ? toAbsolute(font, LETTER_SPACING, scale, fontSize, 0) : parent.letterSpacing;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,6 @@
|
|||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
package com.horcrux.svg;
|
package com.horcrux.svg;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
@@ -15,9 +14,7 @@ import android.graphics.Canvas;
|
|||||||
import android.graphics.Paint;
|
import android.graphics.Paint;
|
||||||
import android.graphics.RectF;
|
import android.graphics.RectF;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
import com.facebook.react.bridge.Dynamic;
|
import com.facebook.react.bridge.Dynamic;
|
||||||
import com.facebook.react.bridge.ReactContext;
|
import com.facebook.react.bridge.ReactContext;
|
||||||
import com.facebook.react.uimanager.annotations.ReactProp;
|
import com.facebook.react.uimanager.annotations.ReactProp;
|
||||||
@@ -25,136 +22,136 @@ import com.facebook.react.uimanager.annotations.ReactProp;
|
|||||||
@SuppressLint("ViewConstructor")
|
@SuppressLint("ViewConstructor")
|
||||||
class ForeignObjectView extends GroupView {
|
class ForeignObjectView extends GroupView {
|
||||||
|
|
||||||
SVGLength mX;
|
SVGLength mX;
|
||||||
SVGLength mY;
|
SVGLength mY;
|
||||||
SVGLength mW;
|
SVGLength mW;
|
||||||
SVGLength mH;
|
SVGLength mH;
|
||||||
|
|
||||||
public ForeignObjectView(ReactContext reactContext) {
|
public ForeignObjectView(ReactContext reactContext) {
|
||||||
super(reactContext);
|
super(reactContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
void draw(Canvas canvas, Paint paint, float opacity) {
|
void draw(Canvas canvas, Paint paint, float opacity) {
|
||||||
float x = (float)relativeOnWidth(mX);
|
float x = (float) relativeOnWidth(mX);
|
||||||
float y = (float)relativeOnHeight(mY);
|
float y = (float) relativeOnHeight(mY);
|
||||||
float w = (float)relativeOnWidth(mW);
|
float w = (float) relativeOnWidth(mW);
|
||||||
float h = (float)relativeOnHeight(mH);
|
float h = (float) relativeOnHeight(mH);
|
||||||
canvas.translate(x, y);
|
canvas.translate(x, y);
|
||||||
canvas.clipRect(0, 0, w, h);
|
canvas.clipRect(0, 0, w, h);
|
||||||
super.draw(canvas, paint, opacity);
|
super.draw(canvas, paint, opacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDescendantInvalidated(@NonNull View child, @NonNull View target) {
|
public void onDescendantInvalidated(@NonNull View child, @NonNull View target) {
|
||||||
super.onDescendantInvalidated(child, target);
|
super.onDescendantInvalidated(child, target);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "x")
|
@ReactProp(name = "x")
|
||||||
public void setX(Dynamic x) {
|
public void setX(Dynamic x) {
|
||||||
mX = SVGLength.from(x);
|
mX = SVGLength.from(x);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setX(String x) {
|
public void setX(String x) {
|
||||||
mX = SVGLength.from(x);
|
mX = SVGLength.from(x);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "y")
|
@ReactProp(name = "y")
|
||||||
public void setY(Dynamic y) {
|
public void setY(Dynamic y) {
|
||||||
mY = SVGLength.from(y);
|
mY = SVGLength.from(y);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setY(String y) {
|
public void setY(String y) {
|
||||||
mY = SVGLength.from(y);
|
mY = SVGLength.from(y);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "width")
|
@ReactProp(name = "width")
|
||||||
public void setWidth(Dynamic width) {
|
public void setWidth(Dynamic width) {
|
||||||
mW = SVGLength.from(width);
|
mW = SVGLength.from(width);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setWidth(String width) {
|
public void setWidth(String width) {
|
||||||
mW = SVGLength.from(width);
|
mW = SVGLength.from(width);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "height")
|
@ReactProp(name = "height")
|
||||||
public void setHeight(Dynamic height) {
|
public void setHeight(Dynamic height) {
|
||||||
mH = SVGLength.from(height);
|
mH = SVGLength.from(height);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setHeight(String height) {
|
public void setHeight(String height) {
|
||||||
mH = SVGLength.from(height);
|
mH = SVGLength.from(height);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
void drawGroup(final Canvas canvas, final Paint paint, final float opacity) {
|
void drawGroup(final Canvas canvas, final Paint paint, final float opacity) {
|
||||||
pushGlyphContext();
|
pushGlyphContext();
|
||||||
final SvgView svg = getSvgView();
|
final SvgView svg = getSvgView();
|
||||||
final GroupView self = this;
|
final GroupView self = this;
|
||||||
final RectF groupRect = new RectF();
|
final RectF groupRect = new RectF();
|
||||||
for (int i = 0; i < getChildCount(); i++) {
|
for (int i = 0; i < getChildCount(); i++) {
|
||||||
View child = getChildAt(i);
|
View child = getChildAt(i);
|
||||||
if (child instanceof MaskView) {
|
if (child instanceof MaskView) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (child instanceof VirtualView) {
|
if (child instanceof VirtualView) {
|
||||||
VirtualView node = ((VirtualView)child);
|
VirtualView node = ((VirtualView) child);
|
||||||
if ("none".equals(node.mDisplay)) {
|
if ("none".equals(node.mDisplay)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (node instanceof RenderableView) {
|
if (node instanceof RenderableView) {
|
||||||
((RenderableView)node).mergeProperties(self);
|
((RenderableView) node).mergeProperties(self);
|
||||||
}
|
|
||||||
|
|
||||||
int count = node.saveAndSetupCanvas(canvas, mCTM);
|
|
||||||
node.render(canvas, paint, opacity * mOpacity);
|
|
||||||
RectF r = node.getClientRect();
|
|
||||||
if (r != null) {
|
|
||||||
groupRect.union(r);
|
|
||||||
}
|
|
||||||
|
|
||||||
node.restoreCanvas(canvas, count);
|
|
||||||
|
|
||||||
if (node instanceof RenderableView) {
|
|
||||||
((RenderableView)node).resetProperties();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (node.isResponsible()) {
|
|
||||||
svg.enableTouchEvents();
|
|
||||||
}
|
|
||||||
} else if (child instanceof SvgView) {
|
|
||||||
SvgView svgView = (SvgView)child;
|
|
||||||
svgView.drawChildren(canvas);
|
|
||||||
if (svgView.isResponsible()) {
|
|
||||||
svg.enableTouchEvents();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Enable rendering other native ancestor views in e.g. masks
|
|
||||||
child.draw(canvas);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
this.setClientRect(groupRect);
|
|
||||||
popGlyphContext();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Enable rendering other native ancestor views in e.g. masks, but don't render them another time
|
int count = node.saveAndSetupCanvas(canvas, mCTM);
|
||||||
Bitmap fakeBitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
|
node.render(canvas, paint, opacity * mOpacity);
|
||||||
Canvas fake = new Canvas(fakeBitmap);
|
RectF r = node.getClientRect();
|
||||||
|
if (r != null) {
|
||||||
|
groupRect.union(r);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
node.restoreCanvas(canvas, count);
|
||||||
protected void dispatchDraw(Canvas canvas) {
|
|
||||||
super.dispatchDraw(fake);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
|
if (node instanceof RenderableView) {
|
||||||
return super.drawChild(fake, child, drawingTime);
|
((RenderableView) node).resetProperties();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node.isResponsible()) {
|
||||||
|
svg.enableTouchEvents();
|
||||||
|
}
|
||||||
|
} else if (child instanceof SvgView) {
|
||||||
|
SvgView svgView = (SvgView) child;
|
||||||
|
svgView.drawChildren(canvas);
|
||||||
|
if (svgView.isResponsible()) {
|
||||||
|
svg.enableTouchEvents();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Enable rendering other native ancestor views in e.g. masks
|
||||||
|
child.draw(canvas);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
this.setClientRect(groupRect);
|
||||||
|
popGlyphContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enable rendering other native ancestor views in e.g. masks, but don't render them another time
|
||||||
|
Bitmap fakeBitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
|
||||||
|
Canvas fake = new Canvas(fakeBitmap);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void dispatchDraw(Canvas canvas) {
|
||||||
|
super.dispatchDraw(fake);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
|
||||||
|
return super.drawChild(fake, child, drawingTime);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,423 +6,410 @@
|
|||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
package com.horcrux.svg;
|
package com.horcrux.svg;
|
||||||
|
|
||||||
import com.facebook.react.bridge.ReadableMap;
|
import com.facebook.react.bridge.ReadableMap;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
// https://www.w3.org/TR/SVG/text.html#TSpanElement
|
// https://www.w3.org/TR/SVG/text.html#TSpanElement
|
||||||
class GlyphContext {
|
class GlyphContext {
|
||||||
|
|
||||||
// Current stack (one per node push/pop)
|
// Current stack (one per node push/pop)
|
||||||
final ArrayList<FontData> mFontContext = new ArrayList<>();
|
final ArrayList<FontData> mFontContext = new ArrayList<>();
|
||||||
|
|
||||||
// Unique input attribute lists (only added if node sets a value)
|
// Unique input attribute lists (only added if node sets a value)
|
||||||
private final ArrayList<SVGLength[]> mXsContext = new ArrayList<>();
|
private final ArrayList<SVGLength[]> mXsContext = new ArrayList<>();
|
||||||
private final ArrayList<SVGLength[]> mYsContext = new ArrayList<>();
|
private final ArrayList<SVGLength[]> mYsContext = new ArrayList<>();
|
||||||
private final ArrayList<SVGLength[]> mDXsContext = new ArrayList<>();
|
private final ArrayList<SVGLength[]> mDXsContext = new ArrayList<>();
|
||||||
private final ArrayList<SVGLength[]> mDYsContext = new ArrayList<>();
|
private final ArrayList<SVGLength[]> mDYsContext = new ArrayList<>();
|
||||||
private final ArrayList<double[]> mRsContext = new ArrayList<>();
|
private final ArrayList<double[]> mRsContext = new ArrayList<>();
|
||||||
|
|
||||||
// Unique index into attribute list (one per unique list)
|
// Unique index into attribute list (one per unique list)
|
||||||
private final ArrayList<Integer> mXIndices = new ArrayList<>();
|
private final ArrayList<Integer> mXIndices = new ArrayList<>();
|
||||||
private final ArrayList<Integer> mYIndices = new ArrayList<>();
|
private final ArrayList<Integer> mYIndices = new ArrayList<>();
|
||||||
private final ArrayList<Integer> mDXIndices = new ArrayList<>();
|
private final ArrayList<Integer> mDXIndices = new ArrayList<>();
|
||||||
private final ArrayList<Integer> mDYIndices = new ArrayList<>();
|
private final ArrayList<Integer> mDYIndices = new ArrayList<>();
|
||||||
private final ArrayList<Integer> mRIndices = new ArrayList<>();
|
private final ArrayList<Integer> mRIndices = new ArrayList<>();
|
||||||
|
|
||||||
// Index of unique context used (one per node push/pop)
|
// Index of unique context used (one per node push/pop)
|
||||||
private final ArrayList<Integer> mXsIndices = new ArrayList<>();
|
private final ArrayList<Integer> mXsIndices = new ArrayList<>();
|
||||||
private final ArrayList<Integer> mYsIndices = new ArrayList<>();
|
private final ArrayList<Integer> mYsIndices = new ArrayList<>();
|
||||||
private final ArrayList<Integer> mDXsIndices = new ArrayList<>();
|
private final ArrayList<Integer> mDXsIndices = new ArrayList<>();
|
||||||
private final ArrayList<Integer> mDYsIndices = new ArrayList<>();
|
private final ArrayList<Integer> mDYsIndices = new ArrayList<>();
|
||||||
private final ArrayList<Integer> mRsIndices = new ArrayList<>();
|
private final ArrayList<Integer> mRsIndices = new ArrayList<>();
|
||||||
|
|
||||||
// Calculated on push context, percentage and em length depends on parent font size
|
// Calculated on push context, percentage and em length depends on parent font size
|
||||||
private double mFontSize = FontData.DEFAULT_FONT_SIZE;
|
private double mFontSize = FontData.DEFAULT_FONT_SIZE;
|
||||||
private FontData topFont = FontData.Defaults;
|
private FontData topFont = FontData.Defaults;
|
||||||
|
|
||||||
// Current accumulated values
|
// Current accumulated values
|
||||||
// https://www.w3.org/TR/SVG/types.html#DataTypeCoordinate
|
// https://www.w3.org/TR/SVG/types.html#DataTypeCoordinate
|
||||||
// <coordinate> syntax is the same as that for <length>
|
// <coordinate> syntax is the same as that for <length>
|
||||||
private double mX;
|
private double mX;
|
||||||
private double mY;
|
private double mY;
|
||||||
|
|
||||||
// https://www.w3.org/TR/SVG/types.html#Length
|
// https://www.w3.org/TR/SVG/types.html#Length
|
||||||
private double mDX;
|
private double mDX;
|
||||||
private double mDY;
|
private double mDY;
|
||||||
|
|
||||||
// Current <list-of-coordinates> SVGLengthList
|
// Current <list-of-coordinates> SVGLengthList
|
||||||
// https://www.w3.org/TR/SVG/types.html#InterfaceSVGLengthList
|
// https://www.w3.org/TR/SVG/types.html#InterfaceSVGLengthList
|
||||||
// https://www.w3.org/TR/SVG/types.html#DataTypeCoordinates
|
// https://www.w3.org/TR/SVG/types.html#DataTypeCoordinates
|
||||||
|
|
||||||
// https://www.w3.org/TR/SVG/text.html#TSpanElementXAttribute
|
// https://www.w3.org/TR/SVG/text.html#TSpanElementXAttribute
|
||||||
private SVGLength[] mXs = new SVGLength[]{};
|
private SVGLength[] mXs = new SVGLength[] {};
|
||||||
|
|
||||||
// https://www.w3.org/TR/SVG/text.html#TSpanElementYAttribute
|
// https://www.w3.org/TR/SVG/text.html#TSpanElementYAttribute
|
||||||
private SVGLength[] mYs = new SVGLength[]{};
|
private SVGLength[] mYs = new SVGLength[] {};
|
||||||
|
|
||||||
// Current <list-of-lengths> SVGLengthList
|
// Current <list-of-lengths> SVGLengthList
|
||||||
// https://www.w3.org/TR/SVG/types.html#DataTypeLengths
|
// https://www.w3.org/TR/SVG/types.html#DataTypeLengths
|
||||||
|
|
||||||
// https://www.w3.org/TR/SVG/text.html#TSpanElementDXAttribute
|
// https://www.w3.org/TR/SVG/text.html#TSpanElementDXAttribute
|
||||||
private SVGLength[] mDXs = new SVGLength[]{};
|
private SVGLength[] mDXs = new SVGLength[] {};
|
||||||
|
|
||||||
// https://www.w3.org/TR/SVG/text.html#TSpanElementDYAttribute
|
// https://www.w3.org/TR/SVG/text.html#TSpanElementDYAttribute
|
||||||
private SVGLength[] mDYs = new SVGLength[]{};
|
private SVGLength[] mDYs = new SVGLength[] {};
|
||||||
|
|
||||||
// Current <list-of-numbers> SVGLengthList
|
// Current <list-of-numbers> SVGLengthList
|
||||||
// https://www.w3.org/TR/SVG/types.html#DataTypeNumbers
|
// https://www.w3.org/TR/SVG/types.html#DataTypeNumbers
|
||||||
|
|
||||||
// https://www.w3.org/TR/SVG/text.html#TSpanElementRotateAttribute
|
// https://www.w3.org/TR/SVG/text.html#TSpanElementRotateAttribute
|
||||||
private double[] mRs = new double[]{0};
|
private double[] mRs = new double[] {0};
|
||||||
|
|
||||||
// Current attribute list index
|
// Current attribute list index
|
||||||
private int mXsIndex;
|
private int mXsIndex;
|
||||||
private int mYsIndex;
|
private int mYsIndex;
|
||||||
private int mDXsIndex;
|
private int mDXsIndex;
|
||||||
private int mDYsIndex;
|
private int mDYsIndex;
|
||||||
private int mRsIndex;
|
private int mRsIndex;
|
||||||
|
|
||||||
// Current value index in current attribute list
|
// Current value index in current attribute list
|
||||||
private int mXIndex = -1;
|
private int mXIndex = -1;
|
||||||
private int mYIndex = -1;
|
private int mYIndex = -1;
|
||||||
private int mDXIndex = -1;
|
private int mDXIndex = -1;
|
||||||
private int mDYIndex = -1;
|
private int mDYIndex = -1;
|
||||||
private int mRIndex = -1;
|
private int mRIndex = -1;
|
||||||
|
|
||||||
// Top index of stack
|
// Top index of stack
|
||||||
private int mTop;
|
private int mTop;
|
||||||
|
|
||||||
// Constructor parameters
|
// Constructor parameters
|
||||||
private final float mScale;
|
private final float mScale;
|
||||||
private final float mWidth;
|
private final float mWidth;
|
||||||
private final float mHeight;
|
private final float mHeight;
|
||||||
|
|
||||||
private void pushIndices() {
|
private void pushIndices() {
|
||||||
mXsIndices.add(mXsIndex);
|
mXsIndices.add(mXsIndex);
|
||||||
mYsIndices.add(mYsIndex);
|
mYsIndices.add(mYsIndex);
|
||||||
mDXsIndices.add(mDXsIndex);
|
mDXsIndices.add(mDXsIndex);
|
||||||
mDYsIndices.add(mDYsIndex);
|
mDYsIndices.add(mDYsIndex);
|
||||||
mRsIndices.add(mRsIndex);
|
mRsIndices.add(mRsIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
GlyphContext(float scale, float width, float height) {
|
||||||
|
mScale = scale;
|
||||||
|
mWidth = width;
|
||||||
|
mHeight = height;
|
||||||
|
|
||||||
|
mXsContext.add(mXs);
|
||||||
|
mYsContext.add(mYs);
|
||||||
|
mDXsContext.add(mDXs);
|
||||||
|
mDYsContext.add(mDYs);
|
||||||
|
mRsContext.add(mRs);
|
||||||
|
|
||||||
|
mXIndices.add(mXIndex);
|
||||||
|
mYIndices.add(mYIndex);
|
||||||
|
mDXIndices.add(mDXIndex);
|
||||||
|
mDYIndices.add(mDYIndex);
|
||||||
|
mRIndices.add(mRIndex);
|
||||||
|
|
||||||
|
mFontContext.add(topFont);
|
||||||
|
|
||||||
|
pushIndices();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void reset() {
|
||||||
|
mXsIndex = mYsIndex = mDXsIndex = mDYsIndex = mRsIndex = 0;
|
||||||
|
mXIndex = mYIndex = mDXIndex = mDYIndex = mRIndex = -1;
|
||||||
|
mX = mY = mDX = mDY = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
FontData getFont() {
|
||||||
|
return topFont;
|
||||||
|
}
|
||||||
|
|
||||||
|
private FontData getTopOrParentFont(GroupView child) {
|
||||||
|
if (mTop > 0) {
|
||||||
|
return topFont;
|
||||||
|
} else {
|
||||||
|
GroupView parentRoot = child.getParentTextRoot();
|
||||||
|
|
||||||
|
while (parentRoot != null) {
|
||||||
|
FontData map = parentRoot.getGlyphContext().getFont();
|
||||||
|
if (map != FontData.Defaults) {
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
parentRoot = parentRoot.getParentTextRoot();
|
||||||
|
}
|
||||||
|
|
||||||
|
return FontData.Defaults;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void pushNodeAndFont(GroupView node, @Nullable ReadableMap font) {
|
||||||
|
FontData parent = getTopOrParentFont(node);
|
||||||
|
mTop++;
|
||||||
|
|
||||||
|
if (font == null) {
|
||||||
|
mFontContext.add(parent);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
GlyphContext(float scale, float width, float height) {
|
FontData data = new FontData(font, parent, mScale);
|
||||||
mScale = scale;
|
mFontSize = data.fontSize;
|
||||||
mWidth = width;
|
mFontContext.add(data);
|
||||||
mHeight = height;
|
topFont = data;
|
||||||
|
}
|
||||||
|
|
||||||
mXsContext.add(mXs);
|
void pushContext(GroupView node, @Nullable ReadableMap font) {
|
||||||
mYsContext.add(mYs);
|
pushNodeAndFont(node, font);
|
||||||
mDXsContext.add(mDXs);
|
pushIndices();
|
||||||
mDYsContext.add(mDYs);
|
}
|
||||||
mRsContext.add(mRs);
|
|
||||||
|
|
||||||
mXIndices.add(mXIndex);
|
private SVGLength[] getStringArrayFromReadableArray(ArrayList<SVGLength> readableArray) {
|
||||||
mYIndices.add(mYIndex);
|
int size = readableArray.size();
|
||||||
mDXIndices.add(mDXIndex);
|
SVGLength[] strings = new SVGLength[size];
|
||||||
mDYIndices.add(mDYIndex);
|
for (int i = 0; i < size; i++) {
|
||||||
mRIndices.add(mRIndex);
|
strings[i] = readableArray.get(i);
|
||||||
|
}
|
||||||
|
return strings;
|
||||||
|
}
|
||||||
|
|
||||||
mFontContext.add(topFont);
|
private double[] getDoubleArrayFromReadableArray(ArrayList<SVGLength> readableArray) {
|
||||||
|
int size = readableArray.size();
|
||||||
|
double[] doubles = new double[size];
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
SVGLength length = readableArray.get(i);
|
||||||
|
doubles[i] = length.value;
|
||||||
|
}
|
||||||
|
return doubles;
|
||||||
|
}
|
||||||
|
|
||||||
pushIndices();
|
void pushContext(
|
||||||
|
boolean reset,
|
||||||
|
TextView node,
|
||||||
|
@Nullable ReadableMap font,
|
||||||
|
@Nullable ArrayList<SVGLength> x,
|
||||||
|
@Nullable ArrayList<SVGLength> y,
|
||||||
|
@Nullable ArrayList<SVGLength> deltaX,
|
||||||
|
@Nullable ArrayList<SVGLength> deltaY,
|
||||||
|
@Nullable ArrayList<SVGLength> rotate) {
|
||||||
|
if (reset) {
|
||||||
|
this.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void reset() {
|
pushNodeAndFont(node, font);
|
||||||
mXsIndex = mYsIndex = mDXsIndex = mDYsIndex = mRsIndex = 0;
|
|
||||||
mXIndex = mYIndex = mDXIndex = mDYIndex = mRIndex = -1;
|
if (x != null && x.size() != 0) {
|
||||||
mX = mY = mDX = mDY = 0;
|
mXsIndex++;
|
||||||
|
mXIndex = -1;
|
||||||
|
mXIndices.add(mXIndex);
|
||||||
|
mXs = getStringArrayFromReadableArray(x);
|
||||||
|
mXsContext.add(mXs);
|
||||||
}
|
}
|
||||||
|
|
||||||
FontData getFont() {
|
if (y != null && y.size() != 0) {
|
||||||
return topFont;
|
mYsIndex++;
|
||||||
|
mYIndex = -1;
|
||||||
|
mYIndices.add(mYIndex);
|
||||||
|
mYs = getStringArrayFromReadableArray(y);
|
||||||
|
mYsContext.add(mYs);
|
||||||
}
|
}
|
||||||
|
|
||||||
private FontData getTopOrParentFont(GroupView child) {
|
if (deltaX != null && deltaX.size() != 0) {
|
||||||
if (mTop > 0) {
|
mDXsIndex++;
|
||||||
return topFont;
|
mDXIndex = -1;
|
||||||
} else {
|
mDXIndices.add(mDXIndex);
|
||||||
GroupView parentRoot = child.getParentTextRoot();
|
mDXs = getStringArrayFromReadableArray(deltaX);
|
||||||
|
mDXsContext.add(mDXs);
|
||||||
while (parentRoot != null) {
|
|
||||||
FontData map = parentRoot.getGlyphContext().getFont();
|
|
||||||
if (map != FontData.Defaults) {
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
parentRoot = parentRoot.getParentTextRoot();
|
|
||||||
}
|
|
||||||
|
|
||||||
return FontData.Defaults;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void pushNodeAndFont(GroupView node, @Nullable ReadableMap font) {
|
if (deltaY != null && deltaY.size() != 0) {
|
||||||
FontData parent = getTopOrParentFont(node);
|
mDYsIndex++;
|
||||||
mTop++;
|
mDYIndex = -1;
|
||||||
|
mDYIndices.add(mDYIndex);
|
||||||
if (font == null) {
|
mDYs = getStringArrayFromReadableArray(deltaY);
|
||||||
mFontContext.add(parent);
|
mDYsContext.add(mDYs);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
FontData data = new FontData(font, parent, mScale);
|
|
||||||
mFontSize = data.fontSize;
|
|
||||||
mFontContext.add(data);
|
|
||||||
topFont = data;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void pushContext(GroupView node, @Nullable ReadableMap font) {
|
if (rotate != null && rotate.size() != 0) {
|
||||||
pushNodeAndFont(node, font);
|
mRsIndex++;
|
||||||
pushIndices();
|
mRIndex = -1;
|
||||||
|
mRIndices.add(mRIndex);
|
||||||
|
mRs = getDoubleArrayFromReadableArray(rotate);
|
||||||
|
mRsContext.add(mRs);
|
||||||
}
|
}
|
||||||
|
|
||||||
private SVGLength[] getStringArrayFromReadableArray(ArrayList<SVGLength> readableArray) {
|
pushIndices();
|
||||||
int size = readableArray.size();
|
}
|
||||||
SVGLength[] strings = new SVGLength[size];
|
|
||||||
for (int i = 0; i < size; i++) {
|
void popContext() {
|
||||||
strings[i] = readableArray.get(i);
|
mFontContext.remove(mTop);
|
||||||
}
|
mXsIndices.remove(mTop);
|
||||||
return strings;
|
mYsIndices.remove(mTop);
|
||||||
|
mDXsIndices.remove(mTop);
|
||||||
|
mDYsIndices.remove(mTop);
|
||||||
|
mRsIndices.remove(mTop);
|
||||||
|
|
||||||
|
mTop--;
|
||||||
|
|
||||||
|
int x = mXsIndex;
|
||||||
|
int y = mYsIndex;
|
||||||
|
int dx = mDXsIndex;
|
||||||
|
int dy = mDYsIndex;
|
||||||
|
int r = mRsIndex;
|
||||||
|
|
||||||
|
topFont = mFontContext.get(mTop);
|
||||||
|
mXsIndex = mXsIndices.get(mTop);
|
||||||
|
mYsIndex = mYsIndices.get(mTop);
|
||||||
|
mDXsIndex = mDXsIndices.get(mTop);
|
||||||
|
mDYsIndex = mDYsIndices.get(mTop);
|
||||||
|
mRsIndex = mRsIndices.get(mTop);
|
||||||
|
|
||||||
|
if (x != mXsIndex) {
|
||||||
|
mXsContext.remove(x);
|
||||||
|
mXs = mXsContext.get(mXsIndex);
|
||||||
|
mXIndex = mXIndices.get(mXsIndex);
|
||||||
|
}
|
||||||
|
if (y != mYsIndex) {
|
||||||
|
mYsContext.remove(y);
|
||||||
|
mYs = mYsContext.get(mYsIndex);
|
||||||
|
mYIndex = mYIndices.get(mYsIndex);
|
||||||
|
}
|
||||||
|
if (dx != mDXsIndex) {
|
||||||
|
mDXsContext.remove(dx);
|
||||||
|
mDXs = mDXsContext.get(mDXsIndex);
|
||||||
|
mDXIndex = mDXIndices.get(mDXsIndex);
|
||||||
|
}
|
||||||
|
if (dy != mDYsIndex) {
|
||||||
|
mDYsContext.remove(dy);
|
||||||
|
mDYs = mDYsContext.get(mDYsIndex);
|
||||||
|
mDYIndex = mDYIndices.get(mDYsIndex);
|
||||||
|
}
|
||||||
|
if (r != mRsIndex) {
|
||||||
|
mRsContext.remove(r);
|
||||||
|
mRs = mRsContext.get(mRsIndex);
|
||||||
|
mRIndex = mRIndices.get(mRsIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void incrementIndices(ArrayList<Integer> indices, int topIndex) {
|
||||||
|
for (int index = topIndex; index >= 0; index--) {
|
||||||
|
int xIndex = indices.get(index);
|
||||||
|
indices.set(index, xIndex + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://www.w3.org/TR/SVG11/text.html#FontSizeProperty
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get font size from context.
|
||||||
|
*
|
||||||
|
* <p>‘font-size’ Value: < absolute-size > | < relative-size > | < length > | < percentage > |
|
||||||
|
* inherit Initial: medium Applies to: text content elements Inherited: yes, the computed value is
|
||||||
|
* inherited Percentages: refer to parent element's font size Media: visual Animatable: yes
|
||||||
|
*
|
||||||
|
* <p>This property refers to the size of the font from baseline to baseline when multiple lines
|
||||||
|
* of text are set solid in a multiline layout environment.
|
||||||
|
*
|
||||||
|
* <p>For SVG, if a < length > is provided without a unit identifier (e.g., an unqualified number
|
||||||
|
* such as 128), the SVG user agent processes the < length > as a height value in the current user
|
||||||
|
* coordinate system.
|
||||||
|
*
|
||||||
|
* <p>If a < length > is provided with one of the unit identifiers (e.g., 12pt or 10%), then the
|
||||||
|
* SVG user agent converts the < length > into a corresponding value in the current user
|
||||||
|
* coordinate system by applying the rules described in Units.
|
||||||
|
*
|
||||||
|
* <p>Except for any additional information provided in this specification, the normative
|
||||||
|
* definition of the property is in CSS2 ([CSS2], section 15.2.4).
|
||||||
|
*/
|
||||||
|
double getFontSize() {
|
||||||
|
return mFontSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
double nextX(double advance) {
|
||||||
|
incrementIndices(mXIndices, mXsIndex);
|
||||||
|
|
||||||
|
int nextIndex = mXIndex + 1;
|
||||||
|
if (nextIndex < mXs.length) {
|
||||||
|
mDX = 0;
|
||||||
|
mXIndex = nextIndex;
|
||||||
|
SVGLength string = mXs[nextIndex];
|
||||||
|
mX = PropHelper.fromRelative(string, mWidth, 0, mScale, mFontSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
private double[] getDoubleArrayFromReadableArray(ArrayList<SVGLength> readableArray) {
|
mX += advance;
|
||||||
int size = readableArray.size();
|
|
||||||
double[] doubles = new double[size];
|
return mX;
|
||||||
for (int i = 0; i < size; i++) {
|
}
|
||||||
SVGLength length = readableArray.get(i);
|
|
||||||
doubles[i] = length.value;
|
double nextY() {
|
||||||
}
|
incrementIndices(mYIndices, mYsIndex);
|
||||||
return doubles;
|
|
||||||
|
int nextIndex = mYIndex + 1;
|
||||||
|
if (nextIndex < mYs.length) {
|
||||||
|
mDY = 0;
|
||||||
|
mYIndex = nextIndex;
|
||||||
|
SVGLength string = mYs[nextIndex];
|
||||||
|
mY = PropHelper.fromRelative(string, mHeight, 0, mScale, mFontSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
void pushContext(
|
return mY;
|
||||||
boolean reset,
|
}
|
||||||
TextView node,
|
|
||||||
@Nullable ReadableMap font,
|
|
||||||
@Nullable ArrayList<SVGLength> x,
|
|
||||||
@Nullable ArrayList<SVGLength> y,
|
|
||||||
@Nullable ArrayList<SVGLength> deltaX,
|
|
||||||
@Nullable ArrayList<SVGLength> deltaY,
|
|
||||||
@Nullable ArrayList<SVGLength> rotate
|
|
||||||
) {
|
|
||||||
if (reset) {
|
|
||||||
this.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
pushNodeAndFont(node, font);
|
double nextDeltaX() {
|
||||||
|
incrementIndices(mDXIndices, mDXsIndex);
|
||||||
|
|
||||||
if (x != null && x.size() != 0) {
|
int nextIndex = mDXIndex + 1;
|
||||||
mXsIndex++;
|
if (nextIndex < mDXs.length) {
|
||||||
mXIndex = -1;
|
mDXIndex = nextIndex;
|
||||||
mXIndices.add(mXIndex);
|
SVGLength string = mDXs[nextIndex];
|
||||||
mXs = getStringArrayFromReadableArray(x);
|
double val = PropHelper.fromRelative(string, mWidth, 0, mScale, mFontSize);
|
||||||
mXsContext.add(mXs);
|
mDX += val;
|
||||||
}
|
|
||||||
|
|
||||||
if (y != null && y.size() != 0) {
|
|
||||||
mYsIndex++;
|
|
||||||
mYIndex = -1;
|
|
||||||
mYIndices.add(mYIndex);
|
|
||||||
mYs = getStringArrayFromReadableArray(y);
|
|
||||||
mYsContext.add(mYs);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (deltaX != null && deltaX.size() != 0) {
|
|
||||||
mDXsIndex++;
|
|
||||||
mDXIndex = -1;
|
|
||||||
mDXIndices.add(mDXIndex);
|
|
||||||
mDXs = getStringArrayFromReadableArray(deltaX);
|
|
||||||
mDXsContext.add(mDXs);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (deltaY != null && deltaY.size() != 0) {
|
|
||||||
mDYsIndex++;
|
|
||||||
mDYIndex = -1;
|
|
||||||
mDYIndices.add(mDYIndex);
|
|
||||||
mDYs = getStringArrayFromReadableArray(deltaY);
|
|
||||||
mDYsContext.add(mDYs);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rotate != null && rotate.size() != 0) {
|
|
||||||
mRsIndex++;
|
|
||||||
mRIndex = -1;
|
|
||||||
mRIndices.add(mRIndex);
|
|
||||||
mRs = getDoubleArrayFromReadableArray(rotate);
|
|
||||||
mRsContext.add(mRs);
|
|
||||||
}
|
|
||||||
|
|
||||||
pushIndices();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void popContext() {
|
return mDX;
|
||||||
mFontContext.remove(mTop);
|
}
|
||||||
mXsIndices.remove(mTop);
|
|
||||||
mYsIndices.remove(mTop);
|
|
||||||
mDXsIndices.remove(mTop);
|
|
||||||
mDYsIndices.remove(mTop);
|
|
||||||
mRsIndices.remove(mTop);
|
|
||||||
|
|
||||||
mTop--;
|
double nextDeltaY() {
|
||||||
|
incrementIndices(mDYIndices, mDYsIndex);
|
||||||
|
|
||||||
int x = mXsIndex;
|
int nextIndex = mDYIndex + 1;
|
||||||
int y = mYsIndex;
|
if (nextIndex < mDYs.length) {
|
||||||
int dx = mDXsIndex;
|
mDYIndex = nextIndex;
|
||||||
int dy = mDYsIndex;
|
SVGLength string = mDYs[nextIndex];
|
||||||
int r = mRsIndex;
|
double val = PropHelper.fromRelative(string, mHeight, 0, mScale, mFontSize);
|
||||||
|
mDY += val;
|
||||||
topFont = mFontContext.get(mTop);
|
|
||||||
mXsIndex = mXsIndices.get(mTop);
|
|
||||||
mYsIndex = mYsIndices.get(mTop);
|
|
||||||
mDXsIndex = mDXsIndices.get(mTop);
|
|
||||||
mDYsIndex = mDYsIndices.get(mTop);
|
|
||||||
mRsIndex = mRsIndices.get(mTop);
|
|
||||||
|
|
||||||
if (x != mXsIndex) {
|
|
||||||
mXsContext.remove(x);
|
|
||||||
mXs = mXsContext.get(mXsIndex);
|
|
||||||
mXIndex = mXIndices.get(mXsIndex);
|
|
||||||
}
|
|
||||||
if (y != mYsIndex) {
|
|
||||||
mYsContext.remove(y);
|
|
||||||
mYs = mYsContext.get(mYsIndex);
|
|
||||||
mYIndex = mYIndices.get(mYsIndex);
|
|
||||||
}
|
|
||||||
if (dx != mDXsIndex) {
|
|
||||||
mDXsContext.remove(dx);
|
|
||||||
mDXs = mDXsContext.get(mDXsIndex);
|
|
||||||
mDXIndex = mDXIndices.get(mDXsIndex);
|
|
||||||
}
|
|
||||||
if (dy != mDYsIndex) {
|
|
||||||
mDYsContext.remove(dy);
|
|
||||||
mDYs = mDYsContext.get(mDYsIndex);
|
|
||||||
mDYIndex = mDYIndices.get(mDYsIndex);
|
|
||||||
}
|
|
||||||
if (r != mRsIndex) {
|
|
||||||
mRsContext.remove(r);
|
|
||||||
mRs = mRsContext.get(mRsIndex);
|
|
||||||
mRIndex = mRIndices.get(mRsIndex);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void incrementIndices(ArrayList<Integer> indices, int topIndex) {
|
return mDY;
|
||||||
for (int index = topIndex; index >= 0; index--) {
|
}
|
||||||
int xIndex = indices.get(index);
|
|
||||||
indices.set(index, xIndex + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://www.w3.org/TR/SVG11/text.html#FontSizeProperty
|
double nextRotation() {
|
||||||
|
incrementIndices(mRIndices, mRsIndex);
|
||||||
|
|
||||||
/**
|
mRIndex = Math.min(mRIndex + 1, mRs.length - 1);
|
||||||
* Get font size from context.
|
|
||||||
* <p>
|
|
||||||
* ‘font-size’
|
|
||||||
* Value: < absolute-size > | < relative-size > | < length > | < percentage > | inherit
|
|
||||||
* Initial: medium
|
|
||||||
* Applies to: text content elements
|
|
||||||
* Inherited: yes, the computed value is inherited
|
|
||||||
* Percentages: refer to parent element's font size
|
|
||||||
* Media: visual
|
|
||||||
* Animatable: yes
|
|
||||||
* <p>
|
|
||||||
* This property refers to the size of the font from baseline to
|
|
||||||
* baseline when multiple lines of text are set solid in a multiline
|
|
||||||
* layout environment.
|
|
||||||
* <p>
|
|
||||||
* For SVG, if a < length > is provided without a unit identifier
|
|
||||||
* (e.g., an unqualified number such as 128), the SVG user agent
|
|
||||||
* processes the < length > as a height value in the current user
|
|
||||||
* coordinate system.
|
|
||||||
* <p>
|
|
||||||
* If a < length > is provided with one of the unit identifiers
|
|
||||||
* (e.g., 12pt or 10%), then the SVG user agent converts the
|
|
||||||
* < length > into a corresponding value in the current user
|
|
||||||
* coordinate system by applying the rules described in Units.
|
|
||||||
* <p>
|
|
||||||
* Except for any additional information provided in this specification,
|
|
||||||
* the normative definition of the property is in CSS2 ([CSS2], section 15.2.4).
|
|
||||||
*/
|
|
||||||
double getFontSize() {
|
|
||||||
return mFontSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
double nextX(double advance) {
|
return mRs[mRIndex];
|
||||||
incrementIndices(mXIndices, mXsIndex);
|
}
|
||||||
|
|
||||||
int nextIndex = mXIndex + 1;
|
float getWidth() {
|
||||||
if (nextIndex < mXs.length) {
|
return mWidth;
|
||||||
mDX = 0;
|
}
|
||||||
mXIndex = nextIndex;
|
|
||||||
SVGLength string = mXs[nextIndex];
|
|
||||||
mX = PropHelper.fromRelative(string, mWidth, 0, mScale, mFontSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
mX += advance;
|
float getHeight() {
|
||||||
|
return mHeight;
|
||||||
return mX;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
double nextY() {
|
|
||||||
incrementIndices(mYIndices, mYsIndex);
|
|
||||||
|
|
||||||
int nextIndex = mYIndex + 1;
|
|
||||||
if (nextIndex < mYs.length) {
|
|
||||||
mDY = 0;
|
|
||||||
mYIndex = nextIndex;
|
|
||||||
SVGLength string = mYs[nextIndex];
|
|
||||||
mY = PropHelper.fromRelative(string, mHeight, 0, mScale, mFontSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
return mY;
|
|
||||||
}
|
|
||||||
|
|
||||||
double nextDeltaX() {
|
|
||||||
incrementIndices(mDXIndices, mDXsIndex);
|
|
||||||
|
|
||||||
int nextIndex = mDXIndex + 1;
|
|
||||||
if (nextIndex < mDXs.length) {
|
|
||||||
mDXIndex = nextIndex;
|
|
||||||
SVGLength string = mDXs[nextIndex];
|
|
||||||
double val = PropHelper.fromRelative(string, mWidth, 0, mScale, mFontSize);
|
|
||||||
mDX += val;
|
|
||||||
}
|
|
||||||
|
|
||||||
return mDX;
|
|
||||||
}
|
|
||||||
|
|
||||||
double nextDeltaY() {
|
|
||||||
incrementIndices(mDYIndices, mDYsIndex);
|
|
||||||
|
|
||||||
int nextIndex = mDYIndex + 1;
|
|
||||||
if (nextIndex < mDYs.length) {
|
|
||||||
mDYIndex = nextIndex;
|
|
||||||
SVGLength string = mDYs[nextIndex];
|
|
||||||
double val = PropHelper.fromRelative(string, mHeight, 0, mScale, mFontSize);
|
|
||||||
mDY += val;
|
|
||||||
}
|
|
||||||
|
|
||||||
return mDY;
|
|
||||||
}
|
|
||||||
|
|
||||||
double nextRotation() {
|
|
||||||
incrementIndices(mRIndices, mRsIndex);
|
|
||||||
|
|
||||||
mRIndex = Math.min(mRIndex + 1, mRs.length - 1);
|
|
||||||
|
|
||||||
return mRs[mRIndex];
|
|
||||||
}
|
|
||||||
|
|
||||||
float getWidth() {
|
|
||||||
return mWidth;
|
|
||||||
}
|
|
||||||
|
|
||||||
float getHeight() {
|
|
||||||
return mHeight;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,47 +2,46 @@ package com.horcrux.svg;
|
|||||||
|
|
||||||
import android.graphics.Paint;
|
import android.graphics.Paint;
|
||||||
import android.graphics.Path;
|
import android.graphics.Path;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
class GlyphPathBag {
|
class GlyphPathBag {
|
||||||
private final ArrayList<Path> paths = new ArrayList<>();
|
private final ArrayList<Path> paths = new ArrayList<>();
|
||||||
private final int[][] data = new int[256][];
|
private final int[][] data = new int[256][];
|
||||||
private final Paint paint;
|
private final Paint paint;
|
||||||
|
|
||||||
GlyphPathBag(Paint paint) {
|
GlyphPathBag(Paint paint) {
|
||||||
this.paint = paint;
|
this.paint = paint;
|
||||||
// Make indexed-by-one, to allow zero to represent non-cached
|
// Make indexed-by-one, to allow zero to represent non-cached
|
||||||
paths.add(new Path());
|
paths.add(new Path());
|
||||||
|
}
|
||||||
|
|
||||||
|
Path getOrCreateAndCache(char ch, String current) {
|
||||||
|
int index = getIndex(ch);
|
||||||
|
Path cached;
|
||||||
|
|
||||||
|
if (index != 0) {
|
||||||
|
cached = paths.get(index);
|
||||||
|
} else {
|
||||||
|
cached = new Path();
|
||||||
|
paint.getTextPath(current, 0, 1, 0, 0, cached);
|
||||||
|
|
||||||
|
int[] bin = data[ch >> 8];
|
||||||
|
if (bin == null) {
|
||||||
|
bin = data[ch >> 8] = new int[256];
|
||||||
|
}
|
||||||
|
bin[ch & 0xFF] = paths.size();
|
||||||
|
|
||||||
|
paths.add(cached);
|
||||||
}
|
}
|
||||||
|
|
||||||
Path getOrCreateAndCache(char ch, String current) {
|
Path glyph = new Path();
|
||||||
int index = getIndex(ch);
|
glyph.addPath(cached);
|
||||||
Path cached;
|
return glyph;
|
||||||
|
}
|
||||||
|
|
||||||
if (index != 0) {
|
private int getIndex(char ch) {
|
||||||
cached = paths.get(index);
|
int[] bin = data[ch >> 8];
|
||||||
} else {
|
if (bin == null) return 0;
|
||||||
cached = new Path();
|
return bin[ch & 0xFF];
|
||||||
paint.getTextPath(current, 0, 1, 0, 0, cached);
|
}
|
||||||
|
|
||||||
int[] bin = data[ch >> 8];
|
|
||||||
if (bin == null) {
|
|
||||||
bin = data[ch >> 8] = new int[256];
|
|
||||||
}
|
|
||||||
bin[ch & 0xFF] = paths.size();
|
|
||||||
|
|
||||||
paths.add(cached);
|
|
||||||
}
|
|
||||||
|
|
||||||
Path glyph = new Path();
|
|
||||||
glyph.addPath(cached);
|
|
||||||
return glyph;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int getIndex(char ch) {
|
|
||||||
int[] bin = data[ch >> 8];
|
|
||||||
if (bin == null) return 0;
|
|
||||||
return bin[ch & 0xFF];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,6 @@
|
|||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
package com.horcrux.svg;
|
package com.horcrux.svg;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
@@ -19,268 +18,264 @@ import android.graphics.RectF;
|
|||||||
import android.graphics.Region;
|
import android.graphics.Region;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
import com.facebook.react.bridge.ReactContext;
|
import com.facebook.react.bridge.ReactContext;
|
||||||
import com.facebook.react.bridge.ReadableMap;
|
import com.facebook.react.bridge.ReadableMap;
|
||||||
import com.facebook.react.uimanager.annotations.ReactProp;
|
import com.facebook.react.uimanager.annotations.ReactProp;
|
||||||
import com.facebook.react.views.view.ReactViewGroup;
|
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
@SuppressLint("ViewConstructor")
|
@SuppressLint("ViewConstructor")
|
||||||
class GroupView extends RenderableView {
|
class GroupView extends RenderableView {
|
||||||
@Nullable ReadableMap mFont;
|
@Nullable ReadableMap mFont;
|
||||||
private GlyphContext mGlyphContext;
|
private GlyphContext mGlyphContext;
|
||||||
|
|
||||||
public GroupView(ReactContext reactContext) {
|
public GroupView(ReactContext reactContext) {
|
||||||
super(reactContext);
|
super(reactContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ReactProp(name = "font")
|
||||||
|
public void setFont(@Nullable ReadableMap font) {
|
||||||
|
mFont = font;
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setupGlyphContext(Canvas canvas) {
|
||||||
|
RectF clipBounds = new RectF(canvas.getClipBounds());
|
||||||
|
if (mMatrix != null) {
|
||||||
|
mMatrix.mapRect(clipBounds);
|
||||||
}
|
}
|
||||||
|
if (mTransform != null) {
|
||||||
@ReactProp(name = "font")
|
mTransform.mapRect(clipBounds);
|
||||||
public void setFont(@Nullable ReadableMap font) {
|
|
||||||
mFont = font;
|
|
||||||
invalidate();
|
|
||||||
}
|
}
|
||||||
|
mGlyphContext = new GlyphContext(mScale, clipBounds.width(), clipBounds.height());
|
||||||
|
}
|
||||||
|
|
||||||
void setupGlyphContext(Canvas canvas) {
|
GlyphContext getGlyphContext() {
|
||||||
RectF clipBounds = new RectF(canvas.getClipBounds());
|
return mGlyphContext;
|
||||||
if (mMatrix != null) {
|
}
|
||||||
mMatrix.mapRect(clipBounds);
|
|
||||||
|
private static <T> T requireNonNull(T obj) {
|
||||||
|
if (obj == null) throw new NullPointerException();
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
GlyphContext getTextRootGlyphContext() {
|
||||||
|
return requireNonNull(getTextRoot()).getGlyphContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
void pushGlyphContext() {
|
||||||
|
getTextRootGlyphContext().pushContext(this, mFont);
|
||||||
|
}
|
||||||
|
|
||||||
|
void popGlyphContext() {
|
||||||
|
getTextRootGlyphContext().popContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw(final Canvas canvas, final Paint paint, final float opacity) {
|
||||||
|
setupGlyphContext(canvas);
|
||||||
|
clip(canvas, paint);
|
||||||
|
drawGroup(canvas, paint, opacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
void drawGroup(final Canvas canvas, final Paint paint, final float opacity) {
|
||||||
|
pushGlyphContext();
|
||||||
|
final SvgView svg = getSvgView();
|
||||||
|
final GroupView self = this;
|
||||||
|
final RectF groupRect = new RectF();
|
||||||
|
for (int i = 0; i < getChildCount(); i++) {
|
||||||
|
View child = getChildAt(i);
|
||||||
|
if (child instanceof MaskView) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (child instanceof VirtualView) {
|
||||||
|
VirtualView node = ((VirtualView) child);
|
||||||
|
if ("none".equals(node.mDisplay)) {
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
if (mTransform != null) {
|
if (node instanceof RenderableView) {
|
||||||
mTransform.mapRect(clipBounds);
|
((RenderableView) node).mergeProperties(self);
|
||||||
}
|
|
||||||
mGlyphContext = new GlyphContext(mScale, clipBounds.width(), clipBounds.height());
|
|
||||||
}
|
|
||||||
|
|
||||||
GlyphContext getGlyphContext() {
|
|
||||||
return mGlyphContext;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static <T> T requireNonNull(T obj) {
|
|
||||||
if (obj == null)
|
|
||||||
throw new NullPointerException();
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
GlyphContext getTextRootGlyphContext() {
|
|
||||||
return requireNonNull(getTextRoot()).getGlyphContext();
|
|
||||||
}
|
|
||||||
|
|
||||||
void pushGlyphContext() {
|
|
||||||
getTextRootGlyphContext().pushContext(this, mFont);
|
|
||||||
}
|
|
||||||
|
|
||||||
void popGlyphContext() {
|
|
||||||
getTextRootGlyphContext().popContext();
|
|
||||||
}
|
|
||||||
|
|
||||||
void draw(final Canvas canvas, final Paint paint, final float opacity) {
|
|
||||||
setupGlyphContext(canvas);
|
|
||||||
clip(canvas, paint);
|
|
||||||
drawGroup(canvas, paint, opacity);
|
|
||||||
}
|
|
||||||
|
|
||||||
void drawGroup(final Canvas canvas, final Paint paint, final float opacity) {
|
|
||||||
pushGlyphContext();
|
|
||||||
final SvgView svg = getSvgView();
|
|
||||||
final GroupView self = this;
|
|
||||||
final RectF groupRect = new RectF();
|
|
||||||
for (int i = 0; i < getChildCount(); i++) {
|
|
||||||
View child = getChildAt(i);
|
|
||||||
if (child instanceof MaskView) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (child instanceof VirtualView) {
|
|
||||||
VirtualView node = ((VirtualView)child);
|
|
||||||
if ("none".equals(node.mDisplay)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (node instanceof RenderableView) {
|
|
||||||
((RenderableView)node).mergeProperties(self);
|
|
||||||
}
|
|
||||||
|
|
||||||
int count = node.saveAndSetupCanvas(canvas, mCTM);
|
|
||||||
node.render(canvas, paint, opacity * mOpacity);
|
|
||||||
RectF r = node.getClientRect();
|
|
||||||
if (r != null) {
|
|
||||||
groupRect.union(r);
|
|
||||||
}
|
|
||||||
|
|
||||||
node.restoreCanvas(canvas, count);
|
|
||||||
|
|
||||||
if (node instanceof RenderableView) {
|
|
||||||
((RenderableView)node).resetProperties();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (node.isResponsible()) {
|
|
||||||
svg.enableTouchEvents();
|
|
||||||
}
|
|
||||||
} else if (child instanceof SvgView) {
|
|
||||||
SvgView svgView = (SvgView)child;
|
|
||||||
svgView.drawChildren(canvas);
|
|
||||||
if (svgView.isResponsible()) {
|
|
||||||
svg.enableTouchEvents();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.setClientRect(groupRect);
|
|
||||||
popGlyphContext();
|
|
||||||
}
|
|
||||||
|
|
||||||
void drawPath(Canvas canvas, Paint paint, float opacity) {
|
|
||||||
super.draw(canvas, paint, opacity);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
Path getPath(final Canvas canvas, final Paint paint) {
|
|
||||||
if (mPath != null) {
|
|
||||||
return mPath;
|
|
||||||
}
|
|
||||||
mPath = new Path();
|
|
||||||
|
|
||||||
for (int i = 0; i < getChildCount(); i++) {
|
|
||||||
View node = getChildAt(i);
|
|
||||||
if (node instanceof MaskView) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (node instanceof VirtualView) {
|
|
||||||
VirtualView n = (VirtualView)node;
|
|
||||||
Matrix transform = n.mMatrix;
|
|
||||||
mPath.addPath(n.getPath(canvas, paint), transform);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return mPath;
|
int count = node.saveAndSetupCanvas(canvas, mCTM);
|
||||||
|
node.render(canvas, paint, opacity * mOpacity);
|
||||||
|
RectF r = node.getClientRect();
|
||||||
|
if (r != null) {
|
||||||
|
groupRect.union(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
node.restoreCanvas(canvas, count);
|
||||||
|
|
||||||
|
if (node instanceof RenderableView) {
|
||||||
|
((RenderableView) node).resetProperties();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node.isResponsible()) {
|
||||||
|
svg.enableTouchEvents();
|
||||||
|
}
|
||||||
|
} else if (child instanceof SvgView) {
|
||||||
|
SvgView svgView = (SvgView) child;
|
||||||
|
svgView.drawChildren(canvas);
|
||||||
|
if (svgView.isResponsible()) {
|
||||||
|
svg.enableTouchEvents();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.setClientRect(groupRect);
|
||||||
|
popGlyphContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
void drawPath(Canvas canvas, Paint paint, float opacity) {
|
||||||
|
super.draw(canvas, paint, opacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
Path getPath(final Canvas canvas, final Paint paint) {
|
||||||
|
if (mPath != null) {
|
||||||
|
return mPath;
|
||||||
|
}
|
||||||
|
mPath = new Path();
|
||||||
|
|
||||||
|
for (int i = 0; i < getChildCount(); i++) {
|
||||||
|
View node = getChildAt(i);
|
||||||
|
if (node instanceof MaskView) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (node instanceof VirtualView) {
|
||||||
|
VirtualView n = (VirtualView) node;
|
||||||
|
Matrix transform = n.mMatrix;
|
||||||
|
mPath.addPath(n.getPath(canvas, paint), transform);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Path getPath(final Canvas canvas, final Paint paint, final Region.Op op) {
|
return mPath;
|
||||||
final Path path = new Path();
|
}
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
Path getPath(final Canvas canvas, final Paint paint, final Region.Op op) {
|
||||||
final Path.Op pop = Path.Op.valueOf(op.name());
|
final Path path = new Path();
|
||||||
for (int i = 0; i < getChildCount(); i++) {
|
|
||||||
View node = getChildAt(i);
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||||
if (node instanceof MaskView) {
|
final Path.Op pop = Path.Op.valueOf(op.name());
|
||||||
continue;
|
for (int i = 0; i < getChildCount(); i++) {
|
||||||
}
|
View node = getChildAt(i);
|
||||||
if (node instanceof VirtualView) {
|
if (node instanceof MaskView) {
|
||||||
VirtualView n = (VirtualView)node;
|
continue;
|
||||||
Matrix transform = n.mMatrix;
|
|
||||||
Path p2;
|
|
||||||
if (n instanceof GroupView) {
|
|
||||||
p2 = ((GroupView)n).getPath(canvas, paint, op);
|
|
||||||
} else {
|
|
||||||
p2 = n.getPath(canvas, paint);
|
|
||||||
}
|
|
||||||
p2.transform(transform);
|
|
||||||
path.op(p2, pop);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Rect clipBounds = canvas.getClipBounds();
|
|
||||||
final Region bounds = new Region(clipBounds);
|
|
||||||
final Region r = new Region();
|
|
||||||
for (int i = 0; i < getChildCount(); i++) {
|
|
||||||
View node = getChildAt(i);
|
|
||||||
if (node instanceof MaskView) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (node instanceof VirtualView) {
|
|
||||||
VirtualView n = (VirtualView)node;
|
|
||||||
Matrix transform = n.mMatrix;
|
|
||||||
Path p2;
|
|
||||||
if (n instanceof GroupView) {
|
|
||||||
p2 = ((GroupView)n).getPath(canvas, paint, op);
|
|
||||||
} else {
|
|
||||||
p2 = n.getPath(canvas, paint);
|
|
||||||
}
|
|
||||||
if (transform != null) {
|
|
||||||
p2.transform(transform);
|
|
||||||
}
|
|
||||||
Region r2 = new Region();
|
|
||||||
r2.setPath(p2, bounds);
|
|
||||||
r.op(r2, op);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
path.addPath(r.getBoundaryPath());
|
|
||||||
}
|
}
|
||||||
|
if (node instanceof VirtualView) {
|
||||||
return path;
|
VirtualView n = (VirtualView) node;
|
||||||
|
Matrix transform = n.mMatrix;
|
||||||
|
Path p2;
|
||||||
|
if (n instanceof GroupView) {
|
||||||
|
p2 = ((GroupView) n).getPath(canvas, paint, op);
|
||||||
|
} else {
|
||||||
|
p2 = n.getPath(canvas, paint);
|
||||||
|
}
|
||||||
|
p2.transform(transform);
|
||||||
|
path.op(p2, pop);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Rect clipBounds = canvas.getClipBounds();
|
||||||
|
final Region bounds = new Region(clipBounds);
|
||||||
|
final Region r = new Region();
|
||||||
|
for (int i = 0; i < getChildCount(); i++) {
|
||||||
|
View node = getChildAt(i);
|
||||||
|
if (node instanceof MaskView) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (node instanceof VirtualView) {
|
||||||
|
VirtualView n = (VirtualView) node;
|
||||||
|
Matrix transform = n.mMatrix;
|
||||||
|
Path p2;
|
||||||
|
if (n instanceof GroupView) {
|
||||||
|
p2 = ((GroupView) n).getPath(canvas, paint, op);
|
||||||
|
} else {
|
||||||
|
p2 = n.getPath(canvas, paint);
|
||||||
|
}
|
||||||
|
if (transform != null) {
|
||||||
|
p2.transform(transform);
|
||||||
|
}
|
||||||
|
Region r2 = new Region();
|
||||||
|
r2.setPath(p2, bounds);
|
||||||
|
r.op(r2, op);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
path.addPath(r.getBoundaryPath());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
return path;
|
||||||
int hitTest(final float[] src) {
|
}
|
||||||
if (!mInvertible || !mTransformInvertible) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
float[] dst = new float[2];
|
@Override
|
||||||
mInvMatrix.mapPoints(dst, src);
|
int hitTest(final float[] src) {
|
||||||
mInvTransform.mapPoints(dst);
|
if (!mInvertible || !mTransformInvertible) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
int x = Math.round(dst[0]);
|
float[] dst = new float[2];
|
||||||
int y = Math.round(dst[1]);
|
mInvMatrix.mapPoints(dst, src);
|
||||||
|
mInvTransform.mapPoints(dst);
|
||||||
|
|
||||||
Path clipPath = getClipPath();
|
int x = Math.round(dst[0]);
|
||||||
if (clipPath != null) {
|
int y = Math.round(dst[1]);
|
||||||
if (mClipRegionPath != clipPath) {
|
|
||||||
mClipRegionPath = clipPath;
|
|
||||||
mClipBounds = new RectF();
|
|
||||||
clipPath.computeBounds(mClipBounds, true);
|
|
||||||
mClipRegion = getRegion(clipPath, mClipBounds);
|
|
||||||
}
|
|
||||||
if (!mClipRegion.contains(x, y)) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = getChildCount() - 1; i >= 0; i--) {
|
|
||||||
View child = getChildAt(i);
|
|
||||||
if (child instanceof VirtualView) {
|
|
||||||
if (child instanceof MaskView) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
VirtualView node = (VirtualView) child;
|
|
||||||
|
|
||||||
int hitChild = node.hitTest(dst);
|
|
||||||
if (hitChild != -1) {
|
|
||||||
return (node.isResponsible() || hitChild != child.getId()) ? hitChild : getId();
|
|
||||||
}
|
|
||||||
} else if (child instanceof SvgView) {
|
|
||||||
SvgView node = (SvgView) child;
|
|
||||||
|
|
||||||
int hitChild = node.reactTagForTouch(dst[0], dst[1]);
|
|
||||||
if (hitChild != child.getId()) {
|
|
||||||
return hitChild;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
Path clipPath = getClipPath();
|
||||||
|
if (clipPath != null) {
|
||||||
|
if (mClipRegionPath != clipPath) {
|
||||||
|
mClipRegionPath = clipPath;
|
||||||
|
mClipBounds = new RectF();
|
||||||
|
clipPath.computeBounds(mClipBounds, true);
|
||||||
|
mClipRegion = getRegion(clipPath, mClipBounds);
|
||||||
|
}
|
||||||
|
if (!mClipRegion.contains(x, y)) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void saveDefinition() {
|
for (int i = getChildCount() - 1; i >= 0; i--) {
|
||||||
if (mName != null) {
|
View child = getChildAt(i);
|
||||||
getSvgView().defineTemplate(this, mName);
|
if (child instanceof VirtualView) {
|
||||||
|
if (child instanceof MaskView) {
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < getChildCount(); i++) {
|
VirtualView node = (VirtualView) child;
|
||||||
View node = getChildAt(i);
|
|
||||||
if (node instanceof VirtualView) {
|
int hitChild = node.hitTest(dst);
|
||||||
((VirtualView)node).saveDefinition();
|
if (hitChild != -1) {
|
||||||
}
|
return (node.isResponsible() || hitChild != child.getId()) ? hitChild : getId();
|
||||||
}
|
}
|
||||||
|
} else if (child instanceof SvgView) {
|
||||||
|
SvgView node = (SvgView) child;
|
||||||
|
|
||||||
|
int hitChild = node.reactTagForTouch(dst[0], dst[1]);
|
||||||
|
if (hitChild != child.getId()) {
|
||||||
|
return hitChild;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
return -1;
|
||||||
void resetProperties() {
|
}
|
||||||
for (int i = 0; i < getChildCount(); i++) {
|
|
||||||
View node = getChildAt(i);
|
void saveDefinition() {
|
||||||
if (node instanceof RenderableView) {
|
if (mName != null) {
|
||||||
((RenderableView)node).resetProperties();
|
getSvgView().defineTemplate(this, mName);
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < getChildCount(); i++) {
|
||||||
|
View node = getChildAt(i);
|
||||||
|
if (node instanceof VirtualView) {
|
||||||
|
((VirtualView) node).saveDefinition();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
void resetProperties() {
|
||||||
|
for (int i = 0; i < getChildCount(); i++) {
|
||||||
|
View node = getChildAt(i);
|
||||||
|
if (node instanceof RenderableView) {
|
||||||
|
((RenderableView) node).resetProperties();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,6 @@
|
|||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
package com.horcrux.svg;
|
package com.horcrux.svg;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
@@ -17,7 +16,6 @@ import android.graphics.Paint;
|
|||||||
import android.graphics.Path;
|
import android.graphics.Path;
|
||||||
import android.graphics.RectF;
|
import android.graphics.RectF;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
|
||||||
import com.facebook.common.executors.UiThreadImmediateExecutorService;
|
import com.facebook.common.executors.UiThreadImmediateExecutorService;
|
||||||
import com.facebook.common.logging.FLog;
|
import com.facebook.common.logging.FLog;
|
||||||
import com.facebook.common.references.CloseableReference;
|
import com.facebook.common.references.CloseableReference;
|
||||||
@@ -35,235 +33,240 @@ import com.facebook.react.common.ReactConstants;
|
|||||||
import com.facebook.react.uimanager.annotations.ReactProp;
|
import com.facebook.react.uimanager.annotations.ReactProp;
|
||||||
import com.facebook.react.views.imagehelper.ImageSource;
|
import com.facebook.react.views.imagehelper.ImageSource;
|
||||||
import com.facebook.react.views.imagehelper.ResourceDrawableIdHelper;
|
import com.facebook.react.views.imagehelper.ResourceDrawableIdHelper;
|
||||||
|
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
@SuppressLint("ViewConstructor")
|
@SuppressLint("ViewConstructor")
|
||||||
class ImageView extends RenderableView {
|
class ImageView extends RenderableView {
|
||||||
private SVGLength mX;
|
private SVGLength mX;
|
||||||
private SVGLength mY;
|
private SVGLength mY;
|
||||||
private SVGLength mW;
|
private SVGLength mW;
|
||||||
private SVGLength mH;
|
private SVGLength mH;
|
||||||
private String uriString;
|
private String uriString;
|
||||||
private int mImageWidth;
|
private int mImageWidth;
|
||||||
private int mImageHeight;
|
private int mImageHeight;
|
||||||
private String mAlign;
|
private String mAlign;
|
||||||
private int mMeetOrSlice;
|
private int mMeetOrSlice;
|
||||||
private final AtomicBoolean mLoading = new AtomicBoolean(false);
|
private final AtomicBoolean mLoading = new AtomicBoolean(false);
|
||||||
|
|
||||||
public ImageView(ReactContext reactContext) {
|
public ImageView(ReactContext reactContext) {
|
||||||
super(reactContext);
|
super(reactContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "x")
|
@ReactProp(name = "x")
|
||||||
public void setX(Dynamic x) {
|
public void setX(Dynamic x) {
|
||||||
mX = SVGLength.from(x);
|
mX = SVGLength.from(x);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setX(String x) {
|
public void setX(String x) {
|
||||||
mX = SVGLength.from(x);
|
mX = SVGLength.from(x);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "y")
|
@ReactProp(name = "y")
|
||||||
public void setY(Dynamic y) {
|
public void setY(Dynamic y) {
|
||||||
mY = SVGLength.from(y);
|
mY = SVGLength.from(y);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setY(String y) {
|
public void setY(String y) {
|
||||||
mY = SVGLength.from(y);
|
mY = SVGLength.from(y);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "width")
|
@ReactProp(name = "width")
|
||||||
public void setWidth(Dynamic width) {
|
public void setWidth(Dynamic width) {
|
||||||
mW = SVGLength.from(width);
|
mW = SVGLength.from(width);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setWidth(String width) {
|
public void setWidth(String width) {
|
||||||
mW = SVGLength.from(width);
|
mW = SVGLength.from(width);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "height")
|
@ReactProp(name = "height")
|
||||||
public void setHeight(Dynamic height) {
|
public void setHeight(Dynamic height) {
|
||||||
mH = SVGLength.from(height);
|
mH = SVGLength.from(height);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setHeight(String height) {
|
public void setHeight(String height) {
|
||||||
mH = SVGLength.from(height);
|
mH = SVGLength.from(height);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ReactProp(name = "src")
|
||||||
|
public void setSrc(@Nullable ReadableMap src) {
|
||||||
|
if (src != null) {
|
||||||
|
uriString = src.getString("uri");
|
||||||
|
|
||||||
@ReactProp(name = "src")
|
if (uriString == null || uriString.isEmpty()) {
|
||||||
public void setSrc(@Nullable ReadableMap src) {
|
// TODO: give warning about this
|
||||||
if (src != null) {
|
return;
|
||||||
uriString = src.getString("uri");
|
}
|
||||||
|
|
||||||
if (uriString == null || uriString.isEmpty()) {
|
if (src.hasKey("width") && src.hasKey("height")) {
|
||||||
//TODO: give warning about this
|
mImageWidth = src.getInt("width");
|
||||||
return;
|
mImageHeight = src.getInt("height");
|
||||||
}
|
} else {
|
||||||
|
mImageWidth = 0;
|
||||||
if (src.hasKey("width") && src.hasKey("height")) {
|
mImageHeight = 0;
|
||||||
mImageWidth = src.getInt("width");
|
}
|
||||||
mImageHeight = src.getInt("height");
|
Uri mUri = Uri.parse(uriString);
|
||||||
} else {
|
if (mUri.getScheme() == null) {
|
||||||
mImageWidth = 0;
|
ResourceDrawableIdHelper.getInstance().getResourceDrawableUri(mContext, uriString);
|
||||||
mImageHeight = 0;
|
}
|
||||||
}
|
|
||||||
Uri mUri = Uri.parse(uriString);
|
|
||||||
if (mUri.getScheme() == null) {
|
|
||||||
ResourceDrawableIdHelper.getInstance().getResourceDrawableUri(mContext, uriString);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@ReactProp(name = "align")
|
@ReactProp(name = "align")
|
||||||
public void setAlign(String align) {
|
public void setAlign(String align) {
|
||||||
mAlign = align;
|
mAlign = align;
|
||||||
invalidate();
|
invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@ReactProp(name = "meetOrSlice")
|
||||||
|
public void setMeetOrSlice(int meetOrSlice) {
|
||||||
|
mMeetOrSlice = meetOrSlice;
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
void draw(final Canvas canvas, final Paint paint, final float opacity) {
|
||||||
|
if (!mLoading.get()) {
|
||||||
|
ImagePipeline imagePipeline = Fresco.getImagePipeline();
|
||||||
|
ImageSource imageSource = new ImageSource(mContext, uriString);
|
||||||
|
ImageRequest request = ImageRequest.fromUri(imageSource.getUri());
|
||||||
|
boolean inMemoryCache = imagePipeline.isInBitmapMemoryCache(request);
|
||||||
|
|
||||||
|
if (inMemoryCache) {
|
||||||
|
tryRenderFromBitmapCache(imagePipeline, request, canvas, paint, opacity * mOpacity);
|
||||||
|
} else {
|
||||||
|
loadBitmap(imagePipeline, request);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@ReactProp(name = "meetOrSlice")
|
@Override
|
||||||
public void setMeetOrSlice(int meetOrSlice) {
|
Path getPath(Canvas canvas, Paint paint) {
|
||||||
mMeetOrSlice = meetOrSlice;
|
mPath = new Path();
|
||||||
invalidate();
|
mPath.addRect(getRect(), Path.Direction.CW);
|
||||||
}
|
return mPath;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
private void loadBitmap(final ImagePipeline imagePipeline, final ImageRequest request) {
|
||||||
void draw(final Canvas canvas, final Paint paint, final float opacity) {
|
mLoading.set(true);
|
||||||
if (!mLoading.get()) {
|
final DataSource<CloseableReference<CloseableImage>> dataSource =
|
||||||
ImagePipeline imagePipeline = Fresco.getImagePipeline();
|
imagePipeline.fetchDecodedImage(request, mContext);
|
||||||
ImageSource imageSource = new ImageSource(mContext, uriString);
|
BaseBitmapDataSubscriber subscriber =
|
||||||
ImageRequest request = ImageRequest.fromUri(imageSource.getUri());
|
new BaseBitmapDataSubscriber() {
|
||||||
boolean inMemoryCache = imagePipeline.isInBitmapMemoryCache(request);
|
@Override
|
||||||
|
public void onNewResultImpl(Bitmap bitmap) {
|
||||||
if (inMemoryCache) {
|
mLoading.set(false);
|
||||||
tryRenderFromBitmapCache(imagePipeline, request, canvas, paint, opacity * mOpacity);
|
SvgView view = getSvgView();
|
||||||
} else {
|
if (view != null) {
|
||||||
loadBitmap(imagePipeline, request);
|
view.invalidate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
Path getPath(Canvas canvas, Paint paint) {
|
public void onFailureImpl(DataSource dataSource) {
|
||||||
mPath = new Path();
|
// No cleanup required here.
|
||||||
mPath.addRect(getRect(), Path.Direction.CW);
|
// TODO: more details about this failure
|
||||||
return mPath;
|
mLoading.set(false);
|
||||||
}
|
FLog.w(
|
||||||
|
ReactConstants.TAG,
|
||||||
private void loadBitmap(final ImagePipeline imagePipeline, final ImageRequest request) {
|
dataSource.getFailureCause(),
|
||||||
mLoading.set(true);
|
"RNSVG: fetchDecodedImage failed!");
|
||||||
final DataSource<CloseableReference<CloseableImage>> dataSource
|
}
|
||||||
= imagePipeline.fetchDecodedImage(request, mContext);
|
|
||||||
BaseBitmapDataSubscriber subscriber = new BaseBitmapDataSubscriber() {
|
|
||||||
@Override
|
|
||||||
public void onNewResultImpl(Bitmap bitmap) {
|
|
||||||
mLoading.set(false);
|
|
||||||
SvgView view = getSvgView();
|
|
||||||
if (view != null) {
|
|
||||||
view.invalidate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onFailureImpl(DataSource dataSource) {
|
|
||||||
// No cleanup required here.
|
|
||||||
// TODO: more details about this failure
|
|
||||||
mLoading.set(false);
|
|
||||||
FLog.w(ReactConstants.TAG, dataSource.getFailureCause(), "RNSVG: fetchDecodedImage failed!");
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
dataSource.subscribe(subscriber, UiThreadImmediateExecutorService.getInstance());
|
dataSource.subscribe(subscriber, UiThreadImmediateExecutorService.getInstance());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
private RectF getRect() {
|
||||||
|
double x = relativeOnWidth(mX);
|
||||||
|
double y = relativeOnHeight(mY);
|
||||||
|
double w = relativeOnWidth(mW);
|
||||||
|
double h = relativeOnHeight(mH);
|
||||||
|
if (w == 0) {
|
||||||
|
w = mImageWidth * mScale;
|
||||||
|
}
|
||||||
|
if (h == 0) {
|
||||||
|
h = mImageHeight * mScale;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nonnull
|
return new RectF((float) x, (float) y, (float) (x + w), (float) (y + h));
|
||||||
private RectF getRect() {
|
}
|
||||||
double x = relativeOnWidth(mX);
|
|
||||||
double y = relativeOnHeight(mY);
|
|
||||||
double w = relativeOnWidth(mW);
|
|
||||||
double h = relativeOnHeight(mH);
|
|
||||||
if (w == 0) {
|
|
||||||
w = mImageWidth * mScale;
|
|
||||||
}
|
|
||||||
if (h == 0) {
|
|
||||||
h = mImageHeight * mScale;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new RectF((float) x, (float) y, (float) (x + w), (float) (y + h));
|
private void doRender(Canvas canvas, Paint paint, Bitmap bitmap, float opacity) {
|
||||||
|
if (mImageWidth == 0 || mImageHeight == 0) {
|
||||||
|
mImageWidth = bitmap.getWidth();
|
||||||
|
mImageHeight = bitmap.getHeight();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void doRender(Canvas canvas, Paint paint, Bitmap bitmap, float opacity) {
|
RectF renderRect = getRect();
|
||||||
if (mImageWidth == 0 || mImageHeight == 0) {
|
RectF vbRect = new RectF(0, 0, mImageWidth, mImageHeight);
|
||||||
mImageWidth = bitmap.getWidth();
|
Matrix transform = ViewBox.getTransform(vbRect, renderRect, mAlign, mMeetOrSlice);
|
||||||
mImageHeight = bitmap.getHeight();
|
transform.mapRect(vbRect);
|
||||||
}
|
|
||||||
|
|
||||||
RectF renderRect = getRect();
|
canvas.clipPath(getPath(canvas, paint));
|
||||||
RectF vbRect = new RectF(0, 0, mImageWidth, mImageHeight);
|
|
||||||
Matrix transform = ViewBox.getTransform(vbRect, renderRect, mAlign, mMeetOrSlice);
|
|
||||||
transform.mapRect(vbRect);
|
|
||||||
|
|
||||||
canvas.clipPath(getPath(canvas, paint));
|
Path clipPath = getClipPath(canvas, paint);
|
||||||
|
if (clipPath != null) {
|
||||||
Path clipPath = getClipPath(canvas, paint);
|
canvas.clipPath(clipPath);
|
||||||
if (clipPath != null) {
|
|
||||||
canvas.clipPath(clipPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
Paint alphaPaint = new Paint();
|
|
||||||
alphaPaint.setAlpha((int) (opacity * 255));
|
|
||||||
canvas.drawBitmap(bitmap, null, vbRect, alphaPaint);
|
|
||||||
mCTM.mapRect(vbRect);
|
|
||||||
this.setClientRect(vbRect);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void tryRenderFromBitmapCache(ImagePipeline imagePipeline, ImageRequest request, Canvas canvas, Paint paint, float opacity) {
|
Paint alphaPaint = new Paint();
|
||||||
final DataSource<CloseableReference<CloseableImage>> dataSource
|
alphaPaint.setAlpha((int) (opacity * 255));
|
||||||
= imagePipeline.fetchImageFromBitmapCache(request, mContext);
|
canvas.drawBitmap(bitmap, null, vbRect, alphaPaint);
|
||||||
|
mCTM.mapRect(vbRect);
|
||||||
|
this.setClientRect(vbRect);
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
private void tryRenderFromBitmapCache(
|
||||||
final CloseableReference<CloseableImage> imageReference = dataSource.getResult();
|
ImagePipeline imagePipeline,
|
||||||
if (imageReference == null) {
|
ImageRequest request,
|
||||||
return;
|
Canvas canvas,
|
||||||
}
|
Paint paint,
|
||||||
|
float opacity) {
|
||||||
|
final DataSource<CloseableReference<CloseableImage>> dataSource =
|
||||||
|
imagePipeline.fetchImageFromBitmapCache(request, mContext);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
CloseableImage closeableImage = imageReference.get();
|
final CloseableReference<CloseableImage> imageReference = dataSource.getResult();
|
||||||
if (!(closeableImage instanceof CloseableBitmap)) {
|
if (imageReference == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
CloseableBitmap closeableBitmap = (CloseableBitmap) closeableImage;
|
try {
|
||||||
final Bitmap bitmap = closeableBitmap.getUnderlyingBitmap();
|
CloseableImage closeableImage = imageReference.get();
|
||||||
|
if (!(closeableImage instanceof CloseableBitmap)) {
|
||||||
if (bitmap == null) {
|
return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
doRender(canvas, paint, bitmap, opacity);
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new IllegalStateException(e);
|
|
||||||
} finally {
|
|
||||||
CloseableReference.closeSafely(imageReference);
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new IllegalStateException(e);
|
|
||||||
} finally {
|
|
||||||
dataSource.close();
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
CloseableBitmap closeableBitmap = (CloseableBitmap) closeableImage;
|
||||||
|
final Bitmap bitmap = closeableBitmap.getUnderlyingBitmap();
|
||||||
|
|
||||||
|
if (bitmap == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
doRender(canvas, paint, bitmap, opacity);
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new IllegalStateException(e);
|
||||||
|
} finally {
|
||||||
|
CloseableReference.closeSafely(imageReference);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new IllegalStateException(e);
|
||||||
|
} finally {
|
||||||
|
dataSource.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,83 +6,81 @@
|
|||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
package com.horcrux.svg;
|
package com.horcrux.svg;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.graphics.Canvas;
|
import android.graphics.Canvas;
|
||||||
import android.graphics.Paint;
|
import android.graphics.Paint;
|
||||||
import android.graphics.Path;
|
import android.graphics.Path;
|
||||||
|
|
||||||
import com.facebook.react.bridge.Dynamic;
|
import com.facebook.react.bridge.Dynamic;
|
||||||
import com.facebook.react.bridge.ReactContext;
|
import com.facebook.react.bridge.ReactContext;
|
||||||
import com.facebook.react.uimanager.annotations.ReactProp;
|
import com.facebook.react.uimanager.annotations.ReactProp;
|
||||||
|
|
||||||
@SuppressLint("ViewConstructor")
|
@SuppressLint("ViewConstructor")
|
||||||
class LineView extends RenderableView {
|
class LineView extends RenderableView {
|
||||||
private SVGLength mX1;
|
private SVGLength mX1;
|
||||||
private SVGLength mY1;
|
private SVGLength mY1;
|
||||||
private SVGLength mX2;
|
private SVGLength mX2;
|
||||||
private SVGLength mY2;
|
private SVGLength mY2;
|
||||||
|
|
||||||
public LineView(ReactContext reactContext) {
|
public LineView(ReactContext reactContext) {
|
||||||
super(reactContext);
|
super(reactContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "x1")
|
@ReactProp(name = "x1")
|
||||||
public void setX1(Dynamic x1) {
|
public void setX1(Dynamic x1) {
|
||||||
mX1 = SVGLength.from(x1);
|
mX1 = SVGLength.from(x1);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setX1(String x1) {
|
public void setX1(String x1) {
|
||||||
mX1 = SVGLength.from(x1);
|
mX1 = SVGLength.from(x1);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "y1")
|
@ReactProp(name = "y1")
|
||||||
public void setY1(Dynamic y1) {
|
public void setY1(Dynamic y1) {
|
||||||
mY1 = SVGLength.from(y1);
|
mY1 = SVGLength.from(y1);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setY1(String y1) {
|
public void setY1(String y1) {
|
||||||
mY1 = SVGLength.from(y1);
|
mY1 = SVGLength.from(y1);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "x2")
|
@ReactProp(name = "x2")
|
||||||
public void setX2(Dynamic x2) {
|
public void setX2(Dynamic x2) {
|
||||||
mX2 = SVGLength.from(x2);
|
mX2 = SVGLength.from(x2);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setX2(String x2) {
|
public void setX2(String x2) {
|
||||||
mX2 = SVGLength.from(x2);
|
mX2 = SVGLength.from(x2);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "y2")
|
@ReactProp(name = "y2")
|
||||||
public void setY2(Dynamic y2) {
|
public void setY2(Dynamic y2) {
|
||||||
mY2 = SVGLength.from(y2);
|
mY2 = SVGLength.from(y2);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setY2(String y2) {
|
public void setY2(String y2) {
|
||||||
mY2 = SVGLength.from(y2);
|
mY2 = SVGLength.from(y2);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
Path getPath(Canvas canvas, Paint paint) {
|
Path getPath(Canvas canvas, Paint paint) {
|
||||||
Path path = new Path();
|
Path path = new Path();
|
||||||
double x1 = relativeOnWidth(mX1);
|
double x1 = relativeOnWidth(mX1);
|
||||||
double y1 = relativeOnHeight(mY1);
|
double y1 = relativeOnHeight(mY1);
|
||||||
double x2 = relativeOnWidth(mX2);
|
double x2 = relativeOnWidth(mX2);
|
||||||
double y2 = relativeOnHeight(mY2);
|
double y2 = relativeOnHeight(mY2);
|
||||||
|
|
||||||
path.moveTo((float) x1, (float) y1);
|
path.moveTo((float) x1, (float) y1);
|
||||||
path.lineTo((float) x2, (float) y2);
|
path.lineTo((float) x2, (float) y2);
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,140 +6,138 @@
|
|||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
package com.horcrux.svg;
|
package com.horcrux.svg;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.graphics.Matrix;
|
import android.graphics.Matrix;
|
||||||
|
|
||||||
import com.facebook.common.logging.FLog;
|
import com.facebook.common.logging.FLog;
|
||||||
import com.facebook.react.bridge.Dynamic;
|
import com.facebook.react.bridge.Dynamic;
|
||||||
import com.facebook.react.bridge.ReactContext;
|
import com.facebook.react.bridge.ReactContext;
|
||||||
import com.facebook.react.bridge.ReadableArray;
|
import com.facebook.react.bridge.ReadableArray;
|
||||||
import com.facebook.react.common.ReactConstants;
|
import com.facebook.react.common.ReactConstants;
|
||||||
import com.facebook.react.uimanager.annotations.ReactProp;
|
import com.facebook.react.uimanager.annotations.ReactProp;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
@SuppressLint("ViewConstructor")
|
@SuppressLint("ViewConstructor")
|
||||||
class LinearGradientView extends DefinitionView {
|
class LinearGradientView extends DefinitionView {
|
||||||
|
|
||||||
private SVGLength mX1;
|
private SVGLength mX1;
|
||||||
private SVGLength mY1;
|
private SVGLength mY1;
|
||||||
private SVGLength mX2;
|
private SVGLength mX2;
|
||||||
private SVGLength mY2;
|
private SVGLength mY2;
|
||||||
private ReadableArray mGradient;
|
private ReadableArray mGradient;
|
||||||
private Brush.BrushUnits mGradientUnits;
|
private Brush.BrushUnits mGradientUnits;
|
||||||
|
|
||||||
private static final float[] sRawMatrix = new float[]{
|
private static final float[] sRawMatrix =
|
||||||
|
new float[] {
|
||||||
1, 0, 0,
|
1, 0, 0,
|
||||||
0, 1, 0,
|
0, 1, 0,
|
||||||
0, 0, 1
|
0, 0, 1
|
||||||
};
|
};
|
||||||
private Matrix mMatrix = null;
|
private Matrix mMatrix = null;
|
||||||
|
|
||||||
public LinearGradientView(ReactContext reactContext) {
|
public LinearGradientView(ReactContext reactContext) {
|
||||||
super(reactContext);
|
super(reactContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "x1")
|
@ReactProp(name = "x1")
|
||||||
public void setX1(Dynamic x1) {
|
public void setX1(Dynamic x1) {
|
||||||
mX1 = SVGLength.from(x1);
|
mX1 = SVGLength.from(x1);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setX1(String x1) {
|
public void setX1(String x1) {
|
||||||
mX1 = SVGLength.from(x1);
|
mX1 = SVGLength.from(x1);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "y1")
|
@ReactProp(name = "y1")
|
||||||
public void setY1(Dynamic y1) {
|
public void setY1(Dynamic y1) {
|
||||||
mY1 = SVGLength.from(y1);
|
mY1 = SVGLength.from(y1);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setY1(String y1) {
|
public void setY1(String y1) {
|
||||||
mY1 = SVGLength.from(y1);
|
mY1 = SVGLength.from(y1);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "x2")
|
@ReactProp(name = "x2")
|
||||||
public void setX2(Dynamic x2) {
|
public void setX2(Dynamic x2) {
|
||||||
mX2 = SVGLength.from(x2);
|
mX2 = SVGLength.from(x2);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setX2(String x2) {
|
public void setX2(String x2) {
|
||||||
mX2 = SVGLength.from(x2);
|
mX2 = SVGLength.from(x2);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "y2")
|
@ReactProp(name = "y2")
|
||||||
public void setY2(Dynamic y2) {
|
public void setY2(Dynamic y2) {
|
||||||
mY2 = SVGLength.from(y2);
|
mY2 = SVGLength.from(y2);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setY2(String y2) {
|
public void setY2(String y2) {
|
||||||
mY2 = SVGLength.from(y2);
|
mY2 = SVGLength.from(y2);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "gradient")
|
@ReactProp(name = "gradient")
|
||||||
public void setGradient(ReadableArray gradient) {
|
public void setGradient(ReadableArray gradient) {
|
||||||
mGradient = gradient;
|
mGradient = gradient;
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "gradientUnits")
|
@ReactProp(name = "gradientUnits")
|
||||||
public void setGradientUnits(int gradientUnits) {
|
public void setGradientUnits(int gradientUnits) {
|
||||||
switch (gradientUnits) {
|
switch (gradientUnits) {
|
||||||
case 0:
|
case 0:
|
||||||
mGradientUnits = Brush.BrushUnits.OBJECT_BOUNDING_BOX;
|
mGradientUnits = Brush.BrushUnits.OBJECT_BOUNDING_BOX;
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
mGradientUnits = Brush.BrushUnits.USER_SPACE_ON_USE;
|
mGradientUnits = Brush.BrushUnits.USER_SPACE_ON_USE;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@ReactProp(name = "gradientTransform")
|
||||||
|
public void setGradientTransform(@Nullable ReadableArray matrixArray) {
|
||||||
|
if (matrixArray != null) {
|
||||||
|
int matrixSize = PropHelper.toMatrixData(matrixArray, sRawMatrix, mScale);
|
||||||
|
if (matrixSize == 6) {
|
||||||
|
if (mMatrix == null) {
|
||||||
|
mMatrix = new Matrix();
|
||||||
}
|
}
|
||||||
invalidate();
|
mMatrix.setValues(sRawMatrix);
|
||||||
|
} else if (matrixSize != -1) {
|
||||||
|
FLog.w(ReactConstants.TAG, "RNSVG: Transform matrices must be of size 6");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mMatrix = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "gradientTransform")
|
invalidate();
|
||||||
public void setGradientTransform(@Nullable ReadableArray matrixArray) {
|
}
|
||||||
if (matrixArray != null) {
|
|
||||||
int matrixSize = PropHelper.toMatrixData(matrixArray, sRawMatrix, mScale);
|
|
||||||
if (matrixSize == 6) {
|
|
||||||
if (mMatrix == null) {
|
|
||||||
mMatrix = new Matrix();
|
|
||||||
}
|
|
||||||
mMatrix.setValues(sRawMatrix);
|
|
||||||
} else if (matrixSize != -1) {
|
|
||||||
FLog.w(ReactConstants.TAG, "RNSVG: Transform matrices must be of size 6");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
mMatrix = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
invalidate();
|
@Override
|
||||||
}
|
void saveDefinition() {
|
||||||
|
if (mName != null) {
|
||||||
@Override
|
SVGLength[] points = new SVGLength[] {mX1, mY1, mX2, mY2};
|
||||||
void saveDefinition() {
|
Brush brush = new Brush(Brush.BrushType.LINEAR_GRADIENT, points, mGradientUnits);
|
||||||
if (mName != null) {
|
brush.setGradientColors(mGradient);
|
||||||
SVGLength[] points = new SVGLength[]{mX1, mY1, mX2, mY2};
|
if (mMatrix != null) {
|
||||||
Brush brush = new Brush(Brush.BrushType.LINEAR_GRADIENT, points, mGradientUnits);
|
brush.setGradientTransform(mMatrix);
|
||||||
brush.setGradientColors(mGradient);
|
}
|
||||||
if (mMatrix != null) {
|
|
||||||
brush.setGradientTransform(mMatrix);
|
SvgView svg = getSvgView();
|
||||||
}
|
if (mGradientUnits == Brush.BrushUnits.USER_SPACE_ON_USE) {
|
||||||
|
brush.setUserSpaceBoundingBox(svg.getCanvasBounds());
|
||||||
SvgView svg = getSvgView();
|
}
|
||||||
if (mGradientUnits == Brush.BrushUnits.USER_SPACE_ON_USE) {
|
|
||||||
brush.setUserSpaceBoundingBox(svg.getCanvasBounds());
|
svg.defineBrush(brush, mName);
|
||||||
}
|
|
||||||
|
|
||||||
svg.defineBrush(brush, mName);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,6 @@
|
|||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
package com.horcrux.svg;
|
package com.horcrux.svg;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
@@ -15,7 +14,6 @@ import android.graphics.Matrix;
|
|||||||
import android.graphics.Paint;
|
import android.graphics.Paint;
|
||||||
import android.graphics.RectF;
|
import android.graphics.RectF;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
import com.facebook.react.bridge.Dynamic;
|
import com.facebook.react.bridge.Dynamic;
|
||||||
import com.facebook.react.bridge.ReactContext;
|
import com.facebook.react.bridge.ReactContext;
|
||||||
import com.facebook.react.uimanager.annotations.ReactProp;
|
import com.facebook.react.uimanager.annotations.ReactProp;
|
||||||
@@ -23,167 +21,173 @@ import com.facebook.react.uimanager.annotations.ReactProp;
|
|||||||
@SuppressLint("ViewConstructor")
|
@SuppressLint("ViewConstructor")
|
||||||
class MarkerView extends GroupView {
|
class MarkerView extends GroupView {
|
||||||
|
|
||||||
private SVGLength mRefX;
|
private SVGLength mRefX;
|
||||||
private SVGLength mRefY;
|
private SVGLength mRefY;
|
||||||
private SVGLength mMarkerWidth;
|
private SVGLength mMarkerWidth;
|
||||||
private SVGLength mMarkerHeight;
|
private SVGLength mMarkerHeight;
|
||||||
private String mMarkerUnits;
|
private String mMarkerUnits;
|
||||||
private String mOrient;
|
private String mOrient;
|
||||||
|
|
||||||
private float mMinX;
|
private float mMinX;
|
||||||
private float mMinY;
|
private float mMinY;
|
||||||
private float mVbWidth;
|
private float mVbWidth;
|
||||||
private float mVbHeight;
|
private float mVbHeight;
|
||||||
String mAlign;
|
String mAlign;
|
||||||
int mMeetOrSlice;
|
int mMeetOrSlice;
|
||||||
|
|
||||||
Matrix markerTransform = new Matrix();
|
Matrix markerTransform = new Matrix();
|
||||||
|
|
||||||
public MarkerView(ReactContext reactContext) {
|
public MarkerView(ReactContext reactContext) {
|
||||||
super(reactContext);
|
super(reactContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "refX")
|
@ReactProp(name = "refX")
|
||||||
public void setRefX(Dynamic refX) {
|
public void setRefX(Dynamic refX) {
|
||||||
mRefX = SVGLength.from(refX);
|
mRefX = SVGLength.from(refX);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setRefX(String refX) {
|
public void setRefX(String refX) {
|
||||||
mRefX = SVGLength.from(refX);
|
mRefX = SVGLength.from(refX);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "refY")
|
@ReactProp(name = "refY")
|
||||||
public void setRefY(Dynamic refY) {
|
public void setRefY(Dynamic refY) {
|
||||||
mRefY = SVGLength.from(refY);
|
mRefY = SVGLength.from(refY);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setRefY(String refY) {
|
public void setRefY(String refY) {
|
||||||
mRefY = SVGLength.from(refY);
|
mRefY = SVGLength.from(refY);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "markerWidth")
|
@ReactProp(name = "markerWidth")
|
||||||
public void setMarkerWidth(Dynamic markerWidth) {
|
public void setMarkerWidth(Dynamic markerWidth) {
|
||||||
mMarkerWidth = SVGLength.from(markerWidth);
|
mMarkerWidth = SVGLength.from(markerWidth);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setMarkerWidth(String markerWidth) {
|
public void setMarkerWidth(String markerWidth) {
|
||||||
mMarkerWidth = SVGLength.from(markerWidth);
|
mMarkerWidth = SVGLength.from(markerWidth);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "markerHeight")
|
@ReactProp(name = "markerHeight")
|
||||||
public void setMarkerHeight(Dynamic markerHeight) {
|
public void setMarkerHeight(Dynamic markerHeight) {
|
||||||
mMarkerHeight = SVGLength.from(markerHeight);
|
mMarkerHeight = SVGLength.from(markerHeight);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setMarkerHeight(String markerHeight) {
|
public void setMarkerHeight(String markerHeight) {
|
||||||
mMarkerHeight = SVGLength.from(markerHeight);
|
mMarkerHeight = SVGLength.from(markerHeight);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "markerUnits")
|
@ReactProp(name = "markerUnits")
|
||||||
public void setMarkerUnits(String markerUnits) {
|
public void setMarkerUnits(String markerUnits) {
|
||||||
mMarkerUnits = markerUnits;
|
mMarkerUnits = markerUnits;
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "orient")
|
@ReactProp(name = "orient")
|
||||||
public void setOrient(String orient) {
|
public void setOrient(String orient) {
|
||||||
mOrient = orient;
|
mOrient = orient;
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "minX")
|
@ReactProp(name = "minX")
|
||||||
public void setMinX(float minX) {
|
public void setMinX(float minX) {
|
||||||
mMinX = minX;
|
mMinX = minX;
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "minY")
|
@ReactProp(name = "minY")
|
||||||
public void setMinY(float minY) {
|
public void setMinY(float minY) {
|
||||||
mMinY = minY;
|
mMinY = minY;
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "vbWidth")
|
@ReactProp(name = "vbWidth")
|
||||||
public void setVbWidth(float vbWidth) {
|
public void setVbWidth(float vbWidth) {
|
||||||
mVbWidth = vbWidth;
|
mVbWidth = vbWidth;
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "vbHeight")
|
@ReactProp(name = "vbHeight")
|
||||||
public void setVbHeight(float vbHeight) {
|
public void setVbHeight(float vbHeight) {
|
||||||
mVbHeight = vbHeight;
|
mVbHeight = vbHeight;
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "align")
|
@ReactProp(name = "align")
|
||||||
public void setAlign(String align) {
|
public void setAlign(String align) {
|
||||||
mAlign = align;
|
mAlign = align;
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "meetOrSlice")
|
@ReactProp(name = "meetOrSlice")
|
||||||
public void setMeetOrSlice(int meetOrSlice) {
|
public void setMeetOrSlice(int meetOrSlice) {
|
||||||
mMeetOrSlice = meetOrSlice;
|
mMeetOrSlice = meetOrSlice;
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
void saveDefinition() {
|
void saveDefinition() {
|
||||||
if (mName != null) {
|
if (mName != null) {
|
||||||
SvgView svg = getSvgView();
|
SvgView svg = getSvgView();
|
||||||
svg.defineMarker(this, mName);
|
svg.defineMarker(this, mName);
|
||||||
for (int i = 0; i < getChildCount(); i++) {
|
for (int i = 0; i < getChildCount(); i++) {
|
||||||
View node = getChildAt(i);
|
View node = getChildAt(i);
|
||||||
if (node instanceof VirtualView) {
|
if (node instanceof VirtualView) {
|
||||||
((VirtualView)node).saveDefinition();
|
((VirtualView) node).saveDefinition();
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void renderMarker(
|
||||||
|
Canvas canvas, Paint paint, float opacity, RNSVGMarkerPosition position, float strokeWidth) {
|
||||||
|
int count = saveAndSetupCanvas(canvas, mCTM);
|
||||||
|
|
||||||
|
markerTransform.reset();
|
||||||
|
Point origin = position.origin;
|
||||||
|
markerTransform.setTranslate((float) origin.x * mScale, (float) origin.y * mScale);
|
||||||
|
|
||||||
|
double markerAngle = "auto".equals(mOrient) ? -1 : Double.parseDouble(mOrient);
|
||||||
|
float degrees = 180 + (float) (markerAngle == -1 ? position.angle : markerAngle);
|
||||||
|
markerTransform.preRotate(degrees);
|
||||||
|
|
||||||
|
boolean useStrokeWidth = "strokeWidth".equals(mMarkerUnits);
|
||||||
|
if (useStrokeWidth) {
|
||||||
|
markerTransform.preScale(strokeWidth, strokeWidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
void renderMarker(Canvas canvas, Paint paint, float opacity, RNSVGMarkerPosition position, float strokeWidth) {
|
double width = relativeOnWidth(mMarkerWidth) / mScale;
|
||||||
int count = saveAndSetupCanvas(canvas, mCTM);
|
double height = relativeOnHeight(mMarkerHeight) / mScale;
|
||||||
|
RectF eRect = new RectF(0, 0, (float) width, (float) height);
|
||||||
markerTransform.reset();
|
if (mAlign != null) {
|
||||||
Point origin = position.origin;
|
RectF vbRect =
|
||||||
markerTransform.setTranslate((float)origin.x * mScale, (float)origin.y * mScale);
|
new RectF(
|
||||||
|
mMinX * mScale,
|
||||||
double markerAngle = "auto".equals(mOrient) ? -1 : Double.parseDouble(mOrient);
|
mMinY * mScale,
|
||||||
float degrees = 180 + (float) (markerAngle == -1 ? position.angle : markerAngle);
|
(mMinX + mVbWidth) * mScale,
|
||||||
markerTransform.preRotate(degrees);
|
(mMinY + mVbHeight) * mScale);
|
||||||
|
Matrix viewBoxMatrix = ViewBox.getTransform(vbRect, eRect, mAlign, mMeetOrSlice);
|
||||||
boolean useStrokeWidth = "strokeWidth".equals(mMarkerUnits);
|
float[] values = new float[9];
|
||||||
if (useStrokeWidth) {
|
viewBoxMatrix.getValues(values);
|
||||||
markerTransform.preScale(strokeWidth, strokeWidth);
|
markerTransform.preScale(values[Matrix.MSCALE_X], values[Matrix.MSCALE_Y]);
|
||||||
}
|
|
||||||
|
|
||||||
double width = relativeOnWidth(mMarkerWidth) / mScale;
|
|
||||||
double height = relativeOnHeight(mMarkerHeight) / mScale;
|
|
||||||
RectF eRect = new RectF(0, 0, (float)width, (float)height);
|
|
||||||
if (mAlign != null) {
|
|
||||||
RectF vbRect = new RectF(mMinX * mScale, mMinY * mScale, (mMinX + mVbWidth) * mScale, (mMinY + mVbHeight) * mScale);
|
|
||||||
Matrix viewBoxMatrix = ViewBox.getTransform(vbRect, eRect, mAlign, mMeetOrSlice);
|
|
||||||
float[] values = new float[9];
|
|
||||||
viewBoxMatrix.getValues(values);
|
|
||||||
markerTransform.preScale(values[Matrix.MSCALE_X], values[Matrix.MSCALE_Y]);
|
|
||||||
}
|
|
||||||
|
|
||||||
double x = relativeOnWidth(mRefX);
|
|
||||||
double y = relativeOnHeight(mRefY);
|
|
||||||
markerTransform.preTranslate((float)-x, (float)-y);
|
|
||||||
|
|
||||||
canvas.concat(markerTransform);
|
|
||||||
|
|
||||||
drawGroup(canvas, paint, opacity);
|
|
||||||
|
|
||||||
restoreCanvas(canvas, count);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double x = relativeOnWidth(mRefX);
|
||||||
|
double y = relativeOnHeight(mRefY);
|
||||||
|
markerTransform.preTranslate((float) -x, (float) -y);
|
||||||
|
|
||||||
|
canvas.concat(markerTransform);
|
||||||
|
|
||||||
|
drawGroup(canvas, paint, opacity);
|
||||||
|
|
||||||
|
restoreCanvas(canvas, count);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,140 +6,139 @@
|
|||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
package com.horcrux.svg;
|
package com.horcrux.svg;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.graphics.Matrix;
|
import android.graphics.Matrix;
|
||||||
|
|
||||||
import com.facebook.common.logging.FLog;
|
import com.facebook.common.logging.FLog;
|
||||||
import com.facebook.react.bridge.Dynamic;
|
import com.facebook.react.bridge.Dynamic;
|
||||||
import com.facebook.react.bridge.ReactContext;
|
import com.facebook.react.bridge.ReactContext;
|
||||||
import com.facebook.react.bridge.ReadableArray;
|
import com.facebook.react.bridge.ReadableArray;
|
||||||
import com.facebook.react.common.ReactConstants;
|
import com.facebook.react.common.ReactConstants;
|
||||||
import com.facebook.react.uimanager.annotations.ReactProp;
|
import com.facebook.react.uimanager.annotations.ReactProp;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
@SuppressLint("ViewConstructor")
|
@SuppressLint("ViewConstructor")
|
||||||
class MaskView extends GroupView {
|
class MaskView extends GroupView {
|
||||||
|
|
||||||
SVGLength mX;
|
SVGLength mX;
|
||||||
SVGLength mY;
|
SVGLength mY;
|
||||||
SVGLength mW;
|
SVGLength mW;
|
||||||
SVGLength mH;
|
SVGLength mH;
|
||||||
|
|
||||||
// TODO implement proper support for units
|
// TODO implement proper support for units
|
||||||
@SuppressWarnings({"FieldCanBeLocal", "unused"})
|
@SuppressWarnings({"FieldCanBeLocal", "unused"})
|
||||||
private Brush.BrushUnits mMaskUnits;
|
private Brush.BrushUnits mMaskUnits;
|
||||||
@SuppressWarnings({"FieldCanBeLocal", "unused"})
|
|
||||||
private Brush.BrushUnits mMaskContentUnits;
|
|
||||||
|
|
||||||
private static final float[] sRawMatrix = new float[]{
|
@SuppressWarnings({"FieldCanBeLocal", "unused"})
|
||||||
|
private Brush.BrushUnits mMaskContentUnits;
|
||||||
|
|
||||||
|
private static final float[] sRawMatrix =
|
||||||
|
new float[] {
|
||||||
1, 0, 0,
|
1, 0, 0,
|
||||||
0, 1, 0,
|
0, 1, 0,
|
||||||
0, 0, 1
|
0, 0, 1
|
||||||
};
|
};
|
||||||
private Matrix mMatrix = null;
|
private Matrix mMatrix = null;
|
||||||
|
|
||||||
public MaskView(ReactContext reactContext) {
|
public MaskView(ReactContext reactContext) {
|
||||||
super(reactContext);
|
super(reactContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "x")
|
@ReactProp(name = "x")
|
||||||
public void setX(Dynamic x) {
|
public void setX(Dynamic x) {
|
||||||
mX = SVGLength.from(x);
|
mX = SVGLength.from(x);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setX(String x) {
|
public void setX(String x) {
|
||||||
mX = SVGLength.from(x);
|
mX = SVGLength.from(x);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "y")
|
@ReactProp(name = "y")
|
||||||
public void setY(Dynamic y) {
|
public void setY(Dynamic y) {
|
||||||
mY = SVGLength.from(y);
|
mY = SVGLength.from(y);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setY(String y) {
|
public void setY(String y) {
|
||||||
mY = SVGLength.from(y);
|
mY = SVGLength.from(y);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "width")
|
@ReactProp(name = "width")
|
||||||
public void setWidth(Dynamic width) {
|
public void setWidth(Dynamic width) {
|
||||||
mW = SVGLength.from(width);
|
mW = SVGLength.from(width);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setWidth(String width) {
|
public void setWidth(String width) {
|
||||||
mW = SVGLength.from(width);
|
mW = SVGLength.from(width);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "height")
|
@ReactProp(name = "height")
|
||||||
public void setHeight(Dynamic height) {
|
public void setHeight(Dynamic height) {
|
||||||
mH = SVGLength.from(height);
|
mH = SVGLength.from(height);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setHeight(String height) {
|
public void setHeight(String height) {
|
||||||
mH = SVGLength.from(height);
|
mH = SVGLength.from(height);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "maskUnits")
|
@ReactProp(name = "maskUnits")
|
||||||
public void setMaskUnits(int maskUnits) {
|
public void setMaskUnits(int maskUnits) {
|
||||||
switch (maskUnits) {
|
switch (maskUnits) {
|
||||||
case 0:
|
case 0:
|
||||||
mMaskUnits = Brush.BrushUnits.OBJECT_BOUNDING_BOX;
|
mMaskUnits = Brush.BrushUnits.OBJECT_BOUNDING_BOX;
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
mMaskUnits = Brush.BrushUnits.USER_SPACE_ON_USE;
|
mMaskUnits = Brush.BrushUnits.USER_SPACE_ON_USE;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@ReactProp(name = "maskContentUnits")
|
||||||
|
public void setMaskContentUnits(int maskContentUnits) {
|
||||||
|
switch (maskContentUnits) {
|
||||||
|
case 0:
|
||||||
|
mMaskContentUnits = Brush.BrushUnits.OBJECT_BOUNDING_BOX;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
mMaskContentUnits = Brush.BrushUnits.USER_SPACE_ON_USE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@ReactProp(name = "maskTransform")
|
||||||
|
public void setMaskTransform(@Nullable ReadableArray matrixArray) {
|
||||||
|
if (matrixArray != null) {
|
||||||
|
int matrixSize = PropHelper.toMatrixData(matrixArray, sRawMatrix, mScale);
|
||||||
|
if (matrixSize == 6) {
|
||||||
|
if (mMatrix == null) {
|
||||||
|
mMatrix = new Matrix();
|
||||||
}
|
}
|
||||||
invalidate();
|
mMatrix.setValues(sRawMatrix);
|
||||||
|
} else if (matrixSize != -1) {
|
||||||
|
FLog.w(ReactConstants.TAG, "RNSVG: Transform matrices must be of size 6");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mMatrix = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "maskContentUnits")
|
invalidate();
|
||||||
public void setMaskContentUnits(int maskContentUnits) {
|
}
|
||||||
switch (maskContentUnits) {
|
|
||||||
case 0:
|
|
||||||
mMaskContentUnits = Brush.BrushUnits.OBJECT_BOUNDING_BOX;
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
mMaskContentUnits = Brush.BrushUnits.USER_SPACE_ON_USE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
invalidate();
|
|
||||||
}
|
|
||||||
|
|
||||||
@ReactProp(name = "maskTransform")
|
@Override
|
||||||
public void setMaskTransform(@Nullable ReadableArray matrixArray) {
|
void saveDefinition() {
|
||||||
if (matrixArray != null) {
|
if (mName != null) {
|
||||||
int matrixSize = PropHelper.toMatrixData(matrixArray, sRawMatrix, mScale);
|
SvgView svg = getSvgView();
|
||||||
if (matrixSize == 6) {
|
svg.defineMask(this, mName);
|
||||||
if (mMatrix == null) {
|
|
||||||
mMatrix = new Matrix();
|
|
||||||
}
|
|
||||||
mMatrix.setValues(sRawMatrix);
|
|
||||||
} else if (matrixSize != -1) {
|
|
||||||
FLog.w(ReactConstants.TAG, "RNSVG: Transform matrices must be of size 6");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
mMatrix = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
invalidate();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
void saveDefinition() {
|
|
||||||
if (mName != null) {
|
|
||||||
SvgView svg = getSvgView();
|
|
||||||
svg.defineMask(this, mName);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -6,37 +6,34 @@
|
|||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
package com.horcrux.svg;
|
package com.horcrux.svg;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.graphics.Canvas;
|
import android.graphics.Canvas;
|
||||||
import android.graphics.Paint;
|
import android.graphics.Paint;
|
||||||
import android.graphics.Path;
|
import android.graphics.Path;
|
||||||
|
|
||||||
import com.facebook.react.bridge.ReactContext;
|
import com.facebook.react.bridge.ReactContext;
|
||||||
import com.facebook.react.uimanager.annotations.ReactProp;
|
import com.facebook.react.uimanager.annotations.ReactProp;
|
||||||
|
|
||||||
@SuppressLint("ViewConstructor")
|
@SuppressLint("ViewConstructor")
|
||||||
class PathView extends RenderableView {
|
class PathView extends RenderableView {
|
||||||
private Path mPath;
|
private Path mPath;
|
||||||
|
|
||||||
public PathView(ReactContext reactContext) {
|
public PathView(ReactContext reactContext) {
|
||||||
super(reactContext);
|
super(reactContext);
|
||||||
PathParser.mScale = mScale;
|
PathParser.mScale = mScale;
|
||||||
mPath = new Path();
|
mPath = new Path();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "d")
|
@ReactProp(name = "d")
|
||||||
public void setD(String d) {
|
public void setD(String d) {
|
||||||
mPath = PathParser.parse(d);
|
mPath = PathParser.parse(d);
|
||||||
elements = PathParser.elements;
|
elements = PathParser.elements;
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
Path getPath(Canvas canvas, Paint paint) {
|
|
||||||
return mPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
Path getPath(Canvas canvas, Paint paint) {
|
||||||
|
return mPath;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,197 +6,197 @@
|
|||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
package com.horcrux.svg;
|
package com.horcrux.svg;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.graphics.Matrix;
|
import android.graphics.Matrix;
|
||||||
import android.graphics.RectF;
|
import android.graphics.RectF;
|
||||||
|
|
||||||
import com.facebook.common.logging.FLog;
|
import com.facebook.common.logging.FLog;
|
||||||
import com.facebook.react.bridge.Dynamic;
|
import com.facebook.react.bridge.Dynamic;
|
||||||
import com.facebook.react.bridge.ReactContext;
|
import com.facebook.react.bridge.ReactContext;
|
||||||
import com.facebook.react.bridge.ReadableArray;
|
import com.facebook.react.bridge.ReadableArray;
|
||||||
import com.facebook.react.common.ReactConstants;
|
import com.facebook.react.common.ReactConstants;
|
||||||
import com.facebook.react.uimanager.annotations.ReactProp;
|
import com.facebook.react.uimanager.annotations.ReactProp;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
@SuppressLint("ViewConstructor")
|
@SuppressLint("ViewConstructor")
|
||||||
class PatternView extends GroupView {
|
class PatternView extends GroupView {
|
||||||
|
|
||||||
private SVGLength mX;
|
private SVGLength mX;
|
||||||
private SVGLength mY;
|
private SVGLength mY;
|
||||||
private SVGLength mW;
|
private SVGLength mW;
|
||||||
private SVGLength mH;
|
private SVGLength mH;
|
||||||
private Brush.BrushUnits mPatternUnits;
|
private Brush.BrushUnits mPatternUnits;
|
||||||
private Brush.BrushUnits mPatternContentUnits;
|
private Brush.BrushUnits mPatternContentUnits;
|
||||||
|
|
||||||
private float mMinX;
|
private float mMinX;
|
||||||
private float mMinY;
|
private float mMinY;
|
||||||
private float mVbWidth;
|
private float mVbWidth;
|
||||||
private float mVbHeight;
|
private float mVbHeight;
|
||||||
String mAlign;
|
String mAlign;
|
||||||
int mMeetOrSlice;
|
int mMeetOrSlice;
|
||||||
|
|
||||||
private static final float[] sRawMatrix = new float[]{
|
private static final float[] sRawMatrix =
|
||||||
|
new float[] {
|
||||||
1, 0, 0,
|
1, 0, 0,
|
||||||
0, 1, 0,
|
0, 1, 0,
|
||||||
0, 0, 1
|
0, 0, 1
|
||||||
};
|
};
|
||||||
private Matrix mMatrix = null;
|
private Matrix mMatrix = null;
|
||||||
|
|
||||||
public PatternView(ReactContext reactContext) {
|
public PatternView(ReactContext reactContext) {
|
||||||
super(reactContext);
|
super(reactContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "x")
|
@ReactProp(name = "x")
|
||||||
public void setX(Dynamic x) {
|
public void setX(Dynamic x) {
|
||||||
mX = SVGLength.from(x);
|
mX = SVGLength.from(x);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setX(String x) {
|
public void setX(String x) {
|
||||||
mX = SVGLength.from(x);
|
mX = SVGLength.from(x);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "y")
|
@ReactProp(name = "y")
|
||||||
public void setY(Dynamic y) {
|
public void setY(Dynamic y) {
|
||||||
mY = SVGLength.from(y);
|
mY = SVGLength.from(y);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setY(String y) {
|
public void setY(String y) {
|
||||||
mY = SVGLength.from(y);
|
mY = SVGLength.from(y);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "width")
|
@ReactProp(name = "width")
|
||||||
public void setWidth(Dynamic width) {
|
public void setWidth(Dynamic width) {
|
||||||
mW = SVGLength.from(width);
|
mW = SVGLength.from(width);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setWidth(String width) {
|
public void setWidth(String width) {
|
||||||
mW = SVGLength.from(width);
|
mW = SVGLength.from(width);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
@ReactProp(name = "height")
|
|
||||||
public void setHeight(Dynamic height) {
|
@ReactProp(name = "height")
|
||||||
mH = SVGLength.from(height);
|
public void setHeight(Dynamic height) {
|
||||||
invalidate();
|
mH = SVGLength.from(height);
|
||||||
}
|
invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
public void setHeight(String height) {
|
public void setHeight(String height) {
|
||||||
mH = SVGLength.from(height);
|
mH = SVGLength.from(height);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "patternUnits")
|
@ReactProp(name = "patternUnits")
|
||||||
public void setPatternUnits(int patternUnits) {
|
public void setPatternUnits(int patternUnits) {
|
||||||
switch (patternUnits) {
|
switch (patternUnits) {
|
||||||
case 0:
|
case 0:
|
||||||
mPatternUnits = Brush.BrushUnits.OBJECT_BOUNDING_BOX;
|
mPatternUnits = Brush.BrushUnits.OBJECT_BOUNDING_BOX;
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
mPatternUnits = Brush.BrushUnits.USER_SPACE_ON_USE;
|
mPatternUnits = Brush.BrushUnits.USER_SPACE_ON_USE;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@ReactProp(name = "patternContentUnits")
|
||||||
|
public void setPatternContentUnits(int patternContentUnits) {
|
||||||
|
switch (patternContentUnits) {
|
||||||
|
case 0:
|
||||||
|
mPatternContentUnits = Brush.BrushUnits.OBJECT_BOUNDING_BOX;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
mPatternContentUnits = Brush.BrushUnits.USER_SPACE_ON_USE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@ReactProp(name = "patternTransform")
|
||||||
|
public void setPatternTransform(@Nullable ReadableArray matrixArray) {
|
||||||
|
if (matrixArray != null) {
|
||||||
|
int matrixSize = PropHelper.toMatrixData(matrixArray, sRawMatrix, mScale);
|
||||||
|
if (matrixSize == 6) {
|
||||||
|
if (mMatrix == null) {
|
||||||
|
mMatrix = new Matrix();
|
||||||
}
|
}
|
||||||
invalidate();
|
mMatrix.setValues(sRawMatrix);
|
||||||
|
} else if (matrixSize != -1) {
|
||||||
|
FLog.w(ReactConstants.TAG, "RNSVG: Transform matrices must be of size 6");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mMatrix = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "patternContentUnits")
|
invalidate();
|
||||||
public void setPatternContentUnits(int patternContentUnits) {
|
}
|
||||||
switch (patternContentUnits) {
|
|
||||||
case 0:
|
@ReactProp(name = "minX")
|
||||||
mPatternContentUnits = Brush.BrushUnits.OBJECT_BOUNDING_BOX;
|
public void setMinX(float minX) {
|
||||||
break;
|
mMinX = minX;
|
||||||
case 1:
|
invalidate();
|
||||||
mPatternContentUnits = Brush.BrushUnits.USER_SPACE_ON_USE;
|
}
|
||||||
break;
|
|
||||||
}
|
@ReactProp(name = "minY")
|
||||||
invalidate();
|
public void setMinY(float minY) {
|
||||||
}
|
mMinY = minY;
|
||||||
|
invalidate();
|
||||||
@ReactProp(name = "patternTransform")
|
}
|
||||||
public void setPatternTransform(@Nullable ReadableArray matrixArray) {
|
|
||||||
if (matrixArray != null) {
|
@ReactProp(name = "vbWidth")
|
||||||
int matrixSize = PropHelper.toMatrixData(matrixArray, sRawMatrix, mScale);
|
public void setVbWidth(float vbWidth) {
|
||||||
if (matrixSize == 6) {
|
mVbWidth = vbWidth;
|
||||||
if (mMatrix == null) {
|
invalidate();
|
||||||
mMatrix = new Matrix();
|
}
|
||||||
}
|
|
||||||
mMatrix.setValues(sRawMatrix);
|
@ReactProp(name = "vbHeight")
|
||||||
} else if (matrixSize != -1) {
|
public void setVbHeight(float vbHeight) {
|
||||||
FLog.w(ReactConstants.TAG, "RNSVG: Transform matrices must be of size 6");
|
mVbHeight = vbHeight;
|
||||||
}
|
invalidate();
|
||||||
} else {
|
}
|
||||||
mMatrix = null;
|
|
||||||
}
|
@ReactProp(name = "align")
|
||||||
|
public void setAlign(String align) {
|
||||||
invalidate();
|
mAlign = align;
|
||||||
}
|
invalidate();
|
||||||
|
}
|
||||||
@ReactProp(name = "minX")
|
|
||||||
public void setMinX(float minX) {
|
@ReactProp(name = "meetOrSlice")
|
||||||
mMinX = minX;
|
public void setMeetOrSlice(int meetOrSlice) {
|
||||||
invalidate();
|
mMeetOrSlice = meetOrSlice;
|
||||||
}
|
invalidate();
|
||||||
|
}
|
||||||
@ReactProp(name = "minY")
|
|
||||||
public void setMinY(float minY) {
|
RectF getViewBox() {
|
||||||
mMinY = minY;
|
return new RectF(
|
||||||
invalidate();
|
mMinX * mScale, mMinY * mScale, (mMinX + mVbWidth) * mScale, (mMinY + mVbHeight) * mScale);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "vbWidth")
|
@Override
|
||||||
public void setVbWidth(float vbWidth) {
|
void saveDefinition() {
|
||||||
mVbWidth = vbWidth;
|
if (mName != null) {
|
||||||
invalidate();
|
SVGLength[] points = new SVGLength[] {mX, mY, mW, mH};
|
||||||
}
|
Brush brush = new Brush(Brush.BrushType.PATTERN, points, mPatternUnits);
|
||||||
|
brush.setContentUnits(mPatternContentUnits);
|
||||||
@ReactProp(name = "vbHeight")
|
brush.setPattern(this);
|
||||||
public void setVbHeight(float vbHeight) {
|
|
||||||
mVbHeight = vbHeight;
|
if (mMatrix != null) {
|
||||||
invalidate();
|
brush.setGradientTransform(mMatrix);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "align")
|
SvgView svg = getSvgView();
|
||||||
public void setAlign(String align) {
|
if (mPatternUnits == Brush.BrushUnits.USER_SPACE_ON_USE
|
||||||
mAlign = align;
|
|| mPatternContentUnits == Brush.BrushUnits.USER_SPACE_ON_USE) {
|
||||||
invalidate();
|
brush.setUserSpaceBoundingBox(svg.getCanvasBounds());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "meetOrSlice")
|
svg.defineBrush(brush, mName);
|
||||||
public void setMeetOrSlice(int meetOrSlice) {
|
|
||||||
mMeetOrSlice = meetOrSlice;
|
|
||||||
invalidate();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
RectF getViewBox() {
|
|
||||||
return new RectF(mMinX * mScale, mMinY * mScale, (mMinX + mVbWidth) * mScale, (mMinY + mVbHeight) * mScale);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
void saveDefinition() {
|
|
||||||
if (mName != null) {
|
|
||||||
SVGLength[] points = new SVGLength[]{mX,mY,mW,mH};
|
|
||||||
Brush brush = new Brush(Brush.BrushType.PATTERN, points, mPatternUnits);
|
|
||||||
brush.setContentUnits(mPatternContentUnits);
|
|
||||||
brush.setPattern(this);
|
|
||||||
|
|
||||||
if (mMatrix != null) {
|
|
||||||
brush.setGradientTransform(mMatrix);
|
|
||||||
}
|
|
||||||
|
|
||||||
SvgView svg = getSvgView();
|
|
||||||
if (mPatternUnits == Brush.BrushUnits.USER_SPACE_ON_USE || mPatternContentUnits == Brush.BrushUnits.USER_SPACE_ON_USE) {
|
|
||||||
brush.setUserSpaceBoundingBox(svg.getCanvasBounds());
|
|
||||||
}
|
|
||||||
|
|
||||||
svg.defineBrush(brush, mName);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,215 +6,211 @@
|
|||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
package com.horcrux.svg;
|
package com.horcrux.svg;
|
||||||
|
|
||||||
import com.facebook.react.bridge.ReadableArray;
|
import com.facebook.react.bridge.ReadableArray;
|
||||||
|
|
||||||
/**
|
/** Contains static helper methods for accessing props. */
|
||||||
* Contains static helper methods for accessing props.
|
|
||||||
*/
|
|
||||||
class PropHelper {
|
class PropHelper {
|
||||||
|
|
||||||
private static final int inputMatrixDataSize = 6;
|
private static final int inputMatrixDataSize = 6;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts given {@link ReadableArray} to a matrix data array, {@code float[6]}.
|
* Converts given {@link ReadableArray} to a matrix data array, {@code float[6]}. Writes result to
|
||||||
* Writes result to the array passed in {@param into}.
|
* the array passed in {@param into}. This method will write exactly six items to the output array
|
||||||
* This method will write exactly six items to the output array from the input array.
|
* from the input array.
|
||||||
*
|
*
|
||||||
* If the input array has a different size, then only the size is returned;
|
* <p>If the input array has a different size, then only the size is returned; Does not check
|
||||||
* Does not check output array size. Ensure space for at least six elements.
|
* output array size. Ensure space for at least six elements.
|
||||||
*
|
*
|
||||||
* @param value input array
|
* @param value input array
|
||||||
* @param sRawMatrix output matrix
|
* @param sRawMatrix output matrix
|
||||||
* @param mScale current resolution scaling
|
* @param mScale current resolution scaling
|
||||||
* @return size of input array
|
* @return size of input array
|
||||||
*/
|
*/
|
||||||
static int toMatrixData(ReadableArray value, float[] sRawMatrix, float mScale) {
|
static int toMatrixData(ReadableArray value, float[] sRawMatrix, float mScale) {
|
||||||
int fromSize = value.size();
|
int fromSize = value.size();
|
||||||
if (fromSize != inputMatrixDataSize) {
|
if (fromSize != inputMatrixDataSize) {
|
||||||
return fromSize;
|
return fromSize;
|
||||||
}
|
|
||||||
|
|
||||||
sRawMatrix[0] = (float) value.getDouble(0);
|
|
||||||
sRawMatrix[1] = (float) value.getDouble(2);
|
|
||||||
sRawMatrix[2] = (float) value.getDouble(4) * mScale;
|
|
||||||
sRawMatrix[3] = (float) value.getDouble(1);
|
|
||||||
sRawMatrix[4] = (float) value.getDouble(3);
|
|
||||||
sRawMatrix[5] = (float) value.getDouble(5) * mScale;
|
|
||||||
|
|
||||||
return inputMatrixDataSize;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
sRawMatrix[0] = (float) value.getDouble(0);
|
||||||
* Converts length string into px / user units
|
sRawMatrix[1] = (float) value.getDouble(2);
|
||||||
* in the current user coordinate system
|
sRawMatrix[2] = (float) value.getDouble(4) * mScale;
|
||||||
*
|
sRawMatrix[3] = (float) value.getDouble(1);
|
||||||
* @param length length string
|
sRawMatrix[4] = (float) value.getDouble(3);
|
||||||
* @param relative relative size for percentages
|
sRawMatrix[5] = (float) value.getDouble(5) * mScale;
|
||||||
* @param scale scaling parameter
|
|
||||||
* @param fontSize current font size
|
|
||||||
* @return value in the current user coordinate system
|
|
||||||
*/
|
|
||||||
static double fromRelative(String length, double relative, double scale, double fontSize) {
|
|
||||||
/*
|
|
||||||
TODO list
|
|
||||||
|
|
||||||
unit relative to
|
return inputMatrixDataSize;
|
||||||
em font size of the element
|
}
|
||||||
ex x-height of the element’s font
|
|
||||||
ch width of the "0" (ZERO, U+0030) glyph in the element’s font
|
|
||||||
rem font size of the root element
|
|
||||||
vw 1% of viewport’s width
|
|
||||||
vh 1% of viewport’s height
|
|
||||||
vmin 1% of viewport’s smaller dimension
|
|
||||||
vmax 1% of viewport’s larger dimension
|
|
||||||
|
|
||||||
relative-size [ larger | smaller ]
|
/**
|
||||||
absolute-size: [ xx-small | x-small | small | medium | large | x-large | xx-large ]
|
* Converts length string into px / user units in the current user coordinate system
|
||||||
|
*
|
||||||
|
* @param length length string
|
||||||
|
* @param relative relative size for percentages
|
||||||
|
* @param scale scaling parameter
|
||||||
|
* @param fontSize current font size
|
||||||
|
* @return value in the current user coordinate system
|
||||||
|
*/
|
||||||
|
static double fromRelative(String length, double relative, double scale, double fontSize) {
|
||||||
|
/*
|
||||||
|
TODO list
|
||||||
|
|
||||||
https://www.w3.org/TR/css3-values/#relative-lengths
|
unit relative to
|
||||||
https://www.w3.org/TR/css3-values/#absolute-lengths
|
em font size of the element
|
||||||
https://drafts.csswg.org/css-cascade-4/#computed-value
|
ex x-height of the element’s font
|
||||||
https://drafts.csswg.org/css-fonts-3/#propdef-font-size
|
ch width of the "0" (ZERO, U+0030) glyph in the element’s font
|
||||||
https://drafts.csswg.org/css2/fonts.html#propdef-font-size
|
rem font size of the root element
|
||||||
*/
|
vw 1% of viewport’s width
|
||||||
length = length.trim();
|
vh 1% of viewport’s height
|
||||||
int stringLength = length.length();
|
vmin 1% of viewport’s smaller dimension
|
||||||
int percentIndex = stringLength - 1;
|
vmax 1% of viewport’s larger dimension
|
||||||
if (stringLength == 0 || length.equals("normal")) {
|
|
||||||
return 0d;
|
|
||||||
} else if (length.codePointAt(percentIndex) == '%') {
|
|
||||||
return Double.valueOf(length.substring(0, percentIndex)) / 100 * relative;
|
|
||||||
} else {
|
|
||||||
int twoLetterUnitIndex = stringLength - 2;
|
|
||||||
if (twoLetterUnitIndex > 0) {
|
|
||||||
String lastTwo = length.substring(twoLetterUnitIndex);
|
|
||||||
int end = twoLetterUnitIndex;
|
|
||||||
double unit = 1;
|
|
||||||
|
|
||||||
switch (lastTwo) {
|
relative-size [ larger | smaller ]
|
||||||
case "px":
|
absolute-size: [ xx-small | x-small | small | medium | large | x-large | xx-large ]
|
||||||
break;
|
|
||||||
|
|
||||||
case "em":
|
https://www.w3.org/TR/css3-values/#relative-lengths
|
||||||
unit = fontSize;
|
https://www.w3.org/TR/css3-values/#absolute-lengths
|
||||||
break;
|
https://drafts.csswg.org/css-cascade-4/#computed-value
|
||||||
|
https://drafts.csswg.org/css-fonts-3/#propdef-font-size
|
||||||
/*
|
https://drafts.csswg.org/css2/fonts.html#propdef-font-size
|
||||||
"1pt" equals "1.25px" (and therefore 1.25 user units)
|
*/
|
||||||
"1pc" equals "15px" (and therefore 15 user units)
|
length = length.trim();
|
||||||
"1mm" would be "3.543307px" (3.543307 user units)
|
int stringLength = length.length();
|
||||||
"1cm" equals "35.43307px" (and therefore 35.43307 user units)
|
int percentIndex = stringLength - 1;
|
||||||
"1in" equals "90px" (and therefore 90 user units)
|
if (stringLength == 0 || length.equals("normal")) {
|
||||||
*/
|
return 0d;
|
||||||
|
} else if (length.codePointAt(percentIndex) == '%') {
|
||||||
case "pt":
|
return Double.valueOf(length.substring(0, percentIndex)) / 100 * relative;
|
||||||
unit = 1.25d;
|
} else {
|
||||||
break;
|
int twoLetterUnitIndex = stringLength - 2;
|
||||||
|
if (twoLetterUnitIndex > 0) {
|
||||||
case "pc":
|
String lastTwo = length.substring(twoLetterUnitIndex);
|
||||||
unit = 15;
|
int end = twoLetterUnitIndex;
|
||||||
break;
|
|
||||||
|
|
||||||
case "mm":
|
|
||||||
unit = 3.543307d;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "cm":
|
|
||||||
unit = 35.43307d;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "in":
|
|
||||||
unit = 90;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
end = stringLength;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Double.valueOf(length.substring(0, end)) * unit * scale;
|
|
||||||
} else {
|
|
||||||
return Double.valueOf(length) * scale;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Converts SVGLength into px / user units
|
|
||||||
* in the current user coordinate system
|
|
||||||
*
|
|
||||||
* @param length length string
|
|
||||||
* @param relative relative size for percentages
|
|
||||||
* @param offset offset for all units
|
|
||||||
* @param scale scaling parameter
|
|
||||||
* @param fontSize current font size
|
|
||||||
* @return value in the current user coordinate system
|
|
||||||
*/
|
|
||||||
static double fromRelative(SVGLength length, double relative, double offset, double scale, double fontSize) {
|
|
||||||
/*
|
|
||||||
TODO list
|
|
||||||
|
|
||||||
unit relative to
|
|
||||||
em font size of the element
|
|
||||||
ex x-height of the element’s font
|
|
||||||
ch width of the "0" (ZERO, U+0030) glyph in the element’s font
|
|
||||||
rem font size of the root element
|
|
||||||
vw 1% of viewport’s width
|
|
||||||
vh 1% of viewport’s height
|
|
||||||
vmin 1% of viewport’s smaller dimension
|
|
||||||
vmax 1% of viewport’s larger dimension
|
|
||||||
|
|
||||||
relative-size [ larger | smaller ]
|
|
||||||
absolute-size: [ xx-small | x-small | small | medium | large | x-large | xx-large ]
|
|
||||||
|
|
||||||
https://www.w3.org/TR/css3-values/#relative-lengths
|
|
||||||
https://www.w3.org/TR/css3-values/#absolute-lengths
|
|
||||||
https://drafts.csswg.org/css-cascade-4/#computed-value
|
|
||||||
https://drafts.csswg.org/css-fonts-3/#propdef-font-size
|
|
||||||
https://drafts.csswg.org/css2/fonts.html#propdef-font-size
|
|
||||||
*/
|
|
||||||
if (length == null) {
|
|
||||||
return offset;
|
|
||||||
}
|
|
||||||
SVGLength.UnitType unitType = length.unit;
|
|
||||||
double value = length.value;
|
|
||||||
double unit = 1;
|
double unit = 1;
|
||||||
switch (unitType) {
|
|
||||||
case NUMBER:
|
|
||||||
case PX:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PERCENTAGE:
|
switch (lastTwo) {
|
||||||
return value / 100 * relative + offset;
|
case "px":
|
||||||
|
break;
|
||||||
|
|
||||||
case EMS:
|
case "em":
|
||||||
unit = fontSize;
|
unit = fontSize;
|
||||||
break;
|
break;
|
||||||
case EXS:
|
|
||||||
unit = fontSize / 2;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case CM:
|
/*
|
||||||
unit = 35.43307;
|
"1pt" equals "1.25px" (and therefore 1.25 user units)
|
||||||
break;
|
"1pc" equals "15px" (and therefore 15 user units)
|
||||||
case MM:
|
"1mm" would be "3.543307px" (3.543307 user units)
|
||||||
unit = 3.543307;
|
"1cm" equals "35.43307px" (and therefore 35.43307 user units)
|
||||||
break;
|
"1in" equals "90px" (and therefore 90 user units)
|
||||||
case IN:
|
*/
|
||||||
unit = 90;
|
|
||||||
break;
|
|
||||||
case PT:
|
|
||||||
unit = 1.25;
|
|
||||||
break;
|
|
||||||
case PC:
|
|
||||||
unit = 15;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
case "pt":
|
||||||
case UNKNOWN:
|
unit = 1.25d;
|
||||||
return value * scale + offset;
|
break;
|
||||||
|
|
||||||
|
case "pc":
|
||||||
|
unit = 15;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "mm":
|
||||||
|
unit = 3.543307d;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "cm":
|
||||||
|
unit = 35.43307d;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "in":
|
||||||
|
unit = 90;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
end = stringLength;
|
||||||
}
|
}
|
||||||
return value * unit * scale + offset;
|
|
||||||
|
return Double.valueOf(length.substring(0, end)) * unit * scale;
|
||||||
|
} else {
|
||||||
|
return Double.valueOf(length) * scale;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Converts SVGLength into px / user units in the current user coordinate system
|
||||||
|
*
|
||||||
|
* @param length length string
|
||||||
|
* @param relative relative size for percentages
|
||||||
|
* @param offset offset for all units
|
||||||
|
* @param scale scaling parameter
|
||||||
|
* @param fontSize current font size
|
||||||
|
* @return value in the current user coordinate system
|
||||||
|
*/
|
||||||
|
static double fromRelative(
|
||||||
|
SVGLength length, double relative, double offset, double scale, double fontSize) {
|
||||||
|
/*
|
||||||
|
TODO list
|
||||||
|
|
||||||
|
unit relative to
|
||||||
|
em font size of the element
|
||||||
|
ex x-height of the element’s font
|
||||||
|
ch width of the "0" (ZERO, U+0030) glyph in the element’s font
|
||||||
|
rem font size of the root element
|
||||||
|
vw 1% of viewport’s width
|
||||||
|
vh 1% of viewport’s height
|
||||||
|
vmin 1% of viewport’s smaller dimension
|
||||||
|
vmax 1% of viewport’s larger dimension
|
||||||
|
|
||||||
|
relative-size [ larger | smaller ]
|
||||||
|
absolute-size: [ xx-small | x-small | small | medium | large | x-large | xx-large ]
|
||||||
|
|
||||||
|
https://www.w3.org/TR/css3-values/#relative-lengths
|
||||||
|
https://www.w3.org/TR/css3-values/#absolute-lengths
|
||||||
|
https://drafts.csswg.org/css-cascade-4/#computed-value
|
||||||
|
https://drafts.csswg.org/css-fonts-3/#propdef-font-size
|
||||||
|
https://drafts.csswg.org/css2/fonts.html#propdef-font-size
|
||||||
|
*/
|
||||||
|
if (length == null) {
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
SVGLength.UnitType unitType = length.unit;
|
||||||
|
double value = length.value;
|
||||||
|
double unit = 1;
|
||||||
|
switch (unitType) {
|
||||||
|
case NUMBER:
|
||||||
|
case PX:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PERCENTAGE:
|
||||||
|
return value / 100 * relative + offset;
|
||||||
|
|
||||||
|
case EMS:
|
||||||
|
unit = fontSize;
|
||||||
|
break;
|
||||||
|
case EXS:
|
||||||
|
unit = fontSize / 2;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CM:
|
||||||
|
unit = 35.43307;
|
||||||
|
break;
|
||||||
|
case MM:
|
||||||
|
unit = 3.543307;
|
||||||
|
break;
|
||||||
|
case IN:
|
||||||
|
unit = 90;
|
||||||
|
break;
|
||||||
|
case PT:
|
||||||
|
unit = 1.25;
|
||||||
|
break;
|
||||||
|
case PC:
|
||||||
|
unit = 15;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
case UNKNOWN:
|
||||||
|
return value * scale + offset;
|
||||||
|
}
|
||||||
|
return value * unit * scale + offset;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,178 +3,170 @@ package com.horcrux.svg;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
enum RNSVGMarkerType {
|
enum RNSVGMarkerType {
|
||||||
kStartMarker,
|
kStartMarker,
|
||||||
kMidMarker,
|
kMidMarker,
|
||||||
kEndMarker
|
kEndMarker
|
||||||
}
|
}
|
||||||
|
|
||||||
enum ElementType {
|
enum ElementType {
|
||||||
kCGPathElementAddCurveToPoint,
|
kCGPathElementAddCurveToPoint,
|
||||||
kCGPathElementAddQuadCurveToPoint,
|
kCGPathElementAddQuadCurveToPoint,
|
||||||
kCGPathElementMoveToPoint,
|
kCGPathElementMoveToPoint,
|
||||||
kCGPathElementAddLineToPoint,
|
kCGPathElementAddLineToPoint,
|
||||||
kCGPathElementCloseSubpath
|
kCGPathElementCloseSubpath
|
||||||
}
|
}
|
||||||
|
|
||||||
class Point {
|
class Point {
|
||||||
double x;
|
double x;
|
||||||
double y;
|
double y;
|
||||||
Point(double x, double y){
|
|
||||||
this.x = x;
|
Point(double x, double y) {
|
||||||
this.y = y;
|
this.x = x;
|
||||||
}
|
this.y = y;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class SegmentData {
|
class SegmentData {
|
||||||
Point start_tangent; // Tangent in the start point of the segment.
|
Point start_tangent; // Tangent in the start point of the segment.
|
||||||
Point end_tangent; // Tangent in the end point of the segment.
|
Point end_tangent; // Tangent in the end point of the segment.
|
||||||
Point position; // The end point of the segment.
|
Point position; // The end point of the segment.
|
||||||
}
|
}
|
||||||
|
|
||||||
class RNSVGMarkerPosition {
|
class RNSVGMarkerPosition {
|
||||||
|
|
||||||
static private ArrayList<RNSVGMarkerPosition> positions_;
|
private static ArrayList<RNSVGMarkerPosition> positions_;
|
||||||
static private int element_index_;
|
private static int element_index_;
|
||||||
static private Point origin_;
|
private static Point origin_;
|
||||||
static private Point subpath_start_;
|
private static Point subpath_start_;
|
||||||
static private Point in_slope_;
|
private static Point in_slope_;
|
||||||
static private Point out_slope_;
|
private static Point out_slope_;
|
||||||
@SuppressWarnings("unused")
|
|
||||||
static private boolean auto_start_reverse_; // TODO
|
|
||||||
|
|
||||||
RNSVGMarkerType type;
|
@SuppressWarnings("unused")
|
||||||
Point origin;
|
private static boolean auto_start_reverse_; // TODO
|
||||||
double angle;
|
|
||||||
|
|
||||||
private RNSVGMarkerPosition(RNSVGMarkerType type, Point origin, double angle) {
|
RNSVGMarkerType type;
|
||||||
this.type = type;
|
Point origin;
|
||||||
this.origin = origin;
|
double angle;
|
||||||
this.angle = angle;
|
|
||||||
|
private RNSVGMarkerPosition(RNSVGMarkerType type, Point origin, double angle) {
|
||||||
|
this.type = type;
|
||||||
|
this.origin = origin;
|
||||||
|
this.angle = angle;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ArrayList<RNSVGMarkerPosition> fromPath(ArrayList<PathElement> elements) {
|
||||||
|
positions_ = new ArrayList<>();
|
||||||
|
element_index_ = 0;
|
||||||
|
origin_ = new Point(0, 0);
|
||||||
|
subpath_start_ = new Point(0, 0);
|
||||||
|
for (PathElement e : elements) {
|
||||||
|
UpdateFromPathElement(e);
|
||||||
}
|
}
|
||||||
|
PathIsDone();
|
||||||
|
return positions_;
|
||||||
|
}
|
||||||
|
|
||||||
static ArrayList<RNSVGMarkerPosition> fromPath(ArrayList<PathElement> elements) {
|
private static void PathIsDone() {
|
||||||
positions_ = new ArrayList<>();
|
double angle = CurrentAngle(RNSVGMarkerType.kEndMarker);
|
||||||
element_index_ = 0;
|
positions_.add(new RNSVGMarkerPosition(RNSVGMarkerType.kEndMarker, origin_, angle));
|
||||||
origin_ = new Point(0, 0);
|
}
|
||||||
subpath_start_ = new Point(0, 0);
|
|
||||||
for (PathElement e : elements) {
|
|
||||||
UpdateFromPathElement(e);
|
|
||||||
}
|
|
||||||
PathIsDone();
|
|
||||||
return positions_;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void PathIsDone() {
|
private static double BisectingAngle(double in_angle, double out_angle) {
|
||||||
double angle = CurrentAngle(RNSVGMarkerType.kEndMarker);
|
// WK193015: Prevent bugs due to angles being non-continuous.
|
||||||
positions_.add(new RNSVGMarkerPosition(RNSVGMarkerType.kEndMarker, origin_, angle));
|
if (Math.abs(in_angle - out_angle) > 180) in_angle += 360;
|
||||||
}
|
return (in_angle + out_angle) / 2;
|
||||||
|
}
|
||||||
|
|
||||||
private static double BisectingAngle(double in_angle, double out_angle) {
|
private static double rad2deg(double rad) {
|
||||||
// WK193015: Prevent bugs due to angles being non-continuous.
|
double RNSVG_radToDeg = 180 / Math.PI;
|
||||||
if (Math.abs(in_angle - out_angle) > 180)
|
return rad * RNSVG_radToDeg;
|
||||||
in_angle += 360;
|
}
|
||||||
return (in_angle + out_angle) / 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static double rad2deg(double rad) {
|
private static double SlopeAngleRadians(Point p) {
|
||||||
double RNSVG_radToDeg = 180 / Math.PI;
|
return Math.atan2(p.y, p.x);
|
||||||
return rad * RNSVG_radToDeg;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private static double SlopeAngleRadians(Point p) {
|
private static double CurrentAngle(RNSVGMarkerType type) {
|
||||||
return Math.atan2(p.y, p.x);
|
// For details of this calculation, see:
|
||||||
|
// http://www.w3.org/TR/SVG/single-page.html#painting-MarkerElement
|
||||||
|
double in_angle = rad2deg(SlopeAngleRadians(in_slope_));
|
||||||
|
double out_angle = rad2deg(SlopeAngleRadians(out_slope_));
|
||||||
|
switch (type) {
|
||||||
|
case kStartMarker:
|
||||||
|
if (auto_start_reverse_) out_angle += 180;
|
||||||
|
return out_angle;
|
||||||
|
case kMidMarker:
|
||||||
|
return BisectingAngle(in_angle, out_angle);
|
||||||
|
case kEndMarker:
|
||||||
|
return in_angle;
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
private static double CurrentAngle(RNSVGMarkerType type) {
|
private static Point subtract(Point p1, Point p2) {
|
||||||
// For details of this calculation, see:
|
return new Point(p2.x - p1.x, p2.y - p1.y);
|
||||||
// http://www.w3.org/TR/SVG/single-page.html#painting-MarkerElement
|
}
|
||||||
double in_angle = rad2deg(SlopeAngleRadians(in_slope_));
|
|
||||||
double out_angle = rad2deg(SlopeAngleRadians(out_slope_));
|
|
||||||
switch (type) {
|
|
||||||
case kStartMarker:
|
|
||||||
if (auto_start_reverse_)
|
|
||||||
out_angle += 180;
|
|
||||||
return out_angle;
|
|
||||||
case kMidMarker:
|
|
||||||
return BisectingAngle(in_angle, out_angle);
|
|
||||||
case kEndMarker:
|
|
||||||
return in_angle;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Point subtract(Point p1, Point p2) {
|
private static boolean isZero(Point p) {
|
||||||
return new Point(p2.x - p1.x, p2.y - p1.y);
|
return p.x == 0 && p.y == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isZero(Point p) {
|
private static void ComputeQuadTangents(SegmentData data, Point start, Point control, Point end) {
|
||||||
return p.x == 0 && p.y == 0;
|
data.start_tangent = subtract(control, start);
|
||||||
}
|
data.end_tangent = subtract(end, control);
|
||||||
|
if (isZero(data.start_tangent)) data.start_tangent = data.end_tangent;
|
||||||
|
else if (isZero(data.end_tangent)) data.end_tangent = data.start_tangent;
|
||||||
|
}
|
||||||
|
|
||||||
private static void ComputeQuadTangents(SegmentData data,
|
private static SegmentData ExtractPathElementFeatures(PathElement element) {
|
||||||
Point start,
|
SegmentData data = new SegmentData();
|
||||||
Point control,
|
Point[] points = element.points;
|
||||||
Point end) {
|
switch (element.type) {
|
||||||
data.start_tangent = subtract(control, start);
|
case kCGPathElementAddCurveToPoint:
|
||||||
data.end_tangent = subtract(end, control);
|
data.position = points[2];
|
||||||
if (isZero(data.start_tangent))
|
data.start_tangent = subtract(points[0], origin_);
|
||||||
data.start_tangent = data.end_tangent;
|
data.end_tangent = subtract(points[2], points[1]);
|
||||||
else if (isZero(data.end_tangent))
|
if (isZero(data.start_tangent)) ComputeQuadTangents(data, points[0], points[1], points[2]);
|
||||||
data.end_tangent = data.start_tangent;
|
else if (isZero(data.end_tangent)) ComputeQuadTangents(data, origin_, points[0], points[1]);
|
||||||
|
break;
|
||||||
|
case kCGPathElementAddQuadCurveToPoint:
|
||||||
|
data.position = points[1];
|
||||||
|
ComputeQuadTangents(data, origin_, points[0], points[1]);
|
||||||
|
break;
|
||||||
|
case kCGPathElementMoveToPoint:
|
||||||
|
case kCGPathElementAddLineToPoint:
|
||||||
|
data.position = points[0];
|
||||||
|
data.start_tangent = subtract(data.position, origin_);
|
||||||
|
data.end_tangent = subtract(data.position, origin_);
|
||||||
|
break;
|
||||||
|
case kCGPathElementCloseSubpath:
|
||||||
|
data.position = subpath_start_;
|
||||||
|
data.start_tangent = subtract(data.position, origin_);
|
||||||
|
data.end_tangent = subtract(data.position, origin_);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
private static SegmentData ExtractPathElementFeatures(PathElement element) {
|
private static void UpdateFromPathElement(PathElement element) {
|
||||||
SegmentData data = new SegmentData();
|
SegmentData segment_data = ExtractPathElementFeatures(element);
|
||||||
Point[] points = element.points;
|
// First update the outgoing slope for the previous element.
|
||||||
switch (element.type) {
|
out_slope_ = segment_data.start_tangent;
|
||||||
case kCGPathElementAddCurveToPoint:
|
// Record the marker for the previous element.
|
||||||
data.position = points[2];
|
if (element_index_ > 0) {
|
||||||
data.start_tangent = subtract(points[0], origin_);
|
RNSVGMarkerType marker_type =
|
||||||
data.end_tangent = subtract(points[2], points[1]);
|
element_index_ == 1 ? RNSVGMarkerType.kStartMarker : RNSVGMarkerType.kMidMarker;
|
||||||
if (isZero(data.start_tangent))
|
double angle = CurrentAngle(marker_type);
|
||||||
ComputeQuadTangents(data, points[0], points[1], points[2]);
|
positions_.add(new RNSVGMarkerPosition(marker_type, origin_, angle));
|
||||||
else if (isZero(data.end_tangent))
|
|
||||||
ComputeQuadTangents(data, origin_, points[0], points[1]);
|
|
||||||
break;
|
|
||||||
case kCGPathElementAddQuadCurveToPoint:
|
|
||||||
data.position = points[1];
|
|
||||||
ComputeQuadTangents(data, origin_, points[0], points[1]);
|
|
||||||
break;
|
|
||||||
case kCGPathElementMoveToPoint:
|
|
||||||
case kCGPathElementAddLineToPoint:
|
|
||||||
data.position = points[0];
|
|
||||||
data.start_tangent = subtract(data.position, origin_);
|
|
||||||
data.end_tangent = subtract(data.position, origin_);
|
|
||||||
break;
|
|
||||||
case kCGPathElementCloseSubpath:
|
|
||||||
data.position = subpath_start_;
|
|
||||||
data.start_tangent = subtract(data.position, origin_);
|
|
||||||
data.end_tangent = subtract(data.position, origin_);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void UpdateFromPathElement(PathElement element) {
|
|
||||||
SegmentData segment_data = ExtractPathElementFeatures(element);
|
|
||||||
// First update the outgoing slope for the previous element.
|
|
||||||
out_slope_ = segment_data.start_tangent;
|
|
||||||
// Record the marker for the previous element.
|
|
||||||
if (element_index_ > 0) {
|
|
||||||
RNSVGMarkerType marker_type =
|
|
||||||
element_index_ == 1 ? RNSVGMarkerType.kStartMarker : RNSVGMarkerType.kMidMarker;
|
|
||||||
double angle = CurrentAngle(marker_type);
|
|
||||||
positions_.add(new RNSVGMarkerPosition(marker_type, origin_, angle));
|
|
||||||
}
|
|
||||||
// Update the incoming slope for this marker position.
|
|
||||||
in_slope_ = segment_data.end_tangent;
|
|
||||||
// Update marker position.
|
|
||||||
origin_ = segment_data.position;
|
|
||||||
// If this is a 'move to' segment, save the point for use with 'close'.
|
|
||||||
if (element.type == ElementType.kCGPathElementMoveToPoint)
|
|
||||||
subpath_start_ = element.points[0];
|
|
||||||
else if (element.type == ElementType.kCGPathElementCloseSubpath)
|
|
||||||
subpath_start_ = new Point(0, 0);
|
|
||||||
++element_index_;
|
|
||||||
}
|
}
|
||||||
|
// Update the incoming slope for this marker position.
|
||||||
|
in_slope_ = segment_data.end_tangent;
|
||||||
|
// Update marker position.
|
||||||
|
origin_ = segment_data.position;
|
||||||
|
// If this is a 'move to' segment, save the point for use with 'close'.
|
||||||
|
if (element.type == ElementType.kCGPathElementMoveToPoint) subpath_start_ = element.points[0];
|
||||||
|
else if (element.type == ElementType.kCGPathElementCloseSubpath)
|
||||||
|
subpath_start_ = new Point(0, 0);
|
||||||
|
++element_index_;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,16 +6,16 @@
|
|||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
package com.horcrux.svg;
|
package com.horcrux.svg;
|
||||||
|
|
||||||
|
import static com.facebook.react.common.StandardCharsets.UTF_8;
|
||||||
|
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
import android.graphics.Matrix;
|
import android.graphics.Matrix;
|
||||||
import android.graphics.Path;
|
import android.graphics.Path;
|
||||||
import android.graphics.PathMeasure;
|
import android.graphics.PathMeasure;
|
||||||
import android.graphics.RectF;
|
import android.graphics.RectF;
|
||||||
import android.graphics.Region;
|
import android.graphics.Region;
|
||||||
|
|
||||||
import com.facebook.react.bridge.Arguments;
|
import com.facebook.react.bridge.Arguments;
|
||||||
import com.facebook.react.bridge.Promise;
|
import com.facebook.react.bridge.Promise;
|
||||||
import com.facebook.react.bridge.ReactApplicationContext;
|
import com.facebook.react.bridge.ReactApplicationContext;
|
||||||
@@ -23,251 +23,247 @@ import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
|||||||
import com.facebook.react.bridge.ReactMethod;
|
import com.facebook.react.bridge.ReactMethod;
|
||||||
import com.facebook.react.bridge.ReadableMap;
|
import com.facebook.react.bridge.ReadableMap;
|
||||||
import com.facebook.react.bridge.WritableMap;
|
import com.facebook.react.bridge.WritableMap;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
import static com.facebook.react.common.StandardCharsets.UTF_8;
|
|
||||||
|
|
||||||
class RNSVGRenderableManager extends ReactContextBaseJavaModule {
|
class RNSVGRenderableManager extends ReactContextBaseJavaModule {
|
||||||
RNSVGRenderableManager(ReactApplicationContext reactContext) {
|
RNSVGRenderableManager(ReactApplicationContext reactContext) {
|
||||||
super(reactContext);
|
super(reactContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "RNSVGRenderableManager";
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
@ReactMethod(isBlockingSynchronousMethod = true)
|
||||||
|
public boolean isPointInFill(int tag, ReadableMap options) {
|
||||||
|
RenderableView svg = RenderableViewManager.getRenderableViewByTag(tag);
|
||||||
|
if (svg == null) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nonnull
|
float scale = svg.mScale;
|
||||||
@Override
|
float x = (float) options.getDouble("x") * scale;
|
||||||
public String getName() {
|
float y = (float) options.getDouble("y") * scale;
|
||||||
return "RNSVGRenderableManager";
|
|
||||||
|
int i = svg.hitTest(new float[] {x, y});
|
||||||
|
return i != -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
@ReactMethod(isBlockingSynchronousMethod = true)
|
||||||
|
public boolean isPointInStroke(int tag, ReadableMap options) {
|
||||||
|
RenderableView svg = RenderableViewManager.getRenderableViewByTag(tag);
|
||||||
|
if (svg == null) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
try {
|
||||||
@ReactMethod(isBlockingSynchronousMethod = true)
|
svg.getPath(null, null);
|
||||||
public boolean isPointInFill(int tag, ReadableMap options) {
|
} catch (NullPointerException e) {
|
||||||
RenderableView svg = RenderableViewManager.getRenderableViewByTag(tag);
|
svg.invalidate();
|
||||||
if (svg == null) {
|
return false;
|
||||||
return false;
|
}
|
||||||
|
|
||||||
|
svg.initBounds();
|
||||||
|
|
||||||
|
float scale = svg.mScale;
|
||||||
|
int x = (int) (options.getDouble("x") * scale);
|
||||||
|
int y = (int) (options.getDouble("y") * scale);
|
||||||
|
|
||||||
|
Region strokeRegion = svg.mStrokeRegion;
|
||||||
|
return strokeRegion != null && strokeRegion.contains(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
@ReactMethod(isBlockingSynchronousMethod = true)
|
||||||
|
public float getTotalLength(int tag) {
|
||||||
|
RenderableView svg = RenderableViewManager.getRenderableViewByTag(tag);
|
||||||
|
if (svg == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Path path;
|
||||||
|
|
||||||
|
try {
|
||||||
|
path = svg.getPath(null, null);
|
||||||
|
} catch (NullPointerException e) {
|
||||||
|
svg.invalidate();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
PathMeasure pm = new PathMeasure(path, false);
|
||||||
|
return pm.getLength() / svg.mScale;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
@ReactMethod(isBlockingSynchronousMethod = true)
|
||||||
|
public WritableMap getPointAtLength(int tag, ReadableMap options) {
|
||||||
|
RenderableView svg = RenderableViewManager.getRenderableViewByTag(tag);
|
||||||
|
if (svg == null) {
|
||||||
|
return Arguments.createMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
Path path;
|
||||||
|
|
||||||
|
try {
|
||||||
|
path = svg.getPath(null, null);
|
||||||
|
} catch (NullPointerException e) {
|
||||||
|
svg.invalidate();
|
||||||
|
return Arguments.createMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
PathMeasure pm = new PathMeasure(path, false);
|
||||||
|
float length = (float) options.getDouble("length");
|
||||||
|
float scale = svg.mScale;
|
||||||
|
|
||||||
|
float[] pos = new float[2];
|
||||||
|
float[] tan = new float[2];
|
||||||
|
float distance = Math.max(0, Math.min(length, pm.getLength()));
|
||||||
|
pm.getPosTan(distance, pos, tan);
|
||||||
|
|
||||||
|
double angle = Math.atan2(tan[1], tan[0]);
|
||||||
|
WritableMap result = Arguments.createMap();
|
||||||
|
result.putDouble("x", pos[0] / scale);
|
||||||
|
result.putDouble("y", pos[1] / scale);
|
||||||
|
result.putDouble("angle", angle);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
@ReactMethod(isBlockingSynchronousMethod = true)
|
||||||
|
public WritableMap getBBox(int tag, ReadableMap options) {
|
||||||
|
RenderableView svg = RenderableViewManager.getRenderableViewByTag(tag);
|
||||||
|
if (svg == null) {
|
||||||
|
return Arguments.createMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean fill = options.getBoolean("fill");
|
||||||
|
boolean stroke = options.getBoolean("stroke");
|
||||||
|
boolean markers = options.getBoolean("markers");
|
||||||
|
boolean clipped = options.getBoolean("clipped");
|
||||||
|
|
||||||
|
try {
|
||||||
|
svg.getPath(null, null);
|
||||||
|
} catch (NullPointerException e) {
|
||||||
|
svg.invalidate();
|
||||||
|
return Arguments.createMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
float scale = svg.mScale;
|
||||||
|
svg.initBounds();
|
||||||
|
|
||||||
|
RectF bounds = new RectF();
|
||||||
|
RectF fillBounds = svg.mFillBounds;
|
||||||
|
RectF strokeBounds = svg.mStrokeBounds;
|
||||||
|
RectF markerBounds = svg.mMarkerBounds;
|
||||||
|
RectF clipBounds = svg.mClipBounds;
|
||||||
|
|
||||||
|
if (fill && fillBounds != null) {
|
||||||
|
bounds.union(fillBounds);
|
||||||
|
}
|
||||||
|
if (stroke && strokeBounds != null) {
|
||||||
|
bounds.union(strokeBounds);
|
||||||
|
}
|
||||||
|
if (markers && markerBounds != null) {
|
||||||
|
bounds.union(markerBounds);
|
||||||
|
}
|
||||||
|
if (clipped && clipBounds != null) {
|
||||||
|
bounds.intersect(clipBounds);
|
||||||
|
}
|
||||||
|
|
||||||
|
WritableMap result = Arguments.createMap();
|
||||||
|
result.putDouble("x", bounds.left / scale);
|
||||||
|
result.putDouble("y", bounds.top / scale);
|
||||||
|
result.putDouble("width", bounds.width() / scale);
|
||||||
|
result.putDouble("height", bounds.height() / scale);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
@ReactMethod(isBlockingSynchronousMethod = true)
|
||||||
|
public WritableMap getCTM(int tag) {
|
||||||
|
RenderableView svg = RenderableViewManager.getRenderableViewByTag(tag);
|
||||||
|
if (svg == null) {
|
||||||
|
return Arguments.createMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
float scale = svg.mScale;
|
||||||
|
Matrix ctm = new Matrix(svg.mCTM);
|
||||||
|
Matrix invViewBoxMatrix = svg.getSvgView().mInvViewBoxMatrix;
|
||||||
|
ctm.preConcat(invViewBoxMatrix);
|
||||||
|
|
||||||
|
float[] values = new float[9];
|
||||||
|
ctm.getValues(values);
|
||||||
|
|
||||||
|
WritableMap result = Arguments.createMap();
|
||||||
|
result.putDouble("a", values[Matrix.MSCALE_X]);
|
||||||
|
result.putDouble("b", values[Matrix.MSKEW_Y]);
|
||||||
|
result.putDouble("c", values[Matrix.MSKEW_X]);
|
||||||
|
result.putDouble("d", values[Matrix.MSCALE_Y]);
|
||||||
|
result.putDouble("e", values[Matrix.MTRANS_X] / scale);
|
||||||
|
result.putDouble("f", values[Matrix.MTRANS_Y] / scale);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
@ReactMethod(isBlockingSynchronousMethod = true)
|
||||||
|
public WritableMap getScreenCTM(int tag) {
|
||||||
|
RenderableView svg = RenderableViewManager.getRenderableViewByTag(tag);
|
||||||
|
if (svg == null) {
|
||||||
|
return Arguments.createMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
float[] values = new float[9];
|
||||||
|
svg.mCTM.getValues(values);
|
||||||
|
float scale = svg.mScale;
|
||||||
|
|
||||||
|
WritableMap result = Arguments.createMap();
|
||||||
|
result.putDouble("a", values[Matrix.MSCALE_X]);
|
||||||
|
result.putDouble("b", values[Matrix.MSKEW_Y]);
|
||||||
|
result.putDouble("c", values[Matrix.MSKEW_X]);
|
||||||
|
result.putDouble("d", values[Matrix.MSCALE_Y]);
|
||||||
|
result.putDouble("e", values[Matrix.MTRANS_X] / scale);
|
||||||
|
result.putDouble("f", values[Matrix.MTRANS_Y] / scale);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ReactMethod
|
||||||
|
public void getRawResource(String name, Promise promise) {
|
||||||
|
try {
|
||||||
|
ReactApplicationContext context = getReactApplicationContext();
|
||||||
|
Resources resources = context.getResources();
|
||||||
|
String packageName = context.getPackageName();
|
||||||
|
int id = resources.getIdentifier(name, "raw", packageName);
|
||||||
|
InputStream stream = resources.openRawResource(id);
|
||||||
|
try {
|
||||||
|
InputStreamReader reader = new InputStreamReader(stream, UTF_8);
|
||||||
|
char[] buffer = new char[DEFAULT_BUFFER_SIZE];
|
||||||
|
StringBuilder builder = new StringBuilder();
|
||||||
|
int n;
|
||||||
|
while ((n = reader.read(buffer, 0, DEFAULT_BUFFER_SIZE)) != EOF) {
|
||||||
|
builder.append(buffer, 0, n);
|
||||||
}
|
}
|
||||||
|
String result = builder.toString();
|
||||||
float scale = svg.mScale;
|
promise.resolve(result);
|
||||||
float x = (float) options.getDouble("x") * scale;
|
} finally {
|
||||||
float y = (float) options.getDouble("y") * scale;
|
|
||||||
|
|
||||||
int i = svg.hitTest(new float[]{x, y});
|
|
||||||
return i != -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
@ReactMethod(isBlockingSynchronousMethod = true)
|
|
||||||
public boolean isPointInStroke(int tag, ReadableMap options) {
|
|
||||||
RenderableView svg = RenderableViewManager.getRenderableViewByTag(tag);
|
|
||||||
if (svg == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
svg.getPath(null, null);
|
stream.close();
|
||||||
} catch (NullPointerException e) {
|
} catch (IOException ioe) {
|
||||||
svg.invalidate();
|
// ignore
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
svg.initBounds();
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
float scale = svg.mScale;
|
promise.reject(e);
|
||||||
int x = (int) (options.getDouble("x") * scale);
|
|
||||||
int y = (int) (options.getDouble("y") * scale);
|
|
||||||
|
|
||||||
Region strokeRegion = svg.mStrokeRegion;
|
|
||||||
return strokeRegion != null && strokeRegion.contains(x, y);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
private static final int EOF = -1;
|
||||||
@ReactMethod(isBlockingSynchronousMethod = true)
|
private static final int DEFAULT_BUFFER_SIZE = 1024 * 4;
|
||||||
public float getTotalLength(int tag) {
|
|
||||||
RenderableView svg = RenderableViewManager.getRenderableViewByTag(tag);
|
|
||||||
if (svg == null) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
Path path;
|
|
||||||
|
|
||||||
try {
|
|
||||||
path = svg.getPath(null, null);
|
|
||||||
} catch (NullPointerException e) {
|
|
||||||
svg.invalidate();
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
PathMeasure pm = new PathMeasure(path, false);
|
|
||||||
return pm.getLength() / svg.mScale;
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
@ReactMethod(isBlockingSynchronousMethod = true)
|
|
||||||
public WritableMap getPointAtLength(int tag, ReadableMap options) {
|
|
||||||
RenderableView svg = RenderableViewManager.getRenderableViewByTag(tag);
|
|
||||||
if (svg == null) {
|
|
||||||
return Arguments.createMap();
|
|
||||||
}
|
|
||||||
|
|
||||||
Path path;
|
|
||||||
|
|
||||||
try {
|
|
||||||
path = svg.getPath(null, null);
|
|
||||||
} catch (NullPointerException e) {
|
|
||||||
svg.invalidate();
|
|
||||||
return Arguments.createMap();
|
|
||||||
}
|
|
||||||
|
|
||||||
PathMeasure pm = new PathMeasure(path, false);
|
|
||||||
float length = (float) options.getDouble("length");
|
|
||||||
float scale = svg.mScale;
|
|
||||||
|
|
||||||
float[] pos = new float[2];
|
|
||||||
float[] tan = new float[2];
|
|
||||||
float distance = Math.max(0, Math.min(length, pm.getLength()));
|
|
||||||
pm.getPosTan(distance, pos, tan);
|
|
||||||
|
|
||||||
double angle = Math.atan2(tan[1], tan[0]);
|
|
||||||
WritableMap result = Arguments.createMap();
|
|
||||||
result.putDouble("x", pos[0] / scale);
|
|
||||||
result.putDouble("y", pos[1] / scale);
|
|
||||||
result.putDouble("angle", angle);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
@ReactMethod(isBlockingSynchronousMethod = true)
|
|
||||||
public WritableMap getBBox(int tag, ReadableMap options) {
|
|
||||||
RenderableView svg = RenderableViewManager.getRenderableViewByTag(tag);
|
|
||||||
if (svg == null) {
|
|
||||||
return Arguments.createMap();
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean fill = options.getBoolean("fill");
|
|
||||||
boolean stroke = options.getBoolean("stroke");
|
|
||||||
boolean markers = options.getBoolean("markers");
|
|
||||||
boolean clipped = options.getBoolean("clipped");
|
|
||||||
|
|
||||||
try {
|
|
||||||
svg.getPath(null, null);
|
|
||||||
} catch (NullPointerException e) {
|
|
||||||
svg.invalidate();
|
|
||||||
return Arguments.createMap();
|
|
||||||
}
|
|
||||||
|
|
||||||
float scale = svg.mScale;
|
|
||||||
svg.initBounds();
|
|
||||||
|
|
||||||
RectF bounds = new RectF();
|
|
||||||
RectF fillBounds = svg.mFillBounds;
|
|
||||||
RectF strokeBounds = svg.mStrokeBounds;
|
|
||||||
RectF markerBounds = svg.mMarkerBounds;
|
|
||||||
RectF clipBounds = svg.mClipBounds;
|
|
||||||
|
|
||||||
if (fill && fillBounds != null) {
|
|
||||||
bounds.union(fillBounds);
|
|
||||||
}
|
|
||||||
if (stroke && strokeBounds != null) {
|
|
||||||
bounds.union(strokeBounds);
|
|
||||||
}
|
|
||||||
if (markers && markerBounds != null) {
|
|
||||||
bounds.union(markerBounds);
|
|
||||||
}
|
|
||||||
if (clipped && clipBounds != null) {
|
|
||||||
bounds.intersect(clipBounds);
|
|
||||||
}
|
|
||||||
|
|
||||||
WritableMap result = Arguments.createMap();
|
|
||||||
result.putDouble("x", bounds.left / scale);
|
|
||||||
result.putDouble("y", bounds.top / scale);
|
|
||||||
result.putDouble("width", bounds.width() / scale);
|
|
||||||
result.putDouble("height", bounds.height() / scale);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
@ReactMethod(isBlockingSynchronousMethod = true)
|
|
||||||
public WritableMap getCTM(int tag) {
|
|
||||||
RenderableView svg = RenderableViewManager.getRenderableViewByTag(tag);
|
|
||||||
if (svg == null) {
|
|
||||||
return Arguments.createMap();
|
|
||||||
}
|
|
||||||
|
|
||||||
float scale = svg.mScale;
|
|
||||||
Matrix ctm = new Matrix(svg.mCTM);
|
|
||||||
Matrix invViewBoxMatrix = svg.getSvgView().mInvViewBoxMatrix;
|
|
||||||
ctm.preConcat(invViewBoxMatrix);
|
|
||||||
|
|
||||||
float[] values = new float[9];
|
|
||||||
ctm.getValues(values);
|
|
||||||
|
|
||||||
WritableMap result = Arguments.createMap();
|
|
||||||
result.putDouble("a", values[Matrix.MSCALE_X]);
|
|
||||||
result.putDouble("b", values[Matrix.MSKEW_Y]);
|
|
||||||
result.putDouble("c", values[Matrix.MSKEW_X]);
|
|
||||||
result.putDouble("d", values[Matrix.MSCALE_Y]);
|
|
||||||
result.putDouble("e", values[Matrix.MTRANS_X] / scale);
|
|
||||||
result.putDouble("f", values[Matrix.MTRANS_Y] / scale);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
@ReactMethod(isBlockingSynchronousMethod = true)
|
|
||||||
public WritableMap getScreenCTM(int tag) {
|
|
||||||
RenderableView svg = RenderableViewManager.getRenderableViewByTag(tag);
|
|
||||||
if (svg == null) {
|
|
||||||
return Arguments.createMap();
|
|
||||||
}
|
|
||||||
|
|
||||||
float[] values = new float[9];
|
|
||||||
svg.mCTM.getValues(values);
|
|
||||||
float scale = svg.mScale;
|
|
||||||
|
|
||||||
WritableMap result = Arguments.createMap();
|
|
||||||
result.putDouble("a", values[Matrix.MSCALE_X]);
|
|
||||||
result.putDouble("b", values[Matrix.MSKEW_Y]);
|
|
||||||
result.putDouble("c", values[Matrix.MSKEW_X]);
|
|
||||||
result.putDouble("d", values[Matrix.MSCALE_Y]);
|
|
||||||
result.putDouble("e", values[Matrix.MTRANS_X] / scale);
|
|
||||||
result.putDouble("f", values[Matrix.MTRANS_Y] / scale);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
@ReactMethod
|
|
||||||
public void getRawResource(String name, Promise promise) {
|
|
||||||
try {
|
|
||||||
ReactApplicationContext context = getReactApplicationContext();
|
|
||||||
Resources resources = context.getResources();
|
|
||||||
String packageName = context.getPackageName();
|
|
||||||
int id = resources.getIdentifier(name, "raw", packageName);
|
|
||||||
InputStream stream = resources.openRawResource(id);
|
|
||||||
try {
|
|
||||||
InputStreamReader reader = new InputStreamReader(stream, UTF_8);
|
|
||||||
char[] buffer = new char[DEFAULT_BUFFER_SIZE];
|
|
||||||
StringBuilder builder = new StringBuilder();
|
|
||||||
int n;
|
|
||||||
while ((n = reader.read(buffer, 0, DEFAULT_BUFFER_SIZE)) != EOF) {
|
|
||||||
builder.append(buffer, 0, n);
|
|
||||||
}
|
|
||||||
String result = builder.toString();
|
|
||||||
promise.resolve(result);
|
|
||||||
} finally {
|
|
||||||
try {
|
|
||||||
stream.close();
|
|
||||||
} catch (IOException ioe) {
|
|
||||||
// ignore
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
promise.reject(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final int EOF = -1;
|
|
||||||
private static final int DEFAULT_BUFFER_SIZE = 1024 * 4;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,163 +6,161 @@
|
|||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
package com.horcrux.svg;
|
package com.horcrux.svg;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.graphics.Matrix;
|
import android.graphics.Matrix;
|
||||||
|
|
||||||
import com.facebook.common.logging.FLog;
|
import com.facebook.common.logging.FLog;
|
||||||
import com.facebook.react.bridge.Dynamic;
|
import com.facebook.react.bridge.Dynamic;
|
||||||
import com.facebook.react.bridge.ReactContext;
|
import com.facebook.react.bridge.ReactContext;
|
||||||
import com.facebook.react.bridge.ReadableArray;
|
import com.facebook.react.bridge.ReadableArray;
|
||||||
import com.facebook.react.common.ReactConstants;
|
import com.facebook.react.common.ReactConstants;
|
||||||
import com.facebook.react.uimanager.annotations.ReactProp;
|
import com.facebook.react.uimanager.annotations.ReactProp;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
@SuppressLint("ViewConstructor")
|
@SuppressLint("ViewConstructor")
|
||||||
class RadialGradientView extends DefinitionView {
|
class RadialGradientView extends DefinitionView {
|
||||||
private SVGLength mFx;
|
private SVGLength mFx;
|
||||||
private SVGLength mFy;
|
private SVGLength mFy;
|
||||||
private SVGLength mRx;
|
private SVGLength mRx;
|
||||||
private SVGLength mRy;
|
private SVGLength mRy;
|
||||||
private SVGLength mCx;
|
private SVGLength mCx;
|
||||||
private SVGLength mCy;
|
private SVGLength mCy;
|
||||||
private ReadableArray mGradient;
|
private ReadableArray mGradient;
|
||||||
private Brush.BrushUnits mGradientUnits;
|
private Brush.BrushUnits mGradientUnits;
|
||||||
|
|
||||||
private static final float[] sRawMatrix = new float[]{
|
private static final float[] sRawMatrix =
|
||||||
|
new float[] {
|
||||||
1, 0, 0,
|
1, 0, 0,
|
||||||
0, 1, 0,
|
0, 1, 0,
|
||||||
0, 0, 1
|
0, 0, 1
|
||||||
};
|
};
|
||||||
private Matrix mMatrix = null;
|
private Matrix mMatrix = null;
|
||||||
|
|
||||||
public RadialGradientView(ReactContext reactContext) {
|
public RadialGradientView(ReactContext reactContext) {
|
||||||
super(reactContext);
|
super(reactContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "fx")
|
@ReactProp(name = "fx")
|
||||||
public void setFx(Dynamic fx) {
|
public void setFx(Dynamic fx) {
|
||||||
mFx = SVGLength.from(fx);
|
mFx = SVGLength.from(fx);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setFx(String fx) {
|
public void setFx(String fx) {
|
||||||
mFx = SVGLength.from(fx);
|
mFx = SVGLength.from(fx);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "fy")
|
@ReactProp(name = "fy")
|
||||||
public void setFy(Dynamic fy) {
|
public void setFy(Dynamic fy) {
|
||||||
mFy = SVGLength.from(fy);
|
mFy = SVGLength.from(fy);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setFy(String fy) {
|
public void setFy(String fy) {
|
||||||
mFy = SVGLength.from(fy);
|
mFy = SVGLength.from(fy);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "rx")
|
@ReactProp(name = "rx")
|
||||||
public void setRx(Dynamic rx) {
|
public void setRx(Dynamic rx) {
|
||||||
mRx = SVGLength.from(rx);
|
mRx = SVGLength.from(rx);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setRx(String rx) {
|
public void setRx(String rx) {
|
||||||
mRx = SVGLength.from(rx);
|
mRx = SVGLength.from(rx);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "ry")
|
@ReactProp(name = "ry")
|
||||||
public void setRy(Dynamic ry) {
|
public void setRy(Dynamic ry) {
|
||||||
mRy = SVGLength.from(ry);
|
mRy = SVGLength.from(ry);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setRy(String ry) {
|
public void setRy(String ry) {
|
||||||
mRy = SVGLength.from(ry);
|
mRy = SVGLength.from(ry);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "cx")
|
@ReactProp(name = "cx")
|
||||||
public void setCx(Dynamic cx) {
|
public void setCx(Dynamic cx) {
|
||||||
mCx = SVGLength.from(cx);
|
mCx = SVGLength.from(cx);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCx(String cx) {
|
public void setCx(String cx) {
|
||||||
mCx = SVGLength.from(cx);
|
mCx = SVGLength.from(cx);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "cy")
|
@ReactProp(name = "cy")
|
||||||
public void setCy(Dynamic cy) {
|
public void setCy(Dynamic cy) {
|
||||||
mCy = SVGLength.from(cy);
|
mCy = SVGLength.from(cy);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCy(String cy) {
|
public void setCy(String cy) {
|
||||||
mCy = SVGLength.from(cy);
|
mCy = SVGLength.from(cy);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "gradient")
|
@ReactProp(name = "gradient")
|
||||||
public void setGradient(ReadableArray gradient) {
|
public void setGradient(ReadableArray gradient) {
|
||||||
mGradient = gradient;
|
mGradient = gradient;
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "gradientUnits")
|
@ReactProp(name = "gradientUnits")
|
||||||
public void setGradientUnits(int gradientUnits) {
|
public void setGradientUnits(int gradientUnits) {
|
||||||
switch (gradientUnits) {
|
switch (gradientUnits) {
|
||||||
case 0:
|
case 0:
|
||||||
mGradientUnits = Brush.BrushUnits.OBJECT_BOUNDING_BOX;
|
mGradientUnits = Brush.BrushUnits.OBJECT_BOUNDING_BOX;
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
mGradientUnits = Brush.BrushUnits.USER_SPACE_ON_USE;
|
mGradientUnits = Brush.BrushUnits.USER_SPACE_ON_USE;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@ReactProp(name = "gradientTransform")
|
||||||
|
public void setGradientTransform(@Nullable ReadableArray matrixArray) {
|
||||||
|
if (matrixArray != null) {
|
||||||
|
int matrixSize = PropHelper.toMatrixData(matrixArray, sRawMatrix, mScale);
|
||||||
|
if (matrixSize == 6) {
|
||||||
|
if (mMatrix == null) {
|
||||||
|
mMatrix = new Matrix();
|
||||||
}
|
}
|
||||||
invalidate();
|
mMatrix.setValues(sRawMatrix);
|
||||||
|
} else if (matrixSize != -1) {
|
||||||
|
FLog.w(ReactConstants.TAG, "RNSVG: Transform matrices must be of size 6");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mMatrix = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "gradientTransform")
|
invalidate();
|
||||||
public void setGradientTransform(@Nullable ReadableArray matrixArray) {
|
}
|
||||||
if (matrixArray != null) {
|
|
||||||
int matrixSize = PropHelper.toMatrixData(matrixArray, sRawMatrix, mScale);
|
|
||||||
if (matrixSize == 6) {
|
|
||||||
if (mMatrix == null) {
|
|
||||||
mMatrix = new Matrix();
|
|
||||||
}
|
|
||||||
mMatrix.setValues(sRawMatrix);
|
|
||||||
} else if (matrixSize != -1) {
|
|
||||||
FLog.w(ReactConstants.TAG, "RNSVG: Transform matrices must be of size 6");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
mMatrix = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
invalidate();
|
@Override
|
||||||
}
|
void saveDefinition() {
|
||||||
|
if (mName != null) {
|
||||||
@Override
|
SVGLength[] points = new SVGLength[] {mFx, mFy, mRx, mRy, mCx, mCy};
|
||||||
void saveDefinition() {
|
Brush brush = new Brush(Brush.BrushType.RADIAL_GRADIENT, points, mGradientUnits);
|
||||||
if (mName != null) {
|
brush.setGradientColors(mGradient);
|
||||||
SVGLength[] points = new SVGLength[]{mFx,mFy,mRx,mRy,mCx,mCy};
|
if (mMatrix != null) {
|
||||||
Brush brush = new Brush(Brush.BrushType.RADIAL_GRADIENT, points, mGradientUnits);
|
brush.setGradientTransform(mMatrix);
|
||||||
brush.setGradientColors(mGradient);
|
}
|
||||||
if (mMatrix != null) {
|
|
||||||
brush.setGradientTransform(mMatrix);
|
SvgView svg = getSvgView();
|
||||||
}
|
if (mGradientUnits == Brush.BrushUnits.USER_SPACE_ON_USE) {
|
||||||
|
brush.setUserSpaceBoundingBox(svg.getCanvasBounds());
|
||||||
SvgView svg = getSvgView();
|
}
|
||||||
if (mGradientUnits == Brush.BrushUnits.USER_SPACE_ON_USE) {
|
|
||||||
brush.setUserSpaceBoundingBox(svg.getCanvasBounds());
|
svg.defineBrush(brush, mName);
|
||||||
}
|
|
||||||
|
|
||||||
svg.defineBrush(brush, mName);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,6 @@
|
|||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
package com.horcrux.svg;
|
package com.horcrux.svg;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
@@ -15,128 +14,139 @@ import android.graphics.Paint;
|
|||||||
import android.graphics.Path;
|
import android.graphics.Path;
|
||||||
import android.graphics.RectF;
|
import android.graphics.RectF;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
|
|
||||||
import com.facebook.react.bridge.Dynamic;
|
import com.facebook.react.bridge.Dynamic;
|
||||||
import com.facebook.react.bridge.ReactContext;
|
import com.facebook.react.bridge.ReactContext;
|
||||||
import com.facebook.react.uimanager.annotations.ReactProp;
|
import com.facebook.react.uimanager.annotations.ReactProp;
|
||||||
|
|
||||||
@SuppressLint("ViewConstructor")
|
@SuppressLint("ViewConstructor")
|
||||||
class RectView extends RenderableView {
|
class RectView extends RenderableView {
|
||||||
private SVGLength mX;
|
private SVGLength mX;
|
||||||
private SVGLength mY;
|
private SVGLength mY;
|
||||||
private SVGLength mW;
|
private SVGLength mW;
|
||||||
private SVGLength mH;
|
private SVGLength mH;
|
||||||
private SVGLength mRx;
|
private SVGLength mRx;
|
||||||
private SVGLength mRy;
|
private SVGLength mRy;
|
||||||
|
|
||||||
public RectView(ReactContext reactContext) {
|
public RectView(ReactContext reactContext) {
|
||||||
super(reactContext);
|
super(reactContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "x")
|
@ReactProp(name = "x")
|
||||||
public void setX(Dynamic x) {
|
public void setX(Dynamic x) {
|
||||||
mX = SVGLength.from(x);
|
mX = SVGLength.from(x);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setX(String x) {
|
public void setX(String x) {
|
||||||
mX = SVGLength.from(x);
|
mX = SVGLength.from(x);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "y")
|
@ReactProp(name = "y")
|
||||||
public void setY(Dynamic y) {
|
public void setY(Dynamic y) {
|
||||||
mY = SVGLength.from(y);
|
mY = SVGLength.from(y);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setY(String y) {
|
public void setY(String y) {
|
||||||
mY = SVGLength.from(y);
|
mY = SVGLength.from(y);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "width")
|
@ReactProp(name = "width")
|
||||||
public void setWidth(Dynamic width) {
|
public void setWidth(Dynamic width) {
|
||||||
mW = SVGLength.from(width);
|
mW = SVGLength.from(width);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setWidth(String width) {
|
public void setWidth(String width) {
|
||||||
mW = SVGLength.from(width);
|
mW = SVGLength.from(width);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "height")
|
@ReactProp(name = "height")
|
||||||
public void setHeight(Dynamic height) {
|
public void setHeight(Dynamic height) {
|
||||||
mH = SVGLength.from(height);
|
mH = SVGLength.from(height);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setHeight(String height) {
|
public void setHeight(String height) {
|
||||||
mH = SVGLength.from(height);
|
mH = SVGLength.from(height);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "rx")
|
@ReactProp(name = "rx")
|
||||||
public void setRx(Dynamic rx) {
|
public void setRx(Dynamic rx) {
|
||||||
mRx = SVGLength.from(rx);
|
mRx = SVGLength.from(rx);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setRx(String rx) {
|
public void setRx(String rx) {
|
||||||
mRx = SVGLength.from(rx);
|
mRx = SVGLength.from(rx);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "ry")
|
@ReactProp(name = "ry")
|
||||||
public void setRy(Dynamic ry) {
|
public void setRy(Dynamic ry) {
|
||||||
mRy = SVGLength.from(ry);
|
mRy = SVGLength.from(ry);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setRy(String ry) {
|
public void setRy(String ry) {
|
||||||
mRy = SVGLength.from(ry);
|
mRy = SVGLength.from(ry);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
Path getPath(Canvas canvas, Paint paint) {
|
Path getPath(Canvas canvas, Paint paint) {
|
||||||
Path path = new Path();
|
Path path = new Path();
|
||||||
double x = relativeOnWidth(mX);
|
double x = relativeOnWidth(mX);
|
||||||
double y = relativeOnHeight(mY);
|
double y = relativeOnHeight(mY);
|
||||||
double w = relativeOnWidth(mW);
|
double w = relativeOnWidth(mW);
|
||||||
double h = relativeOnHeight(mH);
|
double h = relativeOnHeight(mH);
|
||||||
|
|
||||||
if (mRx != null || mRy != null) {
|
if (mRx != null || mRy != null) {
|
||||||
double rx = 0d;
|
double rx = 0d;
|
||||||
double ry = 0d;
|
double ry = 0d;
|
||||||
if (mRx == null) {
|
if (mRx == null) {
|
||||||
ry = relativeOnHeight(mRy);
|
ry = relativeOnHeight(mRy);
|
||||||
rx = ry;
|
rx = ry;
|
||||||
} else if (mRy == null) {
|
} else if (mRy == null) {
|
||||||
rx = relativeOnWidth(mRx);
|
rx = relativeOnWidth(mRx);
|
||||||
ry = rx;
|
ry = rx;
|
||||||
} else {
|
} else {
|
||||||
rx = relativeOnWidth(mRx);
|
rx = relativeOnWidth(mRx);
|
||||||
ry = relativeOnHeight(mRy);
|
ry = relativeOnHeight(mRy);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rx > w / 2) {
|
if (rx > w / 2) {
|
||||||
rx = w / 2;
|
rx = w / 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ry > h / 2) {
|
if (ry > h / 2) {
|
||||||
ry = h / 2;
|
ry = h / 2;
|
||||||
}
|
}
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||||
path.addRoundRect((float) x, (float) y, (float) (x + w), (float) (y + h), (float) rx, (float) ry, Path.Direction.CW);
|
path.addRoundRect(
|
||||||
} else {
|
(float) x,
|
||||||
path.addRoundRect(new RectF((float) x, (float) y, (float) (x + w), (float) (y + h)), (float) rx, (float) ry, Path.Direction.CW);
|
(float) y,
|
||||||
}
|
(float) (x + w),
|
||||||
} else {
|
(float) (y + h),
|
||||||
path.addRect((float) x, (float) y, (float) (x + w), (float) (y + h), Path.Direction.CW);
|
(float) rx,
|
||||||
path.close(); // Ensure isSimplePath = false such that rect doesn't become represented using integers
|
(float) ry,
|
||||||
}
|
Path.Direction.CW);
|
||||||
return path;
|
} else {
|
||||||
|
path.addRoundRect(
|
||||||
|
new RectF((float) x, (float) y, (float) (x + w), (float) (y + h)),
|
||||||
|
(float) rx,
|
||||||
|
(float) ry,
|
||||||
|
Path.Direction.CW);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
path.addRect((float) x, (float) y, (float) (x + w), (float) (y + h), Path.Direction.CW);
|
||||||
|
path.close(); // Ensure isSimplePath = false such that rect doesn't become represented using
|
||||||
|
// integers
|
||||||
}
|
}
|
||||||
|
return path;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -2,7 +2,6 @@ package com.horcrux.svg;
|
|||||||
|
|
||||||
import com.facebook.react.bridge.Dynamic;
|
import com.facebook.react.bridge.Dynamic;
|
||||||
import com.facebook.react.bridge.ReadableArray;
|
import com.facebook.react.bridge.ReadableArray;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
class SVGLength {
|
class SVGLength {
|
||||||
@@ -121,26 +120,29 @@ class SVGLength {
|
|||||||
|
|
||||||
static ArrayList<SVGLength> arrayFrom(Dynamic dynamic) {
|
static ArrayList<SVGLength> arrayFrom(Dynamic dynamic) {
|
||||||
switch (dynamic.getType()) {
|
switch (dynamic.getType()) {
|
||||||
case Number: {
|
case Number:
|
||||||
ArrayList<SVGLength> list = new ArrayList<>(1);
|
{
|
||||||
list.add(new SVGLength(dynamic.asDouble()));
|
ArrayList<SVGLength> list = new ArrayList<>(1);
|
||||||
return list;
|
list.add(new SVGLength(dynamic.asDouble()));
|
||||||
}
|
return list;
|
||||||
case Array: {
|
}
|
||||||
ReadableArray arr = dynamic.asArray();
|
case Array:
|
||||||
int size = arr.size();
|
{
|
||||||
ArrayList<SVGLength> list = new ArrayList<>(size);
|
ReadableArray arr = dynamic.asArray();
|
||||||
for (int i = 0; i < size; i++) {
|
int size = arr.size();
|
||||||
Dynamic val = arr.getDynamic(i);
|
ArrayList<SVGLength> list = new ArrayList<>(size);
|
||||||
list.add(from(val));
|
for (int i = 0; i < size; i++) {
|
||||||
|
Dynamic val = arr.getDynamic(i);
|
||||||
|
list.add(from(val));
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
case String:
|
||||||
|
{
|
||||||
|
ArrayList<SVGLength> list = new ArrayList<>(1);
|
||||||
|
list.add(new SVGLength(dynamic.asString()));
|
||||||
|
return list;
|
||||||
}
|
}
|
||||||
return list;
|
|
||||||
}
|
|
||||||
case String: {
|
|
||||||
ArrayList<SVGLength> list = new ArrayList<>(1);
|
|
||||||
list.add(new SVGLength(dynamic.asString()));
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,71 +6,66 @@
|
|||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
package com.horcrux.svg;
|
package com.horcrux.svg;
|
||||||
|
|
||||||
|
import static com.horcrux.svg.RenderableViewManager.*;
|
||||||
|
|
||||||
import com.facebook.react.ReactPackage;
|
import com.facebook.react.ReactPackage;
|
||||||
import com.facebook.react.bridge.JavaScriptModule;
|
import com.facebook.react.bridge.JavaScriptModule;
|
||||||
import com.facebook.react.bridge.NativeModule;
|
import com.facebook.react.bridge.NativeModule;
|
||||||
import com.facebook.react.bridge.ReactApplicationContext;
|
import com.facebook.react.bridge.ReactApplicationContext;
|
||||||
import com.facebook.react.uimanager.ViewManager;
|
import com.facebook.react.uimanager.ViewManager;
|
||||||
import com.facebook.soloader.SoLoader;
|
import com.facebook.soloader.SoLoader;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
import static com.horcrux.svg.RenderableViewManager.*;
|
|
||||||
|
|
||||||
public class SvgPackage implements ReactPackage {
|
public class SvgPackage implements ReactPackage {
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@Override
|
@Override
|
||||||
public List<ViewManager> createViewManagers(@Nonnull ReactApplicationContext reactContext) {
|
public List<ViewManager> createViewManagers(@Nonnull ReactApplicationContext reactContext) {
|
||||||
return Arrays.<ViewManager>asList(
|
return Arrays.<ViewManager>asList(
|
||||||
new GroupViewManager(),
|
new GroupViewManager(),
|
||||||
new PathViewManager(),
|
new PathViewManager(),
|
||||||
new CircleViewManager(),
|
new CircleViewManager(),
|
||||||
new EllipseViewManager(),
|
new EllipseViewManager(),
|
||||||
new LineViewManager(),
|
new LineViewManager(),
|
||||||
new RectViewManager(),
|
new RectViewManager(),
|
||||||
new TextViewManager(),
|
new TextViewManager(),
|
||||||
new TSpanViewManager(),
|
new TSpanViewManager(),
|
||||||
new TextPathViewManager(),
|
new TextPathViewManager(),
|
||||||
new ImageViewManager(),
|
new ImageViewManager(),
|
||||||
new ClipPathViewManager(),
|
new ClipPathViewManager(),
|
||||||
new DefsViewManager(),
|
new DefsViewManager(),
|
||||||
new UseViewManager(),
|
new UseViewManager(),
|
||||||
new SymbolManager(),
|
new SymbolManager(),
|
||||||
new LinearGradientManager(),
|
new LinearGradientManager(),
|
||||||
new RadialGradientManager(),
|
new RadialGradientManager(),
|
||||||
new PatternManager(),
|
new PatternManager(),
|
||||||
new MaskManager(),
|
new MaskManager(),
|
||||||
new ForeignObjectManager(),
|
new ForeignObjectManager(),
|
||||||
new MarkerManager(),
|
new MarkerManager(),
|
||||||
new SvgViewManager());
|
new SvgViewManager());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@Override
|
@Override
|
||||||
public List<NativeModule> createNativeModules(@Nonnull ReactApplicationContext reactContext) {
|
public List<NativeModule> createNativeModules(@Nonnull ReactApplicationContext reactContext) {
|
||||||
if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
|
if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
|
||||||
// For Fabric, we load c++ native library here, this triggers svg's Fabric
|
// For Fabric, we load c++ native library here, this triggers svg's Fabric
|
||||||
// component registration which is necessary in order to avoid asking users
|
// component registration which is necessary in order to avoid asking users
|
||||||
// to manually add init calls in their application code.
|
// to manually add init calls in their application code.
|
||||||
// This should no longer be needed if RN's autolink mechanism has Fabric support
|
// This should no longer be needed if RN's autolink mechanism has Fabric support
|
||||||
SoLoader.loadLibrary("rnsvg_modules");
|
SoLoader.loadLibrary("rnsvg_modules");
|
||||||
}
|
|
||||||
return Arrays.<NativeModule>asList(
|
|
||||||
new SvgViewModule(reactContext),
|
|
||||||
new RNSVGRenderableManager(reactContext)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
return Arrays.<NativeModule>asList(
|
||||||
|
new SvgViewModule(reactContext), new RNSVGRenderableManager(reactContext));
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public List<Class<? extends JavaScriptModule>> createJSModules() {
|
public List<Class<? extends JavaScriptModule>> createJSModules() {
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,6 @@
|
|||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
package com.horcrux.svg;
|
package com.horcrux.svg;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
@@ -20,9 +19,6 @@ import android.graphics.Typeface;
|
|||||||
import android.util.Base64;
|
import android.util.Base64;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewParent;
|
import android.view.ViewParent;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
|
|
||||||
import com.facebook.react.bridge.ColorPropConverter;
|
import com.facebook.react.bridge.ColorPropConverter;
|
||||||
import com.facebook.react.bridge.Dynamic;
|
import com.facebook.react.bridge.Dynamic;
|
||||||
import com.facebook.react.bridge.ReactContext;
|
import com.facebook.react.bridge.ReactContext;
|
||||||
@@ -30,207 +26,203 @@ import com.facebook.react.uimanager.DisplayMetricsHolder;
|
|||||||
import com.facebook.react.uimanager.ReactCompoundView;
|
import com.facebook.react.uimanager.ReactCompoundView;
|
||||||
import com.facebook.react.uimanager.ReactCompoundViewGroup;
|
import com.facebook.react.uimanager.ReactCompoundViewGroup;
|
||||||
import com.facebook.react.uimanager.annotations.ReactProp;
|
import com.facebook.react.uimanager.annotations.ReactProp;
|
||||||
import com.facebook.react.views.view.ReactViewGroup;
|
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
/**
|
/** Custom {@link View} implementation that draws an RNSVGSvg React view and its children. */
|
||||||
* Custom {@link View} implementation that draws an RNSVGSvg React view and its children.
|
|
||||||
*/
|
|
||||||
@SuppressLint("ViewConstructor")
|
@SuppressLint("ViewConstructor")
|
||||||
public class SvgView extends FabricEnabledViewGroup implements ReactCompoundView, ReactCompoundViewGroup {
|
public class SvgView extends FabricEnabledViewGroup
|
||||||
|
implements ReactCompoundView, ReactCompoundViewGroup {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean interceptsTouchEvent(float touchX, float touchY) {
|
public boolean interceptsTouchEvent(float touchX, float touchY) {
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public enum Events {
|
||||||
|
EVENT_DATA_URL("onDataURL");
|
||||||
|
|
||||||
|
private final String mName;
|
||||||
|
|
||||||
|
Events(final String name) {
|
||||||
|
mName = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@Nonnull
|
||||||
public enum Events {
|
public String toString() {
|
||||||
EVENT_DATA_URL("onDataURL");
|
return mName;
|
||||||
|
|
||||||
private final String mName;
|
|
||||||
|
|
||||||
Events(final String name) {
|
|
||||||
mName = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nonnull
|
|
||||||
public String toString() {
|
|
||||||
return mName;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private @Nullable Bitmap mBitmap;
|
private @Nullable Bitmap mBitmap;
|
||||||
|
|
||||||
public SvgView(ReactContext reactContext) {
|
public SvgView(ReactContext reactContext) {
|
||||||
super(reactContext);
|
super(reactContext);
|
||||||
mScale = DisplayMetricsHolder.getScreenDisplayMetrics().density;
|
mScale = DisplayMetricsHolder.getScreenDisplayMetrics().density;
|
||||||
// for some reason on Fabric the `onDraw` won't be called without it
|
// for some reason on Fabric the `onDraw` won't be called without it
|
||||||
setWillNotDraw(false);
|
setWillNotDraw(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setId(int id) {
|
public void setId(int id) {
|
||||||
super.setId(id);
|
super.setId(id);
|
||||||
SvgViewManager.setSvgView(id, this);
|
SvgViewManager.setSvgView(id, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void invalidate() {
|
public void invalidate() {
|
||||||
super.invalidate();
|
super.invalidate();
|
||||||
ViewParent parent = getParent();
|
ViewParent parent = getParent();
|
||||||
if (parent instanceof VirtualView) {
|
if (parent instanceof VirtualView) {
|
||||||
if (!mRendered) {
|
if (!mRendered) {
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
mRendered = false;
|
|
||||||
((VirtualView) parent).getSvgView().invalidate();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (mBitmap != null) {
|
|
||||||
mBitmap.recycle();
|
|
||||||
}
|
|
||||||
mBitmap = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onDraw(Canvas canvas) {
|
|
||||||
if (getParent() instanceof VirtualView) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
super.onDraw(canvas);
|
|
||||||
if (mBitmap == null) {
|
|
||||||
mBitmap = drawOutput();
|
|
||||||
}
|
|
||||||
if (mBitmap != null) {
|
|
||||||
canvas.drawBitmap(mBitmap, 0, 0, null);
|
|
||||||
if (toDataUrlTask != null) {
|
|
||||||
toDataUrlTask.run();
|
|
||||||
toDataUrlTask = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Runnable toDataUrlTask = null;
|
|
||||||
|
|
||||||
void setToDataUrlTask(Runnable task) {
|
|
||||||
toDataUrlTask = task;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
|
|
||||||
super.onSizeChanged(w, h, oldw, oldh);
|
|
||||||
this.invalidate();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int reactTagForTouch(float touchX, float touchY) {
|
|
||||||
return hitTest(touchX, touchY);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean mResponsible = false;
|
|
||||||
|
|
||||||
private final Map<String, VirtualView> mDefinedClipPaths = new HashMap<>();
|
|
||||||
private final Map<String, VirtualView> mDefinedTemplates = new HashMap<>();
|
|
||||||
private final Map<String, VirtualView> mDefinedMarkers = new HashMap<>();
|
|
||||||
private final Map<String, VirtualView> mDefinedMasks = new HashMap<>();
|
|
||||||
private final Map<String, Brush> mDefinedBrushes = new HashMap<>();
|
|
||||||
private Canvas mCanvas;
|
|
||||||
private final float mScale;
|
|
||||||
|
|
||||||
private float mMinX;
|
|
||||||
private float mMinY;
|
|
||||||
private float mVbWidth;
|
|
||||||
private float mVbHeight;
|
|
||||||
private SVGLength mbbWidth;
|
|
||||||
private SVGLength mbbHeight;
|
|
||||||
private String mAlign;
|
|
||||||
private int mMeetOrSlice;
|
|
||||||
final Matrix mInvViewBoxMatrix = new Matrix();
|
|
||||||
private boolean mInvertible = true;
|
|
||||||
private boolean mRendered = false;
|
|
||||||
int mTintColor = 0;
|
|
||||||
|
|
||||||
boolean notRendered() {
|
|
||||||
return !mRendered;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void clearChildCache() {
|
|
||||||
if (!mRendered) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
mRendered = false;
|
|
||||||
for (int i = 0; i < getChildCount(); i++) {
|
|
||||||
View node = getChildAt(i);
|
|
||||||
if (node instanceof VirtualView) {
|
|
||||||
VirtualView n = ((VirtualView)node);
|
|
||||||
n.clearChildCache();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@ReactProp(name = "tintColor")
|
|
||||||
public void setTintColor(@Nullable Dynamic tintColor) {
|
|
||||||
switch (tintColor.getType()) {
|
|
||||||
case Map:
|
|
||||||
mTintColor = ColorPropConverter.getColor(tintColor.asMap(), getContext());
|
|
||||||
break;
|
|
||||||
case Number:
|
|
||||||
mTintColor = tintColor.asInt();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
mTintColor = 0;
|
|
||||||
}
|
}
|
||||||
invalidate();
|
mRendered = false;
|
||||||
clearChildCache();
|
((VirtualView) parent).getSvgView().invalidate();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
if (mBitmap != null) {
|
||||||
|
mBitmap.recycle();
|
||||||
|
}
|
||||||
|
mBitmap = null;
|
||||||
|
}
|
||||||
|
|
||||||
public void setTintColor(@Nullable Integer tintColor) {
|
@Override
|
||||||
mTintColor = tintColor;
|
protected void onDraw(Canvas canvas) {
|
||||||
|
if (getParent() instanceof VirtualView) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
super.onDraw(canvas);
|
||||||
|
if (mBitmap == null) {
|
||||||
|
mBitmap = drawOutput();
|
||||||
|
}
|
||||||
|
if (mBitmap != null) {
|
||||||
|
canvas.drawBitmap(mBitmap, 0, 0, null);
|
||||||
|
if (toDataUrlTask != null) {
|
||||||
|
toDataUrlTask.run();
|
||||||
|
toDataUrlTask = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Runnable toDataUrlTask = null;
|
||||||
|
|
||||||
|
void setToDataUrlTask(Runnable task) {
|
||||||
|
toDataUrlTask = task;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
|
||||||
|
super.onSizeChanged(w, h, oldw, oldh);
|
||||||
|
this.invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int reactTagForTouch(float touchX, float touchY) {
|
||||||
|
return hitTest(touchX, touchY);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean mResponsible = false;
|
||||||
|
|
||||||
|
private final Map<String, VirtualView> mDefinedClipPaths = new HashMap<>();
|
||||||
|
private final Map<String, VirtualView> mDefinedTemplates = new HashMap<>();
|
||||||
|
private final Map<String, VirtualView> mDefinedMarkers = new HashMap<>();
|
||||||
|
private final Map<String, VirtualView> mDefinedMasks = new HashMap<>();
|
||||||
|
private final Map<String, Brush> mDefinedBrushes = new HashMap<>();
|
||||||
|
private Canvas mCanvas;
|
||||||
|
private final float mScale;
|
||||||
|
|
||||||
|
private float mMinX;
|
||||||
|
private float mMinY;
|
||||||
|
private float mVbWidth;
|
||||||
|
private float mVbHeight;
|
||||||
|
private SVGLength mbbWidth;
|
||||||
|
private SVGLength mbbHeight;
|
||||||
|
private String mAlign;
|
||||||
|
private int mMeetOrSlice;
|
||||||
|
final Matrix mInvViewBoxMatrix = new Matrix();
|
||||||
|
private boolean mInvertible = true;
|
||||||
|
private boolean mRendered = false;
|
||||||
|
int mTintColor = 0;
|
||||||
|
|
||||||
|
boolean notRendered() {
|
||||||
|
return !mRendered;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void clearChildCache() {
|
||||||
|
if (!mRendered) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mRendered = false;
|
||||||
|
for (int i = 0; i < getChildCount(); i++) {
|
||||||
|
View node = getChildAt(i);
|
||||||
|
if (node instanceof VirtualView) {
|
||||||
|
VirtualView n = ((VirtualView) node);
|
||||||
|
n.clearChildCache();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ReactProp(name = "tintColor")
|
||||||
|
public void setTintColor(@Nullable Dynamic tintColor) {
|
||||||
|
switch (tintColor.getType()) {
|
||||||
|
case Map:
|
||||||
|
mTintColor = ColorPropConverter.getColor(tintColor.asMap(), getContext());
|
||||||
|
break;
|
||||||
|
case Number:
|
||||||
|
mTintColor = tintColor.asInt();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
mTintColor = 0;
|
||||||
|
}
|
||||||
invalidate();
|
invalidate();
|
||||||
clearChildCache();
|
clearChildCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "minX")
|
public void setTintColor(@Nullable Integer tintColor) {
|
||||||
public void setMinX(float minX) {
|
mTintColor = tintColor;
|
||||||
mMinX = minX;
|
invalidate();
|
||||||
invalidate();
|
clearChildCache();
|
||||||
clearChildCache();
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@ReactProp(name = "minY")
|
@ReactProp(name = "minX")
|
||||||
public void setMinY(float minY) {
|
public void setMinX(float minX) {
|
||||||
mMinY = minY;
|
mMinX = minX;
|
||||||
invalidate();
|
invalidate();
|
||||||
clearChildCache();
|
clearChildCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "vbWidth")
|
@ReactProp(name = "minY")
|
||||||
public void setVbWidth(float vbWidth) {
|
public void setMinY(float minY) {
|
||||||
mVbWidth = vbWidth;
|
mMinY = minY;
|
||||||
invalidate();
|
invalidate();
|
||||||
clearChildCache();
|
clearChildCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "vbHeight")
|
@ReactProp(name = "vbWidth")
|
||||||
public void setVbHeight(float vbHeight) {
|
public void setVbWidth(float vbWidth) {
|
||||||
mVbHeight = vbHeight;
|
mVbWidth = vbWidth;
|
||||||
invalidate();
|
invalidate();
|
||||||
clearChildCache();
|
clearChildCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "bbWidth")
|
@ReactProp(name = "vbHeight")
|
||||||
public void setBbWidth(Dynamic bbWidth) {
|
public void setVbHeight(float vbHeight) {
|
||||||
mbbWidth = SVGLength.from(bbWidth);
|
mVbHeight = vbHeight;
|
||||||
invalidate();
|
invalidate();
|
||||||
clearChildCache();
|
clearChildCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ReactProp(name = "bbWidth")
|
||||||
|
public void setBbWidth(Dynamic bbWidth) {
|
||||||
|
mbbWidth = SVGLength.from(bbWidth);
|
||||||
|
invalidate();
|
||||||
|
clearChildCache();
|
||||||
|
}
|
||||||
|
|
||||||
public void setBbWidth(String bbWidth) {
|
public void setBbWidth(String bbWidth) {
|
||||||
mbbWidth = SVGLength.from(bbWidth);
|
mbbWidth = SVGLength.from(bbWidth);
|
||||||
@@ -238,12 +230,12 @@ public class SvgView extends FabricEnabledViewGroup implements ReactCompoundView
|
|||||||
clearChildCache();
|
clearChildCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "bbHeight")
|
@ReactProp(name = "bbHeight")
|
||||||
public void setBbHeight(Dynamic bbHeight) {
|
public void setBbHeight(Dynamic bbHeight) {
|
||||||
mbbHeight = SVGLength.from(bbHeight);
|
mbbHeight = SVGLength.from(bbHeight);
|
||||||
invalidate();
|
invalidate();
|
||||||
clearChildCache();
|
clearChildCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setBbHeight(String bbHeight) {
|
public void setBbHeight(String bbHeight) {
|
||||||
mbbHeight = SVGLength.from(bbHeight);
|
mbbHeight = SVGLength.from(bbHeight);
|
||||||
@@ -251,202 +243,198 @@ public class SvgView extends FabricEnabledViewGroup implements ReactCompoundView
|
|||||||
clearChildCache();
|
clearChildCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "align")
|
@ReactProp(name = "align")
|
||||||
public void setAlign(String align) {
|
public void setAlign(String align) {
|
||||||
mAlign = align;
|
mAlign = align;
|
||||||
invalidate();
|
invalidate();
|
||||||
clearChildCache();
|
clearChildCache();
|
||||||
|
}
|
||||||
|
|
||||||
|
@ReactProp(name = "meetOrSlice")
|
||||||
|
public void setMeetOrSlice(int meetOrSlice) {
|
||||||
|
mMeetOrSlice = meetOrSlice;
|
||||||
|
invalidate();
|
||||||
|
clearChildCache();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Bitmap drawOutput() {
|
||||||
|
mRendered = true;
|
||||||
|
float width = getWidth();
|
||||||
|
float height = getHeight();
|
||||||
|
boolean invalid =
|
||||||
|
Float.isNaN(width)
|
||||||
|
|| Float.isNaN(height)
|
||||||
|
|| width < 1
|
||||||
|
|| height < 1
|
||||||
|
|| (Math.log10(width) + Math.log10(height) > 42);
|
||||||
|
if (invalid) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Bitmap bitmap = Bitmap.createBitmap((int) width, (int) height, Bitmap.Config.ARGB_8888);
|
||||||
|
|
||||||
|
drawChildren(new Canvas(bitmap));
|
||||||
|
return bitmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
Rect getCanvasBounds() {
|
||||||
|
return mCanvas.getClipBounds();
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized void drawChildren(final Canvas canvas) {
|
||||||
|
mRendered = true;
|
||||||
|
mCanvas = canvas;
|
||||||
|
Matrix mViewBoxMatrix = new Matrix();
|
||||||
|
if (mAlign != null) {
|
||||||
|
RectF vbRect = getViewBox();
|
||||||
|
float width = canvas.getWidth();
|
||||||
|
float height = canvas.getHeight();
|
||||||
|
boolean nested = getParent() instanceof VirtualView;
|
||||||
|
if (nested) {
|
||||||
|
width = (float) PropHelper.fromRelative(mbbWidth, width, 0f, mScale, 12);
|
||||||
|
height = (float) PropHelper.fromRelative(mbbHeight, height, 0f, mScale, 12);
|
||||||
|
}
|
||||||
|
RectF eRect = new RectF(0, 0, width, height);
|
||||||
|
if (nested) {
|
||||||
|
canvas.clipRect(eRect);
|
||||||
|
}
|
||||||
|
mViewBoxMatrix = ViewBox.getTransform(vbRect, eRect, mAlign, mMeetOrSlice);
|
||||||
|
mInvertible = mViewBoxMatrix.invert(mInvViewBoxMatrix);
|
||||||
|
canvas.concat(mViewBoxMatrix);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "meetOrSlice")
|
final Paint paint = new Paint();
|
||||||
public void setMeetOrSlice(int meetOrSlice) {
|
|
||||||
mMeetOrSlice = meetOrSlice;
|
paint.setFlags(Paint.ANTI_ALIAS_FLAG | Paint.DEV_KERN_TEXT_FLAG | Paint.SUBPIXEL_TEXT_FLAG);
|
||||||
invalidate();
|
|
||||||
clearChildCache();
|
paint.setTypeface(Typeface.DEFAULT);
|
||||||
|
|
||||||
|
for (int i = 0; i < getChildCount(); i++) {
|
||||||
|
View node = getChildAt(i);
|
||||||
|
if (node instanceof VirtualView) {
|
||||||
|
((VirtualView) node).saveDefinition();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Bitmap drawOutput() {
|
for (int i = 0; i < getChildCount(); i++) {
|
||||||
mRendered = true;
|
View lNode = getChildAt(i);
|
||||||
float width = getWidth();
|
if (lNode instanceof VirtualView) {
|
||||||
float height = getHeight();
|
VirtualView node = (VirtualView) lNode;
|
||||||
boolean invalid = Float.isNaN(width) || Float.isNaN(height) || width < 1 || height < 1 || (Math.log10(width) + Math.log10(height) > 42);
|
int count = node.saveAndSetupCanvas(canvas, mViewBoxMatrix);
|
||||||
if (invalid) {
|
node.render(canvas, paint, 1f);
|
||||||
return null;
|
node.restoreCanvas(canvas, count);
|
||||||
|
|
||||||
|
if (node.isResponsible() && !mResponsible) {
|
||||||
|
mResponsible = true;
|
||||||
}
|
}
|
||||||
Bitmap bitmap = Bitmap.createBitmap(
|
}
|
||||||
(int) width,
|
}
|
||||||
(int) height,
|
}
|
||||||
Bitmap.Config.ARGB_8888);
|
|
||||||
|
|
||||||
drawChildren(new Canvas(bitmap));
|
private RectF getViewBox() {
|
||||||
return bitmap;
|
return new RectF(
|
||||||
|
mMinX * mScale, mMinY * mScale, (mMinX + mVbWidth) * mScale, (mMinY + mVbHeight) * mScale);
|
||||||
|
}
|
||||||
|
|
||||||
|
String toDataURL() {
|
||||||
|
Bitmap bitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
|
||||||
|
|
||||||
|
clearChildCache();
|
||||||
|
drawChildren(new Canvas(bitmap));
|
||||||
|
clearChildCache();
|
||||||
|
this.invalidate();
|
||||||
|
ByteArrayOutputStream stream = new ByteArrayOutputStream();
|
||||||
|
bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
|
||||||
|
bitmap.recycle();
|
||||||
|
byte[] bitmapBytes = stream.toByteArray();
|
||||||
|
return Base64.encodeToString(bitmapBytes, Base64.DEFAULT);
|
||||||
|
}
|
||||||
|
|
||||||
|
String toDataURL(int width, int height) {
|
||||||
|
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
|
||||||
|
|
||||||
|
clearChildCache();
|
||||||
|
drawChildren(new Canvas(bitmap));
|
||||||
|
clearChildCache();
|
||||||
|
this.invalidate();
|
||||||
|
ByteArrayOutputStream stream = new ByteArrayOutputStream();
|
||||||
|
bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
|
||||||
|
bitmap.recycle();
|
||||||
|
byte[] bitmapBytes = stream.toByteArray();
|
||||||
|
return Base64.encodeToString(bitmapBytes, Base64.DEFAULT);
|
||||||
|
}
|
||||||
|
|
||||||
|
void enableTouchEvents() {
|
||||||
|
if (!mResponsible) {
|
||||||
|
mResponsible = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isResponsible() {
|
||||||
|
return mResponsible;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int hitTest(float touchX, float touchY) {
|
||||||
|
if (!mResponsible || !mInvertible) {
|
||||||
|
return getId();
|
||||||
}
|
}
|
||||||
|
|
||||||
Rect getCanvasBounds() {
|
float[] transformed = {touchX, touchY};
|
||||||
return mCanvas.getClipBounds();
|
mInvViewBoxMatrix.mapPoints(transformed);
|
||||||
|
|
||||||
|
int count = getChildCount();
|
||||||
|
int viewTag = -1;
|
||||||
|
for (int i = count - 1; i >= 0; i--) {
|
||||||
|
View child = getChildAt(i);
|
||||||
|
if (child instanceof VirtualView) {
|
||||||
|
viewTag = ((VirtualView) child).hitTest(transformed);
|
||||||
|
} else if (child instanceof SvgView) {
|
||||||
|
viewTag = ((SvgView) child).hitTest(touchX, touchY);
|
||||||
|
}
|
||||||
|
if (viewTag != -1) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized void drawChildren(final Canvas canvas) {
|
return viewTag == -1 ? getId() : viewTag;
|
||||||
mRendered = true;
|
}
|
||||||
mCanvas = canvas;
|
|
||||||
Matrix mViewBoxMatrix = new Matrix();
|
|
||||||
if (mAlign != null) {
|
|
||||||
RectF vbRect = getViewBox();
|
|
||||||
float width = canvas.getWidth();
|
|
||||||
float height = canvas.getHeight();
|
|
||||||
boolean nested = getParent() instanceof VirtualView;
|
|
||||||
if (nested) {
|
|
||||||
width = (float) PropHelper.fromRelative(mbbWidth, width, 0f, mScale, 12);
|
|
||||||
height = (float) PropHelper.fromRelative(mbbHeight, height, 0f, mScale, 12);
|
|
||||||
}
|
|
||||||
RectF eRect = new RectF(0,0, width, height);
|
|
||||||
if (nested) {
|
|
||||||
canvas.clipRect(eRect);
|
|
||||||
}
|
|
||||||
mViewBoxMatrix = ViewBox.getTransform(vbRect, eRect, mAlign, mMeetOrSlice);
|
|
||||||
mInvertible = mViewBoxMatrix.invert(mInvViewBoxMatrix);
|
|
||||||
canvas.concat(mViewBoxMatrix);
|
|
||||||
}
|
|
||||||
|
|
||||||
final Paint paint = new Paint();
|
void defineClipPath(VirtualView clipPath, String clipPathRef) {
|
||||||
|
mDefinedClipPaths.put(clipPathRef, clipPath);
|
||||||
|
}
|
||||||
|
|
||||||
paint.setFlags(Paint.ANTI_ALIAS_FLAG | Paint.DEV_KERN_TEXT_FLAG | Paint.SUBPIXEL_TEXT_FLAG);
|
VirtualView getDefinedClipPath(String clipPathRef) {
|
||||||
|
return mDefinedClipPaths.get(clipPathRef);
|
||||||
|
}
|
||||||
|
|
||||||
paint.setTypeface(Typeface.DEFAULT);
|
void defineTemplate(VirtualView template, String templateRef) {
|
||||||
|
mDefinedTemplates.put(templateRef, template);
|
||||||
|
}
|
||||||
|
|
||||||
|
VirtualView getDefinedTemplate(String templateRef) {
|
||||||
|
return mDefinedTemplates.get(templateRef);
|
||||||
|
}
|
||||||
|
|
||||||
for (int i = 0; i < getChildCount(); i++) {
|
void defineBrush(Brush brush, String brushRef) {
|
||||||
View node = getChildAt(i);
|
mDefinedBrushes.put(brushRef, brush);
|
||||||
if (node instanceof VirtualView) {
|
}
|
||||||
((VirtualView)node).saveDefinition();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < getChildCount(); i++) {
|
Brush getDefinedBrush(String brushRef) {
|
||||||
View lNode = getChildAt(i);
|
return mDefinedBrushes.get(brushRef);
|
||||||
if (lNode instanceof VirtualView) {
|
}
|
||||||
VirtualView node = (VirtualView)lNode;
|
|
||||||
int count = node.saveAndSetupCanvas(canvas, mViewBoxMatrix);
|
|
||||||
node.render(canvas, paint, 1f);
|
|
||||||
node.restoreCanvas(canvas, count);
|
|
||||||
|
|
||||||
if (node.isResponsible() && !mResponsible) {
|
void defineMask(VirtualView mask, String maskRef) {
|
||||||
mResponsible = true;
|
mDefinedMasks.put(maskRef, mask);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private RectF getViewBox() {
|
VirtualView getDefinedMask(String maskRef) {
|
||||||
return new RectF(mMinX * mScale, mMinY * mScale, (mMinX + mVbWidth) * mScale, (mMinY + mVbHeight) * mScale);
|
return mDefinedMasks.get(maskRef);
|
||||||
}
|
}
|
||||||
|
|
||||||
String toDataURL() {
|
void defineMarker(VirtualView marker, String markerRef) {
|
||||||
Bitmap bitmap = Bitmap.createBitmap(
|
mDefinedMarkers.put(markerRef, marker);
|
||||||
getWidth(),
|
}
|
||||||
getHeight(),
|
|
||||||
Bitmap.Config.ARGB_8888);
|
|
||||||
|
|
||||||
clearChildCache();
|
VirtualView getDefinedMarker(String markerRef) {
|
||||||
drawChildren(new Canvas(bitmap));
|
return mDefinedMarkers.get(markerRef);
|
||||||
clearChildCache();
|
}
|
||||||
this.invalidate();
|
|
||||||
ByteArrayOutputStream stream = new ByteArrayOutputStream();
|
|
||||||
bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
|
|
||||||
bitmap.recycle();
|
|
||||||
byte[] bitmapBytes = stream.toByteArray();
|
|
||||||
return Base64.encodeToString(bitmapBytes, Base64.DEFAULT);
|
|
||||||
}
|
|
||||||
|
|
||||||
String toDataURL(int width, int height) {
|
|
||||||
Bitmap bitmap = Bitmap.createBitmap(
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
Bitmap.Config.ARGB_8888);
|
|
||||||
|
|
||||||
clearChildCache();
|
|
||||||
drawChildren(new Canvas(bitmap));
|
|
||||||
clearChildCache();
|
|
||||||
this.invalidate();
|
|
||||||
ByteArrayOutputStream stream = new ByteArrayOutputStream();
|
|
||||||
bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
|
|
||||||
bitmap.recycle();
|
|
||||||
byte[] bitmapBytes = stream.toByteArray();
|
|
||||||
return Base64.encodeToString(bitmapBytes, Base64.DEFAULT);
|
|
||||||
}
|
|
||||||
|
|
||||||
void enableTouchEvents() {
|
|
||||||
if (!mResponsible) {
|
|
||||||
mResponsible = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean isResponsible() {
|
|
||||||
return mResponsible;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int hitTest(float touchX, float touchY) {
|
|
||||||
if (!mResponsible || !mInvertible) {
|
|
||||||
return getId();
|
|
||||||
}
|
|
||||||
|
|
||||||
float[] transformed = { touchX, touchY };
|
|
||||||
mInvViewBoxMatrix.mapPoints(transformed);
|
|
||||||
|
|
||||||
int count = getChildCount();
|
|
||||||
int viewTag = -1;
|
|
||||||
for (int i = count - 1; i >= 0; i--) {
|
|
||||||
View child = getChildAt(i);
|
|
||||||
if (child instanceof VirtualView) {
|
|
||||||
viewTag = ((VirtualView) child).hitTest(transformed);
|
|
||||||
} else if (child instanceof SvgView) {
|
|
||||||
viewTag = ((SvgView) child).hitTest(touchX, touchY);
|
|
||||||
}
|
|
||||||
if (viewTag != -1) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return viewTag == -1 ? getId() : viewTag;
|
|
||||||
}
|
|
||||||
|
|
||||||
void defineClipPath(VirtualView clipPath, String clipPathRef) {
|
|
||||||
mDefinedClipPaths.put(clipPathRef, clipPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
VirtualView getDefinedClipPath(String clipPathRef) {
|
|
||||||
return mDefinedClipPaths.get(clipPathRef);
|
|
||||||
}
|
|
||||||
|
|
||||||
void defineTemplate(VirtualView template, String templateRef) {
|
|
||||||
mDefinedTemplates.put(templateRef, template);
|
|
||||||
}
|
|
||||||
|
|
||||||
VirtualView getDefinedTemplate(String templateRef) {
|
|
||||||
return mDefinedTemplates.get(templateRef);
|
|
||||||
}
|
|
||||||
|
|
||||||
void defineBrush(Brush brush, String brushRef) {
|
|
||||||
mDefinedBrushes.put(brushRef, brush);
|
|
||||||
}
|
|
||||||
|
|
||||||
Brush getDefinedBrush(String brushRef) {
|
|
||||||
return mDefinedBrushes.get(brushRef);
|
|
||||||
}
|
|
||||||
|
|
||||||
void defineMask(VirtualView mask, String maskRef) {
|
|
||||||
mDefinedMasks.put(maskRef, mask);
|
|
||||||
}
|
|
||||||
|
|
||||||
VirtualView getDefinedMask(String maskRef) {
|
|
||||||
return mDefinedMasks.get(maskRef);
|
|
||||||
}
|
|
||||||
|
|
||||||
void defineMarker(VirtualView marker, String markerRef) {
|
|
||||||
mDefinedMarkers.put(markerRef, marker);
|
|
||||||
}
|
|
||||||
|
|
||||||
VirtualView getDefinedMarker(String markerRef) {
|
|
||||||
return mDefinedMarkers.get(markerRef);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,145 +6,142 @@
|
|||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
package com.horcrux.svg;
|
package com.horcrux.svg;
|
||||||
|
|
||||||
import android.util.SparseArray;
|
import android.util.SparseArray;
|
||||||
|
|
||||||
import com.facebook.react.bridge.Dynamic;
|
import com.facebook.react.bridge.Dynamic;
|
||||||
import com.facebook.react.uimanager.ThemedReactContext;
|
import com.facebook.react.uimanager.ThemedReactContext;
|
||||||
import com.facebook.react.uimanager.ViewManagerDelegate;
|
import com.facebook.react.uimanager.ViewManagerDelegate;
|
||||||
import com.facebook.react.uimanager.annotations.ReactProp;
|
import com.facebook.react.uimanager.annotations.ReactProp;
|
||||||
import com.facebook.react.views.view.ReactViewGroup;
|
|
||||||
import com.facebook.react.views.view.ReactViewManager;
|
|
||||||
import com.facebook.react.viewmanagers.RNSVGSvgViewManagerDelegate;
|
import com.facebook.react.viewmanagers.RNSVGSvgViewManagerDelegate;
|
||||||
import com.facebook.react.viewmanagers.RNSVGSvgViewManagerInterface;
|
import com.facebook.react.viewmanagers.RNSVGSvgViewManagerInterface;
|
||||||
|
import com.facebook.react.views.view.ReactViewGroup;
|
||||||
|
import com.facebook.react.views.view.ReactViewManager;
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ViewManager for RNSVGSvgView React views. Renders as a {@link SvgView} and handles
|
* ViewManager for RNSVGSvgView React views. Renders as a {@link SvgView} and handles invalidating
|
||||||
* invalidating the native view on view updates happening in the underlying tree.
|
* the native view on view updates happening in the underlying tree.
|
||||||
*/
|
*/
|
||||||
class SvgViewManager extends ReactViewManager implements RNSVGSvgViewManagerInterface<SvgView> {
|
class SvgViewManager extends ReactViewManager implements RNSVGSvgViewManagerInterface<SvgView> {
|
||||||
|
|
||||||
private static final String REACT_CLASS = "RNSVGSvgView";
|
private static final String REACT_CLASS = "RNSVGSvgView";
|
||||||
|
|
||||||
private static final SparseArray<SvgView> mTagToSvgView = new SparseArray<>();
|
private static final SparseArray<SvgView> mTagToSvgView = new SparseArray<>();
|
||||||
private static final SparseArray<Runnable> mTagToRunnable = new SparseArray<>();
|
private static final SparseArray<Runnable> mTagToRunnable = new SparseArray<>();
|
||||||
|
|
||||||
private final ViewManagerDelegate<SvgView> mDelegate;
|
private final ViewManagerDelegate<SvgView> mDelegate;
|
||||||
|
|
||||||
protected ViewManagerDelegate getDelegate(){
|
protected ViewManagerDelegate getDelegate() {
|
||||||
return mDelegate;
|
return mDelegate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SvgViewManager() {
|
||||||
|
mDelegate = new RNSVGSvgViewManagerDelegate(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void setSvgView(int tag, SvgView svg) {
|
||||||
|
mTagToSvgView.put(tag, svg);
|
||||||
|
Runnable task = mTagToRunnable.get(tag);
|
||||||
|
if (task != null) {
|
||||||
|
task.run();
|
||||||
|
mTagToRunnable.delete(tag);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public SvgViewManager() {
|
static void runWhenViewIsAvailable(int tag, Runnable task) {
|
||||||
mDelegate = new RNSVGSvgViewManagerDelegate(this);
|
mTagToRunnable.put(tag, task);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void setSvgView(int tag, SvgView svg) {
|
static @Nullable SvgView getSvgViewByTag(int tag) {
|
||||||
mTagToSvgView.put(tag, svg);
|
return mTagToSvgView.get(tag);
|
||||||
Runnable task = mTagToRunnable.get(tag);
|
}
|
||||||
if (task != null) {
|
|
||||||
task.run();
|
|
||||||
mTagToRunnable.delete(tag);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void runWhenViewIsAvailable(int tag, Runnable task) {
|
@Nonnull
|
||||||
mTagToRunnable.put(tag, task);
|
@Override
|
||||||
}
|
public String getName() {
|
||||||
|
return REACT_CLASS;
|
||||||
|
}
|
||||||
|
|
||||||
static @Nullable SvgView getSvgViewByTag(int tag) {
|
@Nonnull
|
||||||
return mTagToSvgView.get(tag);
|
@Override
|
||||||
}
|
public ReactViewGroup createViewInstance(ThemedReactContext reactContext) {
|
||||||
|
return new SvgView(reactContext);
|
||||||
|
}
|
||||||
|
|
||||||
@Nonnull
|
@Override
|
||||||
@Override
|
public void updateExtraData(ReactViewGroup root, Object extraData) {
|
||||||
public String getName() {
|
super.updateExtraData(root, extraData);
|
||||||
return REACT_CLASS;
|
root.invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nonnull
|
@Override
|
||||||
@Override
|
public void onDropViewInstance(@Nonnull ReactViewGroup view) {
|
||||||
public ReactViewGroup createViewInstance(ThemedReactContext reactContext) {
|
super.onDropViewInstance(view);
|
||||||
return new SvgView(reactContext);
|
mTagToSvgView.remove(view.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateExtraData(ReactViewGroup root, Object extraData) {
|
public boolean needsCustomLayoutForChildren() {
|
||||||
super.updateExtraData(root, extraData);
|
return true;
|
||||||
root.invalidate();
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@ReactProp(name = "tintColor")
|
||||||
public void onDropViewInstance(@Nonnull ReactViewGroup view) {
|
public void setTintColor(SvgView node, @Nullable Dynamic tintColor) {
|
||||||
super.onDropViewInstance(view);
|
node.setTintColor(tintColor);
|
||||||
mTagToSvgView.remove(view.getId());
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@ReactProp(name = "color")
|
||||||
public boolean needsCustomLayoutForChildren() {
|
public void setColor(SvgView node, @Nullable Dynamic color) {
|
||||||
return true;
|
node.setTintColor(color);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "tintColor")
|
@ReactProp(name = "minX")
|
||||||
public void setTintColor(SvgView node, @Nullable Dynamic tintColor) {
|
@Override
|
||||||
node.setTintColor(tintColor);
|
public void setMinX(SvgView node, float minX) {
|
||||||
}
|
node.setMinX(minX);
|
||||||
|
}
|
||||||
|
|
||||||
@ReactProp(name = "color")
|
@ReactProp(name = "minY")
|
||||||
public void setColor(SvgView node, @Nullable Dynamic color) {
|
@Override
|
||||||
node.setTintColor(color);
|
public void setMinY(SvgView node, float minY) {
|
||||||
}
|
node.setMinY(minY);
|
||||||
|
}
|
||||||
|
|
||||||
@ReactProp(name = "minX")
|
@ReactProp(name = "vbWidth")
|
||||||
@Override
|
@Override
|
||||||
public void setMinX(SvgView node, float minX) {
|
public void setVbWidth(SvgView node, float vbWidth) {
|
||||||
node.setMinX(minX);
|
node.setVbWidth(vbWidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "minY")
|
@ReactProp(name = "vbHeight")
|
||||||
@Override
|
@Override
|
||||||
public void setMinY(SvgView node, float minY) {
|
public void setVbHeight(SvgView node, float vbHeight) {
|
||||||
node.setMinY(minY);
|
node.setVbHeight(vbHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "vbWidth")
|
@ReactProp(name = "bbWidth")
|
||||||
@Override
|
public void setBbWidth(SvgView node, Dynamic bbWidth) {
|
||||||
public void setVbWidth(SvgView node, float vbWidth) {
|
node.setBbWidth(bbWidth);
|
||||||
node.setVbWidth(vbWidth);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@ReactProp(name = "vbHeight")
|
@ReactProp(name = "bbHeight")
|
||||||
@Override
|
public void setBbHeight(SvgView node, Dynamic bbHeight) {
|
||||||
public void setVbHeight(SvgView node, float vbHeight) {
|
node.setBbHeight(bbHeight);
|
||||||
node.setVbHeight(vbHeight);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@ReactProp(name = "bbWidth")
|
@ReactProp(name = "align")
|
||||||
public void setBbWidth(SvgView node, Dynamic bbWidth) {
|
@Override
|
||||||
node.setBbWidth(bbWidth);
|
public void setAlign(SvgView node, String align) {
|
||||||
}
|
node.setAlign(align);
|
||||||
|
}
|
||||||
|
|
||||||
@ReactProp(name = "bbHeight")
|
@ReactProp(name = "meetOrSlice")
|
||||||
public void setBbHeight(SvgView node, Dynamic bbHeight) {
|
@Override
|
||||||
node.setBbHeight(bbHeight);
|
public void setMeetOrSlice(SvgView node, int meetOrSlice) {
|
||||||
}
|
node.setMeetOrSlice(meetOrSlice);
|
||||||
|
}
|
||||||
@ReactProp(name = "align")
|
|
||||||
@Override
|
|
||||||
public void setAlign(SvgView node, String align) {
|
|
||||||
node.setAlign(align);
|
|
||||||
}
|
|
||||||
|
|
||||||
@ReactProp(name = "meetOrSlice")
|
|
||||||
@Override
|
|
||||||
public void setMeetOrSlice(SvgView node, int meetOrSlice) {
|
|
||||||
node.setMeetOrSlice(meetOrSlice);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setTintColor(SvgView view, @Nullable Integer value) {
|
public void setTintColor(SvgView view, @Nullable Integer value) {
|
||||||
@@ -165,5 +162,4 @@ class SvgViewManager extends ReactViewManager implements RNSVGSvgViewManagerInte
|
|||||||
public void setBbHeight(SvgView view, @Nullable String value) {
|
public void setBbHeight(SvgView view, @Nullable String value) {
|
||||||
view.setBbHeight(value);
|
view.setBbHeight(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,6 @@
|
|||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
package com.horcrux.svg;
|
package com.horcrux.svg;
|
||||||
|
|
||||||
import com.facebook.react.bridge.Callback;
|
import com.facebook.react.bridge.Callback;
|
||||||
@@ -15,70 +14,69 @@ import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
|||||||
import com.facebook.react.bridge.ReactMethod;
|
import com.facebook.react.bridge.ReactMethod;
|
||||||
import com.facebook.react.bridge.ReadableMap;
|
import com.facebook.react.bridge.ReadableMap;
|
||||||
import com.facebook.react.bridge.UiThreadUtil;
|
import com.facebook.react.bridge.UiThreadUtil;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
class SvgViewModule extends ReactContextBaseJavaModule {
|
class SvgViewModule extends ReactContextBaseJavaModule {
|
||||||
SvgViewModule(ReactApplicationContext reactContext) {
|
SvgViewModule(ReactApplicationContext reactContext) {
|
||||||
super(reactContext);
|
super(reactContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return "RNSVGSvgViewManager";
|
return "RNSVGSvgViewManager";
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void toDataURL(final int tag, final ReadableMap options, final Callback successCallback, final int attempt) {
|
private static void toDataURL(
|
||||||
UiThreadUtil.runOnUiThread(
|
final int tag, final ReadableMap options, final Callback successCallback, final int attempt) {
|
||||||
new Runnable() {
|
UiThreadUtil.runOnUiThread(
|
||||||
|
new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
SvgView svg = SvgViewManager.getSvgViewByTag(tag);
|
||||||
|
|
||||||
|
if (svg == null) {
|
||||||
|
SvgViewManager.runWhenViewIsAvailable(
|
||||||
|
tag,
|
||||||
|
new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
SvgView svg = SvgViewManager.getSvgViewByTag(tag);
|
SvgView svg = SvgViewManager.getSvgViewByTag(tag);
|
||||||
|
if (svg == null) { // Should never happen
|
||||||
if (svg == null) {
|
return;
|
||||||
SvgViewManager.runWhenViewIsAvailable(tag, new Runnable() {
|
}
|
||||||
@Override
|
svg.setToDataUrlTask(
|
||||||
public void run() {
|
new Runnable() {
|
||||||
SvgView svg = SvgViewManager.getSvgViewByTag(tag);
|
@Override
|
||||||
if (svg == null) { // Should never happen
|
public void run() {
|
||||||
return;
|
toDataURL(tag, options, successCallback, attempt + 1);
|
||||||
}
|
|
||||||
svg.setToDataUrlTask(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
toDataURL(tag, options, successCallback, attempt + 1);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else if (svg.notRendered()) {
|
|
||||||
svg.setToDataUrlTask(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
toDataURL(tag, options, successCallback, attempt + 1);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
if (options != null) {
|
|
||||||
successCallback.invoke(
|
|
||||||
svg.toDataURL(
|
|
||||||
options.getInt("width"),
|
|
||||||
options.getInt("height")
|
|
||||||
)
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
successCallback.invoke(svg.toDataURL());
|
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
);
|
} else if (svg.notRendered()) {
|
||||||
}
|
svg.setToDataUrlTask(
|
||||||
|
new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
toDataURL(tag, options, successCallback, attempt + 1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
if (options != null) {
|
||||||
|
successCallback.invoke(
|
||||||
|
svg.toDataURL(options.getInt("width"), options.getInt("height")));
|
||||||
|
} else {
|
||||||
|
successCallback.invoke(svg.toDataURL());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
@ReactMethod
|
@ReactMethod
|
||||||
public void toDataURL(int tag, ReadableMap options, Callback successCallback) {
|
public void toDataURL(int tag, ReadableMap options, Callback successCallback) {
|
||||||
toDataURL(tag, options, successCallback, 0);
|
toDataURL(tag, options, successCallback, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,6 @@
|
|||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
package com.horcrux.svg;
|
package com.horcrux.svg;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
@@ -14,72 +13,76 @@ import android.graphics.Canvas;
|
|||||||
import android.graphics.Matrix;
|
import android.graphics.Matrix;
|
||||||
import android.graphics.Paint;
|
import android.graphics.Paint;
|
||||||
import android.graphics.RectF;
|
import android.graphics.RectF;
|
||||||
|
|
||||||
import com.facebook.react.bridge.ReactContext;
|
import com.facebook.react.bridge.ReactContext;
|
||||||
import com.facebook.react.uimanager.annotations.ReactProp;
|
import com.facebook.react.uimanager.annotations.ReactProp;
|
||||||
|
|
||||||
@SuppressLint("ViewConstructor")
|
@SuppressLint("ViewConstructor")
|
||||||
class SymbolView extends GroupView {
|
class SymbolView extends GroupView {
|
||||||
|
|
||||||
private float mMinX;
|
private float mMinX;
|
||||||
private float mMinY;
|
private float mMinY;
|
||||||
private float mVbWidth;
|
private float mVbWidth;
|
||||||
private float mVbHeight;
|
private float mVbHeight;
|
||||||
private String mAlign;
|
private String mAlign;
|
||||||
private int mMeetOrSlice;
|
private int mMeetOrSlice;
|
||||||
|
|
||||||
public SymbolView(ReactContext reactContext) {
|
public SymbolView(ReactContext reactContext) {
|
||||||
super(reactContext);
|
super(reactContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "minX")
|
@ReactProp(name = "minX")
|
||||||
public void setMinX(float minX) {
|
public void setMinX(float minX) {
|
||||||
mMinX = minX;
|
mMinX = minX;
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "minY")
|
@ReactProp(name = "minY")
|
||||||
public void setMinY(float minY) {
|
public void setMinY(float minY) {
|
||||||
mMinY = minY;
|
mMinY = minY;
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "vbWidth")
|
@ReactProp(name = "vbWidth")
|
||||||
public void setVbWidth(float vbWidth) {
|
public void setVbWidth(float vbWidth) {
|
||||||
mVbWidth = vbWidth;
|
mVbWidth = vbWidth;
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "vbHeight")
|
@ReactProp(name = "vbHeight")
|
||||||
public void setVbHeight(float vbHeight) {
|
public void setVbHeight(float vbHeight) {
|
||||||
mVbHeight = vbHeight;
|
mVbHeight = vbHeight;
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "align")
|
@ReactProp(name = "align")
|
||||||
public void setAlign(String align) {
|
public void setAlign(String align) {
|
||||||
mAlign = align;
|
mAlign = align;
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "meetOrSlice")
|
@ReactProp(name = "meetOrSlice")
|
||||||
public void setMeetOrSlice(int meetOrSlice) {
|
public void setMeetOrSlice(int meetOrSlice) {
|
||||||
mMeetOrSlice = meetOrSlice;
|
mMeetOrSlice = meetOrSlice;
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
void draw(Canvas canvas, Paint paint, float opacity) {
|
void draw(Canvas canvas, Paint paint, float opacity) {
|
||||||
saveDefinition();
|
saveDefinition();
|
||||||
}
|
}
|
||||||
|
|
||||||
void drawSymbol(Canvas canvas, Paint paint, float opacity, float width, float height) {
|
void drawSymbol(Canvas canvas, Paint paint, float opacity, float width, float height) {
|
||||||
if (mAlign != null) {
|
if (mAlign != null) {
|
||||||
RectF vbRect = new RectF(mMinX * mScale, mMinY * mScale, (mMinX + mVbWidth) * mScale, (mMinY + mVbHeight) * mScale);
|
RectF vbRect =
|
||||||
RectF eRect = new RectF(0, 0, width, height);
|
new RectF(
|
||||||
Matrix viewBoxMatrix = ViewBox.getTransform(vbRect, eRect, mAlign, mMeetOrSlice);
|
mMinX * mScale,
|
||||||
canvas.concat(viewBoxMatrix);
|
mMinY * mScale,
|
||||||
super.draw(canvas, paint, opacity);
|
(mMinX + mVbWidth) * mScale,
|
||||||
}
|
(mMinY + mVbHeight) * mScale);
|
||||||
|
RectF eRect = new RectF(0, 0, width, height);
|
||||||
|
Matrix viewBoxMatrix = ViewBox.getTransform(vbRect, eRect, mAlign, mMeetOrSlice);
|
||||||
|
canvas.concat(viewBoxMatrix);
|
||||||
|
super.draw(canvas, paint, opacity);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -6,129 +6,126 @@
|
|||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
package com.horcrux.svg;
|
package com.horcrux.svg;
|
||||||
|
|
||||||
|
import static com.horcrux.svg.TextProperties.*;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.graphics.Canvas;
|
import android.graphics.Canvas;
|
||||||
import android.graphics.Paint;
|
import android.graphics.Paint;
|
||||||
import android.graphics.Path;
|
import android.graphics.Path;
|
||||||
|
|
||||||
import com.facebook.react.bridge.Dynamic;
|
import com.facebook.react.bridge.Dynamic;
|
||||||
import com.facebook.react.bridge.ReactContext;
|
import com.facebook.react.bridge.ReactContext;
|
||||||
import com.facebook.react.uimanager.annotations.ReactProp;
|
import com.facebook.react.uimanager.annotations.ReactProp;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import static com.horcrux.svg.TextProperties.*;
|
|
||||||
|
|
||||||
@SuppressLint("ViewConstructor")
|
@SuppressLint("ViewConstructor")
|
||||||
class TextPathView extends TextView {
|
class TextPathView extends TextView {
|
||||||
|
|
||||||
private String mHref;
|
private String mHref;
|
||||||
private TextPathSide mSide;
|
private TextPathSide mSide;
|
||||||
private TextPathMidLine mMidLine;
|
private TextPathMidLine mMidLine;
|
||||||
private @Nullable SVGLength mStartOffset;
|
private @Nullable SVGLength mStartOffset;
|
||||||
private TextPathMethod mMethod = TextPathMethod.align;
|
private TextPathMethod mMethod = TextPathMethod.align;
|
||||||
private TextPathSpacing mSpacing = TextPathSpacing.exact;
|
private TextPathSpacing mSpacing = TextPathSpacing.exact;
|
||||||
|
|
||||||
public TextPathView(ReactContext reactContext) {
|
public TextPathView(ReactContext reactContext) {
|
||||||
super(reactContext);
|
super(reactContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "href")
|
@ReactProp(name = "href")
|
||||||
public void setHref(String href) {
|
public void setHref(String href) {
|
||||||
mHref = href;
|
mHref = href;
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "startOffset")
|
@ReactProp(name = "startOffset")
|
||||||
public void setStartOffset(Dynamic startOffset) {
|
public void setStartOffset(Dynamic startOffset) {
|
||||||
mStartOffset = SVGLength.from(startOffset);
|
mStartOffset = SVGLength.from(startOffset);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setStartOffset(String startOffset) {
|
public void setStartOffset(String startOffset) {
|
||||||
mStartOffset = SVGLength.from(startOffset);
|
mStartOffset = SVGLength.from(startOffset);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "method")
|
@ReactProp(name = "method")
|
||||||
public void setMethod(@Nullable String method) {
|
public void setMethod(@Nullable String method) {
|
||||||
mMethod = TextPathMethod.valueOf(method);
|
mMethod = TextPathMethod.valueOf(method);
|
||||||
invalidate();
|
invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@ReactProp(name = "spacing")
|
||||||
|
public void setSpacing(@Nullable String spacing) {
|
||||||
|
mSpacing = TextPathSpacing.valueOf(spacing);
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@ReactProp(name = "side")
|
||||||
|
public void setSide(@Nullable String side) {
|
||||||
|
mSide = TextPathSide.valueOf(side);
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@ReactProp(name = "midLine")
|
||||||
|
public void setSharp(@Nullable String midLine) {
|
||||||
|
mMidLine = TextPathMidLine.valueOf(midLine);
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
TextPathMethod getMethod() {
|
||||||
|
return mMethod;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
TextPathSpacing getSpacing() {
|
||||||
|
return mSpacing;
|
||||||
|
}
|
||||||
|
|
||||||
|
TextPathSide getSide() {
|
||||||
|
return mSide;
|
||||||
|
}
|
||||||
|
|
||||||
|
TextPathMidLine getMidLine() {
|
||||||
|
return mMidLine;
|
||||||
|
}
|
||||||
|
|
||||||
|
SVGLength getStartOffset() {
|
||||||
|
return mStartOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
void draw(Canvas canvas, Paint paint, float opacity) {
|
||||||
|
drawGroup(canvas, paint, opacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
Path getTextPath(Canvas canvas, Paint paint) {
|
||||||
|
SvgView svg = getSvgView();
|
||||||
|
VirtualView template = svg.getDefinedTemplate(mHref);
|
||||||
|
|
||||||
|
if (!(template instanceof RenderableView)) {
|
||||||
|
// warning about this.
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "spacing")
|
RenderableView view = (RenderableView) template;
|
||||||
public void setSpacing(@Nullable String spacing) {
|
return view.getPath(canvas, paint);
|
||||||
mSpacing = TextPathSpacing.valueOf(spacing);
|
}
|
||||||
invalidate();
|
|
||||||
}
|
|
||||||
|
|
||||||
@ReactProp(name = "side")
|
@Override
|
||||||
public void setSide(@Nullable String side) {
|
Path getPath(Canvas canvas, Paint paint) {
|
||||||
mSide = TextPathSide.valueOf(side);
|
return getGroupPath(canvas, paint);
|
||||||
invalidate();
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@ReactProp(name = "midLine")
|
@Override
|
||||||
public void setSharp(@Nullable String midLine) {
|
void pushGlyphContext() {
|
||||||
mMidLine = TextPathMidLine.valueOf(midLine);
|
// do nothing
|
||||||
invalidate();
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@Override
|
||||||
TextPathMethod getMethod() {
|
void popGlyphContext() {
|
||||||
return mMethod;
|
// do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
TextPathSpacing getSpacing() {
|
|
||||||
return mSpacing;
|
|
||||||
}
|
|
||||||
|
|
||||||
TextPathSide getSide() {
|
|
||||||
return mSide;
|
|
||||||
}
|
|
||||||
|
|
||||||
TextPathMidLine getMidLine() {
|
|
||||||
return mMidLine;
|
|
||||||
}
|
|
||||||
|
|
||||||
SVGLength getStartOffset() {
|
|
||||||
return mStartOffset;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
void draw(Canvas canvas, Paint paint, float opacity) {
|
|
||||||
drawGroup(canvas, paint, opacity);
|
|
||||||
}
|
|
||||||
|
|
||||||
Path getTextPath(Canvas canvas, Paint paint) {
|
|
||||||
SvgView svg = getSvgView();
|
|
||||||
VirtualView template = svg.getDefinedTemplate(mHref);
|
|
||||||
|
|
||||||
if (!(template instanceof RenderableView)) {
|
|
||||||
// warning about this.
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
RenderableView view = (RenderableView)template;
|
|
||||||
return view.getPath(canvas, paint);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
Path getPath(Canvas canvas, Paint paint) {
|
|
||||||
return getGroupPath(canvas, paint);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
void pushGlyphContext() {
|
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
void popGlyphContext() {
|
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,212 +2,218 @@ package com.horcrux.svg;
|
|||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
class TextProperties {
|
class TextProperties {
|
||||||
|
|
||||||
|
/*
|
||||||
|
https://drafts.csswg.org/css-inline/#propdef-alignment-baseline
|
||||||
|
2.2.1. Alignment Point: alignment-baseline longhand
|
||||||
|
|
||||||
|
Name: alignment-baseline
|
||||||
|
Value: baseline | text-bottom | alphabetic | ideographic | middle | central | mathematical | text-top | bottom | center | top
|
||||||
|
Initial: baseline
|
||||||
|
Applies to: inline-level boxes, flex items, grid items, table cells
|
||||||
|
Inherited: no
|
||||||
|
Percentages: N/A
|
||||||
|
Media: visual
|
||||||
|
Computed value: as specified
|
||||||
|
Canonical order: per grammar
|
||||||
|
Animation type: discrete
|
||||||
|
*/
|
||||||
|
enum AlignmentBaseline {
|
||||||
|
baseline("baseline"),
|
||||||
|
textBottom("text-bottom"),
|
||||||
|
alphabetic("alphabetic"),
|
||||||
|
ideographic("ideographic"),
|
||||||
|
middle("middle"),
|
||||||
|
central("central"),
|
||||||
|
mathematical("mathematical"),
|
||||||
|
textTop("text-top"),
|
||||||
|
bottom("bottom"),
|
||||||
|
center("center"),
|
||||||
|
top("top"),
|
||||||
/*
|
/*
|
||||||
https://drafts.csswg.org/css-inline/#propdef-alignment-baseline
|
SVG implementations may support the following aliases in order to support legacy content:
|
||||||
2.2.1. Alignment Point: alignment-baseline longhand
|
|
||||||
|
|
||||||
Name: alignment-baseline
|
text-before-edge = text-top
|
||||||
Value: baseline | text-bottom | alphabetic | ideographic | middle | central | mathematical | text-top | bottom | center | top
|
text-after-edge = text-bottom
|
||||||
Initial: baseline
|
*/
|
||||||
Applies to: inline-level boxes, flex items, grid items, table cells
|
textBeforeEdge("text-before-edge"),
|
||||||
Inherited: no
|
textAfterEdge("text-after-edge"),
|
||||||
Percentages: N/A
|
// SVG 1.1
|
||||||
Media: visual
|
beforeEdge("before-edge"),
|
||||||
Computed value: as specified
|
afterEdge("after-edge"),
|
||||||
Canonical order: per grammar
|
hanging("hanging"),
|
||||||
Animation type: discrete
|
;
|
||||||
*/
|
|
||||||
enum AlignmentBaseline {
|
|
||||||
baseline("baseline"),
|
|
||||||
textBottom("text-bottom"),
|
|
||||||
alphabetic("alphabetic"),
|
|
||||||
ideographic("ideographic"),
|
|
||||||
middle("middle"),
|
|
||||||
central("central"),
|
|
||||||
mathematical("mathematical"),
|
|
||||||
textTop("text-top"),
|
|
||||||
bottom("bottom"),
|
|
||||||
center("center"),
|
|
||||||
top("top"),
|
|
||||||
/*
|
|
||||||
SVG implementations may support the following aliases in order to support legacy content:
|
|
||||||
|
|
||||||
text-before-edge = text-top
|
private final String alignment;
|
||||||
text-after-edge = text-bottom
|
|
||||||
*/
|
|
||||||
textBeforeEdge("text-before-edge"),
|
|
||||||
textAfterEdge("text-after-edge"),
|
|
||||||
// SVG 1.1
|
|
||||||
beforeEdge("before-edge"),
|
|
||||||
afterEdge("after-edge"),
|
|
||||||
hanging("hanging"),
|
|
||||||
;
|
|
||||||
|
|
||||||
private final String alignment;
|
AlignmentBaseline(String alignment) {
|
||||||
|
this.alignment = alignment;
|
||||||
AlignmentBaseline(String alignment) {
|
|
||||||
this.alignment = alignment;
|
|
||||||
}
|
|
||||||
|
|
||||||
static AlignmentBaseline getEnum(String strVal) {
|
|
||||||
if (!alignmentToEnum.containsKey(strVal)) {
|
|
||||||
throw new IllegalArgumentException("Unknown String Value: " + strVal);
|
|
||||||
}
|
|
||||||
return alignmentToEnum.get(strVal);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final Map<String, AlignmentBaseline> alignmentToEnum = new HashMap<>();
|
|
||||||
|
|
||||||
static {
|
|
||||||
for (final AlignmentBaseline en : AlignmentBaseline.values()) {
|
|
||||||
alignmentToEnum.put(en.alignment, en);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nonnull
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return alignment;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO implement rtl
|
static AlignmentBaseline getEnum(String strVal) {
|
||||||
|
if (!alignmentToEnum.containsKey(strVal)) {
|
||||||
|
throw new IllegalArgumentException("Unknown String Value: " + strVal);
|
||||||
|
}
|
||||||
|
return alignmentToEnum.get(strVal);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final Map<String, AlignmentBaseline> alignmentToEnum = new HashMap<>();
|
||||||
|
|
||||||
|
static {
|
||||||
|
for (final AlignmentBaseline en : AlignmentBaseline.values()) {
|
||||||
|
alignmentToEnum.put(en.alignment, en);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return alignment;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO implement rtl
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
enum Direction {
|
||||||
|
ltr,
|
||||||
|
rtl
|
||||||
|
}
|
||||||
|
|
||||||
|
enum FontVariantLigatures {
|
||||||
|
normal,
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
enum Direction {
|
none
|
||||||
ltr,
|
}
|
||||||
rtl
|
|
||||||
|
enum FontStyle {
|
||||||
|
normal,
|
||||||
|
italic,
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
oblique
|
||||||
|
}
|
||||||
|
|
||||||
|
enum FontWeight {
|
||||||
|
// Absolute
|
||||||
|
Normal("normal"),
|
||||||
|
Bold("bold"),
|
||||||
|
w100("100"),
|
||||||
|
w200("200"),
|
||||||
|
w300("300"),
|
||||||
|
w400("400"),
|
||||||
|
w500("500"),
|
||||||
|
w600("600"),
|
||||||
|
w700("700"),
|
||||||
|
w800("800"),
|
||||||
|
w900("900"),
|
||||||
|
// Relative
|
||||||
|
Bolder("bolder"),
|
||||||
|
Lighter("lighter");
|
||||||
|
|
||||||
|
private final String weight;
|
||||||
|
|
||||||
|
FontWeight(String weight) {
|
||||||
|
this.weight = weight;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum FontVariantLigatures {
|
static boolean hasEnum(String strVal) {
|
||||||
normal,
|
return weightToEnum.containsKey(strVal);
|
||||||
@SuppressWarnings("unused")none
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enum FontStyle {
|
static FontWeight get(String strVal) {
|
||||||
normal,
|
return weightToEnum.get(strVal);
|
||||||
italic,
|
|
||||||
@SuppressWarnings("unused")oblique
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enum FontWeight {
|
private static final Map<String, FontWeight> weightToEnum = new HashMap<>();
|
||||||
// Absolute
|
|
||||||
Normal ("normal"),
|
|
||||||
Bold ("bold"),
|
|
||||||
w100 ("100"),
|
|
||||||
w200 ("200"),
|
|
||||||
w300 ("300"),
|
|
||||||
w400 ("400"),
|
|
||||||
w500 ("500"),
|
|
||||||
w600 ("600"),
|
|
||||||
w700 ("700"),
|
|
||||||
w800 ("800"),
|
|
||||||
w900 ("900"),
|
|
||||||
// Relative
|
|
||||||
Bolder ("bolder"),
|
|
||||||
Lighter ("lighter");
|
|
||||||
|
|
||||||
private final String weight;
|
static {
|
||||||
FontWeight(String weight) {
|
for (final FontWeight en : FontWeight.values()) {
|
||||||
this.weight = weight;
|
weightToEnum.put(en.weight, en);
|
||||||
}
|
}
|
||||||
|
|
||||||
static boolean hasEnum(String strVal) {
|
|
||||||
return weightToEnum.containsKey(strVal);
|
|
||||||
}
|
|
||||||
|
|
||||||
static FontWeight get(String strVal) {
|
|
||||||
return weightToEnum.get(strVal);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final Map<String, FontWeight> weightToEnum = new HashMap<>();
|
|
||||||
static {
|
|
||||||
for (final FontWeight en : FontWeight.values()) {
|
|
||||||
weightToEnum.put(en.weight, en);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nonnull
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return weight;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enum TextAnchor
|
@Nonnull
|
||||||
{
|
@Override
|
||||||
start,
|
public String toString() {
|
||||||
middle,
|
return weight;
|
||||||
end
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum TextAnchor {
|
||||||
|
start,
|
||||||
|
middle,
|
||||||
|
end
|
||||||
|
}
|
||||||
|
|
||||||
|
enum TextDecoration {
|
||||||
|
None("none"),
|
||||||
|
Underline("underline"),
|
||||||
|
Overline("overline"),
|
||||||
|
LineThrough("line-through"),
|
||||||
|
Blink("blink");
|
||||||
|
|
||||||
|
private final String decoration;
|
||||||
|
|
||||||
|
TextDecoration(String decoration) {
|
||||||
|
this.decoration = decoration;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum TextDecoration
|
static TextDecoration getEnum(String strVal) {
|
||||||
{
|
if (!decorationToEnum.containsKey(strVal)) {
|
||||||
None("none"),
|
throw new IllegalArgumentException("Unknown String Value: " + strVal);
|
||||||
Underline("underline"),
|
}
|
||||||
Overline("overline"),
|
return decorationToEnum.get(strVal);
|
||||||
LineThrough("line-through"),
|
|
||||||
Blink("blink");
|
|
||||||
|
|
||||||
private final String decoration;
|
|
||||||
TextDecoration(String decoration) {
|
|
||||||
this.decoration = decoration;
|
|
||||||
}
|
|
||||||
|
|
||||||
static TextDecoration getEnum(String strVal) {
|
|
||||||
if(!decorationToEnum.containsKey(strVal)) {
|
|
||||||
throw new IllegalArgumentException("Unknown String Value: " + strVal);
|
|
||||||
}
|
|
||||||
return decorationToEnum.get(strVal);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final Map<String, TextDecoration> decorationToEnum = new HashMap<>();
|
|
||||||
static {
|
|
||||||
for (final TextDecoration en : TextDecoration.values()) {
|
|
||||||
decorationToEnum.put(en.decoration, en);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nonnull
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return decoration;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enum TextLengthAdjust
|
private static final Map<String, TextDecoration> decorationToEnum = new HashMap<>();
|
||||||
{
|
|
||||||
spacing,
|
static {
|
||||||
spacingAndGlyphs
|
for (final TextDecoration en : TextDecoration.values()) {
|
||||||
|
decorationToEnum.put(en.decoration, en);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum TextPathMethod {
|
@Nonnull
|
||||||
align,
|
@Override
|
||||||
@SuppressWarnings("unused")stretch
|
public String toString() {
|
||||||
|
return decoration;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
enum TextLengthAdjust {
|
||||||
TODO suggest adding a compatibility mid-line rendering attribute to textPath,
|
spacing,
|
||||||
for a chrome/firefox/opera/safari compatible sharp text path rendering,
|
spacingAndGlyphs
|
||||||
which doesn't bend text smoothly along a right angle curve, (like Edge does)
|
}
|
||||||
but keeps the mid-line orthogonal to the mid-point tangent at all times instead.
|
|
||||||
*/
|
|
||||||
enum TextPathMidLine {
|
|
||||||
sharp,
|
|
||||||
@SuppressWarnings("unused")smooth
|
|
||||||
}
|
|
||||||
|
|
||||||
enum TextPathSide {
|
enum TextPathMethod {
|
||||||
@SuppressWarnings("unused")left,
|
align,
|
||||||
right
|
@SuppressWarnings("unused")
|
||||||
}
|
stretch
|
||||||
|
}
|
||||||
|
|
||||||
enum TextPathSpacing {
|
/*
|
||||||
@SuppressWarnings("unused")auto,
|
TODO suggest adding a compatibility mid-line rendering attribute to textPath,
|
||||||
exact
|
for a chrome/firefox/opera/safari compatible sharp text path rendering,
|
||||||
}
|
which doesn't bend text smoothly along a right angle curve, (like Edge does)
|
||||||
|
but keeps the mid-line orthogonal to the mid-point tangent at all times instead.
|
||||||
|
*/
|
||||||
|
enum TextPathMidLine {
|
||||||
|
sharp,
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
smooth
|
||||||
|
}
|
||||||
|
|
||||||
|
enum TextPathSide {
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
left,
|
||||||
|
right
|
||||||
|
}
|
||||||
|
|
||||||
|
enum TextPathSpacing {
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
auto,
|
||||||
|
exact
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,9 +6,11 @@
|
|||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
package com.horcrux.svg;
|
package com.horcrux.svg;
|
||||||
|
|
||||||
|
import static com.horcrux.svg.TextProperties.AlignmentBaseline;
|
||||||
|
import static com.horcrux.svg.TextProperties.TextLengthAdjust;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.graphics.Canvas;
|
import android.graphics.Canvas;
|
||||||
import android.graphics.Paint;
|
import android.graphics.Paint;
|
||||||
@@ -16,292 +18,288 @@ import android.graphics.Path;
|
|||||||
import android.graphics.Region;
|
import android.graphics.Region;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewParent;
|
import android.view.ViewParent;
|
||||||
|
|
||||||
import com.facebook.react.bridge.Dynamic;
|
import com.facebook.react.bridge.Dynamic;
|
||||||
import com.facebook.react.bridge.ReactContext;
|
import com.facebook.react.bridge.ReactContext;
|
||||||
import com.facebook.react.bridge.ReadableArray;
|
import com.facebook.react.bridge.ReadableArray;
|
||||||
import com.facebook.react.uimanager.annotations.ReactProp;
|
import com.facebook.react.uimanager.annotations.ReactProp;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import static com.horcrux.svg.TextProperties.AlignmentBaseline;
|
|
||||||
import static com.horcrux.svg.TextProperties.TextLengthAdjust;
|
|
||||||
|
|
||||||
@SuppressLint("ViewConstructor")
|
@SuppressLint("ViewConstructor")
|
||||||
class TextView extends GroupView {
|
class TextView extends GroupView {
|
||||||
SVGLength mInlineSize = null;
|
SVGLength mInlineSize = null;
|
||||||
SVGLength mTextLength = null;
|
SVGLength mTextLength = null;
|
||||||
private String mBaselineShift = null;
|
private String mBaselineShift = null;
|
||||||
TextLengthAdjust mLengthAdjust = TextLengthAdjust.spacing;
|
TextLengthAdjust mLengthAdjust = TextLengthAdjust.spacing;
|
||||||
private AlignmentBaseline mAlignmentBaseline;
|
private AlignmentBaseline mAlignmentBaseline;
|
||||||
@Nullable private ArrayList<SVGLength> mPositionX;
|
@Nullable private ArrayList<SVGLength> mPositionX;
|
||||||
@Nullable private ArrayList<SVGLength> mPositionY;
|
@Nullable private ArrayList<SVGLength> mPositionY;
|
||||||
@Nullable private ArrayList<SVGLength> mRotate;
|
@Nullable private ArrayList<SVGLength> mRotate;
|
||||||
@Nullable private ArrayList<SVGLength> mDeltaX;
|
@Nullable private ArrayList<SVGLength> mDeltaX;
|
||||||
@Nullable private ArrayList<SVGLength> mDeltaY;
|
@Nullable private ArrayList<SVGLength> mDeltaY;
|
||||||
double cachedAdvance = Double.NaN;
|
double cachedAdvance = Double.NaN;
|
||||||
|
|
||||||
public TextView(ReactContext reactContext) {
|
public TextView(ReactContext reactContext) {
|
||||||
super(reactContext);
|
super(reactContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void invalidate() {
|
public void invalidate() {
|
||||||
if (mPath == null) {
|
if (mPath == null) {
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
super.invalidate();
|
|
||||||
getTextContainer().clearChildCache();
|
|
||||||
}
|
}
|
||||||
|
super.invalidate();
|
||||||
|
getTextContainer().clearChildCache();
|
||||||
|
}
|
||||||
|
|
||||||
void clearCache() {
|
void clearCache() {
|
||||||
cachedAdvance = Double.NaN;
|
cachedAdvance = Double.NaN;
|
||||||
super.clearCache();
|
super.clearCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "inlineSize")
|
@ReactProp(name = "inlineSize")
|
||||||
public void setInlineSize(Dynamic inlineSize) {
|
public void setInlineSize(Dynamic inlineSize) {
|
||||||
mInlineSize = SVGLength.from(inlineSize);
|
mInlineSize = SVGLength.from(inlineSize);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setInlineSize(String inlineSize) {
|
public void setInlineSize(String inlineSize) {
|
||||||
mInlineSize = SVGLength.from(inlineSize);
|
mInlineSize = SVGLength.from(inlineSize);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "textLength")
|
@ReactProp(name = "textLength")
|
||||||
public void setTextLength(Dynamic length) {
|
public void setTextLength(Dynamic length) {
|
||||||
mTextLength = SVGLength.from(length);
|
mTextLength = SVGLength.from(length);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setTextLength(String length) {
|
public void setTextLength(String length) {
|
||||||
mTextLength = SVGLength.from(length);
|
mTextLength = SVGLength.from(length);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "lengthAdjust")
|
@ReactProp(name = "lengthAdjust")
|
||||||
public void setLengthAdjust(@Nullable String adjustment) {
|
public void setLengthAdjust(@Nullable String adjustment) {
|
||||||
mLengthAdjust = TextLengthAdjust.valueOf(adjustment);
|
mLengthAdjust = TextLengthAdjust.valueOf(adjustment);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "alignmentBaseline")
|
@ReactProp(name = "alignmentBaseline")
|
||||||
public void setMethod(@Nullable String alignment) {
|
public void setMethod(@Nullable String alignment) {
|
||||||
mAlignmentBaseline = AlignmentBaseline.getEnum(alignment);
|
mAlignmentBaseline = AlignmentBaseline.getEnum(alignment);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "baselineShift")
|
@ReactProp(name = "baselineShift")
|
||||||
public void setBaselineShift(Dynamic baselineShift) {
|
public void setBaselineShift(Dynamic baselineShift) {
|
||||||
mBaselineShift = SVGLength.toString(baselineShift);
|
mBaselineShift = SVGLength.toString(baselineShift);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setBaselineShift(String baselineShift) {
|
public void setBaselineShift(String baselineShift) {
|
||||||
mBaselineShift = baselineShift;
|
mBaselineShift = baselineShift;
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "verticalAlign")
|
@ReactProp(name = "verticalAlign")
|
||||||
public void setVerticalAlign(@Nullable String verticalAlign) {
|
public void setVerticalAlign(@Nullable String verticalAlign) {
|
||||||
if (verticalAlign != null) {
|
if (verticalAlign != null) {
|
||||||
verticalAlign = verticalAlign.trim();
|
verticalAlign = verticalAlign.trim();
|
||||||
int i = verticalAlign.lastIndexOf(' ');
|
int i = verticalAlign.lastIndexOf(' ');
|
||||||
try {
|
try {
|
||||||
mAlignmentBaseline = AlignmentBaseline.getEnum(verticalAlign.substring(i));
|
mAlignmentBaseline = AlignmentBaseline.getEnum(verticalAlign.substring(i));
|
||||||
} catch (IllegalArgumentException e) {
|
} catch (IllegalArgumentException e) {
|
||||||
mAlignmentBaseline = AlignmentBaseline.baseline;
|
mAlignmentBaseline = AlignmentBaseline.baseline;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
mBaselineShift = verticalAlign.substring(0, i);
|
mBaselineShift = verticalAlign.substring(0, i);
|
||||||
} catch (IndexOutOfBoundsException e) {
|
} catch (IndexOutOfBoundsException e) {
|
||||||
mBaselineShift = null;
|
mBaselineShift = null;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
mAlignmentBaseline = AlignmentBaseline.baseline;
|
mAlignmentBaseline = AlignmentBaseline.baseline;
|
||||||
mBaselineShift = null;
|
mBaselineShift = null;
|
||||||
}
|
|
||||||
invalidate();
|
|
||||||
}
|
}
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
@ReactProp(name = "rotate")
|
@ReactProp(name = "rotate")
|
||||||
public void setRotate(Dynamic rotate) {
|
public void setRotate(Dynamic rotate) {
|
||||||
mRotate = SVGLength.arrayFrom(rotate);
|
mRotate = SVGLength.arrayFrom(rotate);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setRotate(ReadableArray rotate) {
|
public void setRotate(ReadableArray rotate) {
|
||||||
mRotate = SVGLength.arrayFrom(rotate);
|
mRotate = SVGLength.arrayFrom(rotate);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "dx")
|
@ReactProp(name = "dx")
|
||||||
public void setDeltaX(Dynamic deltaX) {
|
public void setDeltaX(Dynamic deltaX) {
|
||||||
mDeltaX = SVGLength.arrayFrom(deltaX);
|
mDeltaX = SVGLength.arrayFrom(deltaX);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setDeltaX(ReadableArray deltaX) {
|
public void setDeltaX(ReadableArray deltaX) {
|
||||||
mDeltaX = SVGLength.arrayFrom(deltaX);
|
mDeltaX = SVGLength.arrayFrom(deltaX);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "dy")
|
@ReactProp(name = "dy")
|
||||||
public void setDeltaY(Dynamic deltaY) {
|
public void setDeltaY(Dynamic deltaY) {
|
||||||
mDeltaY = SVGLength.arrayFrom(deltaY);
|
mDeltaY = SVGLength.arrayFrom(deltaY);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setDeltaY(ReadableArray deltaY) {
|
public void setDeltaY(ReadableArray deltaY) {
|
||||||
mDeltaY = SVGLength.arrayFrom(deltaY);
|
mDeltaY = SVGLength.arrayFrom(deltaY);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "x")
|
@ReactProp(name = "x")
|
||||||
public void setPositionX(Dynamic positionX) {
|
public void setPositionX(Dynamic positionX) {
|
||||||
mPositionX = SVGLength.arrayFrom(positionX);
|
mPositionX = SVGLength.arrayFrom(positionX);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPositionX(ReadableArray positionX) {
|
public void setPositionX(ReadableArray positionX) {
|
||||||
mPositionX = SVGLength.arrayFrom(positionX);
|
mPositionX = SVGLength.arrayFrom(positionX);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ReactProp(name = "y")
|
@ReactProp(name = "y")
|
||||||
public void setPositionY(Dynamic positionY) {
|
public void setPositionY(Dynamic positionY) {
|
||||||
mPositionY = SVGLength.arrayFrom(positionY);
|
mPositionY = SVGLength.arrayFrom(positionY);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPositionY(ReadableArray positionY) {
|
public void setPositionY(ReadableArray positionY) {
|
||||||
mPositionY = SVGLength.arrayFrom(positionY);
|
mPositionY = SVGLength.arrayFrom(positionY);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
void draw(Canvas canvas, Paint paint, float opacity) {
|
void draw(Canvas canvas, Paint paint, float opacity) {
|
||||||
setupGlyphContext(canvas);
|
setupGlyphContext(canvas);
|
||||||
clip(canvas, paint);
|
clip(canvas, paint);
|
||||||
getGroupPath(canvas, paint);
|
getGroupPath(canvas, paint);
|
||||||
pushGlyphContext();
|
pushGlyphContext();
|
||||||
drawGroup(canvas, paint, opacity);
|
drawGroup(canvas, paint, opacity);
|
||||||
popGlyphContext();
|
popGlyphContext();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
Path getPath(Canvas canvas, Paint paint) {
|
Path getPath(Canvas canvas, Paint paint) {
|
||||||
if (mPath != null) {
|
if (mPath != null) {
|
||||||
return mPath;
|
return mPath;
|
||||||
|
}
|
||||||
|
setupGlyphContext(canvas);
|
||||||
|
return getGroupPath(canvas, paint);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
Path getPath(Canvas canvas, Paint paint, Region.Op op) {
|
||||||
|
return getPath(canvas, paint);
|
||||||
|
}
|
||||||
|
|
||||||
|
AlignmentBaseline getAlignmentBaseline() {
|
||||||
|
if (mAlignmentBaseline == null) {
|
||||||
|
ViewParent parent = this.getParent();
|
||||||
|
while (parent != null) {
|
||||||
|
if (parent instanceof TextView) {
|
||||||
|
TextView node = (TextView) parent;
|
||||||
|
final AlignmentBaseline baseline = node.mAlignmentBaseline;
|
||||||
|
if (baseline != null) {
|
||||||
|
mAlignmentBaseline = baseline;
|
||||||
|
return baseline;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
setupGlyphContext(canvas);
|
parent = parent.getParent();
|
||||||
return getGroupPath(canvas, paint);
|
}
|
||||||
}
|
}
|
||||||
|
if (mAlignmentBaseline == null) {
|
||||||
@Override
|
mAlignmentBaseline = AlignmentBaseline.baseline;
|
||||||
Path getPath(Canvas canvas, Paint paint, Region.Op op) {
|
|
||||||
return getPath(canvas, paint);
|
|
||||||
}
|
}
|
||||||
|
return mAlignmentBaseline;
|
||||||
|
}
|
||||||
|
|
||||||
AlignmentBaseline getAlignmentBaseline() {
|
String getBaselineShift() {
|
||||||
if (mAlignmentBaseline == null) {
|
if (mBaselineShift == null) {
|
||||||
ViewParent parent = this.getParent();
|
ViewParent parent = this.getParent();
|
||||||
while (parent != null) {
|
while (parent != null) {
|
||||||
if (parent instanceof TextView) {
|
if (parent instanceof TextView) {
|
||||||
TextView node = (TextView)parent;
|
TextView node = (TextView) parent;
|
||||||
final AlignmentBaseline baseline = node.mAlignmentBaseline;
|
final String baselineShift = node.mBaselineShift;
|
||||||
if (baseline != null) {
|
if (baselineShift != null) {
|
||||||
mAlignmentBaseline = baseline;
|
mBaselineShift = baselineShift;
|
||||||
return baseline;
|
return baselineShift;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
parent = parent.getParent();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (mAlignmentBaseline == null) {
|
parent = parent.getParent();
|
||||||
mAlignmentBaseline = AlignmentBaseline.baseline;
|
}
|
||||||
}
|
|
||||||
return mAlignmentBaseline;
|
|
||||||
}
|
}
|
||||||
|
return mBaselineShift;
|
||||||
|
}
|
||||||
|
|
||||||
String getBaselineShift() {
|
Path getGroupPath(Canvas canvas, Paint paint) {
|
||||||
if (mBaselineShift == null) {
|
if (mPath != null) {
|
||||||
ViewParent parent = this.getParent();
|
return mPath;
|
||||||
while (parent != null) {
|
|
||||||
if (parent instanceof TextView) {
|
|
||||||
TextView node = (TextView)parent;
|
|
||||||
final String baselineShift = node.mBaselineShift;
|
|
||||||
if (baselineShift != null) {
|
|
||||||
mBaselineShift = baselineShift;
|
|
||||||
return baselineShift;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
parent = parent.getParent();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return mBaselineShift;
|
|
||||||
}
|
}
|
||||||
|
pushGlyphContext();
|
||||||
|
mPath = super.getPath(canvas, paint);
|
||||||
|
popGlyphContext();
|
||||||
|
|
||||||
Path getGroupPath(Canvas canvas, Paint paint) {
|
return mPath;
|
||||||
if (mPath != null) {
|
}
|
||||||
return mPath;
|
|
||||||
}
|
|
||||||
pushGlyphContext();
|
|
||||||
mPath = super.getPath(canvas, paint);
|
|
||||||
popGlyphContext();
|
|
||||||
|
|
||||||
return mPath;
|
@Override
|
||||||
}
|
void pushGlyphContext() {
|
||||||
|
boolean isTextNode = !(this instanceof TextPathView) && !(this instanceof TSpanView);
|
||||||
|
getTextRootGlyphContext()
|
||||||
|
.pushContext(isTextNode, this, mFont, mPositionX, mPositionY, mDeltaX, mDeltaY, mRotate);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
TextView getTextAnchorRoot() {
|
||||||
void pushGlyphContext() {
|
GlyphContext gc = getTextRootGlyphContext();
|
||||||
boolean isTextNode = !(this instanceof TextPathView) && !(this instanceof TSpanView);
|
ArrayList<FontData> font = gc.mFontContext;
|
||||||
getTextRootGlyphContext().pushContext(isTextNode, this, mFont, mPositionX, mPositionY, mDeltaX, mDeltaY, mRotate);
|
TextView node = this;
|
||||||
}
|
ViewParent parent = this.getParent();
|
||||||
|
for (int i = font.size() - 1; i >= 0; i--) {
|
||||||
TextView getTextAnchorRoot() {
|
if (!(parent instanceof TextView)
|
||||||
GlyphContext gc = getTextRootGlyphContext();
|
|| font.get(i).textAnchor == TextProperties.TextAnchor.start
|
||||||
ArrayList<FontData> font = gc.mFontContext;
|
|| node.mPositionX != null) {
|
||||||
TextView node = this;
|
|
||||||
ViewParent parent = this.getParent();
|
|
||||||
for (int i = font.size() - 1; i >= 0; i--) {
|
|
||||||
if (!(parent instanceof TextView) || font.get(i).textAnchor == TextProperties.TextAnchor.start || node.mPositionX != null) {
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
node = (TextView) parent;
|
|
||||||
parent = node.getParent();
|
|
||||||
}
|
|
||||||
return node;
|
return node;
|
||||||
|
}
|
||||||
|
node = (TextView) parent;
|
||||||
|
parent = node.getParent();
|
||||||
}
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
double getSubtreeTextChunksTotalAdvance(Paint paint) {
|
double getSubtreeTextChunksTotalAdvance(Paint paint) {
|
||||||
if (!Double.isNaN(cachedAdvance)) {
|
if (!Double.isNaN(cachedAdvance)) {
|
||||||
return cachedAdvance;
|
return cachedAdvance;
|
||||||
}
|
|
||||||
double advance = 0;
|
|
||||||
for (int i = 0; i < getChildCount(); i++) {
|
|
||||||
View child = getChildAt(i);
|
|
||||||
if (child instanceof TextView) {
|
|
||||||
TextView text = (TextView) child;
|
|
||||||
advance += text.getSubtreeTextChunksTotalAdvance(paint);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cachedAdvance = advance;
|
|
||||||
return advance;
|
|
||||||
}
|
}
|
||||||
|
double advance = 0;
|
||||||
|
for (int i = 0; i < getChildCount(); i++) {
|
||||||
|
View child = getChildAt(i);
|
||||||
|
if (child instanceof TextView) {
|
||||||
|
TextView text = (TextView) child;
|
||||||
|
advance += text.getSubtreeTextChunksTotalAdvance(paint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cachedAdvance = advance;
|
||||||
|
return advance;
|
||||||
|
}
|
||||||
|
|
||||||
TextView getTextContainer() {
|
TextView getTextContainer() {
|
||||||
TextView node = this;
|
TextView node = this;
|
||||||
ViewParent parent = this.getParent();
|
ViewParent parent = this.getParent();
|
||||||
while (parent instanceof TextView) {
|
while (parent instanceof TextView) {
|
||||||
node = (TextView) parent;
|
node = (TextView) parent;
|
||||||
parent = node.getParent();
|
parent = node.getParent();
|
||||||
}
|
|
||||||
return node;
|
|
||||||
}
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,6 @@
|
|||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
package com.horcrux.svg;
|
package com.horcrux.svg;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
@@ -14,7 +13,6 @@ import android.graphics.Canvas;
|
|||||||
import android.graphics.Matrix;
|
import android.graphics.Matrix;
|
||||||
import android.graphics.Paint;
|
import android.graphics.Paint;
|
||||||
import android.graphics.Path;
|
import android.graphics.Path;
|
||||||
|
|
||||||
import com.facebook.common.logging.FLog;
|
import com.facebook.common.logging.FLog;
|
||||||
import com.facebook.react.bridge.Dynamic;
|
import com.facebook.react.bridge.Dynamic;
|
||||||
import com.facebook.react.bridge.ReactContext;
|
import com.facebook.react.bridge.ReactContext;
|
||||||
@@ -23,138 +21,151 @@ import com.facebook.react.uimanager.annotations.ReactProp;
|
|||||||
|
|
||||||
@SuppressLint("ViewConstructor")
|
@SuppressLint("ViewConstructor")
|
||||||
class UseView extends RenderableView {
|
class UseView extends RenderableView {
|
||||||
private String mHref;
|
private String mHref;
|
||||||
private SVGLength mX;
|
private SVGLength mX;
|
||||||
private SVGLength mY;
|
private SVGLength mY;
|
||||||
private SVGLength mW;
|
private SVGLength mW;
|
||||||
private SVGLength mH;
|
private SVGLength mH;
|
||||||
|
|
||||||
public UseView(ReactContext reactContext) {
|
public UseView(ReactContext reactContext) {
|
||||||
super(reactContext);
|
super(reactContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "href")
|
@ReactProp(name = "href")
|
||||||
public void setHref(String href) {
|
public void setHref(String href) {
|
||||||
mHref = href;
|
mHref = href;
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "x")
|
@ReactProp(name = "x")
|
||||||
public void setX(Dynamic x) {
|
public void setX(Dynamic x) {
|
||||||
mX = SVGLength.from(x);
|
mX = SVGLength.from(x);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setX(String x) {
|
public void setX(String x) {
|
||||||
mX = SVGLength.from(x);
|
mX = SVGLength.from(x);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "y")
|
@ReactProp(name = "y")
|
||||||
public void setY(Dynamic y) {
|
public void setY(Dynamic y) {
|
||||||
mY = SVGLength.from(y);
|
mY = SVGLength.from(y);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setY(String y) {
|
public void setY(String y) {
|
||||||
mY = SVGLength.from(y);
|
mY = SVGLength.from(y);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "width")
|
@ReactProp(name = "width")
|
||||||
public void setWidth(Dynamic width) {
|
public void setWidth(Dynamic width) {
|
||||||
mW = SVGLength.from(width);
|
mW = SVGLength.from(width);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setWidth(String width) {
|
public void setWidth(String width) {
|
||||||
mW = SVGLength.from(width);
|
mW = SVGLength.from(width);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactProp(name = "height")
|
@ReactProp(name = "height")
|
||||||
public void setHeight(Dynamic height) {
|
public void setHeight(Dynamic height) {
|
||||||
mH = SVGLength.from(height);
|
mH = SVGLength.from(height);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setHeight(String height) {
|
public void setHeight(String height) {
|
||||||
mH = SVGLength.from(height);
|
mH = SVGLength.from(height);
|
||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
void draw(Canvas canvas, Paint paint, float opacity) {
|
void draw(Canvas canvas, Paint paint, float opacity) {
|
||||||
VirtualView template = getSvgView().getDefinedTemplate(mHref);
|
VirtualView template = getSvgView().getDefinedTemplate(mHref);
|
||||||
|
|
||||||
if (template == null) {
|
if (template == null) {
|
||||||
FLog.w(ReactConstants.TAG, "`Use` element expected a pre-defined svg template as `href` prop, " +
|
FLog.w(
|
||||||
"template named: " + mHref + " is not defined.");
|
ReactConstants.TAG,
|
||||||
return;
|
"`Use` element expected a pre-defined svg template as `href` prop, "
|
||||||
}
|
+ "template named: "
|
||||||
|
+ mHref
|
||||||
template.clearCache();
|
+ " is not defined.");
|
||||||
canvas.translate((float) relativeOnWidth(mX), (float) relativeOnHeight(mY));
|
return;
|
||||||
if (template instanceof RenderableView) {
|
|
||||||
((RenderableView)template).mergeProperties(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
int count = template.saveAndSetupCanvas(canvas, mCTM);
|
|
||||||
clip(canvas, paint);
|
|
||||||
|
|
||||||
if (template instanceof SymbolView) {
|
|
||||||
SymbolView symbol = (SymbolView)template;
|
|
||||||
symbol.drawSymbol(canvas, paint, opacity, (float) relativeOnWidth(mW), (float) relativeOnHeight(mH));
|
|
||||||
} else {
|
|
||||||
template.draw(canvas, paint, opacity * mOpacity);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setClientRect(template.getClientRect());
|
|
||||||
|
|
||||||
template.restoreCanvas(canvas, count);
|
|
||||||
if (template instanceof RenderableView) {
|
|
||||||
((RenderableView)template).resetProperties();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
template.clearCache();
|
||||||
int hitTest(float[] src) {
|
canvas.translate((float) relativeOnWidth(mX), (float) relativeOnHeight(mY));
|
||||||
if (!mInvertible || !mTransformInvertible) {
|
if (template instanceof RenderableView) {
|
||||||
return -1;
|
((RenderableView) template).mergeProperties(this);
|
||||||
}
|
|
||||||
|
|
||||||
float[] dst = new float[2];
|
|
||||||
mInvMatrix.mapPoints(dst, src);
|
|
||||||
mInvTransform.mapPoints(dst);
|
|
||||||
|
|
||||||
VirtualView template = getSvgView().getDefinedTemplate(mHref);
|
|
||||||
if (template == null) {
|
|
||||||
FLog.w(ReactConstants.TAG, "`Use` element expected a pre-defined svg template as `href` prop, " +
|
|
||||||
"template named: " + mHref + " is not defined.");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int hitChild = template.hitTest(dst);
|
|
||||||
if (hitChild != -1) {
|
|
||||||
return (template.isResponsible() || hitChild != template.getId()) ? hitChild : getId();
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
int count = template.saveAndSetupCanvas(canvas, mCTM);
|
||||||
Path getPath(Canvas canvas, Paint paint) {
|
clip(canvas, paint);
|
||||||
VirtualView template = getSvgView().getDefinedTemplate(mHref);
|
|
||||||
if (template == null) {
|
if (template instanceof SymbolView) {
|
||||||
FLog.w(ReactConstants.TAG, "`Use` element expected a pre-defined svg template as `href` prop, " +
|
SymbolView symbol = (SymbolView) template;
|
||||||
"template named: " + mHref + " is not defined.");
|
symbol.drawSymbol(
|
||||||
return null;
|
canvas, paint, opacity, (float) relativeOnWidth(mW), (float) relativeOnHeight(mH));
|
||||||
}
|
} else {
|
||||||
Path path = template.getPath(canvas, paint);
|
template.draw(canvas, paint, opacity * mOpacity);
|
||||||
Path use = new Path();
|
|
||||||
Matrix m = new Matrix();
|
|
||||||
m.setTranslate((float) relativeOnWidth(mX), (float) relativeOnHeight(mY));
|
|
||||||
path.transform(m, use);
|
|
||||||
return use;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.setClientRect(template.getClientRect());
|
||||||
|
|
||||||
|
template.restoreCanvas(canvas, count);
|
||||||
|
if (template instanceof RenderableView) {
|
||||||
|
((RenderableView) template).resetProperties();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
int hitTest(float[] src) {
|
||||||
|
if (!mInvertible || !mTransformInvertible) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
float[] dst = new float[2];
|
||||||
|
mInvMatrix.mapPoints(dst, src);
|
||||||
|
mInvTransform.mapPoints(dst);
|
||||||
|
|
||||||
|
VirtualView template = getSvgView().getDefinedTemplate(mHref);
|
||||||
|
if (template == null) {
|
||||||
|
FLog.w(
|
||||||
|
ReactConstants.TAG,
|
||||||
|
"`Use` element expected a pre-defined svg template as `href` prop, "
|
||||||
|
+ "template named: "
|
||||||
|
+ mHref
|
||||||
|
+ " is not defined.");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int hitChild = template.hitTest(dst);
|
||||||
|
if (hitChild != -1) {
|
||||||
|
return (template.isResponsible() || hitChild != template.getId()) ? hitChild : getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
Path getPath(Canvas canvas, Paint paint) {
|
||||||
|
VirtualView template = getSvgView().getDefinedTemplate(mHref);
|
||||||
|
if (template == null) {
|
||||||
|
FLog.w(
|
||||||
|
ReactConstants.TAG,
|
||||||
|
"`Use` element expected a pre-defined svg template as `href` prop, "
|
||||||
|
+ "template named: "
|
||||||
|
+ mHref
|
||||||
|
+ " is not defined.");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Path path = template.getPath(canvas, paint);
|
||||||
|
Path use = new Path();
|
||||||
|
Matrix m = new Matrix();
|
||||||
|
m.setTranslate((float) relativeOnWidth(mX), (float) relativeOnHeight(mY));
|
||||||
|
path.transform(m, use);
|
||||||
|
return use;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,6 @@
|
|||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
package com.horcrux.svg;
|
package com.horcrux.svg;
|
||||||
|
|
||||||
import android.graphics.Matrix;
|
import android.graphics.Matrix;
|
||||||
@@ -14,90 +13,91 @@ import android.graphics.RectF;
|
|||||||
|
|
||||||
class ViewBox {
|
class ViewBox {
|
||||||
|
|
||||||
private static final int MOS_MEET = 0;
|
private static final int MOS_MEET = 0;
|
||||||
private static final int MOS_SLICE = 1;
|
private static final int MOS_SLICE = 1;
|
||||||
private static final int MOS_NONE = 2;
|
private static final int MOS_NONE = 2;
|
||||||
|
|
||||||
static Matrix getTransform(RectF vbRect, RectF eRect, String align, int meetOrSlice) {
|
static Matrix getTransform(RectF vbRect, RectF eRect, String align, int meetOrSlice) {
|
||||||
// based on https://svgwg.org/svg2-draft/coords.html#ComputingAViewportsTransform
|
// based on https://svgwg.org/svg2-draft/coords.html#ComputingAViewportsTransform
|
||||||
|
|
||||||
// Let vb-x, vb-y, vb-width, vb-height be the min-x, min-y, width and height values of the viewBox attribute respectively.
|
// Let vb-x, vb-y, vb-width, vb-height be the min-x, min-y, width and height values of the
|
||||||
double vbX = vbRect.left;
|
// viewBox attribute respectively.
|
||||||
double vbY = vbRect.top;
|
double vbX = vbRect.left;
|
||||||
double vbWidth = vbRect.width();
|
double vbY = vbRect.top;
|
||||||
double vbHeight = vbRect.height();
|
double vbWidth = vbRect.width();
|
||||||
|
double vbHeight = vbRect.height();
|
||||||
|
|
||||||
// Let e-x, e-y, e-width, e-height be the position and size of the element respectively.
|
// Let e-x, e-y, e-width, e-height be the position and size of the element respectively.
|
||||||
double eX = eRect.left;
|
double eX = eRect.left;
|
||||||
double eY = eRect.top;
|
double eY = eRect.top;
|
||||||
double eWidth = eRect.width();
|
double eWidth = eRect.width();
|
||||||
double eHeight = eRect.height();
|
double eHeight = eRect.height();
|
||||||
|
|
||||||
|
// Initialize scale-x to e-width/vb-width.
|
||||||
|
double scaleX = eWidth / vbWidth;
|
||||||
|
|
||||||
// Initialize scale-x to e-width/vb-width.
|
// Initialize scale-y to e-height/vb-height.
|
||||||
double scaleX = eWidth / vbWidth;
|
double scaleY = eHeight / vbHeight;
|
||||||
|
|
||||||
// Initialize scale-y to e-height/vb-height.
|
// Initialize translate-x to e-x - (vb-x * scale-x).
|
||||||
double scaleY = eHeight / vbHeight;
|
// Initialize translate-y to e-y - (vb-y * scale-y).
|
||||||
|
double translateX = eX - (vbX * scaleX);
|
||||||
|
double translateY = eY - (vbY * scaleY);
|
||||||
|
|
||||||
// Initialize translate-x to e-x - (vb-x * scale-x).
|
// If align is 'none'
|
||||||
// Initialize translate-y to e-y - (vb-y * scale-y).
|
if (meetOrSlice == MOS_NONE) {
|
||||||
double translateX = eX - (vbX * scaleX);
|
// Let scale be set the smaller value of scale-x and scale-y.
|
||||||
double translateY = eY - (vbY * scaleY);
|
// Assign scale-x and scale-y to scale.
|
||||||
|
double scale = scaleX = scaleY = Math.min(scaleX, scaleY);
|
||||||
|
|
||||||
// If align is 'none'
|
// If scale is greater than 1
|
||||||
if (meetOrSlice == MOS_NONE) {
|
if (scale > 1) {
|
||||||
// Let scale be set the smaller value of scale-x and scale-y.
|
// Minus translateX by (eWidth / scale - vbWidth) / 2
|
||||||
// Assign scale-x and scale-y to scale.
|
// Minus translateY by (eHeight / scale - vbHeight) / 2
|
||||||
double scale = scaleX = scaleY = Math.min(scaleX, scaleY);
|
translateX -= (eWidth / scale - vbWidth) / 2;
|
||||||
|
translateY -= (eHeight / scale - vbHeight) / 2;
|
||||||
|
} else {
|
||||||
|
translateX -= (eWidth - vbWidth * scale) / 2;
|
||||||
|
translateY -= (eHeight - vbHeight * scale) / 2;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// If align is not 'none' and meetOrSlice is 'meet', set the larger of scale-x and scale-y to
|
||||||
|
// the smaller.
|
||||||
|
// Otherwise, if align is not 'none' and meetOrSlice is 'slice', set the smaller of scale-x
|
||||||
|
// and scale-y to the larger.
|
||||||
|
|
||||||
// If scale is greater than 1
|
if (!align.equals("none") && meetOrSlice == MOS_MEET) {
|
||||||
if (scale > 1) {
|
scaleX = scaleY = Math.min(scaleX, scaleY);
|
||||||
// Minus translateX by (eWidth / scale - vbWidth) / 2
|
} else if (!align.equals("none") && meetOrSlice == MOS_SLICE) {
|
||||||
// Minus translateY by (eHeight / scale - vbHeight) / 2
|
scaleX = scaleY = Math.max(scaleX, scaleY);
|
||||||
translateX -= (eWidth / scale - vbWidth) / 2;
|
}
|
||||||
translateY -= (eHeight / scale - vbHeight) / 2;
|
|
||||||
} else {
|
|
||||||
translateX -= (eWidth - vbWidth * scale) / 2;
|
|
||||||
translateY -= (eHeight - vbHeight * scale) / 2;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// If align is not 'none' and meetOrSlice is 'meet', set the larger of scale-x and scale-y to the smaller.
|
|
||||||
// Otherwise, if align is not 'none' and meetOrSlice is 'slice', set the smaller of scale-x and scale-y to the larger.
|
|
||||||
|
|
||||||
if (!align.equals("none") && meetOrSlice == MOS_MEET) {
|
// If align contains 'xMid', add (e-width - vb-width * scale-x) / 2 to translate-x.
|
||||||
scaleX = scaleY = Math.min(scaleX, scaleY);
|
if (align.contains("xMid")) {
|
||||||
} else if (!align.equals("none") && meetOrSlice == MOS_SLICE) {
|
translateX += (eWidth - vbWidth * scaleX) / 2.0d;
|
||||||
scaleX = scaleY = Math.max(scaleX, scaleY);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// If align contains 'xMid', add (e-width - vb-width * scale-x) / 2 to translate-x.
|
// If align contains 'xMax', add (e-width - vb-width * scale-x) to translate-x.
|
||||||
if (align.contains("xMid")) {
|
if (align.contains("xMax")) {
|
||||||
translateX += (eWidth - vbWidth * scaleX) / 2.0d;
|
translateX += (eWidth - vbWidth * scaleX);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If align contains 'xMax', add (e-width - vb-width * scale-x) to translate-x.
|
// If align contains 'yMid', add (e-height - vb-height * scale-y) / 2 to translate-y.
|
||||||
if (align.contains("xMax")) {
|
if (align.contains("YMid")) {
|
||||||
translateX += (eWidth - vbWidth * scaleX);
|
translateY += (eHeight - vbHeight * scaleY) / 2.0d;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If align contains 'yMid', add (e-height - vb-height * scale-y) / 2 to translate-y.
|
// If align contains 'yMax', add (e-height - vb-height * scale-y) to translate-y.
|
||||||
if (align.contains("YMid")) {
|
if (align.contains("YMax")) {
|
||||||
translateY += (eHeight - vbHeight * scaleY) / 2.0d;
|
translateY += (eHeight - vbHeight * scaleY);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If align contains 'yMax', add (e-height - vb-height * scale-y) to translate-y.
|
|
||||||
if (align.contains("YMax")) {
|
|
||||||
translateY += (eHeight - vbHeight * scaleY);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// The transform applied to content contained by the element is given by
|
|
||||||
// translate(translate-x, translate-y) scale(scale-x, scale-y).
|
|
||||||
Matrix transform = new Matrix();
|
|
||||||
transform.postTranslate((float) translateX, (float) translateY);
|
|
||||||
transform.preScale((float) scaleX, (float) scaleY);
|
|
||||||
return transform;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The transform applied to content contained by the element is given by
|
||||||
|
// translate(translate-x, translate-y) scale(scale-x, scale-y).
|
||||||
|
Matrix transform = new Matrix();
|
||||||
|
transform.postTranslate((float) translateX, (float) translateY);
|
||||||
|
transform.preScale((float) scaleX, (float) scaleY);
|
||||||
|
return transform;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,9 +1,7 @@
|
|||||||
package com.horcrux.svg;
|
package com.horcrux.svg;
|
||||||
|
|
||||||
|
|
||||||
import com.facebook.react.bridge.ReactContext;
|
import com.facebook.react.bridge.ReactContext;
|
||||||
import com.facebook.react.views.view.ReactViewGroup;
|
import com.facebook.react.views.view.ReactViewGroup;
|
||||||
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
public abstract class FabricEnabledViewGroup extends ReactViewGroup {
|
public abstract class FabricEnabledViewGroup extends ReactViewGroup {
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
|
|
||||||
@interface RNSVGBrush : NSObject
|
@interface RNSVGBrush : NSObject
|
||||||
|
|
||||||
@property (nonatomic, strong) NSString* brushRef;
|
@property (nonatomic, strong) NSString *brushRef;
|
||||||
|
|
||||||
/* @abstract */
|
/* @abstract */
|
||||||
- (instancetype)initWithArray:(NSArray *)data;
|
- (instancetype)initWithArray:(NSArray *)data;
|
||||||
|
|||||||
@@ -13,31 +13,30 @@
|
|||||||
|
|
||||||
- (instancetype)initWithArray:(NSArray *)data
|
- (instancetype)initWithArray:(NSArray *)data
|
||||||
{
|
{
|
||||||
return [super init];
|
return [super init];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)paint:(CGContextRef)context opacity:(CGFloat)opacity painter:(RNSVGPainter *)painter bounds:(CGRect)bounds
|
- (void)paint:(CGContextRef)context opacity:(CGFloat)opacity painter:(RNSVGPainter *)painter bounds:(CGRect)bounds
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)applyFillColor:(CGContextRef)context opacity:(CGFloat)opacity
|
- (BOOL)applyFillColor:(CGContextRef)context opacity:(CGFloat)opacity
|
||||||
{
|
{
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)applyStrokeColor:(CGContextRef)context opacity:(CGFloat)opacity
|
- (BOOL)applyStrokeColor:(CGContextRef)context opacity:(CGFloat)opacity
|
||||||
{
|
{
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CGColorRef)getColorWithOpacity:(CGFloat)opacity
|
- (CGColorRef)getColorWithOpacity:(CGFloat)opacity
|
||||||
{
|
{
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)paint:(CGContextRef)context opacity:(CGFloat)opacity painter:(RNSVGPainter *)painter
|
- (void)paint:(CGContextRef)context opacity:(CGFloat)opacity painter:(RNSVGPainter *)painter
|
||||||
{
|
{
|
||||||
// abstract
|
// abstract
|
||||||
}
|
}
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -7,8 +7,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
kRNSVGUndefinedType,
|
kRNSVGUndefinedType,
|
||||||
kRNSVGLinearGradient,
|
kRNSVGLinearGradient,
|
||||||
kRNSVGRadialGradient,
|
kRNSVGRadialGradient,
|
||||||
kRNSVGPattern
|
kRNSVGPattern
|
||||||
} RNSVGBrushType;
|
} RNSVGBrushType;
|
||||||
|
|||||||
@@ -7,31 +7,30 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#import "RNSVGContextBrush.h"
|
#import "RNSVGContextBrush.h"
|
||||||
#import "RNSVGRenderable.h"
|
|
||||||
#import "RNSVGNode.h"
|
#import "RNSVGNode.h"
|
||||||
|
#import "RNSVGRenderable.h"
|
||||||
|
|
||||||
#import "RCTConvert+RNSVG.h"
|
|
||||||
#import <React/RCTLog.h>
|
#import <React/RCTLog.h>
|
||||||
|
#import "RCTConvert+RNSVG.h"
|
||||||
|
|
||||||
@implementation RNSVGContextBrush
|
@implementation RNSVGContextBrush {
|
||||||
{
|
BOOL _isStroke;
|
||||||
BOOL _isStroke;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (instancetype)initFill
|
- (instancetype)initFill
|
||||||
{
|
{
|
||||||
if ((self = [super initWithArray:nil])) {
|
if ((self = [super initWithArray:nil])) {
|
||||||
_isStroke = NO;
|
_isStroke = NO;
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (instancetype)initStroke
|
- (instancetype)initStroke
|
||||||
{
|
{
|
||||||
if ((self = [super initWithArray:nil])) {
|
if ((self = [super initWithArray:nil])) {
|
||||||
_isStroke = YES;
|
_isStroke = YES;
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)dealloc
|
- (void)dealloc
|
||||||
@@ -40,46 +39,44 @@
|
|||||||
|
|
||||||
- (BOOL)applyFillColor:(CGContextRef)context opacity:(CGFloat)opacity
|
- (BOOL)applyFillColor:(CGContextRef)context opacity:(CGFloat)opacity
|
||||||
{
|
{
|
||||||
RNSVGRenderable *element = RNSVGRenderable.contextElement;
|
RNSVGRenderable *element = RNSVGRenderable.contextElement;
|
||||||
if (!element) {
|
if (!element) {
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
RNSVGBrush *brush = _isStroke ? element.stroke : element.fill;
|
RNSVGBrush *brush = _isStroke ? element.stroke : element.fill;
|
||||||
|
|
||||||
BOOL fillColor;
|
BOOL fillColor;
|
||||||
|
|
||||||
if (brush.class == RNSVGBrush.class) {
|
if (brush.class == RNSVGBrush.class) {
|
||||||
CGContextSetFillColorWithColor(context, [element.tintColor CGColor]);
|
CGContextSetFillColorWithColor(context, [element.tintColor CGColor]);
|
||||||
fillColor = YES;
|
fillColor = YES;
|
||||||
} else {
|
} else {
|
||||||
fillColor = [brush applyFillColor:context opacity:opacity];
|
fillColor = [brush applyFillColor:context opacity:opacity];
|
||||||
}
|
}
|
||||||
|
|
||||||
return fillColor;
|
return fillColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
- (BOOL)applyStrokeColor:(CGContextRef)context opacity:(CGFloat)opacity
|
- (BOOL)applyStrokeColor:(CGContextRef)context opacity:(CGFloat)opacity
|
||||||
{
|
{
|
||||||
RNSVGRenderable *element = RNSVGRenderable.contextElement;
|
RNSVGRenderable *element = RNSVGRenderable.contextElement;
|
||||||
if (!element) {
|
if (!element) {
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
RNSVGBrush *brush = _isStroke ? element.stroke : element.fill;
|
RNSVGBrush *brush = _isStroke ? element.stroke : element.fill;
|
||||||
|
|
||||||
BOOL strokeColor;
|
BOOL strokeColor;
|
||||||
|
|
||||||
if (brush.class == RNSVGBrush.class) {
|
if (brush.class == RNSVGBrush.class) {
|
||||||
CGContextSetStrokeColorWithColor(context, [element.tintColor CGColor]);
|
CGContextSetStrokeColorWithColor(context, [element.tintColor CGColor]);
|
||||||
strokeColor = YES;
|
strokeColor = YES;
|
||||||
} else {
|
} else {
|
||||||
strokeColor = [brush applyStrokeColor:context opacity:opacity];
|
strokeColor = [brush applyStrokeColor:context opacity:opacity];
|
||||||
}
|
}
|
||||||
|
|
||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -8,14 +8,14 @@
|
|||||||
|
|
||||||
#import "RCTConvert+RNSVG.h"
|
#import "RCTConvert+RNSVG.h"
|
||||||
#import "RNSVGBrushType.h"
|
#import "RNSVGBrushType.h"
|
||||||
#import "RNSVGUnits.h"
|
|
||||||
#import "RNSVGLength.h"
|
#import "RNSVGLength.h"
|
||||||
|
#import "RNSVGUnits.h"
|
||||||
|
|
||||||
@class RNSVGPattern;
|
@class RNSVGPattern;
|
||||||
|
|
||||||
@interface RNSVGPainter : NSObject
|
@interface RNSVGPainter : NSObject
|
||||||
|
|
||||||
@property (nonatomic, assign) RNSVGPattern* pattern;
|
@property (nonatomic, assign) RNSVGPattern *pattern;
|
||||||
@property (nonatomic, assign) CGRect paintBounds;
|
@property (nonatomic, assign) CGRect paintBounds;
|
||||||
@property (nonatomic, assign) bool useObjectBoundingBoxForContentUnits;
|
@property (nonatomic, assign) bool useObjectBoundingBoxForContentUnits;
|
||||||
@property (nonatomic, assign) CGRect bounds;
|
@property (nonatomic, assign) CGRect bounds;
|
||||||
|
|||||||
@@ -10,246 +10,242 @@
|
|||||||
#import "RNSVGPattern.h"
|
#import "RNSVGPattern.h"
|
||||||
#import "RNSVGViewBox.h"
|
#import "RNSVGViewBox.h"
|
||||||
|
|
||||||
@implementation RNSVGPainter
|
@implementation RNSVGPainter {
|
||||||
{
|
NSArray<RNSVGLength *> *_points;
|
||||||
NSArray<RNSVGLength *> *_points;
|
NSArray<NSNumber *> *_colors;
|
||||||
NSArray<NSNumber *> *_colors;
|
RNSVGBrushType _type;
|
||||||
RNSVGBrushType _type;
|
BOOL _useObjectBoundingBox;
|
||||||
BOOL _useObjectBoundingBox;
|
BOOL _useContentObjectBoundingBox;
|
||||||
BOOL _useContentObjectBoundingBox;
|
CGAffineTransform _transform;
|
||||||
CGAffineTransform _transform;
|
CGRect _userSpaceBoundingBox;
|
||||||
CGRect _userSpaceBoundingBox;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (instancetype)initWithPointsArray:(NSArray<RNSVGLength *> *)pointsArray
|
- (instancetype)initWithPointsArray:(NSArray<RNSVGLength *> *)pointsArray
|
||||||
{
|
{
|
||||||
if ((self = [super init])) {
|
if ((self = [super init])) {
|
||||||
_points = pointsArray;
|
_points = pointsArray;
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
RCT_NOT_IMPLEMENTED(- (instancetype)init)
|
RCT_NOT_IMPLEMENTED(-(instancetype)init)
|
||||||
|
|
||||||
- (void)setUnits:(RNSVGUnits)unit
|
- (void)setUnits:(RNSVGUnits)unit
|
||||||
{
|
{
|
||||||
_useObjectBoundingBox = unit == kRNSVGUnitsObjectBoundingBox;
|
_useObjectBoundingBox = unit == kRNSVGUnitsObjectBoundingBox;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setContentUnits:(RNSVGUnits)unit
|
- (void)setContentUnits:(RNSVGUnits)unit
|
||||||
{
|
{
|
||||||
_useContentObjectBoundingBox = unit == kRNSVGUnitsObjectBoundingBox;
|
_useContentObjectBoundingBox = unit == kRNSVGUnitsObjectBoundingBox;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setUserSpaceBoundingBox:(CGRect)userSpaceBoundingBox
|
- (void)setUserSpaceBoundingBox:(CGRect)userSpaceBoundingBox
|
||||||
{
|
{
|
||||||
_userSpaceBoundingBox = userSpaceBoundingBox;
|
_userSpaceBoundingBox = userSpaceBoundingBox;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setTransform:(CGAffineTransform)transform
|
- (void)setTransform:(CGAffineTransform)transform
|
||||||
{
|
{
|
||||||
_transform = transform;
|
_transform = transform;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setPattern:(RNSVGPattern *)pattern
|
- (void)setPattern:(RNSVGPattern *)pattern
|
||||||
{
|
{
|
||||||
if (_type != kRNSVGUndefinedType) {
|
if (_type != kRNSVGUndefinedType) {
|
||||||
// todo: throw error
|
// todo: throw error
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_type = kRNSVGPattern;
|
_type = kRNSVGPattern;
|
||||||
_pattern = pattern;
|
_pattern = pattern;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setLinearGradientColors:(NSArray<NSNumber *> *)colors
|
- (void)setLinearGradientColors:(NSArray<NSNumber *> *)colors
|
||||||
{
|
{
|
||||||
if (_type != kRNSVGUndefinedType) {
|
if (_type != kRNSVGUndefinedType) {
|
||||||
// todo: throw error
|
// todo: throw error
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_type = kRNSVGLinearGradient;
|
_type = kRNSVGLinearGradient;
|
||||||
_colors = colors;
|
_colors = colors;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setRadialGradientColors:(NSArray<NSNumber *> *)colors
|
- (void)setRadialGradientColors:(NSArray<NSNumber *> *)colors
|
||||||
{
|
{
|
||||||
if (_type != kRNSVGUndefinedType) {
|
if (_type != kRNSVGUndefinedType) {
|
||||||
// todo: throw error
|
// todo: throw error
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_type = kRNSVGRadialGradient;
|
_type = kRNSVGRadialGradient;
|
||||||
_colors = colors;
|
_colors = colors;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)paint:(CGContextRef)context bounds:(CGRect)bounds
|
- (void)paint:(CGContextRef)context bounds:(CGRect)bounds
|
||||||
{
|
{
|
||||||
if (_type == kRNSVGLinearGradient) {
|
if (_type == kRNSVGLinearGradient) {
|
||||||
[self paintLinearGradient:context bounds:bounds];
|
[self paintLinearGradient:context bounds:bounds];
|
||||||
} else if (_type == kRNSVGRadialGradient) {
|
} else if (_type == kRNSVGRadialGradient) {
|
||||||
[self paintRadialGradient:context bounds:bounds];
|
[self paintRadialGradient:context bounds:bounds];
|
||||||
} else if (_type == kRNSVGPattern) {
|
} else if (_type == kRNSVGPattern) {
|
||||||
[self paintPattern:context bounds:bounds];
|
[self paintPattern:context bounds:bounds];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CGRect)getPaintRect:(CGContextRef)context bounds:(CGRect)bounds
|
- (CGRect)getPaintRect:(CGContextRef)context bounds:(CGRect)bounds
|
||||||
{
|
{
|
||||||
CGRect rect = _useObjectBoundingBox ? bounds : _userSpaceBoundingBox;
|
CGRect rect = _useObjectBoundingBox ? bounds : _userSpaceBoundingBox;
|
||||||
CGFloat height = CGRectGetHeight(rect);
|
CGFloat height = CGRectGetHeight(rect);
|
||||||
CGFloat width = CGRectGetWidth(rect);
|
CGFloat width = CGRectGetWidth(rect);
|
||||||
CGFloat x = 0.0;
|
CGFloat x = 0.0;
|
||||||
CGFloat y = 0.0;
|
CGFloat y = 0.0;
|
||||||
|
|
||||||
if (_useObjectBoundingBox) {
|
if (_useObjectBoundingBox) {
|
||||||
x = CGRectGetMinX(rect);
|
x = CGRectGetMinX(rect);
|
||||||
y = CGRectGetMinY(rect);
|
y = CGRectGetMinY(rect);
|
||||||
}
|
}
|
||||||
|
|
||||||
return CGRectMake(x, y, width, height);
|
return CGRectMake(x, y, width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PatternFunction(void* info, CGContextRef context)
|
void PatternFunction(void *info, CGContextRef context)
|
||||||
{
|
{
|
||||||
RNSVGPainter *_painter = (__bridge RNSVGPainter *)info;
|
RNSVGPainter *_painter = (__bridge RNSVGPainter *)info;
|
||||||
RNSVGPattern *_pattern = [_painter pattern];
|
RNSVGPattern *_pattern = [_painter pattern];
|
||||||
CGRect rect = _painter.paintBounds;
|
CGRect rect = _painter.paintBounds;
|
||||||
CGFloat minX = _pattern.minX;
|
CGFloat minX = _pattern.minX;
|
||||||
CGFloat minY = _pattern.minY;
|
CGFloat minY = _pattern.minY;
|
||||||
CGFloat vbWidth = _pattern.vbWidth;
|
CGFloat vbWidth = _pattern.vbWidth;
|
||||||
CGFloat vbHeight = _pattern.vbHeight;
|
CGFloat vbHeight = _pattern.vbHeight;
|
||||||
if (vbWidth > 0 && vbHeight > 0) {
|
if (vbWidth > 0 && vbHeight > 0) {
|
||||||
CGRect vbRect = CGRectMake(minX, minY, vbWidth, vbHeight);
|
CGRect vbRect = CGRectMake(minX, minY, vbWidth, vbHeight);
|
||||||
CGAffineTransform _viewBoxTransform = [RNSVGViewBox
|
CGAffineTransform _viewBoxTransform = [RNSVGViewBox getTransform:vbRect
|
||||||
getTransform:vbRect
|
eRect:rect
|
||||||
eRect:rect
|
align:_pattern.align
|
||||||
align:_pattern.align
|
meetOrSlice:_pattern.meetOrSlice];
|
||||||
meetOrSlice:_pattern.meetOrSlice];
|
CGContextConcatCTM(context, _viewBoxTransform);
|
||||||
CGContextConcatCTM(context, _viewBoxTransform);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (_painter.useObjectBoundingBoxForContentUnits) {
|
if (_painter.useObjectBoundingBoxForContentUnits) {
|
||||||
CGRect bounds = _painter.bounds;
|
CGRect bounds = _painter.bounds;
|
||||||
CGContextConcatCTM(context, CGAffineTransformMakeScale(bounds.size.width, bounds.size.height));
|
CGContextConcatCTM(context, CGAffineTransformMakeScale(bounds.size.width, bounds.size.height));
|
||||||
}
|
}
|
||||||
|
|
||||||
[_pattern renderTo:context rect:rect];
|
[_pattern renderTo:context rect:rect];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CGFloat)getVal:(RNSVGLength*)length relative:(CGFloat)relative
|
- (CGFloat)getVal:(RNSVGLength *)length relative:(CGFloat)relative
|
||||||
{
|
{
|
||||||
RNSVGLengthUnitType unit = [length unit];
|
RNSVGLengthUnitType unit = [length unit];
|
||||||
CGFloat val = [RNSVGPropHelper fromRelative:length
|
CGFloat val = [RNSVGPropHelper fromRelative:length relative:relative];
|
||||||
relative:relative];
|
return _useObjectBoundingBox && unit == SVG_LENGTHTYPE_NUMBER ? val * relative : val;
|
||||||
return _useObjectBoundingBox &&
|
|
||||||
unit == SVG_LENGTHTYPE_NUMBER ? val * relative : val;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)paintPattern:(CGContextRef)context bounds:(CGRect)bounds
|
- (void)paintPattern:(CGContextRef)context bounds:(CGRect)bounds
|
||||||
{
|
{
|
||||||
CGRect rect = [self getPaintRect:context bounds:bounds];
|
CGRect rect = [self getPaintRect:context bounds:bounds];
|
||||||
CGFloat height = CGRectGetHeight(rect);
|
CGFloat height = CGRectGetHeight(rect);
|
||||||
CGFloat width = CGRectGetWidth(rect);
|
CGFloat width = CGRectGetWidth(rect);
|
||||||
|
|
||||||
CGFloat x = [self getVal:[_points objectAtIndex:0] relative:width];
|
CGFloat x = [self getVal:[_points objectAtIndex:0] relative:width];
|
||||||
CGFloat y = [self getVal:[_points objectAtIndex:1] relative:height];
|
CGFloat y = [self getVal:[_points objectAtIndex:1] relative:height];
|
||||||
CGFloat w = [self getVal:[_points objectAtIndex:2] relative:width];
|
CGFloat w = [self getVal:[_points objectAtIndex:2] relative:width];
|
||||||
CGFloat h = [self getVal:[_points objectAtIndex:3] relative:height];
|
CGFloat h = [self getVal:[_points objectAtIndex:3] relative:height];
|
||||||
|
|
||||||
CGAffineTransform viewbox = [self.pattern.svgView getViewBoxTransform];
|
CGAffineTransform viewbox = [self.pattern.svgView getViewBoxTransform];
|
||||||
#if TARGET_OS_OSX
|
#if TARGET_OS_OSX
|
||||||
// This is needed because macOS and iOS have different conventions for where the origin is.
|
// This is needed because macOS and iOS have different conventions for where the origin is.
|
||||||
// For macOS, it's in the bottom-left corner. For iOS, it's in the top-left corner.
|
// For macOS, it's in the bottom-left corner. For iOS, it's in the top-left corner.
|
||||||
viewbox = CGAffineTransformScale(viewbox, 1, -1);
|
viewbox = CGAffineTransformScale(viewbox, 1, -1);
|
||||||
#endif // TARGET_OS_OSX
|
#endif // TARGET_OS_OSX
|
||||||
CGRect newBounds = CGRectMake(x, y, w, h);
|
CGRect newBounds = CGRectMake(x, y, w, h);
|
||||||
CGSize size = newBounds.size;
|
CGSize size = newBounds.size;
|
||||||
self.useObjectBoundingBoxForContentUnits = _useContentObjectBoundingBox;
|
self.useObjectBoundingBoxForContentUnits = _useContentObjectBoundingBox;
|
||||||
self.paintBounds = newBounds;
|
self.paintBounds = newBounds;
|
||||||
self.bounds = rect;
|
self.bounds = rect;
|
||||||
|
|
||||||
const CGPatternCallbacks callbacks = { 0, &PatternFunction, NULL };
|
const CGPatternCallbacks callbacks = {0, &PatternFunction, NULL};
|
||||||
CGColorSpaceRef patternSpace = CGColorSpaceCreatePattern(NULL);
|
CGColorSpaceRef patternSpace = CGColorSpaceCreatePattern(NULL);
|
||||||
CGContextSetFillColorSpace(context, patternSpace);
|
CGContextSetFillColorSpace(context, patternSpace);
|
||||||
CGColorSpaceRelease(patternSpace);
|
CGColorSpaceRelease(patternSpace);
|
||||||
|
|
||||||
CGPatternRef pattern = CGPatternCreate((__bridge void * _Nullable)(self),
|
CGPatternRef pattern = CGPatternCreate(
|
||||||
newBounds,
|
(__bridge void *_Nullable)(self),
|
||||||
viewbox,
|
newBounds,
|
||||||
size.width,
|
viewbox,
|
||||||
size.height,
|
size.width,
|
||||||
kCGPatternTilingConstantSpacing,
|
size.height,
|
||||||
true,
|
kCGPatternTilingConstantSpacing,
|
||||||
&callbacks);
|
true,
|
||||||
CGFloat alpha = 1.0;
|
&callbacks);
|
||||||
CGContextSetFillPattern(context, pattern, &alpha);
|
CGFloat alpha = 1.0;
|
||||||
CGPatternRelease(pattern);
|
CGContextSetFillPattern(context, pattern, &alpha);
|
||||||
|
CGPatternRelease(pattern);
|
||||||
|
|
||||||
CGContextFillRect(context, bounds);
|
CGContextFillRect(context, bounds);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)paintLinearGradient:(CGContextRef)context bounds:(CGRect)bounds
|
- (void)paintLinearGradient:(CGContextRef)context bounds:(CGRect)bounds
|
||||||
{
|
{
|
||||||
if ([_colors count] == 0) {
|
if ([_colors count] == 0) {
|
||||||
RCTLogWarn(@"No stops in gradient");
|
RCTLogWarn(@"No stops in gradient");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
CGGradientRef gradient = CGGradientRetain([RCTConvert RNSVGCGGradient:_colors]);
|
CGGradientRef gradient = CGGradientRetain([RCTConvert RNSVGCGGradient:_colors]);
|
||||||
CGGradientDrawingOptions extendOptions = kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation;
|
CGGradientDrawingOptions extendOptions = kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation;
|
||||||
|
|
||||||
CGRect rect = [self getPaintRect:context bounds:bounds];
|
CGRect rect = [self getPaintRect:context bounds:bounds];
|
||||||
CGFloat height = CGRectGetHeight(rect);
|
CGFloat height = CGRectGetHeight(rect);
|
||||||
CGFloat width = CGRectGetWidth(rect);
|
CGFloat width = CGRectGetWidth(rect);
|
||||||
CGFloat offsetX = CGRectGetMinX(rect);
|
CGFloat offsetX = CGRectGetMinX(rect);
|
||||||
CGFloat offsetY = CGRectGetMinY(rect);
|
CGFloat offsetY = CGRectGetMinY(rect);
|
||||||
|
|
||||||
CGFloat x1 = [self getVal:[_points objectAtIndex:0] relative:width] + offsetX;
|
CGFloat x1 = [self getVal:[_points objectAtIndex:0] relative:width] + offsetX;
|
||||||
CGFloat y1 = [self getVal:[_points objectAtIndex:1] relative:height] + offsetY;
|
CGFloat y1 = [self getVal:[_points objectAtIndex:1] relative:height] + offsetY;
|
||||||
CGFloat x2 = [self getVal:[_points objectAtIndex:2] relative:width] + offsetX;
|
CGFloat x2 = [self getVal:[_points objectAtIndex:2] relative:width] + offsetX;
|
||||||
CGFloat y2 = [self getVal:[_points objectAtIndex:3] relative:height] + offsetY;
|
CGFloat y2 = [self getVal:[_points objectAtIndex:3] relative:height] + offsetY;
|
||||||
|
|
||||||
CGContextConcatCTM(context, _transform);
|
CGContextConcatCTM(context, _transform);
|
||||||
CGContextDrawLinearGradient(context, gradient, CGPointMake(x1, y1), CGPointMake(x2, y2), extendOptions);
|
CGContextDrawLinearGradient(context, gradient, CGPointMake(x1, y1), CGPointMake(x2, y2), extendOptions);
|
||||||
CGGradientRelease(gradient);
|
CGGradientRelease(gradient);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)paintRadialGradient:(CGContextRef)context bounds:(CGRect)bounds
|
- (void)paintRadialGradient:(CGContextRef)context bounds:(CGRect)bounds
|
||||||
{
|
{
|
||||||
if ([_colors count] == 0) {
|
if ([_colors count] == 0) {
|
||||||
RCTLogWarn(@"No stops in gradient");
|
RCTLogWarn(@"No stops in gradient");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
CGGradientRef gradient = CGGradientRetain([RCTConvert RNSVGCGGradient:_colors]);
|
CGGradientRef gradient = CGGradientRetain([RCTConvert RNSVGCGGradient:_colors]);
|
||||||
CGGradientDrawingOptions extendOptions = kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation;
|
CGGradientDrawingOptions extendOptions = kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation;
|
||||||
|
|
||||||
CGRect rect = [self getPaintRect:context bounds:bounds];
|
CGRect rect = [self getPaintRect:context bounds:bounds];
|
||||||
|
|
||||||
CGFloat width = CGRectGetWidth(rect);
|
CGFloat width = CGRectGetWidth(rect);
|
||||||
CGFloat height = CGRectGetHeight(rect);
|
CGFloat height = CGRectGetHeight(rect);
|
||||||
|
|
||||||
CGFloat offsetX = CGRectGetMinX(rect);
|
CGFloat offsetX = CGRectGetMinX(rect);
|
||||||
CGFloat offsetY = CGRectGetMinY(rect);
|
CGFloat offsetY = CGRectGetMinY(rect);
|
||||||
|
|
||||||
CGFloat rx = [self getVal:[_points objectAtIndex:2] relative:width];
|
CGFloat rx = [self getVal:[_points objectAtIndex:2] relative:width];
|
||||||
CGFloat ry = [self getVal:[_points objectAtIndex:3] relative:height];
|
CGFloat ry = [self getVal:[_points objectAtIndex:3] relative:height];
|
||||||
|
|
||||||
double ratio = ry / rx;
|
double ratio = ry / rx;
|
||||||
|
|
||||||
CGFloat fx = [self getVal:[_points objectAtIndex:0] relative:width] + offsetX;
|
CGFloat fx = [self getVal:[_points objectAtIndex:0] relative:width] + offsetX;
|
||||||
CGFloat fy = ([self getVal:[_points objectAtIndex:1] relative:height] + offsetY) / ratio;
|
CGFloat fy = ([self getVal:[_points objectAtIndex:1] relative:height] + offsetY) / ratio;
|
||||||
|
|
||||||
CGFloat cx = [self getVal:[_points objectAtIndex:4] relative:width] + offsetX;
|
CGFloat cx = [self getVal:[_points objectAtIndex:4] relative:width] + offsetX;
|
||||||
CGFloat cy = ([self getVal:[_points objectAtIndex:5] relative:height] + offsetY) / ratio;
|
CGFloat cy = ([self getVal:[_points objectAtIndex:5] relative:height] + offsetY) / ratio;
|
||||||
|
|
||||||
CGAffineTransform transform = CGAffineTransformMakeScale(1, ratio);
|
CGAffineTransform transform = CGAffineTransformMakeScale(1, ratio);
|
||||||
CGContextConcatCTM(context, transform);
|
CGContextConcatCTM(context, transform);
|
||||||
|
|
||||||
CGContextConcatCTM(context, _transform);
|
CGContextConcatCTM(context, _transform);
|
||||||
CGContextDrawRadialGradient(context, gradient, CGPointMake(fx, fy), 0, CGPointMake(cx, cy), rx, extendOptions);
|
CGContextDrawRadialGradient(context, gradient, CGPointMake(fx, fy), 0, CGPointMake(cx, cy), rx, extendOptions);
|
||||||
CGGradientRelease(gradient);
|
CGGradientRelease(gradient);
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|||||||
@@ -7,39 +7,38 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#import "RNSVGPainterBrush.h"
|
#import "RNSVGPainterBrush.h"
|
||||||
#import "RNSVGPainter.h"
|
|
||||||
#import "RCTConvert+RNSVG.h"
|
|
||||||
#import <React/RCTLog.h>
|
#import <React/RCTLog.h>
|
||||||
|
#import "RCTConvert+RNSVG.h"
|
||||||
|
#import "RNSVGPainter.h"
|
||||||
|
|
||||||
@implementation RNSVGPainterBrush
|
@implementation RNSVGPainterBrush
|
||||||
|
|
||||||
- (instancetype)initWithArray:(NSArray *)array
|
- (instancetype)initWithArray:(NSArray *)array
|
||||||
{
|
{
|
||||||
if ((self = [super initWithArray:array])) {
|
if ((self = [super initWithArray:array])) {
|
||||||
if (array.count != 2) {
|
if (array.count != 2) {
|
||||||
RCTLogError(@"-[%@ %@] expects 2 elements, received %@",
|
RCTLogError(@"-[%@ %@] expects 2 elements, received %@", self.class, NSStringFromSelector(_cmd), array);
|
||||||
self.class, NSStringFromSelector(_cmd), array);
|
return nil;
|
||||||
return nil;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.brushRef = [array objectAtIndex:1];
|
|
||||||
}
|
}
|
||||||
return self;
|
|
||||||
|
self.brushRef = [array objectAtIndex:1];
|
||||||
|
}
|
||||||
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)paint:(CGContextRef)context opacity:(CGFloat)opacity painter:(RNSVGPainter *)painter bounds:(CGRect)bounds
|
- (void)paint:(CGContextRef)context opacity:(CGFloat)opacity painter:(RNSVGPainter *)painter bounds:(CGRect)bounds
|
||||||
{
|
{
|
||||||
BOOL transparency = opacity < 1;
|
BOOL transparency = opacity < 1;
|
||||||
if (transparency) {
|
if (transparency) {
|
||||||
CGContextSetAlpha(context, opacity);
|
CGContextSetAlpha(context, opacity);
|
||||||
CGContextBeginTransparencyLayer(context, NULL);
|
CGContextBeginTransparencyLayer(context, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
[painter paint:context bounds:bounds];
|
[painter paint:context bounds:bounds];
|
||||||
|
|
||||||
if (transparency) {
|
if (transparency) {
|
||||||
CGContextEndTransparencyLayer(context);
|
CGContextEndTransparencyLayer(context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -9,65 +9,63 @@
|
|||||||
#import "RNSVGSolidColorBrush.h"
|
#import "RNSVGSolidColorBrush.h"
|
||||||
#import "RNSVGUIKit.h"
|
#import "RNSVGUIKit.h"
|
||||||
|
|
||||||
#import "RCTConvert+RNSVG.h"
|
|
||||||
#import <React/RCTLog.h>
|
#import <React/RCTLog.h>
|
||||||
|
#import "RCTConvert+RNSVG.h"
|
||||||
|
|
||||||
@implementation RNSVGSolidColorBrush
|
@implementation RNSVGSolidColorBrush {
|
||||||
{
|
RNSVGColor *_color;
|
||||||
RNSVGColor *_color;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (instancetype)initWithArray:(NSArray<RNSVGLength *> *)array
|
- (instancetype)initWithArray:(NSArray<RNSVGLength *> *)array
|
||||||
{
|
{
|
||||||
if ((self = [super initWithArray:array])) {
|
if ((self = [super initWithArray:array])) {
|
||||||
_color = [RCTConvert RNSVGColor:array offset:1];
|
_color = [RCTConvert RNSVGColor:array offset:1];
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (instancetype)initWithNumber:(NSNumber *)number
|
- (instancetype)initWithNumber:(NSNumber *)number
|
||||||
{
|
{
|
||||||
if ((self = [super init])) {
|
if ((self = [super init])) {
|
||||||
_color = [RCTConvert RNSVGColor:number];
|
_color = [RCTConvert RNSVGColor:number];
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (instancetype)initWithColor:(RNSVGColor *)color
|
- (instancetype)initWithColor:(RNSVGColor *)color
|
||||||
{
|
{
|
||||||
if ((self = [super init])) {
|
if ((self = [super init])) {
|
||||||
_color = color;
|
_color = color;
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (void)dealloc
|
- (void)dealloc
|
||||||
{
|
{
|
||||||
_color = nil;
|
_color = nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CGColorRef)getColorWithOpacity:(CGFloat)opacity
|
- (CGColorRef)getColorWithOpacity:(CGFloat)opacity
|
||||||
{
|
{
|
||||||
CGColorRef baseColor = _color.CGColor;
|
CGColorRef baseColor = _color.CGColor;
|
||||||
CGColorRef color = CGColorCreateCopyWithAlpha(baseColor, opacity * CGColorGetAlpha(baseColor));
|
CGColorRef color = CGColorCreateCopyWithAlpha(baseColor, opacity * CGColorGetAlpha(baseColor));
|
||||||
return color;
|
return color;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)applyFillColor:(CGContextRef)context opacity:(CGFloat)opacity
|
- (BOOL)applyFillColor:(CGContextRef)context opacity:(CGFloat)opacity
|
||||||
{
|
{
|
||||||
CGColorRef color = [self getColorWithOpacity:opacity];
|
CGColorRef color = [self getColorWithOpacity:opacity];
|
||||||
CGContextSetFillColorWithColor(context, color);
|
CGContextSetFillColorWithColor(context, color);
|
||||||
CGColorRelease(color);
|
CGColorRelease(color);
|
||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)applyStrokeColor:(CGContextRef)context opacity:(CGFloat)opacity
|
- (BOOL)applyStrokeColor:(CGContextRef)context opacity:(CGFloat)opacity
|
||||||
{
|
{
|
||||||
CGColorRef color = [self getColorWithOpacity:opacity];
|
CGColorRef color = [self getColorWithOpacity:opacity];
|
||||||
CGContextSetStrokeColorWithColor(context, color);
|
CGContextSetStrokeColorWithColor(context, color);
|
||||||
CGColorRelease(color);
|
CGColorRelease(color);
|
||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -10,9 +10,9 @@
|
|||||||
|
|
||||||
#ifdef RN_FABRIC_ENABLED
|
#ifdef RN_FABRIC_ENABLED
|
||||||
#import <react/renderer/components/rnsvg/ComponentDescriptors.h>
|
#import <react/renderer/components/rnsvg/ComponentDescriptors.h>
|
||||||
#import "RCTFabricComponentsPlugins.h"
|
|
||||||
#import "RCTConversions.h"
|
|
||||||
#import <react/renderer/components/view/conversions.h>
|
#import <react/renderer/components/view/conversions.h>
|
||||||
|
#import "RCTConversions.h"
|
||||||
|
#import "RCTFabricComponentsPlugins.h"
|
||||||
#import "RNSVGFabricConversions.h"
|
#import "RNSVGFabricConversions.h"
|
||||||
#endif // RN_FABRIC_ENABLED
|
#endif // RN_FABRIC_ENABLED
|
||||||
|
|
||||||
@@ -39,33 +39,32 @@ using namespace facebook::react;
|
|||||||
|
|
||||||
- (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps
|
- (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps
|
||||||
{
|
{
|
||||||
const auto &newProps = *std::static_pointer_cast<const RNSVGClipPathProps>(props);
|
const auto &newProps = *std::static_pointer_cast<const RNSVGClipPathProps>(props);
|
||||||
setCommonNodeProps(newProps, self);
|
setCommonNodeProps(newProps, self);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)prepareForRecycle
|
- (void)prepareForRecycle
|
||||||
{
|
{
|
||||||
[super prepareForRecycle];
|
[super prepareForRecycle];
|
||||||
}
|
}
|
||||||
#endif // RN_FABRIC_ENABLED
|
#endif // RN_FABRIC_ENABLED
|
||||||
|
|
||||||
- (void)parseReference
|
- (void)parseReference
|
||||||
{
|
{
|
||||||
self.dirty = false;
|
self.dirty = false;
|
||||||
[self.svgView defineClipPath:self clipPathName:self.name];
|
[self.svgView defineClipPath:self clipPathName:self.name];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (BOOL)isSimpleClipPath
|
- (BOOL)isSimpleClipPath
|
||||||
{
|
{
|
||||||
NSArray<RNSVGView*> *children = self.subviews;
|
NSArray<RNSVGView *> *children = self.subviews;
|
||||||
if (children.count == 1) {
|
if (children.count == 1) {
|
||||||
RNSVGView* child = children[0];
|
RNSVGView *child = children[0];
|
||||||
if ([child class] != [RNSVGGroup class]) {
|
if ([child class] != [RNSVGGroup class]) {
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return false;
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -9,9 +9,9 @@
|
|||||||
|
|
||||||
#ifdef RN_FABRIC_ENABLED
|
#ifdef RN_FABRIC_ENABLED
|
||||||
#import <react/renderer/components/rnsvg/ComponentDescriptors.h>
|
#import <react/renderer/components/rnsvg/ComponentDescriptors.h>
|
||||||
#import "RCTFabricComponentsPlugins.h"
|
|
||||||
#import "RCTConversions.h"
|
|
||||||
#import <react/renderer/components/view/conversions.h>
|
#import <react/renderer/components/view/conversions.h>
|
||||||
|
#import "RCTConversions.h"
|
||||||
|
#import "RCTFabricComponentsPlugins.h"
|
||||||
#import "RNSVGFabricConversions.h"
|
#import "RNSVGFabricConversions.h"
|
||||||
#endif // RN_FABRIC_ENABLED
|
#endif // RN_FABRIC_ENABLED
|
||||||
|
|
||||||
@@ -39,23 +39,23 @@ using namespace facebook::react;
|
|||||||
|
|
||||||
- (void)renderTo:(CGContextRef)context
|
- (void)renderTo:(CGContextRef)context
|
||||||
{
|
{
|
||||||
// Defs do not render
|
// Defs do not render
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)parseReference
|
- (void)parseReference
|
||||||
{
|
{
|
||||||
self.dirty = false;
|
self.dirty = false;
|
||||||
[self traverseSubviews:^(RNSVGNode *node) {
|
[self traverseSubviews:^(RNSVGNode *node) {
|
||||||
if ([node isKindOfClass:[RNSVGNode class]]) {
|
if ([node isKindOfClass:[RNSVGNode class]]) {
|
||||||
[node parseReference];
|
[node parseReference];
|
||||||
}
|
}
|
||||||
return YES;
|
return YES;
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (RNSVGPlatformView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
|
- (RNSVGPlatformView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
|
||||||
{
|
{
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -12,9 +12,9 @@
|
|||||||
|
|
||||||
#ifdef RN_FABRIC_ENABLED
|
#ifdef RN_FABRIC_ENABLED
|
||||||
#import <react/renderer/components/rnsvg/ComponentDescriptors.h>
|
#import <react/renderer/components/rnsvg/ComponentDescriptors.h>
|
||||||
#import "RCTFabricComponentsPlugins.h"
|
|
||||||
#import "RCTConversions.h"
|
|
||||||
#import <react/renderer/components/view/conversions.h>
|
#import <react/renderer/components/view/conversions.h>
|
||||||
|
#import "RCTConversions.h"
|
||||||
|
#import "RCTFabricComponentsPlugins.h"
|
||||||
#import "RNSVGFabricConversions.h"
|
#import "RNSVGFabricConversions.h"
|
||||||
#endif // RN_FABRIC_ENABLED
|
#endif // RN_FABRIC_ENABLED
|
||||||
|
|
||||||
@@ -41,177 +41,177 @@ using namespace facebook::react;
|
|||||||
|
|
||||||
- (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps
|
- (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps
|
||||||
{
|
{
|
||||||
const auto &newProps = *std::static_pointer_cast<const RNSVGForeignObjectProps>(props);
|
const auto &newProps = *std::static_pointer_cast<const RNSVGForeignObjectProps>(props);
|
||||||
|
|
||||||
self.x = RCTNSStringFromStringNilIfEmpty(newProps.x) ? [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.x)] : nil;
|
self.x = RCTNSStringFromStringNilIfEmpty(newProps.x)
|
||||||
self.y = RCTNSStringFromStringNilIfEmpty(newProps.y) ? [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.y)] : nil;
|
? [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.x)]
|
||||||
if (RCTNSStringFromStringNilIfEmpty(newProps.foreignObjectheight)) {
|
: nil;
|
||||||
self.foreignObjectheight = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.foreignObjectheight)];
|
self.y = RCTNSStringFromStringNilIfEmpty(newProps.y)
|
||||||
}
|
? [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.y)]
|
||||||
if (RCTNSStringFromStringNilIfEmpty(newProps.foreignObjectwidth)) {
|
: nil;
|
||||||
self.foreignObjectwidth = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.foreignObjectwidth)];
|
if (RCTNSStringFromStringNilIfEmpty(newProps.foreignObjectheight)) {
|
||||||
}
|
self.foreignObjectheight = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.foreignObjectheight)];
|
||||||
if (RCTNSStringFromStringNilIfEmpty(newProps.height)) {
|
}
|
||||||
self.foreignObjectheight = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.height)];
|
if (RCTNSStringFromStringNilIfEmpty(newProps.foreignObjectwidth)) {
|
||||||
}
|
self.foreignObjectwidth = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.foreignObjectwidth)];
|
||||||
if (RCTNSStringFromStringNilIfEmpty(newProps.width)) {
|
}
|
||||||
self.foreignObjectwidth = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.width)];
|
if (RCTNSStringFromStringNilIfEmpty(newProps.height)) {
|
||||||
}
|
self.foreignObjectheight = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.height)];
|
||||||
|
}
|
||||||
|
if (RCTNSStringFromStringNilIfEmpty(newProps.width)) {
|
||||||
|
self.foreignObjectwidth = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.width)];
|
||||||
|
}
|
||||||
|
|
||||||
setCommonGroupProps(newProps, self);
|
setCommonGroupProps(newProps, self);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)prepareForRecycle
|
- (void)prepareForRecycle
|
||||||
{
|
{
|
||||||
[super prepareForRecycle];
|
[super prepareForRecycle];
|
||||||
_x = nil;
|
_x = nil;
|
||||||
_y = nil;
|
_y = nil;
|
||||||
_foreignObjectheight = nil;
|
_foreignObjectheight = nil;
|
||||||
_foreignObjectwidth = nil;
|
_foreignObjectwidth = nil;
|
||||||
}
|
}
|
||||||
#endif // RN_FABRIC_ENABLED
|
#endif // RN_FABRIC_ENABLED
|
||||||
- (RNSVGPlatformView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
|
- (RNSVGPlatformView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
|
||||||
{
|
{
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)parseReference
|
- (void)parseReference
|
||||||
{
|
{
|
||||||
self.dirty = false;
|
self.dirty = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)renderLayerTo:(CGContextRef)context rect:(CGRect)rect
|
- (void)renderLayerTo:(CGContextRef)context rect:(CGRect)rect
|
||||||
{
|
{
|
||||||
[self clip:context];
|
[self clip:context];
|
||||||
CGContextTranslateCTM(context, [self relativeOnWidth:self.x], [self relativeOnHeight:self.y]);
|
CGContextTranslateCTM(context, [self relativeOnWidth:self.x], [self relativeOnHeight:self.y]);
|
||||||
CGRect clip = CGRectMake(
|
CGRect clip = CGRectMake(
|
||||||
0,
|
0, 0, [self relativeOnWidth:self.foreignObjectwidth], [self relativeOnHeight:self.foreignObjectheight]);
|
||||||
0,
|
CGContextClipToRect(context, clip);
|
||||||
[self relativeOnWidth:self.foreignObjectwidth],
|
[super renderLayerTo:context rect:rect];
|
||||||
[self relativeOnHeight:self.foreignObjectheight]
|
|
||||||
);
|
|
||||||
CGContextClipToRect(context, clip);
|
|
||||||
[super renderLayerTo:context rect:rect];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)renderGroupTo:(CGContextRef)context rect:(CGRect)rect
|
- (void)renderGroupTo:(CGContextRef)context rect:(CGRect)rect
|
||||||
{
|
{
|
||||||
[self pushGlyphContext];
|
[self pushGlyphContext];
|
||||||
|
|
||||||
__block CGRect bounds = CGRectNull;
|
__block CGRect bounds = CGRectNull;
|
||||||
|
|
||||||
[self traverseSubviews:^(RNSVGView *node) {
|
|
||||||
if ([node isKindOfClass:[RNSVGMask class]] || [node isKindOfClass:[RNSVGClipPath class]]) {
|
|
||||||
// no-op
|
|
||||||
} else if ([node isKindOfClass:[RNSVGNode class]]) {
|
|
||||||
RNSVGNode* svgNode = (RNSVGNode*)node;
|
|
||||||
if (svgNode.display && [@"none" isEqualToString:svgNode.display]) {
|
|
||||||
return YES;
|
|
||||||
}
|
|
||||||
if (svgNode.responsible && !self.svgView.responsible) {
|
|
||||||
self.svgView.responsible = YES;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ([node isKindOfClass:[RNSVGRenderable class]]) {
|
|
||||||
[(RNSVGRenderable*)node mergeProperties:self];
|
|
||||||
}
|
|
||||||
|
|
||||||
[svgNode renderTo:context rect:rect];
|
|
||||||
|
|
||||||
CGRect nodeRect = svgNode.clientRect;
|
|
||||||
if (!CGRectIsEmpty(nodeRect)) {
|
|
||||||
bounds = CGRectUnion(bounds, nodeRect);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ([node isKindOfClass:[RNSVGRenderable class]]) {
|
|
||||||
[(RNSVGRenderable*)node resetProperties];
|
|
||||||
}
|
|
||||||
} else if ([node isKindOfClass:[RNSVGSvgView class]]) {
|
|
||||||
RNSVGSvgView* svgView = (RNSVGSvgView*)node;
|
|
||||||
CGFloat width = [self relativeOnWidth:svgView.bbWidth];
|
|
||||||
CGFloat height = [self relativeOnHeight:svgView.bbHeight];
|
|
||||||
CGRect rect = CGRectMake(0, 0, width, height);
|
|
||||||
CGContextClipToRect(context, rect);
|
|
||||||
[svgView drawToContext:context withRect:rect];
|
|
||||||
} else {
|
|
||||||
node.hidden = false;
|
|
||||||
[node.layer renderInContext:context];
|
|
||||||
node.hidden = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
[self traverseSubviews:^(RNSVGView *node) {
|
||||||
|
if ([node isKindOfClass:[RNSVGMask class]] || [node isKindOfClass:[RNSVGClipPath class]]) {
|
||||||
|
// no-op
|
||||||
|
} else if ([node isKindOfClass:[RNSVGNode class]]) {
|
||||||
|
RNSVGNode *svgNode = (RNSVGNode *)node;
|
||||||
|
if (svgNode.display && [@"none" isEqualToString:svgNode.display]) {
|
||||||
return YES;
|
return YES;
|
||||||
}];
|
}
|
||||||
CGPathRef path = [self getPath:context];
|
if (svgNode.responsible && !self.svgView.responsible) {
|
||||||
[self setHitArea:path];
|
self.svgView.responsible = YES;
|
||||||
if (!CGRectEqualToRect(bounds, CGRectNull)) {
|
}
|
||||||
self.clientRect = bounds;
|
|
||||||
self.fillBounds = CGPathGetBoundingBox(path);
|
|
||||||
self.strokeBounds = CGPathGetBoundingBox(self.strokePath);
|
|
||||||
self.pathBounds = CGRectUnion(self.fillBounds, self.strokeBounds);
|
|
||||||
|
|
||||||
CGAffineTransform current = CGContextGetCTM(context);
|
if ([node isKindOfClass:[RNSVGRenderable class]]) {
|
||||||
CGAffineTransform svgToClientTransform = CGAffineTransformConcat(current, self.svgView.invInitialCTM);
|
[(RNSVGRenderable *)node mergeProperties:self];
|
||||||
|
}
|
||||||
|
|
||||||
self.ctm = svgToClientTransform;
|
[svgNode renderTo:context rect:rect];
|
||||||
self.screenCTM = current;
|
|
||||||
|
|
||||||
CGAffineTransform transform = CGAffineTransformConcat(self.matrix, self.transforms);
|
CGRect nodeRect = svgNode.clientRect;
|
||||||
CGPoint mid = CGPointMake(CGRectGetMidX(bounds), CGRectGetMidY(bounds));
|
if (!CGRectIsEmpty(nodeRect)) {
|
||||||
CGPoint center = CGPointApplyAffineTransform(mid, transform);
|
bounds = CGRectUnion(bounds, nodeRect);
|
||||||
|
}
|
||||||
|
|
||||||
self.bounds = bounds;
|
if ([node isKindOfClass:[RNSVGRenderable class]]) {
|
||||||
if (!isnan(center.x) && !isnan(center.y)) {
|
[(RNSVGRenderable *)node resetProperties];
|
||||||
self.center = center;
|
}
|
||||||
}
|
} else if ([node isKindOfClass:[RNSVGSvgView class]]) {
|
||||||
self.frame = bounds;
|
RNSVGSvgView *svgView = (RNSVGSvgView *)node;
|
||||||
|
CGFloat width = [self relativeOnWidth:svgView.bbWidth];
|
||||||
|
CGFloat height = [self relativeOnHeight:svgView.bbHeight];
|
||||||
|
CGRect rect = CGRectMake(0, 0, width, height);
|
||||||
|
CGContextClipToRect(context, rect);
|
||||||
|
[svgView drawToContext:context withRect:rect];
|
||||||
|
} else {
|
||||||
|
node.hidden = false;
|
||||||
|
[node.layer renderInContext:context];
|
||||||
|
node.hidden = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
[self popGlyphContext];
|
return YES;
|
||||||
|
}];
|
||||||
|
CGPathRef path = [self getPath:context];
|
||||||
|
[self setHitArea:path];
|
||||||
|
if (!CGRectEqualToRect(bounds, CGRectNull)) {
|
||||||
|
self.clientRect = bounds;
|
||||||
|
self.fillBounds = CGPathGetBoundingBox(path);
|
||||||
|
self.strokeBounds = CGPathGetBoundingBox(self.strokePath);
|
||||||
|
self.pathBounds = CGRectUnion(self.fillBounds, self.strokeBounds);
|
||||||
|
|
||||||
|
CGAffineTransform current = CGContextGetCTM(context);
|
||||||
|
CGAffineTransform svgToClientTransform = CGAffineTransformConcat(current, self.svgView.invInitialCTM);
|
||||||
|
|
||||||
|
self.ctm = svgToClientTransform;
|
||||||
|
self.screenCTM = current;
|
||||||
|
|
||||||
|
CGAffineTransform transform = CGAffineTransformConcat(self.matrix, self.transforms);
|
||||||
|
CGPoint mid = CGPointMake(CGRectGetMidX(bounds), CGRectGetMidY(bounds));
|
||||||
|
CGPoint center = CGPointApplyAffineTransform(mid, transform);
|
||||||
|
|
||||||
|
self.bounds = bounds;
|
||||||
|
if (!isnan(center.x) && !isnan(center.y)) {
|
||||||
|
self.center = center;
|
||||||
|
}
|
||||||
|
self.frame = bounds;
|
||||||
|
}
|
||||||
|
|
||||||
|
[self popGlyphContext];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)drawRect:(CGRect)rect
|
- (void)drawRect:(CGRect)rect
|
||||||
{
|
{
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setX:(RNSVGLength *)x
|
- (void)setX:(RNSVGLength *)x
|
||||||
{
|
{
|
||||||
if ([x isEqualTo:_x]) {
|
if ([x isEqualTo:_x]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_x = x;
|
_x = x;
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setY:(RNSVGLength *)y
|
- (void)setY:(RNSVGLength *)y
|
||||||
{
|
{
|
||||||
if ([y isEqualTo:_y]) {
|
if ([y isEqualTo:_y]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_y = y;
|
_y = y;
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setForeignObjectwidth:(RNSVGLength *)foreignObjectwidth
|
- (void)setForeignObjectwidth:(RNSVGLength *)foreignObjectwidth
|
||||||
{
|
{
|
||||||
if ([foreignObjectwidth isEqualTo:_foreignObjectwidth]) {
|
if ([foreignObjectwidth isEqualTo:_foreignObjectwidth]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_foreignObjectwidth = foreignObjectwidth;
|
_foreignObjectwidth = foreignObjectwidth;
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setForeignObjectheight:(RNSVGLength *)foreignObjectheight
|
- (void)setForeignObjectheight:(RNSVGLength *)foreignObjectheight
|
||||||
{
|
{
|
||||||
if ([foreignObjectheight isEqualTo:_foreignObjectheight]) {
|
if ([foreignObjectheight isEqualTo:_foreignObjectheight]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_foreignObjectheight = foreignObjectheight;
|
_foreignObjectheight = foreignObjectheight;
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -10,11 +10,11 @@
|
|||||||
|
|
||||||
#import "RNSVGUIKit.h"
|
#import "RNSVGUIKit.h"
|
||||||
|
|
||||||
#import "RNSVGContainer.h"
|
|
||||||
#import "RNSVGCGFCRule.h"
|
#import "RNSVGCGFCRule.h"
|
||||||
#import "RNSVGSvgView.h"
|
#import "RNSVGContainer.h"
|
||||||
#import "RNSVGPath.h"
|
|
||||||
#import "RNSVGGlyphContext.h"
|
#import "RNSVGGlyphContext.h"
|
||||||
|
#import "RNSVGPath.h"
|
||||||
|
#import "RNSVGSvgView.h"
|
||||||
|
|
||||||
@interface RNSVGGroup : RNSVGPath <RNSVGContainer>
|
@interface RNSVGGroup : RNSVGPath <RNSVGContainer>
|
||||||
|
|
||||||
|
|||||||
@@ -10,18 +10,16 @@
|
|||||||
#import "RNSVGClipPath.h"
|
#import "RNSVGClipPath.h"
|
||||||
#import "RNSVGMask.h"
|
#import "RNSVGMask.h"
|
||||||
|
|
||||||
|
|
||||||
#ifdef RN_FABRIC_ENABLED
|
#ifdef RN_FABRIC_ENABLED
|
||||||
#import <react/renderer/components/rnsvg/ComponentDescriptors.h>
|
#import <react/renderer/components/rnsvg/ComponentDescriptors.h>
|
||||||
#import "RCTFabricComponentsPlugins.h"
|
|
||||||
#import "RCTConversions.h"
|
|
||||||
#import <react/renderer/components/view/conversions.h>
|
#import <react/renderer/components/view/conversions.h>
|
||||||
|
#import "RCTConversions.h"
|
||||||
|
#import "RCTFabricComponentsPlugins.h"
|
||||||
#import "RNSVGFabricConversions.h"
|
#import "RNSVGFabricConversions.h"
|
||||||
#endif // RN_FABRIC_ENABLED
|
#endif // RN_FABRIC_ENABLED
|
||||||
|
|
||||||
@implementation RNSVGGroup
|
@implementation RNSVGGroup {
|
||||||
{
|
RNSVGGlyphContext *_glyphContext;
|
||||||
RNSVGGlyphContext *_glyphContext;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef RN_FABRIC_ENABLED
|
#ifdef RN_FABRIC_ENABLED
|
||||||
@@ -45,251 +43,251 @@ using namespace facebook::react;
|
|||||||
|
|
||||||
- (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps
|
- (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps
|
||||||
{
|
{
|
||||||
const auto &newProps = *std::static_pointer_cast<const RNSVGGroupProps>(props);
|
const auto &newProps = *std::static_pointer_cast<const RNSVGGroupProps>(props);
|
||||||
|
|
||||||
setCommonGroupProps(newProps, self);
|
setCommonGroupProps(newProps, self);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)prepareForRecycle
|
- (void)prepareForRecycle
|
||||||
{
|
{
|
||||||
[super prepareForRecycle];
|
[super prepareForRecycle];
|
||||||
_font = nil;
|
_font = nil;
|
||||||
_glyphContext = nil;
|
_glyphContext = nil;
|
||||||
}
|
}
|
||||||
#endif // RN_FABRIC_ENABLED
|
#endif // RN_FABRIC_ENABLED
|
||||||
|
|
||||||
- (void)setFont:(NSDictionary*)font
|
- (void)setFont:(NSDictionary *)font
|
||||||
{
|
{
|
||||||
if (font == _font) {
|
if (font == _font) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
_font = font;
|
_font = font;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)renderLayerTo:(CGContextRef)context rect:(CGRect)rect
|
- (void)renderLayerTo:(CGContextRef)context rect:(CGRect)rect
|
||||||
{
|
{
|
||||||
[self clip:context];
|
[self clip:context];
|
||||||
[self setupGlyphContext:context];
|
[self setupGlyphContext:context];
|
||||||
[self renderGroupTo:context rect:rect];
|
[self renderGroupTo:context rect:rect];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)renderGroupTo:(CGContextRef)context rect:(CGRect)rect
|
- (void)renderGroupTo:(CGContextRef)context rect:(CGRect)rect
|
||||||
{
|
{
|
||||||
[self pushGlyphContext];
|
[self pushGlyphContext];
|
||||||
|
|
||||||
__block CGRect bounds = CGRectNull;
|
__block CGRect bounds = CGRectNull;
|
||||||
|
|
||||||
[self traverseSubviews:^(RNSVGView *node) {
|
|
||||||
if ([node isKindOfClass:[RNSVGMask class]] || [node isKindOfClass:[RNSVGClipPath class]]) {
|
|
||||||
// no-op
|
|
||||||
} else if ([node isKindOfClass:[RNSVGNode class]]) {
|
|
||||||
RNSVGNode* svgNode = (RNSVGNode*)node;
|
|
||||||
if (svgNode.display && [@"none" isEqualToString:svgNode.display]) {
|
|
||||||
return YES;
|
|
||||||
}
|
|
||||||
if (svgNode.responsible && !self.svgView.responsible) {
|
|
||||||
self.svgView.responsible = YES;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ([node isKindOfClass:[RNSVGRenderable class]]) {
|
|
||||||
[(RNSVGRenderable*)node mergeProperties:self];
|
|
||||||
}
|
|
||||||
|
|
||||||
[svgNode renderTo:context rect:rect];
|
|
||||||
|
|
||||||
CGRect nodeRect = svgNode.clientRect;
|
|
||||||
if (!CGRectIsEmpty(nodeRect)) {
|
|
||||||
bounds = CGRectUnion(bounds, nodeRect);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ([node isKindOfClass:[RNSVGRenderable class]]) {
|
|
||||||
[(RNSVGRenderable*)node resetProperties];
|
|
||||||
}
|
|
||||||
} else if ([node isKindOfClass:[RNSVGSvgView class]]) {
|
|
||||||
RNSVGSvgView* svgView = (RNSVGSvgView*)node;
|
|
||||||
CGFloat width = [self relativeOnWidth:svgView.bbWidth];
|
|
||||||
CGFloat height = [self relativeOnHeight:svgView.bbHeight];
|
|
||||||
CGRect rect = CGRectMake(0, 0, width, height);
|
|
||||||
CGContextClipToRect(context, rect);
|
|
||||||
[svgView drawToContext:context withRect:rect];
|
|
||||||
} else {
|
|
||||||
[node drawRect:rect];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
[self traverseSubviews:^(RNSVGView *node) {
|
||||||
|
if ([node isKindOfClass:[RNSVGMask class]] || [node isKindOfClass:[RNSVGClipPath class]]) {
|
||||||
|
// no-op
|
||||||
|
} else if ([node isKindOfClass:[RNSVGNode class]]) {
|
||||||
|
RNSVGNode *svgNode = (RNSVGNode *)node;
|
||||||
|
if (svgNode.display && [@"none" isEqualToString:svgNode.display]) {
|
||||||
return YES;
|
return YES;
|
||||||
}];
|
}
|
||||||
CGPathRef path = [self getPath:context];
|
if (svgNode.responsible && !self.svgView.responsible) {
|
||||||
[self setHitArea:path];
|
self.svgView.responsible = YES;
|
||||||
if (!CGRectEqualToRect(bounds, CGRectNull)) {
|
}
|
||||||
self.clientRect = bounds;
|
|
||||||
self.fillBounds = CGPathGetBoundingBox(path);
|
|
||||||
self.strokeBounds = CGPathGetBoundingBox(self.strokePath);
|
|
||||||
self.pathBounds = CGRectUnion(self.fillBounds, self.strokeBounds);
|
|
||||||
|
|
||||||
CGAffineTransform current = CGContextGetCTM(context);
|
if ([node isKindOfClass:[RNSVGRenderable class]]) {
|
||||||
CGAffineTransform svgToClientTransform = CGAffineTransformConcat(current, self.svgView.invInitialCTM);
|
[(RNSVGRenderable *)node mergeProperties:self];
|
||||||
|
}
|
||||||
|
|
||||||
self.ctm = svgToClientTransform;
|
[svgNode renderTo:context rect:rect];
|
||||||
self.screenCTM = current;
|
|
||||||
|
|
||||||
CGAffineTransform transform = CGAffineTransformConcat(self.matrix, self.transforms);
|
CGRect nodeRect = svgNode.clientRect;
|
||||||
CGPoint mid = CGPointMake(CGRectGetMidX(bounds), CGRectGetMidY(bounds));
|
if (!CGRectIsEmpty(nodeRect)) {
|
||||||
CGPoint center = CGPointApplyAffineTransform(mid, transform);
|
bounds = CGRectUnion(bounds, nodeRect);
|
||||||
|
}
|
||||||
|
|
||||||
self.bounds = bounds;
|
if ([node isKindOfClass:[RNSVGRenderable class]]) {
|
||||||
if (!isnan(center.x) && !isnan(center.y)) {
|
[(RNSVGRenderable *)node resetProperties];
|
||||||
self.center = center;
|
}
|
||||||
}
|
} else if ([node isKindOfClass:[RNSVGSvgView class]]) {
|
||||||
self.frame = bounds;
|
RNSVGSvgView *svgView = (RNSVGSvgView *)node;
|
||||||
|
CGFloat width = [self relativeOnWidth:svgView.bbWidth];
|
||||||
|
CGFloat height = [self relativeOnHeight:svgView.bbHeight];
|
||||||
|
CGRect rect = CGRectMake(0, 0, width, height);
|
||||||
|
CGContextClipToRect(context, rect);
|
||||||
|
[svgView drawToContext:context withRect:rect];
|
||||||
|
} else {
|
||||||
|
[node drawRect:rect];
|
||||||
}
|
}
|
||||||
|
|
||||||
[self popGlyphContext];
|
return YES;
|
||||||
|
}];
|
||||||
|
CGPathRef path = [self getPath:context];
|
||||||
|
[self setHitArea:path];
|
||||||
|
if (!CGRectEqualToRect(bounds, CGRectNull)) {
|
||||||
|
self.clientRect = bounds;
|
||||||
|
self.fillBounds = CGPathGetBoundingBox(path);
|
||||||
|
self.strokeBounds = CGPathGetBoundingBox(self.strokePath);
|
||||||
|
self.pathBounds = CGRectUnion(self.fillBounds, self.strokeBounds);
|
||||||
|
|
||||||
|
CGAffineTransform current = CGContextGetCTM(context);
|
||||||
|
CGAffineTransform svgToClientTransform = CGAffineTransformConcat(current, self.svgView.invInitialCTM);
|
||||||
|
|
||||||
|
self.ctm = svgToClientTransform;
|
||||||
|
self.screenCTM = current;
|
||||||
|
|
||||||
|
CGAffineTransform transform = CGAffineTransformConcat(self.matrix, self.transforms);
|
||||||
|
CGPoint mid = CGPointMake(CGRectGetMidX(bounds), CGRectGetMidY(bounds));
|
||||||
|
CGPoint center = CGPointApplyAffineTransform(mid, transform);
|
||||||
|
|
||||||
|
self.bounds = bounds;
|
||||||
|
if (!isnan(center.x) && !isnan(center.y)) {
|
||||||
|
self.center = center;
|
||||||
|
}
|
||||||
|
self.frame = bounds;
|
||||||
|
}
|
||||||
|
|
||||||
|
[self popGlyphContext];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setupGlyphContext:(CGContextRef)context
|
- (void)setupGlyphContext:(CGContextRef)context
|
||||||
{
|
{
|
||||||
CGRect clipBounds = CGContextGetClipBoundingBox(context);
|
CGRect clipBounds = CGContextGetClipBoundingBox(context);
|
||||||
clipBounds = CGRectApplyAffineTransform(clipBounds, self.matrix);
|
clipBounds = CGRectApplyAffineTransform(clipBounds, self.matrix);
|
||||||
clipBounds = CGRectApplyAffineTransform(clipBounds, self.transforms);
|
clipBounds = CGRectApplyAffineTransform(clipBounds, self.transforms);
|
||||||
CGFloat width = CGRectGetWidth(clipBounds);
|
CGFloat width = CGRectGetWidth(clipBounds);
|
||||||
CGFloat height = CGRectGetHeight(clipBounds);
|
CGFloat height = CGRectGetHeight(clipBounds);
|
||||||
|
|
||||||
_glyphContext = [[RNSVGGlyphContext alloc] initWithWidth:width
|
_glyphContext = [[RNSVGGlyphContext alloc] initWithWidth:width height:height];
|
||||||
height:height];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (RNSVGGlyphContext *)getGlyphContext
|
- (RNSVGGlyphContext *)getGlyphContext
|
||||||
{
|
{
|
||||||
return _glyphContext;
|
return _glyphContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)pushGlyphContext
|
- (void)pushGlyphContext
|
||||||
{
|
{
|
||||||
__typeof__(self) __weak weakSelf = self;
|
__typeof__(self) __weak weakSelf = self;
|
||||||
[[self.textRoot getGlyphContext] pushContext:weakSelf font:self.font];
|
[[self.textRoot getGlyphContext] pushContext:weakSelf font:self.font];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)popGlyphContext
|
- (void)popGlyphContext
|
||||||
{
|
{
|
||||||
[[self.textRoot getGlyphContext] popContext];
|
[[self.textRoot getGlyphContext] popContext];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)renderPathTo:(CGContextRef)context rect:(CGRect)rect
|
- (void)renderPathTo:(CGContextRef)context rect:(CGRect)rect
|
||||||
{
|
{
|
||||||
[super renderLayerTo:context rect:rect];
|
[super renderLayerTo:context rect:rect];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CGPathRef)getPath:(CGContextRef)context
|
- (CGPathRef)getPath:(CGContextRef)context
|
||||||
{
|
{
|
||||||
CGPathRef cached = self.path;
|
CGPathRef cached = self.path;
|
||||||
if (cached) {
|
if (cached) {
|
||||||
return cached;
|
|
||||||
}
|
|
||||||
CGMutablePathRef __block path = CGPathCreateMutable();
|
|
||||||
[self traverseSubviews:^(RNSVGNode *node) {
|
|
||||||
if ([node isKindOfClass:[RNSVGNode class]] && ![node isKindOfClass:[RNSVGMask class]]) {
|
|
||||||
CGAffineTransform transform = CGAffineTransformConcat(node.matrix, node.transforms);
|
|
||||||
CGPathAddPath(path, &transform, [node getPath:context]);
|
|
||||||
CGPathAddPath(path, &transform, [node markerPath]);
|
|
||||||
node.dirty = false;
|
|
||||||
}
|
|
||||||
return YES;
|
|
||||||
}];
|
|
||||||
|
|
||||||
cached = CGPathRetain((CGPathRef)CFAutorelease(path));
|
|
||||||
self.path = cached;
|
|
||||||
return cached;
|
return cached;
|
||||||
|
}
|
||||||
|
CGMutablePathRef __block path = CGPathCreateMutable();
|
||||||
|
[self traverseSubviews:^(RNSVGNode *node) {
|
||||||
|
if ([node isKindOfClass:[RNSVGNode class]] && ![node isKindOfClass:[RNSVGMask class]]) {
|
||||||
|
CGAffineTransform transform = CGAffineTransformConcat(node.matrix, node.transforms);
|
||||||
|
CGPathAddPath(path, &transform, [node getPath:context]);
|
||||||
|
CGPathAddPath(path, &transform, [node markerPath]);
|
||||||
|
node.dirty = false;
|
||||||
|
}
|
||||||
|
return YES;
|
||||||
|
}];
|
||||||
|
|
||||||
|
cached = CGPathRetain((CGPathRef)CFAutorelease(path));
|
||||||
|
self.path = cached;
|
||||||
|
return cached;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (RNSVGPlatformView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
|
- (RNSVGPlatformView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
|
||||||
{
|
{
|
||||||
CGPoint transformed = CGPointApplyAffineTransform(point, self.invmatrix);
|
CGPoint transformed = CGPointApplyAffineTransform(point, self.invmatrix);
|
||||||
transformed = CGPointApplyAffineTransform(transformed, self.invTransform);
|
transformed = CGPointApplyAffineTransform(transformed, self.invTransform);
|
||||||
|
|
||||||
if (!CGRectContainsPoint(self.pathBounds, transformed)) {
|
|
||||||
return nil;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (self.clipPath) {
|
|
||||||
RNSVGClipPath *clipNode = (RNSVGClipPath*)[self.svgView getDefinedClipPath:self.clipPath];
|
|
||||||
if ([clipNode isSimpleClipPath]) {
|
|
||||||
CGPathRef clipPath = [self getClipPath];
|
|
||||||
if (clipPath && !CGPathContainsPoint(clipPath, nil, transformed, clipNode.clipRule == kRNSVGCGFCRuleEvenodd)) {
|
|
||||||
return nil;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
RNSVGRenderable *clipGroup = (RNSVGRenderable*)clipNode;
|
|
||||||
if (![clipGroup hitTest:transformed withEvent:event]) {
|
|
||||||
return nil;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!event) {
|
|
||||||
NSPredicate *const anyActive = [NSPredicate predicateWithFormat:@"self isKindOfClass: %@ AND active == TRUE", [RNSVGNode class]];
|
|
||||||
NSArray *const filtered = [self.subviews filteredArrayUsingPredicate:anyActive];
|
|
||||||
if ([filtered count] != 0) {
|
|
||||||
return [filtered.lastObject hitTest:transformed withEvent:event];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (RNSVGView *node in [self.subviews reverseObjectEnumerator]) {
|
|
||||||
if ([node isKindOfClass:[RNSVGNode class]]) {
|
|
||||||
if ([node isKindOfClass:[RNSVGMask class]]) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
RNSVGNode* svgNode = (RNSVGNode*)node;
|
|
||||||
if (event) {
|
|
||||||
svgNode.active = NO;
|
|
||||||
}
|
|
||||||
RNSVGPlatformView *hitChild = [svgNode hitTest:transformed withEvent:event];
|
|
||||||
if (hitChild) {
|
|
||||||
svgNode.active = YES;
|
|
||||||
return (svgNode.responsible || (svgNode != hitChild)) ? hitChild : self;
|
|
||||||
}
|
|
||||||
} else if ([node isKindOfClass:[RNSVGSvgView class]]) {
|
|
||||||
RNSVGSvgView* svgView = (RNSVGSvgView*)node;
|
|
||||||
RNSVGPlatformView *hitChild = [svgView hitTest:transformed withEvent:event];
|
|
||||||
if (hitChild) {
|
|
||||||
return hitChild;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
RNSVGPlatformView *hitSelf = [super hitTest:transformed withEvent:event];
|
|
||||||
if (hitSelf) {
|
|
||||||
return hitSelf;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (!CGRectContainsPoint(self.pathBounds, transformed)) {
|
||||||
return nil;
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self.clipPath) {
|
||||||
|
RNSVGClipPath *clipNode = (RNSVGClipPath *)[self.svgView getDefinedClipPath:self.clipPath];
|
||||||
|
if ([clipNode isSimpleClipPath]) {
|
||||||
|
CGPathRef clipPath = [self getClipPath];
|
||||||
|
if (clipPath && !CGPathContainsPoint(clipPath, nil, transformed, clipNode.clipRule == kRNSVGCGFCRuleEvenodd)) {
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
RNSVGRenderable *clipGroup = (RNSVGRenderable *)clipNode;
|
||||||
|
if (![clipGroup hitTest:transformed withEvent:event]) {
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!event) {
|
||||||
|
NSPredicate *const anyActive =
|
||||||
|
[NSPredicate predicateWithFormat:@"self isKindOfClass: %@ AND active == TRUE", [RNSVGNode class]];
|
||||||
|
NSArray *const filtered = [self.subviews filteredArrayUsingPredicate:anyActive];
|
||||||
|
if ([filtered count] != 0) {
|
||||||
|
return [filtered.lastObject hitTest:transformed withEvent:event];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (RNSVGView *node in [self.subviews reverseObjectEnumerator]) {
|
||||||
|
if ([node isKindOfClass:[RNSVGNode class]]) {
|
||||||
|
if ([node isKindOfClass:[RNSVGMask class]]) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
RNSVGNode *svgNode = (RNSVGNode *)node;
|
||||||
|
if (event) {
|
||||||
|
svgNode.active = NO;
|
||||||
|
}
|
||||||
|
RNSVGPlatformView *hitChild = [svgNode hitTest:transformed withEvent:event];
|
||||||
|
if (hitChild) {
|
||||||
|
svgNode.active = YES;
|
||||||
|
return (svgNode.responsible || (svgNode != hitChild)) ? hitChild : self;
|
||||||
|
}
|
||||||
|
} else if ([node isKindOfClass:[RNSVGSvgView class]]) {
|
||||||
|
RNSVGSvgView *svgView = (RNSVGSvgView *)node;
|
||||||
|
RNSVGPlatformView *hitChild = [svgView hitTest:transformed withEvent:event];
|
||||||
|
if (hitChild) {
|
||||||
|
return hitChild;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RNSVGPlatformView *hitSelf = [super hitTest:transformed withEvent:event];
|
||||||
|
if (hitSelf) {
|
||||||
|
return hitSelf;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)parseReference
|
- (void)parseReference
|
||||||
{
|
{
|
||||||
self.dirty = false;
|
self.dirty = false;
|
||||||
if (self.name) {
|
if (self.name) {
|
||||||
__typeof__(self) __weak weakSelf = self;
|
__typeof__(self) __weak weakSelf = self;
|
||||||
[self.svgView defineTemplate:weakSelf templateName:self.name];
|
[self.svgView defineTemplate:weakSelf templateName:self.name];
|
||||||
}
|
}
|
||||||
|
|
||||||
[self traverseSubviews:^(RNSVGNode *node) {
|
[self traverseSubviews:^(RNSVGNode *node) {
|
||||||
if ([node isKindOfClass:[RNSVGNode class]]) {
|
if ([node isKindOfClass:[RNSVGNode class]]) {
|
||||||
[node parseReference];
|
[node parseReference];
|
||||||
}
|
}
|
||||||
return YES;
|
return YES;
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)resetProperties
|
- (void)resetProperties
|
||||||
{
|
{
|
||||||
[self traverseSubviews:^(__kindof RNSVGNode *node) {
|
[self traverseSubviews:^(__kindof RNSVGNode *node) {
|
||||||
if ([node isKindOfClass:[RNSVGRenderable class]]) {
|
if ([node isKindOfClass:[RNSVGRenderable class]]) {
|
||||||
[(RNSVGRenderable*)node resetProperties];
|
[(RNSVGRenderable *)node resetProperties];
|
||||||
}
|
}
|
||||||
return YES;
|
return YES;
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -9,9 +9,9 @@
|
|||||||
#import <Foundation/Foundation.h>
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
#import <React/RCTBridge.h>
|
#import <React/RCTBridge.h>
|
||||||
|
#import "RNSVGLength.h"
|
||||||
#import "RNSVGRenderable.h"
|
#import "RNSVGRenderable.h"
|
||||||
#import "RNSVGVBMOS.h"
|
#import "RNSVGVBMOS.h"
|
||||||
#import "RNSVGLength.h"
|
|
||||||
|
|
||||||
#import <React/RCTImageSource.h>
|
#import <React/RCTImageSource.h>
|
||||||
|
|
||||||
@@ -19,10 +19,10 @@
|
|||||||
|
|
||||||
@property (nonatomic, weak) RCTBridge *bridge;
|
@property (nonatomic, weak) RCTBridge *bridge;
|
||||||
@property (nonatomic, assign) id src;
|
@property (nonatomic, assign) id src;
|
||||||
@property (nonatomic, strong) RNSVGLength* x;
|
@property (nonatomic, strong) RNSVGLength *x;
|
||||||
@property (nonatomic, strong) RNSVGLength* y;
|
@property (nonatomic, strong) RNSVGLength *y;
|
||||||
@property (nonatomic, strong) RNSVGLength* imagewidth;
|
@property (nonatomic, strong) RNSVGLength *imagewidth;
|
||||||
@property (nonatomic, strong) RNSVGLength* imageheight;
|
@property (nonatomic, strong) RNSVGLength *imageheight;
|
||||||
@property (nonatomic, strong) NSString *align;
|
@property (nonatomic, strong) NSString *align;
|
||||||
@property (nonatomic, assign) RNSVGVBMOS meetOrSlice;
|
@property (nonatomic, assign) RNSVGVBMOS meetOrSlice;
|
||||||
|
|
||||||
|
|||||||
@@ -15,25 +15,25 @@
|
|||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
#import <React/RCTImageURLLoader.h>
|
|
||||||
#import <React/RCTImageShadowView.h>
|
|
||||||
#import <React/RCTImageView.h>
|
|
||||||
#import <React/RCTImageLoaderProtocol.h>
|
#import <React/RCTImageLoaderProtocol.h>
|
||||||
|
#import <React/RCTImageShadowView.h>
|
||||||
|
#import <React/RCTImageURLLoader.h>
|
||||||
|
#import <React/RCTImageView.h>
|
||||||
|
|
||||||
#endif // RN_FABRIC_ENABLED
|
#endif // RN_FABRIC_ENABLED
|
||||||
|
|
||||||
#import <React/RCTLog.h>
|
#import <React/RCTLog.h>
|
||||||
#import "RNSVGViewBox.h"
|
|
||||||
#import "RCTBridge.h"
|
#import "RCTBridge.h"
|
||||||
|
#import "RNSVGViewBox.h"
|
||||||
|
|
||||||
#ifdef RN_FABRIC_ENABLED
|
#ifdef RN_FABRIC_ENABLED
|
||||||
#import <react/renderer/components/rnsvg/ComponentDescriptors.h>
|
#import <react/renderer/components/rnsvg/ComponentDescriptors.h>
|
||||||
#import "RCTFabricComponentsPlugins.h"
|
|
||||||
#import "RCTConversions.h"
|
|
||||||
#import <react/renderer/components/view/conversions.h>
|
#import <react/renderer/components/view/conversions.h>
|
||||||
#import "RNSVGFabricConversions.h"
|
#import "RCTConversions.h"
|
||||||
|
#import "RCTFabricComponentsPlugins.h"
|
||||||
#import "RCTImagePrimitivesConversions.h"
|
#import "RCTImagePrimitivesConversions.h"
|
||||||
#import "RCTImageSource.h"
|
#import "RCTImageSource.h"
|
||||||
|
#import "RNSVGFabricConversions.h"
|
||||||
|
|
||||||
// Some RN private method hacking below similar to how it is done in RNScreens:
|
// Some RN private method hacking below similar to how it is done in RNScreens:
|
||||||
// https://github.com/software-mansion/react-native-screens/blob/90e548739f35b5ded2524a9d6410033fc233f586/ios/RNSScreenStackHeaderConfig.mm#L30
|
// https://github.com/software-mansion/react-native-screens/blob/90e548739f35b5ded2524a9d6410033fc233f586/ios/RNSScreenStackHeaderConfig.mm#L30
|
||||||
@@ -43,11 +43,10 @@
|
|||||||
|
|
||||||
#endif // RN_FABRIC_ENABLED
|
#endif // RN_FABRIC_ENABLED
|
||||||
|
|
||||||
@implementation RNSVGImage
|
@implementation RNSVGImage {
|
||||||
{
|
CGImageRef _image;
|
||||||
CGImageRef _image;
|
CGSize _imageSize;
|
||||||
CGSize _imageSize;
|
RCTImageLoaderCancellationBlock _reloadImageCancellationBlock;
|
||||||
RCTImageLoaderCancellationBlock _reloadImageCancellationBlock;
|
|
||||||
}
|
}
|
||||||
#ifdef RN_FABRIC_ENABLED
|
#ifdef RN_FABRIC_ENABLED
|
||||||
using namespace facebook::react;
|
using namespace facebook::react;
|
||||||
@@ -71,104 +70,106 @@ using namespace facebook::react;
|
|||||||
- (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps
|
- (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps
|
||||||
{
|
{
|
||||||
const auto &newProps = *std::static_pointer_cast<const RNSVGImageProps>(props);
|
const auto &newProps = *std::static_pointer_cast<const RNSVGImageProps>(props);
|
||||||
const auto &oldImageProps = *std::static_pointer_cast<const RNSVGImageProps>(oldProps);
|
const auto &oldImageProps = *std::static_pointer_cast<const RNSVGImageProps>(oldProps);
|
||||||
|
|
||||||
self.x = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.x)];
|
self.x = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.x)];
|
||||||
self.y = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.y)];
|
self.y = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.y)];
|
||||||
if (RCTNSStringFromStringNilIfEmpty(newProps.imageheight)) {
|
if (RCTNSStringFromStringNilIfEmpty(newProps.imageheight)) {
|
||||||
self.imageheight = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.imageheight)];
|
self.imageheight = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.imageheight)];
|
||||||
}
|
}
|
||||||
if (RCTNSStringFromStringNilIfEmpty(newProps.imagewidth)) {
|
if (RCTNSStringFromStringNilIfEmpty(newProps.imagewidth)) {
|
||||||
self.imagewidth = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.imagewidth)];
|
self.imagewidth = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.imagewidth)];
|
||||||
}
|
}
|
||||||
if (RCTNSStringFromStringNilIfEmpty(newProps.height)) {
|
if (RCTNSStringFromStringNilIfEmpty(newProps.height)) {
|
||||||
self.imageheight = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.height)];
|
self.imageheight = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.height)];
|
||||||
}
|
}
|
||||||
if (RCTNSStringFromStringNilIfEmpty(newProps.width)) {
|
if (RCTNSStringFromStringNilIfEmpty(newProps.width)) {
|
||||||
self.imagewidth = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.width)];
|
self.imagewidth = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.width)];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (oldProps == nullptr || oldImageProps.src != newProps.src) {
|
if (oldProps == nullptr || oldImageProps.src != newProps.src) {
|
||||||
// TODO: make it the same as in e.g. slider
|
// TODO: make it the same as in e.g. slider
|
||||||
NSURLRequest *request = NSURLRequestFromImageSource(newProps.src);
|
NSURLRequest *request = NSURLRequestFromImageSource(newProps.src);
|
||||||
CGSize size = RCTCGSizeFromSize(newProps.src.size);
|
CGSize size = RCTCGSizeFromSize(newProps.src.size);
|
||||||
CGFloat scale = newProps.src.scale;
|
CGFloat scale = newProps.src.scale;
|
||||||
RCTImageSource *imageSource = [[RCTImageSource alloc] initWithURLRequest:request size:size scale:scale];
|
RCTImageSource *imageSource = [[RCTImageSource alloc] initWithURLRequest:request size:size scale:scale];
|
||||||
[self setImageSrc:imageSource request:request];
|
[self setImageSrc:imageSource request:request];
|
||||||
}
|
}
|
||||||
self.align = RCTNSStringFromStringNilIfEmpty(newProps.align);
|
self.align = RCTNSStringFromStringNilIfEmpty(newProps.align);
|
||||||
self.meetOrSlice = intToRNSVGVBMOS(newProps.meetOrSlice);
|
self.meetOrSlice = intToRNSVGVBMOS(newProps.meetOrSlice);
|
||||||
|
|
||||||
setCommonRenderableProps(newProps, self);
|
setCommonRenderableProps(newProps, self);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)prepareForRecycle
|
- (void)prepareForRecycle
|
||||||
{
|
{
|
||||||
[super prepareForRecycle];
|
[super prepareForRecycle];
|
||||||
_x = nil;
|
_x = nil;
|
||||||
_y = nil;
|
_y = nil;
|
||||||
_imageheight = nil;
|
_imageheight = nil;
|
||||||
_imagewidth = nil;
|
_imagewidth = nil;
|
||||||
_src = nil;
|
_src = nil;
|
||||||
_align = nil;
|
_align = nil;
|
||||||
_meetOrSlice = kRNSVGVBMOSMeet;
|
_meetOrSlice = kRNSVGVBMOSMeet;
|
||||||
|
|
||||||
if (_image) {
|
if (_image) {
|
||||||
CGImageRelease(_image);
|
CGImageRelease(_image);
|
||||||
}
|
}
|
||||||
_image = nil;
|
_image = nil;
|
||||||
_imageSize = CGSizeZero;
|
_imageSize = CGSizeZero;
|
||||||
_reloadImageCancellationBlock = nil;
|
_reloadImageCancellationBlock = nil;
|
||||||
}
|
}
|
||||||
#endif // RN_FABRIC_ENABLED
|
#endif // RN_FABRIC_ENABLED
|
||||||
|
|
||||||
- (void)setSrc:(id)src
|
- (void)setSrc:(id)src
|
||||||
{
|
{
|
||||||
if (src == _src) {
|
if (src == _src) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_src = src;
|
_src = src;
|
||||||
CGImageRelease(_image);
|
CGImageRelease(_image);
|
||||||
_image = nil;
|
_image = nil;
|
||||||
RCTImageSource *source = [RCTConvert RCTImageSource:src];
|
RCTImageSource *source = [RCTConvert RCTImageSource:src];
|
||||||
if (source.size.width != 0 && source.size.height != 0) {
|
if (source.size.width != 0 && source.size.height != 0) {
|
||||||
_imageSize = source.size;
|
_imageSize = source.size;
|
||||||
} else {
|
} else {
|
||||||
_imageSize = CGSizeMake(0, 0);
|
_imageSize = CGSizeMake(0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
RCTImageLoaderCancellationBlock previousCancellationBlock = _reloadImageCancellationBlock;
|
RCTImageLoaderCancellationBlock previousCancellationBlock = _reloadImageCancellationBlock;
|
||||||
if (previousCancellationBlock) {
|
if (previousCancellationBlock) {
|
||||||
previousCancellationBlock();
|
previousCancellationBlock();
|
||||||
_reloadImageCancellationBlock = nil;
|
_reloadImageCancellationBlock = nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
_reloadImageCancellationBlock = [[self.bridge moduleForName:@"ImageLoader"] loadImageWithURLRequest:[RCTConvert NSURLRequest:src] callback:^(NSError *error, UIImage *image) {
|
_reloadImageCancellationBlock = [[self.bridge moduleForName:@"ImageLoader"]
|
||||||
dispatch_async(dispatch_get_main_queue(), ^{
|
loadImageWithURLRequest:[RCTConvert NSURLRequest:src]
|
||||||
self->_image = CGImageRetain(image.CGImage);
|
callback:^(NSError *error, UIImage *image) {
|
||||||
self->_imageSize = CGSizeMake(CGImageGetWidth(self->_image), CGImageGetHeight(self->_image));
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
[self invalidate];
|
self->_image = CGImageRetain(image.CGImage);
|
||||||
});
|
self->_imageSize = CGSizeMake(CGImageGetWidth(self->_image), CGImageGetHeight(self->_image));
|
||||||
}];
|
[self invalidate];
|
||||||
|
});
|
||||||
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setImageSrc:(RCTImageSource *)source request:(NSURLRequest *)request
|
- (void)setImageSrc:(RCTImageSource *)source request:(NSURLRequest *)request
|
||||||
{
|
{
|
||||||
CGImageRelease(_image);
|
CGImageRelease(_image);
|
||||||
_image = nil;
|
_image = nil;
|
||||||
if (source.size.width != 0 && source.size.height != 0) {
|
if (source.size.width != 0 && source.size.height != 0) {
|
||||||
_imageSize = source.size;
|
_imageSize = source.size;
|
||||||
} else {
|
} else {
|
||||||
_imageSize = CGSizeMake(0, 0);
|
_imageSize = CGSizeMake(0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
RCTImageLoaderCancellationBlock previousCancellationBlock = _reloadImageCancellationBlock;
|
RCTImageLoaderCancellationBlock previousCancellationBlock = _reloadImageCancellationBlock;
|
||||||
if (previousCancellationBlock) {
|
if (previousCancellationBlock) {
|
||||||
previousCancellationBlock();
|
previousCancellationBlock();
|
||||||
_reloadImageCancellationBlock = nil;
|
_reloadImageCancellationBlock = nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
_reloadImageCancellationBlock = [[
|
_reloadImageCancellationBlock = [[
|
||||||
#ifdef RN_FABRIC_ENABLED
|
#ifdef RN_FABRIC_ENABLED
|
||||||
[RCTBridge currentBridge]
|
[RCTBridge currentBridge]
|
||||||
#else
|
#else
|
||||||
@@ -185,130 +186,133 @@ using namespace facebook::react;
|
|||||||
|
|
||||||
- (void)setX:(RNSVGLength *)x
|
- (void)setX:(RNSVGLength *)x
|
||||||
{
|
{
|
||||||
if ([x isEqualTo:_x]) {
|
if ([x isEqualTo:_x]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
_x = x;
|
_x = x;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setY:(RNSVGLength *)y
|
- (void)setY:(RNSVGLength *)y
|
||||||
{
|
{
|
||||||
if ([y isEqualTo:_y]) {
|
if ([y isEqualTo:_y]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
_y = y;
|
_y = y;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setImagewidth:(RNSVGLength *)width
|
- (void)setImagewidth:(RNSVGLength *)width
|
||||||
{
|
{
|
||||||
if ([width isEqualTo:_imagewidth]) {
|
if ([width isEqualTo:_imagewidth]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
_imagewidth = width;
|
_imagewidth = width;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setImageheight:(RNSVGLength *)height
|
- (void)setImageheight:(RNSVGLength *)height
|
||||||
{
|
{
|
||||||
if ([height isEqualTo:_imageheight]) {
|
if ([height isEqualTo:_imageheight]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
_imageheight = height;
|
_imageheight = height;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setAlign:(NSString *)align
|
- (void)setAlign:(NSString *)align
|
||||||
{
|
{
|
||||||
if ([align isEqualToString:_align]) {
|
if ([align isEqualToString:_align]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
_align = align;
|
_align = align;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setMeetOrSlice:(RNSVGVBMOS)meetOrSlice
|
- (void)setMeetOrSlice:(RNSVGVBMOS)meetOrSlice
|
||||||
{
|
{
|
||||||
if (meetOrSlice == _meetOrSlice) {
|
if (meetOrSlice == _meetOrSlice) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
_meetOrSlice = meetOrSlice;
|
_meetOrSlice = meetOrSlice;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)dealloc
|
- (void)dealloc
|
||||||
{
|
{
|
||||||
CGImageRelease(_image);
|
CGImageRelease(_image);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)renderLayerTo:(CGContextRef)context rect:(CGRect)rect
|
- (void)renderLayerTo:(CGContextRef)context rect:(CGRect)rect
|
||||||
{
|
{
|
||||||
if (CGSizeEqualToSize(CGSizeZero, _imageSize)) {
|
if (CGSizeEqualToSize(CGSizeZero, _imageSize)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
CGContextSaveGState(context);
|
CGContextSaveGState(context);
|
||||||
|
|
||||||
// add hit area
|
// add hit area
|
||||||
CGRect hitArea = [self getHitArea];
|
CGRect hitArea = [self getHitArea];
|
||||||
CGPathRef hitAreaPath = CGPathCreateWithRect(hitArea, nil);
|
CGPathRef hitAreaPath = CGPathCreateWithRect(hitArea, nil);
|
||||||
[self setHitArea:hitAreaPath];
|
[self setHitArea:hitAreaPath];
|
||||||
CGPathRelease(hitAreaPath);
|
CGPathRelease(hitAreaPath);
|
||||||
self.pathBounds = hitArea;
|
self.pathBounds = hitArea;
|
||||||
self.fillBounds = hitArea;
|
self.fillBounds = hitArea;
|
||||||
self.strokeBounds = hitArea;
|
self.strokeBounds = hitArea;
|
||||||
|
|
||||||
// apply viewBox transform on Image render.
|
// apply viewBox transform on Image render.
|
||||||
CGRect imageBounds = CGRectMake(0, 0, _imageSize.width, _imageSize.height);
|
CGRect imageBounds = CGRectMake(0, 0, _imageSize.width, _imageSize.height);
|
||||||
CGAffineTransform viewbox = [RNSVGViewBox getTransform:imageBounds eRect:hitArea align:self.align meetOrSlice:self.meetOrSlice];
|
CGAffineTransform viewbox = [RNSVGViewBox getTransform:imageBounds
|
||||||
|
eRect:hitArea
|
||||||
|
align:self.align
|
||||||
|
meetOrSlice:self.meetOrSlice];
|
||||||
|
|
||||||
[self clip:context];
|
[self clip:context];
|
||||||
CGContextClipToRect(context, hitArea);
|
CGContextClipToRect(context, hitArea);
|
||||||
CGContextConcatCTM(context, viewbox);
|
CGContextConcatCTM(context, viewbox);
|
||||||
CGContextTranslateCTM(context, 0, imageBounds.size.height);
|
CGContextTranslateCTM(context, 0, imageBounds.size.height);
|
||||||
CGContextScaleCTM(context, 1, -1);
|
CGContextScaleCTM(context, 1, -1);
|
||||||
CGContextDrawImage(context, imageBounds, _image);
|
CGContextDrawImage(context, imageBounds, _image);
|
||||||
CGContextRestoreGState(context);
|
CGContextRestoreGState(context);
|
||||||
|
|
||||||
CGRect bounds = hitArea;
|
CGRect bounds = hitArea;
|
||||||
self.clientRect = bounds;
|
self.clientRect = bounds;
|
||||||
|
|
||||||
CGAffineTransform current = CGContextGetCTM(context);
|
CGAffineTransform current = CGContextGetCTM(context);
|
||||||
CGAffineTransform svgToClientTransform = CGAffineTransformConcat(current, self.svgView.invInitialCTM);
|
CGAffineTransform svgToClientTransform = CGAffineTransformConcat(current, self.svgView.invInitialCTM);
|
||||||
|
|
||||||
self.ctm = svgToClientTransform;
|
self.ctm = svgToClientTransform;
|
||||||
self.screenCTM = current;
|
self.screenCTM = current;
|
||||||
|
|
||||||
CGAffineTransform transform = CGAffineTransformConcat(self.matrix, self.transforms);
|
CGAffineTransform transform = CGAffineTransformConcat(self.matrix, self.transforms);
|
||||||
CGPoint mid = CGPointMake(CGRectGetMidX(bounds), CGRectGetMidY(bounds));
|
CGPoint mid = CGPointMake(CGRectGetMidX(bounds), CGRectGetMidY(bounds));
|
||||||
CGPoint center = CGPointApplyAffineTransform(mid, transform);
|
CGPoint center = CGPointApplyAffineTransform(mid, transform);
|
||||||
|
|
||||||
self.bounds = bounds;
|
self.bounds = bounds;
|
||||||
if (!isnan(center.x) && !isnan(center.y)) {
|
if (!isnan(center.x) && !isnan(center.y)) {
|
||||||
self.center = center;
|
self.center = center;
|
||||||
}
|
}
|
||||||
self.frame = bounds;
|
self.frame = bounds;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CGRect)getHitArea
|
- (CGRect)getHitArea
|
||||||
{
|
{
|
||||||
CGFloat x = [self relativeOnWidth:self.x];
|
CGFloat x = [self relativeOnWidth:self.x];
|
||||||
CGFloat y = [self relativeOnHeight:self.y];
|
CGFloat y = [self relativeOnHeight:self.y];
|
||||||
CGFloat width = [self relativeOnWidth:self.imagewidth];
|
CGFloat width = [self relativeOnWidth:self.imagewidth];
|
||||||
CGFloat height = [self relativeOnHeight:self.imageheight];
|
CGFloat height = [self relativeOnHeight:self.imageheight];
|
||||||
if (width == 0) {
|
if (width == 0) {
|
||||||
width = _imageSize.width;
|
width = _imageSize.width;
|
||||||
}
|
}
|
||||||
if (height == 0) {
|
if (height == 0) {
|
||||||
height = _imageSize.height;
|
height = _imageSize.height;
|
||||||
}
|
}
|
||||||
|
|
||||||
return CGRectMake(x, y, width, height);
|
return CGRectMake(x, y, width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CGPathRef)getPath:(CGContextRef)context
|
- (CGPathRef)getPath:(CGContextRef)context
|
||||||
{
|
{
|
||||||
return (CGPathRef)CFAutorelease(CGPathCreateWithRect([self getHitArea], nil));
|
return (CGPathRef)CFAutorelease(CGPathCreateWithRect([self getHitArea], nil));
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -6,8 +6,8 @@
|
|||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#import "RNSVGNode.h"
|
|
||||||
#import "RNSVGLength.h"
|
#import "RNSVGLength.h"
|
||||||
|
#import "RNSVGNode.h"
|
||||||
|
|
||||||
@interface RNSVGLinearGradient : RNSVGNode
|
@interface RNSVGLinearGradient : RNSVGNode
|
||||||
|
|
||||||
|
|||||||
@@ -6,14 +6,14 @@
|
|||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
#import "RNSVGLinearGradient.h"
|
#import "RNSVGLinearGradient.h"
|
||||||
#import "RNSVGPainter.h"
|
|
||||||
#import "RNSVGBrushType.h"
|
#import "RNSVGBrushType.h"
|
||||||
|
#import "RNSVGPainter.h"
|
||||||
|
|
||||||
#ifdef RN_FABRIC_ENABLED
|
#ifdef RN_FABRIC_ENABLED
|
||||||
#import <react/renderer/components/rnsvg/ComponentDescriptors.h>
|
#import <react/renderer/components/rnsvg/ComponentDescriptors.h>
|
||||||
#import "RCTFabricComponentsPlugins.h"
|
|
||||||
#import "RCTConversions.h"
|
|
||||||
#import <react/renderer/components/view/conversions.h>
|
#import <react/renderer/components/view/conversions.h>
|
||||||
|
#import "RCTConversions.h"
|
||||||
|
#import "RCTFabricComponentsPlugins.h"
|
||||||
#import "RNSVGFabricConversions.h"
|
#import "RNSVGFabricConversions.h"
|
||||||
#endif // RN_FABRIC_ENABLED
|
#endif // RN_FABRIC_ENABLED
|
||||||
|
|
||||||
@@ -40,133 +40,139 @@ using namespace facebook::react;
|
|||||||
|
|
||||||
- (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps
|
- (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps
|
||||||
{
|
{
|
||||||
const auto &newProps = *std::static_pointer_cast<const RNSVGLinearGradientProps>(props);
|
const auto &newProps = *std::static_pointer_cast<const RNSVGLinearGradientProps>(props);
|
||||||
|
|
||||||
self.x1 = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.x1)];
|
self.x1 = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.x1)];
|
||||||
self.y1 = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.y1)];
|
self.y1 = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.y1)];
|
||||||
self.x2 = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.x2)];
|
self.x2 = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.x2)];
|
||||||
self.y2 = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.y2)];
|
self.y2 = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.y2)];
|
||||||
if (newProps.gradient.size() > 0) {
|
if (newProps.gradient.size() > 0) {
|
||||||
NSMutableArray<NSNumber *> *gradientArray = [NSMutableArray new];
|
NSMutableArray<NSNumber *> *gradientArray = [NSMutableArray new];
|
||||||
for (auto number : newProps.gradient) {
|
for (auto number : newProps.gradient) {
|
||||||
[gradientArray addObject:[NSNumber numberWithDouble:number]];
|
[gradientArray addObject:[NSNumber numberWithDouble:number]];
|
||||||
}
|
|
||||||
self.gradient = gradientArray;
|
|
||||||
}
|
|
||||||
self.gradientUnits = newProps.gradientUnits == 0 ? kRNSVGUnitsObjectBoundingBox : kRNSVGUnitsUserSpaceOnUse;
|
|
||||||
if (newProps.gradientTransform.size() == 6) {
|
|
||||||
self.gradientTransform = CGAffineTransformMake(newProps.gradientTransform.at(0), newProps.gradientTransform.at(1), newProps.gradientTransform.at(2), newProps.gradientTransform.at(3), newProps.gradientTransform.at(4), newProps.gradientTransform.at(5));
|
|
||||||
}
|
}
|
||||||
|
self.gradient = gradientArray;
|
||||||
|
}
|
||||||
|
self.gradientUnits = newProps.gradientUnits == 0 ? kRNSVGUnitsObjectBoundingBox : kRNSVGUnitsUserSpaceOnUse;
|
||||||
|
if (newProps.gradientTransform.size() == 6) {
|
||||||
|
self.gradientTransform = CGAffineTransformMake(
|
||||||
|
newProps.gradientTransform.at(0),
|
||||||
|
newProps.gradientTransform.at(1),
|
||||||
|
newProps.gradientTransform.at(2),
|
||||||
|
newProps.gradientTransform.at(3),
|
||||||
|
newProps.gradientTransform.at(4),
|
||||||
|
newProps.gradientTransform.at(5));
|
||||||
|
}
|
||||||
|
|
||||||
setCommonNodeProps(newProps, self);
|
setCommonNodeProps(newProps, self);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)prepareForRecycle
|
- (void)prepareForRecycle
|
||||||
{
|
{
|
||||||
[super prepareForRecycle];
|
[super prepareForRecycle];
|
||||||
_x1 = nil;
|
_x1 = nil;
|
||||||
_y1 = nil;
|
_y1 = nil;
|
||||||
_x2 = nil;
|
_x2 = nil;
|
||||||
_y2 = nil;
|
_y2 = nil;
|
||||||
_gradient = nil;
|
_gradient = nil;
|
||||||
_gradientUnits = kRNSVGUnitsObjectBoundingBox;
|
_gradientUnits = kRNSVGUnitsObjectBoundingBox;
|
||||||
_gradientTransform = CGAffineTransformIdentity;
|
_gradientTransform = CGAffineTransformIdentity;
|
||||||
}
|
}
|
||||||
#endif // RN_FABRIC_ENABLED
|
#endif // RN_FABRIC_ENABLED
|
||||||
|
|
||||||
- (instancetype)init
|
- (instancetype)init
|
||||||
{
|
{
|
||||||
if (self = [super init]) {
|
if (self = [super init]) {
|
||||||
_gradientTransform = CGAffineTransformIdentity;
|
_gradientTransform = CGAffineTransformIdentity;
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setX1:(RNSVGLength *)x1
|
- (void)setX1:(RNSVGLength *)x1
|
||||||
{
|
{
|
||||||
if ([x1 isEqualTo:_x1]) {
|
if ([x1 isEqualTo:_x1]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_x1 = x1;
|
_x1 = x1;
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setY1:(RNSVGLength *)y1
|
- (void)setY1:(RNSVGLength *)y1
|
||||||
{
|
{
|
||||||
if ([y1 isEqualTo:_y1]) {
|
if ([y1 isEqualTo:_y1]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_y1 = y1;
|
_y1 = y1;
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setX2:(RNSVGLength *)x2
|
- (void)setX2:(RNSVGLength *)x2
|
||||||
{
|
{
|
||||||
if ([x2 isEqualTo:_x2]) {
|
if ([x2 isEqualTo:_x2]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_x2 = x2;
|
_x2 = x2;
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setY2:(RNSVGLength *)y2
|
- (void)setY2:(RNSVGLength *)y2
|
||||||
{
|
{
|
||||||
if ([y2 isEqualTo:_y2]) {
|
if ([y2 isEqualTo:_y2]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_y2 = y2;
|
_y2 = y2;
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setGradient:(NSArray<NSNumber *> *)gradient
|
- (void)setGradient:(NSArray<NSNumber *> *)gradient
|
||||||
{
|
{
|
||||||
if (gradient == _gradient) {
|
if (gradient == _gradient) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_gradient = gradient;
|
_gradient = gradient;
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setGradientUnits:(RNSVGUnits)gradientUnits
|
- (void)setGradientUnits:(RNSVGUnits)gradientUnits
|
||||||
{
|
{
|
||||||
if (gradientUnits == _gradientUnits) {
|
if (gradientUnits == _gradientUnits) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_gradientUnits = gradientUnits;
|
_gradientUnits = gradientUnits;
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setGradientTransform:(CGAffineTransform)gradientTransform
|
- (void)setGradientTransform:(CGAffineTransform)gradientTransform
|
||||||
{
|
{
|
||||||
_gradientTransform = gradientTransform;
|
_gradientTransform = gradientTransform;
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (RNSVGPlatformView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
|
- (RNSVGPlatformView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
|
||||||
{
|
{
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)parseReference
|
- (void)parseReference
|
||||||
{
|
{
|
||||||
self.dirty = false;
|
self.dirty = false;
|
||||||
NSArray<RNSVGLength *> *points = @[self.x1, self.y1, self.x2, self.y2];
|
NSArray<RNSVGLength *> *points = @[ self.x1, self.y1, self.x2, self.y2 ];
|
||||||
RNSVGPainter *painter = [[RNSVGPainter alloc] initWithPointsArray:points];
|
RNSVGPainter *painter = [[RNSVGPainter alloc] initWithPointsArray:points];
|
||||||
[painter setUnits:self.gradientUnits];
|
[painter setUnits:self.gradientUnits];
|
||||||
[painter setTransform:self.gradientTransform];
|
[painter setTransform:self.gradientTransform];
|
||||||
[painter setLinearGradientColors:self.gradient];
|
[painter setLinearGradientColors:self.gradient];
|
||||||
|
|
||||||
if (self.gradientUnits == kRNSVGUnitsUserSpaceOnUse) {
|
if (self.gradientUnits == kRNSVGUnitsUserSpaceOnUse) {
|
||||||
[painter setUserSpaceBoundingBox:[self.svgView getContextBounds]];
|
[painter setUserSpaceBoundingBox:[self.svgView getContextBounds]];
|
||||||
}
|
}
|
||||||
|
|
||||||
[self.svgView definePainter:painter painterName:self.name];
|
[self.svgView definePainter:painter painterName:self.name];
|
||||||
}
|
}
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,9 @@
|
|||||||
@property (nonatomic, strong) NSString *align;
|
@property (nonatomic, strong) NSString *align;
|
||||||
@property (nonatomic, assign) RNSVGVBMOS meetOrSlice;
|
@property (nonatomic, assign) RNSVGVBMOS meetOrSlice;
|
||||||
|
|
||||||
- (void)renderMarker:(CGContextRef)context rect:(CGRect)rect position:(RNSVGMarkerPosition*)position strokeWidth:(CGFloat)strokeWidth;
|
- (void)renderMarker:(CGContextRef)context
|
||||||
|
rect:(CGRect)rect
|
||||||
|
position:(RNSVGMarkerPosition *)position
|
||||||
|
strokeWidth:(CGFloat)strokeWidth;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -6,16 +6,16 @@
|
|||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
#import "RNSVGMarker.h"
|
#import "RNSVGMarker.h"
|
||||||
#import "RNSVGPainter.h"
|
|
||||||
#import "RNSVGBrushType.h"
|
#import "RNSVGBrushType.h"
|
||||||
#import "RNSVGNode.h"
|
#import "RNSVGNode.h"
|
||||||
|
#import "RNSVGPainter.h"
|
||||||
#import "RNSVGViewBox.h"
|
#import "RNSVGViewBox.h"
|
||||||
|
|
||||||
#ifdef RN_FABRIC_ENABLED
|
#ifdef RN_FABRIC_ENABLED
|
||||||
#import <react/renderer/components/rnsvg/ComponentDescriptors.h>
|
#import <react/renderer/components/rnsvg/ComponentDescriptors.h>
|
||||||
#import "RCTFabricComponentsPlugins.h"
|
|
||||||
#import "RCTConversions.h"
|
|
||||||
#import <react/renderer/components/view/conversions.h>
|
#import <react/renderer/components/view/conversions.h>
|
||||||
|
#import "RCTConversions.h"
|
||||||
|
#import "RCTFabricComponentsPlugins.h"
|
||||||
#import "RNSVGFabricConversions.h"
|
#import "RNSVGFabricConversions.h"
|
||||||
#endif // RN_FABRIC_ENABLED
|
#endif // RN_FABRIC_ENABLED
|
||||||
|
|
||||||
@@ -42,230 +42,234 @@ using namespace facebook::react;
|
|||||||
|
|
||||||
- (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps
|
- (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps
|
||||||
{
|
{
|
||||||
const auto &newProps = *std::static_pointer_cast<const RNSVGMarkerProps>(props);
|
const auto &newProps = *std::static_pointer_cast<const RNSVGMarkerProps>(props);
|
||||||
|
|
||||||
self.refX = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.refX)];
|
self.refX = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.refX)];
|
||||||
self.refY = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.refY)];
|
self.refY = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.refY)];
|
||||||
self.markerHeight = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.markerHeight)];
|
self.markerHeight = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.markerHeight)];
|
||||||
self.markerWidth = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.markerWidth)];
|
self.markerWidth = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.markerWidth)];
|
||||||
self.markerUnits = RCTNSStringFromStringNilIfEmpty(newProps.markerUnits);
|
self.markerUnits = RCTNSStringFromStringNilIfEmpty(newProps.markerUnits);
|
||||||
self.orient = RCTNSStringFromStringNilIfEmpty(newProps.orient);
|
self.orient = RCTNSStringFromStringNilIfEmpty(newProps.orient);
|
||||||
|
|
||||||
self.minX = newProps.minX;
|
self.minX = newProps.minX;
|
||||||
self.minY = newProps.minY;
|
self.minY = newProps.minY;
|
||||||
self.vbWidth = newProps.vbWidth;
|
self.vbWidth = newProps.vbWidth;
|
||||||
self.vbHeight = newProps.vbHeight;
|
self.vbHeight = newProps.vbHeight;
|
||||||
self.align = RCTNSStringFromStringNilIfEmpty(newProps.align);
|
self.align = RCTNSStringFromStringNilIfEmpty(newProps.align);
|
||||||
self.meetOrSlice = intToRNSVGVBMOS(newProps.meetOrSlice);
|
self.meetOrSlice = intToRNSVGVBMOS(newProps.meetOrSlice);
|
||||||
|
|
||||||
setCommonGroupProps(newProps, self);
|
setCommonGroupProps(newProps, self);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)prepareForRecycle
|
- (void)prepareForRecycle
|
||||||
{
|
{
|
||||||
[super prepareForRecycle];
|
[super prepareForRecycle];
|
||||||
_refX = nil;
|
_refX = nil;
|
||||||
_refY = nil;
|
_refY = nil;
|
||||||
_markerHeight = nil;
|
_markerHeight = nil;
|
||||||
_markerWidth = nil;
|
_markerWidth = nil;
|
||||||
_markerUnits = nil;
|
_markerUnits = nil;
|
||||||
_orient = nil;
|
_orient = nil;
|
||||||
|
|
||||||
_minX = 0;
|
_minX = 0;
|
||||||
_minY = 0;
|
_minY = 0;
|
||||||
_vbWidth = 0;
|
_vbWidth = 0;
|
||||||
_vbHeight = 0;
|
_vbHeight = 0;
|
||||||
_align = nil;
|
_align = nil;
|
||||||
_meetOrSlice = kRNSVGVBMOSMeet;
|
_meetOrSlice = kRNSVGVBMOSMeet;
|
||||||
}
|
}
|
||||||
#endif // RN_FABRIC_ENABLED
|
#endif // RN_FABRIC_ENABLED
|
||||||
|
|
||||||
- (RNSVGPlatformView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
|
- (RNSVGPlatformView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
|
||||||
{
|
{
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)parseReference
|
- (void)parseReference
|
||||||
{
|
{
|
||||||
self.dirty = false;
|
self.dirty = false;
|
||||||
[self.svgView defineMarker:self markerName:self.name];
|
[self.svgView defineMarker:self markerName:self.name];
|
||||||
[self traverseSubviews:^(RNSVGNode *node) {
|
[self traverseSubviews:^(RNSVGNode *node) {
|
||||||
if ([node isKindOfClass:[RNSVGNode class]]) {
|
if ([node isKindOfClass:[RNSVGNode class]]) {
|
||||||
[node parseReference];
|
[node parseReference];
|
||||||
}
|
}
|
||||||
return YES;
|
return YES;
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setX:(RNSVGLength *)refX
|
- (void)setX:(RNSVGLength *)refX
|
||||||
{
|
{
|
||||||
if ([refX isEqualTo:_refX]) {
|
if ([refX isEqualTo:_refX]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_refX = refX;
|
_refX = refX;
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setY:(RNSVGLength *)refY
|
- (void)setY:(RNSVGLength *)refY
|
||||||
{
|
{
|
||||||
if ([refY isEqualTo:_refY]) {
|
if ([refY isEqualTo:_refY]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_refY = refY;
|
_refY = refY;
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setMarkerWidth:(RNSVGLength *)markerWidth
|
- (void)setMarkerWidth:(RNSVGLength *)markerWidth
|
||||||
{
|
{
|
||||||
if ([markerWidth isEqualTo:_markerWidth]) {
|
if ([markerWidth isEqualTo:_markerWidth]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_markerWidth = markerWidth;
|
_markerWidth = markerWidth;
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setMarkerHeight:(RNSVGLength *)markerHeight
|
- (void)setMarkerHeight:(RNSVGLength *)markerHeight
|
||||||
{
|
{
|
||||||
if ([markerHeight isEqualTo:_markerHeight]) {
|
if ([markerHeight isEqualTo:_markerHeight]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_markerHeight = markerHeight;
|
_markerHeight = markerHeight;
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setMarkerUnits:(NSString *)markerUnits
|
- (void)setMarkerUnits:(NSString *)markerUnits
|
||||||
{
|
{
|
||||||
if ([_markerUnits isEqualToString:markerUnits]) {
|
if ([_markerUnits isEqualToString:markerUnits]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_markerUnits = markerUnits;
|
_markerUnits = markerUnits;
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setOrient:(NSString *)orient
|
- (void)setOrient:(NSString *)orient
|
||||||
{
|
{
|
||||||
if ([orient isEqualToString:_orient]) {
|
if ([orient isEqualToString:_orient]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
_orient = orient;
|
_orient = orient;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setMinX:(CGFloat)minX
|
- (void)setMinX:(CGFloat)minX
|
||||||
{
|
{
|
||||||
if (minX == _minX) {
|
if (minX == _minX) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
_minX = minX;
|
_minX = minX;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setMinY:(CGFloat)minY
|
- (void)setMinY:(CGFloat)minY
|
||||||
{
|
{
|
||||||
if (minY == _minY) {
|
if (minY == _minY) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
_minY = minY;
|
_minY = minY;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setVbWidth:(CGFloat)vbWidth
|
- (void)setVbWidth:(CGFloat)vbWidth
|
||||||
{
|
{
|
||||||
if (vbWidth == _vbWidth) {
|
if (vbWidth == _vbWidth) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
_vbWidth = vbWidth;
|
_vbWidth = vbWidth;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setVbHeight:(CGFloat)vbHeight
|
- (void)setVbHeight:(CGFloat)vbHeight
|
||||||
{
|
{
|
||||||
if (_vbHeight == vbHeight) {
|
if (_vbHeight == vbHeight) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
_vbHeight = vbHeight;
|
_vbHeight = vbHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setAlign:(NSString *)align
|
- (void)setAlign:(NSString *)align
|
||||||
{
|
{
|
||||||
if ([align isEqualToString:_align]) {
|
if ([align isEqualToString:_align]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
_align = align;
|
_align = align;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setMeetOrSlice:(RNSVGVBMOS)meetOrSlice
|
- (void)setMeetOrSlice:(RNSVGVBMOS)meetOrSlice
|
||||||
{
|
{
|
||||||
if (meetOrSlice == _meetOrSlice) {
|
if (meetOrSlice == _meetOrSlice) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
_meetOrSlice = meetOrSlice;
|
_meetOrSlice = meetOrSlice;
|
||||||
}
|
}
|
||||||
|
|
||||||
static CGFloat RNSVG_degToRad = (CGFloat)M_PI / 180;
|
static CGFloat RNSVG_degToRad = (CGFloat)M_PI / 180;
|
||||||
|
|
||||||
double deg2rad(CGFloat deg) {
|
double deg2rad(CGFloat deg)
|
||||||
return deg * RNSVG_degToRad;
|
{
|
||||||
|
return deg * RNSVG_degToRad;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)renderMarker:(CGContextRef)context rect:(CGRect)rect position:(RNSVGMarkerPosition*)position strokeWidth:(CGFloat)strokeWidth
|
- (void)renderMarker:(CGContextRef)context
|
||||||
|
rect:(CGRect)rect
|
||||||
|
position:(RNSVGMarkerPosition *)position
|
||||||
|
strokeWidth:(CGFloat)strokeWidth
|
||||||
{
|
{
|
||||||
CGContextSaveGState(context);
|
CGContextSaveGState(context);
|
||||||
|
|
||||||
CGPoint origin = [position origin];
|
CGPoint origin = [position origin];
|
||||||
CGAffineTransform transform = CGAffineTransformMakeTranslation(origin.x, origin.y);
|
CGAffineTransform transform = CGAffineTransformMakeTranslation(origin.x, origin.y);
|
||||||
|
|
||||||
float markerAngle = [@"auto" isEqualToString:_orient] ? -1 : [_orient doubleValue];
|
float markerAngle = [@"auto" isEqualToString:_orient] ? -1 : [_orient doubleValue];
|
||||||
float angle = 180 + (markerAngle == -1 ? [position angle] : markerAngle);
|
float angle = 180 + (markerAngle == -1 ? [position angle] : markerAngle);
|
||||||
float rad = deg2rad(angle);
|
float rad = deg2rad(angle);
|
||||||
transform = CGAffineTransformRotate(transform, rad);
|
transform = CGAffineTransformRotate(transform, rad);
|
||||||
|
|
||||||
bool useStrokeWidth = [@"strokeWidth" isEqualToString:_markerUnits];
|
bool useStrokeWidth = [@"strokeWidth" isEqualToString:_markerUnits];
|
||||||
if (useStrokeWidth) {
|
if (useStrokeWidth) {
|
||||||
transform = CGAffineTransformScale(transform, strokeWidth, strokeWidth);
|
transform = CGAffineTransformScale(transform, strokeWidth, strokeWidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
CGFloat width = [self relativeOnWidth:self.markerWidth];
|
CGFloat width = [self relativeOnWidth:self.markerWidth];
|
||||||
CGFloat height = [self relativeOnHeight:self.markerHeight];
|
CGFloat height = [self relativeOnHeight:self.markerHeight];
|
||||||
CGRect eRect = CGRectMake(0, 0, width, height);
|
CGRect eRect = CGRectMake(0, 0, width, height);
|
||||||
if (self.align) {
|
if (self.align) {
|
||||||
CGAffineTransform viewBoxTransform = [RNSVGViewBox getTransform:CGRectMake(self.minX, self.minY, self.vbWidth, self.vbHeight)
|
CGAffineTransform viewBoxTransform =
|
||||||
eRect:eRect
|
[RNSVGViewBox getTransform:CGRectMake(self.minX, self.minY, self.vbWidth, self.vbHeight)
|
||||||
align:self.align
|
eRect:eRect
|
||||||
meetOrSlice:self.meetOrSlice];
|
align:self.align
|
||||||
transform = CGAffineTransformScale(transform, viewBoxTransform.a, viewBoxTransform.d);
|
meetOrSlice:self.meetOrSlice];
|
||||||
}
|
transform = CGAffineTransformScale(transform, viewBoxTransform.a, viewBoxTransform.d);
|
||||||
|
}
|
||||||
|
|
||||||
CGFloat x = [self relativeOnWidth:self.refX];
|
CGFloat x = [self relativeOnWidth:self.refX];
|
||||||
CGFloat y = [self relativeOnHeight:self.refY];
|
CGFloat y = [self relativeOnHeight:self.refY];
|
||||||
transform = CGAffineTransformTranslate(transform, -x, -y);
|
transform = CGAffineTransformTranslate(transform, -x, -y);
|
||||||
|
|
||||||
self.transform = transform;
|
self.transform = transform;
|
||||||
CGContextConcatCTM(context, transform);
|
CGContextConcatCTM(context, transform);
|
||||||
|
|
||||||
[self renderGroupTo:context rect:eRect];
|
[self renderGroupTo:context rect:eRect];
|
||||||
|
|
||||||
CGContextRestoreGState(context);
|
CGContextRestoreGState(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|
||||||
#ifdef RN_FABRIC_ENABLED
|
#ifdef RN_FABRIC_ENABLED
|
||||||
Class<RCTComponentViewProtocol> RNSVGMarkerCls(void)
|
Class<RCTComponentViewProtocol> RNSVGMarkerCls(void)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -6,16 +6,15 @@
|
|||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
#import "RNSVGMask.h"
|
#import "RNSVGMask.h"
|
||||||
#import "RNSVGPainter.h"
|
|
||||||
#import "RNSVGBrushType.h"
|
#import "RNSVGBrushType.h"
|
||||||
#import "RNSVGNode.h"
|
#import "RNSVGNode.h"
|
||||||
|
#import "RNSVGPainter.h"
|
||||||
|
|
||||||
#ifdef RN_FABRIC_ENABLED
|
#ifdef RN_FABRIC_ENABLED
|
||||||
#import <react/renderer/components/rnsvg/ComponentDescriptors.h>
|
#import <react/renderer/components/rnsvg/ComponentDescriptors.h>
|
||||||
#import "RCTFabricComponentsPlugins.h"
|
|
||||||
#import "RCTConversions.h"
|
|
||||||
#import <react/renderer/components/view/conversions.h>
|
#import <react/renderer/components/view/conversions.h>
|
||||||
|
#import "RCTConversions.h"
|
||||||
|
#import "RCTFabricComponentsPlugins.h"
|
||||||
#import "RNSVGFabricConversions.h"
|
#import "RNSVGFabricConversions.h"
|
||||||
#endif // RN_FABRIC_ENABLED
|
#endif // RN_FABRIC_ENABLED
|
||||||
|
|
||||||
@@ -42,119 +41,125 @@ using namespace facebook::react;
|
|||||||
|
|
||||||
- (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps
|
- (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps
|
||||||
{
|
{
|
||||||
const auto &newProps = *std::static_pointer_cast<const RNSVGMaskProps>(props);
|
const auto &newProps = *std::static_pointer_cast<const RNSVGMaskProps>(props);
|
||||||
|
|
||||||
self.x = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.x)];
|
self.x = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.x)];
|
||||||
self.y = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.y)];
|
self.y = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.y)];
|
||||||
if (RCTNSStringFromStringNilIfEmpty(newProps.maskheight)) {
|
if (RCTNSStringFromStringNilIfEmpty(newProps.maskheight)) {
|
||||||
self.maskheight = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.maskheight)];
|
self.maskheight = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.maskheight)];
|
||||||
}
|
}
|
||||||
if (RCTNSStringFromStringNilIfEmpty(newProps.maskwidth)) {
|
if (RCTNSStringFromStringNilIfEmpty(newProps.maskwidth)) {
|
||||||
self.maskwidth = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.maskwidth)];
|
self.maskwidth = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.maskwidth)];
|
||||||
}
|
}
|
||||||
if (RCTNSStringFromStringNilIfEmpty(newProps.height)) {
|
if (RCTNSStringFromStringNilIfEmpty(newProps.height)) {
|
||||||
self.maskheight = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.height)];
|
self.maskheight = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.height)];
|
||||||
}
|
}
|
||||||
if (RCTNSStringFromStringNilIfEmpty(newProps.width)) {
|
if (RCTNSStringFromStringNilIfEmpty(newProps.width)) {
|
||||||
self.maskwidth = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.width)];
|
self.maskwidth = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.width)];
|
||||||
}
|
}
|
||||||
self.maskUnits = newProps.maskUnits == 0 ? kRNSVGUnitsObjectBoundingBox : kRNSVGUnitsUserSpaceOnUse;
|
self.maskUnits = newProps.maskUnits == 0 ? kRNSVGUnitsObjectBoundingBox : kRNSVGUnitsUserSpaceOnUse;
|
||||||
self.maskContentUnits = newProps.maskUnits == 0 ? kRNSVGUnitsObjectBoundingBox : kRNSVGUnitsUserSpaceOnUse;
|
self.maskContentUnits = newProps.maskUnits == 0 ? kRNSVGUnitsObjectBoundingBox : kRNSVGUnitsUserSpaceOnUse;
|
||||||
if (newProps.maskTransform.size() == 6) {
|
if (newProps.maskTransform.size() == 6) {
|
||||||
self.maskTransform = CGAffineTransformMake(newProps.maskTransform.at(0), newProps.maskTransform.at(1), newProps.maskTransform.at(2), newProps.maskTransform.at(3), newProps.maskTransform.at(4), newProps.maskTransform.at(5));
|
self.maskTransform = CGAffineTransformMake(
|
||||||
}
|
newProps.maskTransform.at(0),
|
||||||
|
newProps.maskTransform.at(1),
|
||||||
|
newProps.maskTransform.at(2),
|
||||||
|
newProps.maskTransform.at(3),
|
||||||
|
newProps.maskTransform.at(4),
|
||||||
|
newProps.maskTransform.at(5));
|
||||||
|
}
|
||||||
|
|
||||||
setCommonGroupProps(newProps, self);
|
setCommonGroupProps(newProps, self);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)prepareForRecycle
|
- (void)prepareForRecycle
|
||||||
{
|
{
|
||||||
[super prepareForRecycle];
|
[super prepareForRecycle];
|
||||||
_x = nil;
|
_x = nil;
|
||||||
_y = nil;
|
_y = nil;
|
||||||
_maskheight = nil;
|
_maskheight = nil;
|
||||||
_maskwidth = nil;
|
_maskwidth = nil;
|
||||||
_maskUnits = kRNSVGUnitsObjectBoundingBox;
|
_maskUnits = kRNSVGUnitsObjectBoundingBox;
|
||||||
_maskContentUnits = kRNSVGUnitsObjectBoundingBox;
|
_maskContentUnits = kRNSVGUnitsObjectBoundingBox;
|
||||||
_maskTransform = CGAffineTransformIdentity;
|
_maskTransform = CGAffineTransformIdentity;
|
||||||
}
|
}
|
||||||
#endif // RN_FABRIC_ENABLED
|
#endif // RN_FABRIC_ENABLED
|
||||||
|
|
||||||
- (RNSVGPlatformView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
|
- (RNSVGPlatformView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
|
||||||
{
|
{
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)parseReference
|
- (void)parseReference
|
||||||
{
|
{
|
||||||
self.dirty = false;
|
self.dirty = false;
|
||||||
[self.svgView defineMask:self maskName:self.name];
|
[self.svgView defineMask:self maskName:self.name];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setX:(RNSVGLength *)x
|
- (void)setX:(RNSVGLength *)x
|
||||||
{
|
{
|
||||||
if ([x isEqualTo:_x]) {
|
if ([x isEqualTo:_x]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_x = x;
|
_x = x;
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setY:(RNSVGLength *)y
|
- (void)setY:(RNSVGLength *)y
|
||||||
{
|
{
|
||||||
if ([y isEqualTo:_y]) {
|
if ([y isEqualTo:_y]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_y = y;
|
_y = y;
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setMaskwidth:(RNSVGLength *)maskwidth
|
- (void)setMaskwidth:(RNSVGLength *)maskwidth
|
||||||
{
|
{
|
||||||
if ([maskwidth isEqualTo:_maskwidth]) {
|
if ([maskwidth isEqualTo:_maskwidth]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_maskwidth = maskwidth;
|
_maskwidth = maskwidth;
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setMaskheight:(RNSVGLength *)maskheight
|
- (void)setMaskheight:(RNSVGLength *)maskheight
|
||||||
{
|
{
|
||||||
if ([maskheight isEqualTo:_maskheight]) {
|
if ([maskheight isEqualTo:_maskheight]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_maskheight = maskheight;
|
_maskheight = maskheight;
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setMaskUnits:(RNSVGUnits)maskUnits
|
- (void)setMaskUnits:(RNSVGUnits)maskUnits
|
||||||
{
|
{
|
||||||
if (maskUnits == _maskUnits) {
|
if (maskUnits == _maskUnits) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_maskUnits = maskUnits;
|
_maskUnits = maskUnits;
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setMaskContentUnits:(RNSVGUnits)maskContentUnits
|
- (void)setMaskContentUnits:(RNSVGUnits)maskContentUnits
|
||||||
{
|
{
|
||||||
if (maskContentUnits == _maskContentUnits) {
|
if (maskContentUnits == _maskContentUnits) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_maskContentUnits = maskContentUnits;
|
_maskContentUnits = maskContentUnits;
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setMaskTransform:(CGAffineTransform)maskTransform
|
- (void)setMaskTransform:(CGAffineTransform)maskTransform
|
||||||
{
|
{
|
||||||
_maskTransform = maskTransform;
|
_maskTransform = maskTransform;
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -10,15 +10,14 @@
|
|||||||
|
|
||||||
#ifdef RN_FABRIC_ENABLED
|
#ifdef RN_FABRIC_ENABLED
|
||||||
#import <react/renderer/components/rnsvg/ComponentDescriptors.h>
|
#import <react/renderer/components/rnsvg/ComponentDescriptors.h>
|
||||||
#import "RCTFabricComponentsPlugins.h"
|
|
||||||
#import "RCTConversions.h"
|
|
||||||
#import <react/renderer/components/view/conversions.h>
|
#import <react/renderer/components/view/conversions.h>
|
||||||
|
#import "RCTConversions.h"
|
||||||
|
#import "RCTFabricComponentsPlugins.h"
|
||||||
#import "RNSVGFabricConversions.h"
|
#import "RNSVGFabricConversions.h"
|
||||||
#endif // RN_FABRIC_ENABLED
|
#endif // RN_FABRIC_ENABLED
|
||||||
|
|
||||||
@implementation RNSVGPath
|
@implementation RNSVGPath {
|
||||||
{
|
CGPathRef _path;
|
||||||
CGPathRef _path;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef RN_FABRIC_ENABLED
|
#ifdef RN_FABRIC_ENABLED
|
||||||
@@ -42,43 +41,43 @@ using namespace facebook::react;
|
|||||||
|
|
||||||
- (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps
|
- (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps
|
||||||
{
|
{
|
||||||
const auto &newProps = *std::static_pointer_cast<const RNSVGPathProps>(props);
|
const auto &newProps = *std::static_pointer_cast<const RNSVGPathProps>(props);
|
||||||
self.d = [[RNSVGPathParser alloc] initWithPathString: RCTNSStringFromString(newProps.d)];
|
self.d = [[RNSVGPathParser alloc] initWithPathString:RCTNSStringFromString(newProps.d)];
|
||||||
|
|
||||||
setCommonRenderableProps(newProps, self);
|
setCommonRenderableProps(newProps, self);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)prepareForRecycle
|
- (void)prepareForRecycle
|
||||||
{
|
{
|
||||||
[super prepareForRecycle];
|
[super prepareForRecycle];
|
||||||
if (_path) {
|
if (_path) {
|
||||||
CGPathRelease(_path);
|
CGPathRelease(_path);
|
||||||
}
|
}
|
||||||
_path = nil;
|
_path = nil;
|
||||||
_d = nil;
|
_d = nil;
|
||||||
}
|
}
|
||||||
#endif // RN_FABRIC_ENABLED
|
#endif // RN_FABRIC_ENABLED
|
||||||
|
|
||||||
- (void)setD:(RNSVGPathParser *)d
|
- (void)setD:(RNSVGPathParser *)d
|
||||||
{
|
{
|
||||||
if (d == _d) {
|
if (d == _d) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
_d = d;
|
_d = d;
|
||||||
CGPathRelease(_path);
|
CGPathRelease(_path);
|
||||||
_path = CGPathRetain([d getPath]);
|
_path = CGPathRetain([d getPath]);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CGPathRef)getPath:(CGContextRef)context
|
- (CGPathRef)getPath:(CGContextRef)context
|
||||||
{
|
{
|
||||||
return _path;
|
return _path;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)dealloc
|
- (void)dealloc
|
||||||
{
|
{
|
||||||
CGPathRelease(_path);
|
CGPathRelease(_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -6,15 +6,15 @@
|
|||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
#import "RNSVGPattern.h"
|
#import "RNSVGPattern.h"
|
||||||
#import "RNSVGPainter.h"
|
|
||||||
#import "RNSVGBrushType.h"
|
#import "RNSVGBrushType.h"
|
||||||
#import "RNSVGNode.h"
|
#import "RNSVGNode.h"
|
||||||
|
#import "RNSVGPainter.h"
|
||||||
|
|
||||||
#ifdef RN_FABRIC_ENABLED
|
#ifdef RN_FABRIC_ENABLED
|
||||||
#import <react/renderer/components/rnsvg/ComponentDescriptors.h>
|
#import <react/renderer/components/rnsvg/ComponentDescriptors.h>
|
||||||
#import "RCTFabricComponentsPlugins.h"
|
|
||||||
#import "RCTConversions.h"
|
|
||||||
#import <react/renderer/components/view/conversions.h>
|
#import <react/renderer/components/view/conversions.h>
|
||||||
|
#import "RCTConversions.h"
|
||||||
|
#import "RCTFabricComponentsPlugins.h"
|
||||||
#import "RNSVGFabricConversions.h"
|
#import "RNSVGFabricConversions.h"
|
||||||
#endif // RN_FABRIC_ENABLED
|
#endif // RN_FABRIC_ENABLED
|
||||||
|
|
||||||
@@ -41,211 +41,217 @@ using namespace facebook::react;
|
|||||||
|
|
||||||
- (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps
|
- (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps
|
||||||
{
|
{
|
||||||
const auto &newProps = *std::static_pointer_cast<const RNSVGPatternProps>(props);
|
const auto &newProps = *std::static_pointer_cast<const RNSVGPatternProps>(props);
|
||||||
|
|
||||||
self.x = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.x)];
|
self.x = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.x)];
|
||||||
self.y = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.y)];
|
self.y = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.y)];
|
||||||
if (RCTNSStringFromStringNilIfEmpty(newProps.patternheight)) {
|
if (RCTNSStringFromStringNilIfEmpty(newProps.patternheight)) {
|
||||||
self.patternheight = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.patternheight)];
|
self.patternheight = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.patternheight)];
|
||||||
}
|
}
|
||||||
if (RCTNSStringFromStringNilIfEmpty(newProps.patternwidth)) {
|
if (RCTNSStringFromStringNilIfEmpty(newProps.patternwidth)) {
|
||||||
self.patternwidth = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.patternwidth)];
|
self.patternwidth = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.patternwidth)];
|
||||||
}
|
}
|
||||||
if (RCTNSStringFromStringNilIfEmpty(newProps.height)) {
|
if (RCTNSStringFromStringNilIfEmpty(newProps.height)) {
|
||||||
self.patternheight = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.height)];
|
self.patternheight = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.height)];
|
||||||
}
|
}
|
||||||
if (RCTNSStringFromStringNilIfEmpty(newProps.width)) {
|
if (RCTNSStringFromStringNilIfEmpty(newProps.width)) {
|
||||||
self.patternwidth = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.width)];
|
self.patternwidth = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.width)];
|
||||||
}
|
}
|
||||||
self.patternUnits = newProps.patternUnits == 0 ? kRNSVGUnitsObjectBoundingBox : kRNSVGUnitsUserSpaceOnUse;
|
self.patternUnits = newProps.patternUnits == 0 ? kRNSVGUnitsObjectBoundingBox : kRNSVGUnitsUserSpaceOnUse;
|
||||||
self.patternContentUnits = newProps.patternUnits == 0 ? kRNSVGUnitsObjectBoundingBox : kRNSVGUnitsUserSpaceOnUse;
|
self.patternContentUnits = newProps.patternUnits == 0 ? kRNSVGUnitsObjectBoundingBox : kRNSVGUnitsUserSpaceOnUse;
|
||||||
if (newProps.patternTransform.size() == 6) {
|
if (newProps.patternTransform.size() == 6) {
|
||||||
self.patternTransform = CGAffineTransformMake(newProps.patternTransform.at(0), newProps.patternTransform.at(1), newProps.patternTransform.at(2), newProps.patternTransform.at(3), newProps.patternTransform.at(4), newProps.patternTransform.at(5));
|
self.patternTransform = CGAffineTransformMake(
|
||||||
}
|
newProps.patternTransform.at(0),
|
||||||
self.minX = newProps.minX;
|
newProps.patternTransform.at(1),
|
||||||
self.minY = newProps.minY;
|
newProps.patternTransform.at(2),
|
||||||
self.vbWidth = newProps.vbWidth;
|
newProps.patternTransform.at(3),
|
||||||
self.vbHeight = newProps.vbHeight;
|
newProps.patternTransform.at(4),
|
||||||
self.align = RCTNSStringFromStringNilIfEmpty(newProps.align);
|
newProps.patternTransform.at(5));
|
||||||
self.meetOrSlice = intToRNSVGVBMOS(newProps.meetOrSlice);
|
}
|
||||||
|
self.minX = newProps.minX;
|
||||||
|
self.minY = newProps.minY;
|
||||||
|
self.vbWidth = newProps.vbWidth;
|
||||||
|
self.vbHeight = newProps.vbHeight;
|
||||||
|
self.align = RCTNSStringFromStringNilIfEmpty(newProps.align);
|
||||||
|
self.meetOrSlice = intToRNSVGVBMOS(newProps.meetOrSlice);
|
||||||
|
|
||||||
setCommonGroupProps(newProps, self);
|
setCommonGroupProps(newProps, self);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)prepareForRecycle
|
- (void)prepareForRecycle
|
||||||
{
|
{
|
||||||
[super prepareForRecycle];
|
[super prepareForRecycle];
|
||||||
_x = nil;
|
_x = nil;
|
||||||
_y = nil;
|
_y = nil;
|
||||||
_patternheight = nil;
|
_patternheight = nil;
|
||||||
_patternwidth = nil;
|
_patternwidth = nil;
|
||||||
_patternUnits = kRNSVGUnitsObjectBoundingBox;
|
_patternUnits = kRNSVGUnitsObjectBoundingBox;
|
||||||
_patternContentUnits = kRNSVGUnitsObjectBoundingBox;
|
_patternContentUnits = kRNSVGUnitsObjectBoundingBox;
|
||||||
_patternTransform = CGAffineTransformIdentity;
|
_patternTransform = CGAffineTransformIdentity;
|
||||||
|
|
||||||
_minX = 0;
|
_minX = 0;
|
||||||
_minY = 0;
|
_minY = 0;
|
||||||
_vbWidth = 0;
|
_vbWidth = 0;
|
||||||
_vbHeight = 0;
|
_vbHeight = 0;
|
||||||
_align = nil;
|
_align = nil;
|
||||||
_meetOrSlice = kRNSVGVBMOSMeet;
|
_meetOrSlice = kRNSVGVBMOSMeet;
|
||||||
}
|
}
|
||||||
#endif // RN_FABRIC_ENABLED
|
#endif // RN_FABRIC_ENABLED
|
||||||
|
|
||||||
- (instancetype)init
|
- (instancetype)init
|
||||||
{
|
{
|
||||||
if (self = [super init]) {
|
if (self = [super init]) {
|
||||||
_patternTransform = CGAffineTransformIdentity;
|
_patternTransform = CGAffineTransformIdentity;
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (RNSVGPlatformView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
|
- (RNSVGPlatformView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
|
||||||
{
|
{
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)parseReference
|
- (void)parseReference
|
||||||
{
|
{
|
||||||
self.dirty = false;
|
self.dirty = false;
|
||||||
NSArray<RNSVGLength *> *points = @[self.x, self.y, self.patternwidth, self.patternheight];
|
NSArray<RNSVGLength *> *points = @[ self.x, self.y, self.patternwidth, self.patternheight ];
|
||||||
RNSVGPainter *painter = [[RNSVGPainter alloc] initWithPointsArray:points];
|
RNSVGPainter *painter = [[RNSVGPainter alloc] initWithPointsArray:points];
|
||||||
[painter setUnits:self.patternUnits];
|
[painter setUnits:self.patternUnits];
|
||||||
[painter setContentUnits:self.patternContentUnits];
|
[painter setContentUnits:self.patternContentUnits];
|
||||||
[painter setTransform:self.patternTransform];
|
[painter setTransform:self.patternTransform];
|
||||||
[painter setPattern:self];
|
[painter setPattern:self];
|
||||||
|
|
||||||
if (self.patternUnits == kRNSVGUnitsUserSpaceOnUse || self.patternContentUnits == kRNSVGUnitsUserSpaceOnUse) {
|
if (self.patternUnits == kRNSVGUnitsUserSpaceOnUse || self.patternContentUnits == kRNSVGUnitsUserSpaceOnUse) {
|
||||||
[painter setUserSpaceBoundingBox:[self.svgView getContextBounds]];
|
[painter setUserSpaceBoundingBox:[self.svgView getContextBounds]];
|
||||||
}
|
}
|
||||||
|
|
||||||
[self.svgView definePainter:painter painterName:self.name];
|
[self.svgView definePainter:painter painterName:self.name];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setX:(RNSVGLength *)x
|
- (void)setX:(RNSVGLength *)x
|
||||||
{
|
{
|
||||||
if ([x isEqualTo:_x]) {
|
if ([x isEqualTo:_x]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_x = x;
|
_x = x;
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setY:(RNSVGLength *)y
|
- (void)setY:(RNSVGLength *)y
|
||||||
{
|
{
|
||||||
if ([y isEqualTo:_y]) {
|
if ([y isEqualTo:_y]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_y = y;
|
_y = y;
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setPatternwidth:(RNSVGLength *)patternwidth
|
- (void)setPatternwidth:(RNSVGLength *)patternwidth
|
||||||
{
|
{
|
||||||
if ([patternwidth isEqualTo:_patternwidth]) {
|
if ([patternwidth isEqualTo:_patternwidth]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_patternwidth = patternwidth;
|
_patternwidth = patternwidth;
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setPatternheight:(RNSVGLength *)patternheight
|
- (void)setPatternheight:(RNSVGLength *)patternheight
|
||||||
{
|
{
|
||||||
if ([patternheight isEqualTo:_patternheight]) {
|
if ([patternheight isEqualTo:_patternheight]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_patternheight = patternheight;
|
_patternheight = patternheight;
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setPatternUnits:(RNSVGUnits)patternUnits
|
- (void)setPatternUnits:(RNSVGUnits)patternUnits
|
||||||
{
|
{
|
||||||
if (patternUnits == _patternUnits) {
|
if (patternUnits == _patternUnits) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_patternUnits = patternUnits;
|
_patternUnits = patternUnits;
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setPatternContentUnits:(RNSVGUnits)patternContentUnits
|
- (void)setPatternContentUnits:(RNSVGUnits)patternContentUnits
|
||||||
{
|
{
|
||||||
if (patternContentUnits == _patternContentUnits) {
|
if (patternContentUnits == _patternContentUnits) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_patternContentUnits = patternContentUnits;
|
_patternContentUnits = patternContentUnits;
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setPatternTransform:(CGAffineTransform)patternTransform
|
- (void)setPatternTransform:(CGAffineTransform)patternTransform
|
||||||
{
|
{
|
||||||
_patternTransform = patternTransform;
|
_patternTransform = patternTransform;
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setMinX:(CGFloat)minX
|
- (void)setMinX:(CGFloat)minX
|
||||||
{
|
{
|
||||||
if (minX == _minX) {
|
if (minX == _minX) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
_minX = minX;
|
_minX = minX;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setMinY:(CGFloat)minY
|
- (void)setMinY:(CGFloat)minY
|
||||||
{
|
{
|
||||||
if (minY == _minY) {
|
if (minY == _minY) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
_minY = minY;
|
_minY = minY;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setVbWidth:(CGFloat)vbWidth
|
- (void)setVbWidth:(CGFloat)vbWidth
|
||||||
{
|
{
|
||||||
if (vbWidth == _vbWidth) {
|
if (vbWidth == _vbWidth) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
_vbWidth = vbWidth;
|
_vbWidth = vbWidth;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setVbHeight:(CGFloat)vbHeight
|
- (void)setVbHeight:(CGFloat)vbHeight
|
||||||
{
|
{
|
||||||
if (_vbHeight == vbHeight) {
|
if (_vbHeight == vbHeight) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
_vbHeight = vbHeight;
|
_vbHeight = vbHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setAlign:(NSString *)align
|
- (void)setAlign:(NSString *)align
|
||||||
{
|
{
|
||||||
if ([align isEqualToString:_align]) {
|
if ([align isEqualToString:_align]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
_align = align;
|
_align = align;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setMeetOrSlice:(RNSVGVBMOS)meetOrSlice
|
- (void)setMeetOrSlice:(RNSVGVBMOS)meetOrSlice
|
||||||
{
|
{
|
||||||
if (meetOrSlice == _meetOrSlice) {
|
if (meetOrSlice == _meetOrSlice) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
_meetOrSlice = meetOrSlice;
|
_meetOrSlice = meetOrSlice;
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -6,8 +6,8 @@
|
|||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#import "RNSVGNode.h"
|
|
||||||
#import "RNSVGLength.h"
|
#import "RNSVGLength.h"
|
||||||
|
#import "RNSVGNode.h"
|
||||||
|
|
||||||
@interface RNSVGRadialGradient : RNSVGNode
|
@interface RNSVGRadialGradient : RNSVGNode
|
||||||
|
|
||||||
|
|||||||
@@ -9,9 +9,9 @@
|
|||||||
|
|
||||||
#ifdef RN_FABRIC_ENABLED
|
#ifdef RN_FABRIC_ENABLED
|
||||||
#import <react/renderer/components/rnsvg/ComponentDescriptors.h>
|
#import <react/renderer/components/rnsvg/ComponentDescriptors.h>
|
||||||
#import "RCTFabricComponentsPlugins.h"
|
|
||||||
#import "RCTConversions.h"
|
|
||||||
#import <react/renderer/components/view/conversions.h>
|
#import <react/renderer/components/view/conversions.h>
|
||||||
|
#import "RCTConversions.h"
|
||||||
|
#import "RCTFabricComponentsPlugins.h"
|
||||||
#import "RNSVGFabricConversions.h"
|
#import "RNSVGFabricConversions.h"
|
||||||
#endif // RN_FABRIC_ENABLED
|
#endif // RN_FABRIC_ENABLED
|
||||||
|
|
||||||
@@ -38,156 +38,162 @@ using namespace facebook::react;
|
|||||||
|
|
||||||
- (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps
|
- (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps
|
||||||
{
|
{
|
||||||
const auto &newProps = *std::static_pointer_cast<const RNSVGRadialGradientProps>(props);
|
const auto &newProps = *std::static_pointer_cast<const RNSVGRadialGradientProps>(props);
|
||||||
|
|
||||||
self.fx = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.fx)];
|
self.fx = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.fx)];
|
||||||
self.fy = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.fy)];
|
self.fy = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.fy)];
|
||||||
self.cx = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.cx)];
|
self.cx = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.cx)];
|
||||||
self.cy = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.cy)];
|
self.cy = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.cy)];
|
||||||
self.rx = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.rx)];
|
self.rx = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.rx)];
|
||||||
self.ry = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.ry)];
|
self.ry = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.ry)];
|
||||||
if (newProps.gradient.size() > 0) {
|
if (newProps.gradient.size() > 0) {
|
||||||
NSMutableArray<NSNumber *> *gradientArray = [NSMutableArray new];
|
NSMutableArray<NSNumber *> *gradientArray = [NSMutableArray new];
|
||||||
for (auto number : newProps.gradient) {
|
for (auto number : newProps.gradient) {
|
||||||
[gradientArray addObject:[NSNumber numberWithDouble:number]];
|
[gradientArray addObject:[NSNumber numberWithDouble:number]];
|
||||||
}
|
|
||||||
self.gradient = gradientArray;
|
|
||||||
}
|
|
||||||
self.gradientUnits = newProps.gradientUnits == 0 ? kRNSVGUnitsObjectBoundingBox : kRNSVGUnitsUserSpaceOnUse;
|
|
||||||
if (newProps.gradientTransform.size() == 6) {
|
|
||||||
self.gradientTransform = CGAffineTransformMake(newProps.gradientTransform.at(0), newProps.gradientTransform.at(1), newProps.gradientTransform.at(2), newProps.gradientTransform.at(3), newProps.gradientTransform.at(4), newProps.gradientTransform.at(5));
|
|
||||||
}
|
}
|
||||||
|
self.gradient = gradientArray;
|
||||||
|
}
|
||||||
|
self.gradientUnits = newProps.gradientUnits == 0 ? kRNSVGUnitsObjectBoundingBox : kRNSVGUnitsUserSpaceOnUse;
|
||||||
|
if (newProps.gradientTransform.size() == 6) {
|
||||||
|
self.gradientTransform = CGAffineTransformMake(
|
||||||
|
newProps.gradientTransform.at(0),
|
||||||
|
newProps.gradientTransform.at(1),
|
||||||
|
newProps.gradientTransform.at(2),
|
||||||
|
newProps.gradientTransform.at(3),
|
||||||
|
newProps.gradientTransform.at(4),
|
||||||
|
newProps.gradientTransform.at(5));
|
||||||
|
}
|
||||||
|
|
||||||
setCommonNodeProps(newProps, self);
|
setCommonNodeProps(newProps, self);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)prepareForRecycle
|
- (void)prepareForRecycle
|
||||||
{
|
{
|
||||||
[super prepareForRecycle];
|
[super prepareForRecycle];
|
||||||
_fx = nil;
|
_fx = nil;
|
||||||
_fy = nil;
|
_fy = nil;
|
||||||
_cx = nil;
|
_cx = nil;
|
||||||
_cy = nil;
|
_cy = nil;
|
||||||
_rx = nil;
|
_rx = nil;
|
||||||
_ry = nil;
|
_ry = nil;
|
||||||
_gradient = nil;
|
_gradient = nil;
|
||||||
_gradientUnits = kRNSVGUnitsObjectBoundingBox;
|
_gradientUnits = kRNSVGUnitsObjectBoundingBox;
|
||||||
_gradientTransform = CGAffineTransformIdentity;
|
_gradientTransform = CGAffineTransformIdentity;
|
||||||
}
|
}
|
||||||
#endif // RN_FABRIC_ENABLED
|
#endif // RN_FABRIC_ENABLED
|
||||||
- (instancetype)init
|
- (instancetype)init
|
||||||
{
|
{
|
||||||
if (self = [super init]) {
|
if (self = [super init]) {
|
||||||
_gradientTransform = CGAffineTransformIdentity;
|
_gradientTransform = CGAffineTransformIdentity;
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setFx:(RNSVGLength *)fx
|
- (void)setFx:(RNSVGLength *)fx
|
||||||
{
|
{
|
||||||
if ([fx isEqualTo:_fx]) {
|
if ([fx isEqualTo:_fx]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_fx = fx;
|
_fx = fx;
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setFy:(RNSVGLength *)fy
|
- (void)setFy:(RNSVGLength *)fy
|
||||||
{
|
{
|
||||||
if ([fy isEqualTo:_fy]) {
|
if ([fy isEqualTo:_fy]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_fy = fy;
|
_fy = fy;
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setRx:(RNSVGLength *)rx
|
- (void)setRx:(RNSVGLength *)rx
|
||||||
{
|
{
|
||||||
if ([rx isEqualTo:_rx]) {
|
if ([rx isEqualTo:_rx]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_rx = rx;
|
_rx = rx;
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setRy:(RNSVGLength *)ry
|
- (void)setRy:(RNSVGLength *)ry
|
||||||
{
|
{
|
||||||
if ([ry isEqualTo:_ry]) {
|
if ([ry isEqualTo:_ry]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_ry = ry;
|
_ry = ry;
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setCx:(RNSVGLength *)cx
|
- (void)setCx:(RNSVGLength *)cx
|
||||||
{
|
{
|
||||||
if ([cx isEqualTo:_cx]) {
|
if ([cx isEqualTo:_cx]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_cx = cx;
|
_cx = cx;
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setCy:(RNSVGLength *)cy
|
- (void)setCy:(RNSVGLength *)cy
|
||||||
{
|
{
|
||||||
if ([cy isEqualTo:_cy]) {
|
if ([cy isEqualTo:_cy]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_cy = cy;
|
_cy = cy;
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setGradient:(NSArray<NSNumber *> *)gradient
|
- (void)setGradient:(NSArray<NSNumber *> *)gradient
|
||||||
{
|
{
|
||||||
if (gradient == _gradient) {
|
if (gradient == _gradient) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_gradient = gradient;
|
_gradient = gradient;
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setGradientUnits:(RNSVGUnits)gradientUnits
|
- (void)setGradientUnits:(RNSVGUnits)gradientUnits
|
||||||
{
|
{
|
||||||
if (gradientUnits == _gradientUnits) {
|
if (gradientUnits == _gradientUnits) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_gradientUnits = gradientUnits;
|
_gradientUnits = gradientUnits;
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setGradientTransform:(CGAffineTransform)gradientTransform
|
- (void)setGradientTransform:(CGAffineTransform)gradientTransform
|
||||||
{
|
{
|
||||||
_gradientTransform = gradientTransform;
|
_gradientTransform = gradientTransform;
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (RNSVGPlatformView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
|
- (RNSVGPlatformView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
|
||||||
{
|
{
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)parseReference
|
- (void)parseReference
|
||||||
{
|
{
|
||||||
self.dirty = false;
|
self.dirty = false;
|
||||||
NSArray<RNSVGLength *> *points = @[self.fx, self.fy, self.rx, self.ry, self.cx, self.cy];
|
NSArray<RNSVGLength *> *points = @[ self.fx, self.fy, self.rx, self.ry, self.cx, self.cy ];
|
||||||
RNSVGPainter *painter = [[RNSVGPainter alloc] initWithPointsArray:points];
|
RNSVGPainter *painter = [[RNSVGPainter alloc] initWithPointsArray:points];
|
||||||
[painter setUnits:self.gradientUnits];
|
[painter setUnits:self.gradientUnits];
|
||||||
[painter setTransform:self.gradientTransform];
|
[painter setTransform:self.gradientTransform];
|
||||||
[painter setRadialGradientColors:self.gradient];
|
[painter setRadialGradientColors:self.gradient];
|
||||||
|
|
||||||
if (self.gradientUnits == kRNSVGUnitsUserSpaceOnUse) {
|
if (self.gradientUnits == kRNSVGUnitsUserSpaceOnUse) {
|
||||||
[painter setUserSpaceBoundingBox:[self.svgView getContextBounds]];
|
[painter setUserSpaceBoundingBox:[self.svgView getContextBounds]];
|
||||||
}
|
}
|
||||||
|
|
||||||
[self.svgView definePainter:painter painterName:self.name];
|
[self.svgView definePainter:painter painterName:self.name];
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -8,8 +8,8 @@
|
|||||||
|
|
||||||
#import "RNSVGUIKit.h"
|
#import "RNSVGUIKit.h"
|
||||||
|
|
||||||
#import "RNSVGPainter.h"
|
|
||||||
#import "RNSVGContainer.h"
|
#import "RNSVGContainer.h"
|
||||||
|
#import "RNSVGPainter.h"
|
||||||
#import "RNSVGVBMOS.h"
|
#import "RNSVGVBMOS.h"
|
||||||
|
|
||||||
#ifdef RN_FABRIC_ENABLED
|
#ifdef RN_FABRIC_ENABLED
|
||||||
@@ -20,9 +20,9 @@
|
|||||||
|
|
||||||
@interface RNSVGSvgView :
|
@interface RNSVGSvgView :
|
||||||
#ifdef RN_FABRIC_ENABLED
|
#ifdef RN_FABRIC_ENABLED
|
||||||
RCTViewComponentView <RNSVGContainer>
|
RCTViewComponentView <RNSVGContainer>
|
||||||
#else
|
#else
|
||||||
RNSVGView <RNSVGContainer>
|
RNSVGView <RNSVGContainer>
|
||||||
#endif // RN_FABRIC_ENABLED
|
#endif // RN_FABRIC_ENABLED
|
||||||
|
|
||||||
@property (nonatomic, strong) RNSVGLength *bbWidth;
|
@property (nonatomic, strong) RNSVGLength *bbWidth;
|
||||||
|
|||||||
@@ -7,27 +7,26 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#import "RNSVGSvgView.h"
|
#import "RNSVGSvgView.h"
|
||||||
#import "RNSVGViewBox.h"
|
|
||||||
#import "RNSVGNode.h"
|
|
||||||
#import <React/RCTLog.h>
|
#import <React/RCTLog.h>
|
||||||
|
#import "RNSVGNode.h"
|
||||||
|
#import "RNSVGViewBox.h"
|
||||||
|
|
||||||
#ifdef RN_FABRIC_ENABLED
|
#ifdef RN_FABRIC_ENABLED
|
||||||
#import <react/renderer/components/rnsvg/ComponentDescriptors.h>
|
#import <react/renderer/components/rnsvg/ComponentDescriptors.h>
|
||||||
#import "RCTFabricComponentsPlugins.h"
|
|
||||||
#import "RCTConversions.h"
|
|
||||||
#import <react/renderer/components/view/conversions.h>
|
#import <react/renderer/components/view/conversions.h>
|
||||||
|
#import "RCTConversions.h"
|
||||||
|
#import "RCTFabricComponentsPlugins.h"
|
||||||
#import "RNSVGFabricConversions.h"
|
#import "RNSVGFabricConversions.h"
|
||||||
#endif // RN_FABRIC_ENABLED
|
#endif // RN_FABRIC_ENABLED
|
||||||
|
|
||||||
@implementation RNSVGSvgView
|
@implementation RNSVGSvgView {
|
||||||
{
|
NSMutableDictionary<NSString *, RNSVGNode *> *_clipPaths;
|
||||||
NSMutableDictionary<NSString *, RNSVGNode *> *_clipPaths;
|
NSMutableDictionary<NSString *, RNSVGNode *> *_templates;
|
||||||
NSMutableDictionary<NSString *, RNSVGNode *> *_templates;
|
NSMutableDictionary<NSString *, RNSVGPainter *> *_painters;
|
||||||
NSMutableDictionary<NSString *, RNSVGPainter *> *_painters;
|
NSMutableDictionary<NSString *, RNSVGNode *> *_markers;
|
||||||
NSMutableDictionary<NSString *, RNSVGNode *> *_markers;
|
NSMutableDictionary<NSString *, RNSVGNode *> *_masks;
|
||||||
NSMutableDictionary<NSString *, RNSVGNode *> *_masks;
|
CGAffineTransform _invviewBoxTransform;
|
||||||
CGAffineTransform _invviewBoxTransform;
|
bool rendered;
|
||||||
bool rendered;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef RN_FABRIC_ENABLED
|
#ifdef RN_FABRIC_ENABLED
|
||||||
@@ -36,21 +35,21 @@ using namespace facebook::react;
|
|||||||
|
|
||||||
- (instancetype)initWithFrame:(CGRect)frame
|
- (instancetype)initWithFrame:(CGRect)frame
|
||||||
{
|
{
|
||||||
if (self = [super initWithFrame:frame]) {
|
if (self = [super initWithFrame:frame]) {
|
||||||
#if !TARGET_OS_OSX // Not available on macOS
|
#if !TARGET_OS_OSX // Not available on macOS
|
||||||
// This is necessary to ensure that [self setNeedsDisplay] actually triggers
|
// This is necessary to ensure that [self setNeedsDisplay] actually triggers
|
||||||
// a redraw when our parent transitions between hidden and visible.
|
// a redraw when our parent transitions between hidden and visible.
|
||||||
self.contentMode = UIViewContentModeRedraw;
|
self.contentMode = UIViewContentModeRedraw;
|
||||||
#endif // TARGET_OS_OSX
|
#endif // TARGET_OS_OSX
|
||||||
rendered = false;
|
rendered = false;
|
||||||
#ifdef RN_FABRIC_ENABLED
|
#ifdef RN_FABRIC_ENABLED
|
||||||
static const auto defaultProps = std::make_shared<const RNSVGSvgViewProps>();
|
static const auto defaultProps = std::make_shared<const RNSVGSvgViewProps>();
|
||||||
_props = defaultProps;
|
_props = defaultProps;
|
||||||
// TODO: think if we can do it better
|
// TODO: think if we can do it better
|
||||||
self.opaque = NO;
|
self.opaque = NO;
|
||||||
#endif // RN_FABRIC_ENABLED
|
#endif // RN_FABRIC_ENABLED
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef RN_FABRIC_ENABLED
|
#ifdef RN_FABRIC_ENABLED
|
||||||
@@ -63,379 +62,374 @@ using namespace facebook::react;
|
|||||||
|
|
||||||
- (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps
|
- (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps
|
||||||
{
|
{
|
||||||
const auto &newProps = *std::static_pointer_cast<const RNSVGSvgViewProps>(props);
|
const auto &newProps = *std::static_pointer_cast<const RNSVGSvgViewProps>(props);
|
||||||
|
|
||||||
self.minX = newProps.minX;
|
self.minX = newProps.minX;
|
||||||
self.minY = newProps.minY;
|
self.minY = newProps.minY;
|
||||||
self.vbWidth = newProps.vbWidth;
|
self.vbWidth = newProps.vbWidth;
|
||||||
self.vbHeight = newProps.vbHeight;
|
self.vbHeight = newProps.vbHeight;
|
||||||
self.bbWidth = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.bbWidth)];
|
self.bbWidth = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.bbWidth)];
|
||||||
self.bbHeight = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.bbHeight)];
|
self.bbHeight = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.bbHeight)];
|
||||||
self.align = RCTNSStringFromStringNilIfEmpty(newProps.align);
|
self.align = RCTNSStringFromStringNilIfEmpty(newProps.align);
|
||||||
self.meetOrSlice = intToRNSVGVBMOS(newProps.meetOrSlice);
|
self.meetOrSlice = intToRNSVGVBMOS(newProps.meetOrSlice);
|
||||||
if (RCTUIColorFromSharedColor(newProps.tintColor)) {
|
if (RCTUIColorFromSharedColor(newProps.tintColor)) {
|
||||||
self.tintColor = RCTUIColorFromSharedColor(newProps.tintColor);
|
self.tintColor = RCTUIColorFromSharedColor(newProps.tintColor);
|
||||||
}
|
}
|
||||||
if (RCTUIColorFromSharedColor(newProps.color)) {
|
if (RCTUIColorFromSharedColor(newProps.color)) {
|
||||||
self.tintColor = RCTUIColorFromSharedColor(newProps.color);
|
self.tintColor = RCTUIColorFromSharedColor(newProps.color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (void)prepareForRecycle
|
- (void)prepareForRecycle
|
||||||
{
|
{
|
||||||
[super prepareForRecycle];
|
[super prepareForRecycle];
|
||||||
_minX = 0;
|
_minX = 0;
|
||||||
_minY = 0;
|
_minY = 0;
|
||||||
_vbWidth = 0;
|
_vbWidth = 0;
|
||||||
_vbHeight = 0;
|
_vbHeight = 0;
|
||||||
_bbWidth = 0;
|
_bbWidth = 0;
|
||||||
_bbHeight = 0;
|
_bbHeight = 0;
|
||||||
_align = nil;
|
_align = nil;
|
||||||
_meetOrSlice = kRNSVGVBMOSMeet;
|
_meetOrSlice = kRNSVGVBMOSMeet;
|
||||||
|
|
||||||
_responsible = NO;
|
_responsible = NO;
|
||||||
_active = NO;
|
_active = NO;
|
||||||
_boundingBox = CGRectZero;
|
_boundingBox = CGRectZero;
|
||||||
_initialCTM = CGAffineTransformIdentity;
|
_initialCTM = CGAffineTransformIdentity;
|
||||||
_invInitialCTM = CGAffineTransformIdentity;
|
_invInitialCTM = CGAffineTransformIdentity;
|
||||||
_viewBoxTransform = CGAffineTransformIdentity;
|
_viewBoxTransform = CGAffineTransformIdentity;
|
||||||
|
|
||||||
_clipPaths = nil;
|
_clipPaths = nil;
|
||||||
_templates = nil;
|
_templates = nil;
|
||||||
_painters = nil;
|
_painters = nil;
|
||||||
_markers = nil;
|
_markers = nil;
|
||||||
_masks = nil;
|
_masks = nil;
|
||||||
_invviewBoxTransform = CGAffineTransformIdentity;
|
_invviewBoxTransform = CGAffineTransformIdentity;
|
||||||
rendered = NO;
|
rendered = NO;
|
||||||
}
|
}
|
||||||
#endif // RN_FABRIC_ENABLED
|
#endif // RN_FABRIC_ENABLED
|
||||||
|
|
||||||
- (void)insertReactSubview:(RNSVGView *)subview atIndex:(NSInteger)atIndex
|
- (void)insertReactSubview:(RNSVGView *)subview atIndex:(NSInteger)atIndex
|
||||||
{
|
{
|
||||||
[super insertReactSubview:subview atIndex:atIndex];
|
[super insertReactSubview:subview atIndex:atIndex];
|
||||||
[self insertSubview:subview atIndex:atIndex];
|
[self insertSubview:subview atIndex:atIndex];
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)removeReactSubview:(RNSVGView *)subview
|
- (void)removeReactSubview:(RNSVGView *)subview
|
||||||
{
|
{
|
||||||
[super removeReactSubview:subview];
|
[super removeReactSubview:subview];
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)didUpdateReactSubviews
|
- (void)didUpdateReactSubviews
|
||||||
{
|
{
|
||||||
// Do nothing, as subviews are inserted by insertReactSubview:
|
// Do nothing, as subviews are inserted by insertReactSubview:
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)clearChildCache
|
- (void)clearChildCache
|
||||||
{
|
{
|
||||||
if (!rendered) {
|
if (!rendered) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
rendered = false;
|
rendered = false;
|
||||||
for (__kindof RNSVGNode *node in self.subviews) {
|
for (__kindof RNSVGNode *node in self.subviews) {
|
||||||
if ([node isKindOfClass:[RNSVGNode class]]) {
|
if ([node isKindOfClass:[RNSVGNode class]]) {
|
||||||
[node clearChildCache];
|
[node clearChildCache];
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)invalidate
|
- (void)invalidate
|
||||||
{
|
{
|
||||||
RNSVGPlatformView* parent = self.superview;
|
RNSVGPlatformView *parent = self.superview;
|
||||||
if ([parent isKindOfClass:[RNSVGNode class]]) {
|
if ([parent isKindOfClass:[RNSVGNode class]]) {
|
||||||
if (!rendered) {
|
if (!rendered) {
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
RNSVGNode* svgNode = (RNSVGNode*)parent;
|
|
||||||
[svgNode invalidate];
|
|
||||||
rendered = false;
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
[self setNeedsDisplay];
|
RNSVGNode *svgNode = (RNSVGNode *)parent;
|
||||||
|
[svgNode invalidate];
|
||||||
|
rendered = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
[self setNeedsDisplay];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)tintColorDidChange
|
- (void)tintColorDidChange
|
||||||
{
|
{
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
[self clearChildCache];
|
[self clearChildCache];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setMinX:(CGFloat)minX
|
- (void)setMinX:(CGFloat)minX
|
||||||
{
|
{
|
||||||
if (minX == _minX) {
|
if (minX == _minX) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
[self clearChildCache];
|
[self clearChildCache];
|
||||||
_minX = minX;
|
_minX = minX;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setMinY:(CGFloat)minY
|
- (void)setMinY:(CGFloat)minY
|
||||||
{
|
{
|
||||||
if (minY == _minY) {
|
if (minY == _minY) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
[self clearChildCache];
|
[self clearChildCache];
|
||||||
_minY = minY;
|
_minY = minY;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setVbWidth:(CGFloat)vbWidth
|
- (void)setVbWidth:(CGFloat)vbWidth
|
||||||
{
|
{
|
||||||
if (vbWidth == _vbWidth) {
|
if (vbWidth == _vbWidth) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
[self clearChildCache];
|
[self clearChildCache];
|
||||||
_vbWidth = vbWidth;
|
_vbWidth = vbWidth;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setVbHeight:(CGFloat)vbHeight
|
- (void)setVbHeight:(CGFloat)vbHeight
|
||||||
{
|
{
|
||||||
if (_vbHeight == vbHeight) {
|
if (_vbHeight == vbHeight) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
[self clearChildCache];
|
[self clearChildCache];
|
||||||
_vbHeight = vbHeight;
|
_vbHeight = vbHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setBbWidth:(RNSVGLength *)bbWidth
|
- (void)setBbWidth:(RNSVGLength *)bbWidth
|
||||||
{
|
{
|
||||||
if ([bbWidth isEqualTo:_bbWidth]) {
|
if ([bbWidth isEqualTo:_bbWidth]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
[self clearChildCache];
|
[self clearChildCache];
|
||||||
_bbWidth = bbWidth;
|
_bbWidth = bbWidth;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setBbHeight:(RNSVGLength *)bbHeight
|
- (void)setBbHeight:(RNSVGLength *)bbHeight
|
||||||
{
|
{
|
||||||
if ([bbHeight isEqualTo:_bbHeight]) {
|
if ([bbHeight isEqualTo:_bbHeight]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
[self clearChildCache];
|
[self clearChildCache];
|
||||||
_bbHeight = bbHeight;
|
_bbHeight = bbHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setAlign:(NSString *)align
|
- (void)setAlign:(NSString *)align
|
||||||
{
|
{
|
||||||
if ([align isEqualToString:_align]) {
|
if ([align isEqualToString:_align]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
[self clearChildCache];
|
[self clearChildCache];
|
||||||
_align = align;
|
_align = align;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setMeetOrSlice:(RNSVGVBMOS)meetOrSlice
|
- (void)setMeetOrSlice:(RNSVGVBMOS)meetOrSlice
|
||||||
{
|
{
|
||||||
if (meetOrSlice == _meetOrSlice) {
|
if (meetOrSlice == _meetOrSlice) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
[self clearChildCache];
|
[self clearChildCache];
|
||||||
_meetOrSlice = meetOrSlice;
|
_meetOrSlice = meetOrSlice;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)drawToContext:(CGContextRef)context withRect:(CGRect)rect {
|
- (void)drawToContext:(CGContextRef)context withRect:(CGRect)rect
|
||||||
rendered = true;
|
{
|
||||||
self.initialCTM = CGContextGetCTM(context);
|
rendered = true;
|
||||||
self.invInitialCTM = CGAffineTransformInvert(self.initialCTM);
|
self.initialCTM = CGContextGetCTM(context);
|
||||||
if (self.align) {
|
self.invInitialCTM = CGAffineTransformInvert(self.initialCTM);
|
||||||
CGRect tRect = CGRectMake(self.minX, self.minY, self.vbWidth, self.vbHeight);
|
if (self.align) {
|
||||||
_viewBoxTransform = [RNSVGViewBox getTransform:tRect
|
CGRect tRect = CGRectMake(self.minX, self.minY, self.vbWidth, self.vbHeight);
|
||||||
eRect:rect
|
_viewBoxTransform = [RNSVGViewBox getTransform:tRect eRect:rect align:self.align meetOrSlice:self.meetOrSlice];
|
||||||
align:self.align
|
_invviewBoxTransform = CGAffineTransformInvert(_viewBoxTransform);
|
||||||
meetOrSlice:self.meetOrSlice];
|
CGContextConcatCTM(context, _viewBoxTransform);
|
||||||
_invviewBoxTransform = CGAffineTransformInvert(_viewBoxTransform);
|
} else {
|
||||||
CGContextConcatCTM(context, _viewBoxTransform);
|
_viewBoxTransform = CGAffineTransformIdentity;
|
||||||
} else {
|
_invviewBoxTransform = CGAffineTransformIdentity;
|
||||||
_viewBoxTransform = CGAffineTransformIdentity;
|
}
|
||||||
_invviewBoxTransform = CGAffineTransformIdentity;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (RNSVGView *node in self.subviews) {
|
for (RNSVGView *node in self.subviews) {
|
||||||
if ([node isKindOfClass:[RNSVGNode class]]) {
|
if ([node isKindOfClass:[RNSVGNode class]]) {
|
||||||
RNSVGNode *svg = (RNSVGNode *)node;
|
RNSVGNode *svg = (RNSVGNode *)node;
|
||||||
[svg renderTo:context
|
[svg renderTo:context rect:rect];
|
||||||
rect:rect];
|
} else {
|
||||||
} else {
|
[node drawRect:rect];
|
||||||
[node drawRect:rect];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)drawRect:(CGRect)rect
|
- (void)drawRect:(CGRect)rect
|
||||||
{
|
{
|
||||||
RNSVGPlatformView* parent = self.superview;
|
RNSVGPlatformView *parent = self.superview;
|
||||||
if ([parent isKindOfClass:[RNSVGNode class]]) {
|
if ([parent isKindOfClass:[RNSVGNode class]]) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
rendered = true;
|
||||||
|
_clipPaths = nil;
|
||||||
|
_templates = nil;
|
||||||
|
_painters = nil;
|
||||||
|
_boundingBox = rect;
|
||||||
|
CGContextRef context = UIGraphicsGetCurrentContext();
|
||||||
|
|
||||||
|
for (RNSVGPlatformView *node in self.subviews) {
|
||||||
|
if ([node isKindOfClass:[RNSVGNode class]]) {
|
||||||
|
RNSVGNode *svg = (RNSVGNode *)node;
|
||||||
|
if (svg.responsible && !self.responsible) {
|
||||||
|
self.responsible = YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
[svg parseReference];
|
||||||
}
|
}
|
||||||
rendered = true;
|
}
|
||||||
_clipPaths = nil;
|
|
||||||
_templates = nil;
|
|
||||||
_painters = nil;
|
|
||||||
_boundingBox = rect;
|
|
||||||
CGContextRef context = UIGraphicsGetCurrentContext();
|
|
||||||
|
|
||||||
for (RNSVGPlatformView *node in self.subviews) {
|
[self drawToContext:context withRect:rect];
|
||||||
if ([node isKindOfClass:[RNSVGNode class]]) {
|
|
||||||
RNSVGNode *svg = (RNSVGNode *)node;
|
|
||||||
if (svg.responsible && !self.responsible) {
|
|
||||||
self.responsible = YES;
|
|
||||||
}
|
|
||||||
|
|
||||||
[svg parseReference];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[self drawToContext:context withRect:rect];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (RNSVGPlatformView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
|
- (RNSVGPlatformView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
|
||||||
{
|
{
|
||||||
CGPoint transformed = point;
|
CGPoint transformed = point;
|
||||||
if (self.align) {
|
if (self.align) {
|
||||||
transformed = CGPointApplyAffineTransform(transformed, _invviewBoxTransform);
|
transformed = CGPointApplyAffineTransform(transformed, _invviewBoxTransform);
|
||||||
|
}
|
||||||
|
for (RNSVGNode *node in [self.subviews reverseObjectEnumerator]) {
|
||||||
|
if (![node isKindOfClass:[RNSVGNode class]]) {
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
for (RNSVGNode *node in [self.subviews reverseObjectEnumerator]) {
|
|
||||||
if (![node isKindOfClass:[RNSVGNode class]]) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (event) {
|
if (event) {
|
||||||
node.active = NO;
|
node.active = NO;
|
||||||
}
|
|
||||||
|
|
||||||
RNSVGPlatformView *hitChild = [node hitTest:transformed withEvent:event];
|
|
||||||
|
|
||||||
if (hitChild) {
|
|
||||||
node.active = YES;
|
|
||||||
return (node.responsible || (node != hitChild)) ? hitChild : self;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return nil;
|
|
||||||
|
RNSVGPlatformView *hitChild = [node hitTest:transformed withEvent:event];
|
||||||
|
|
||||||
|
if (hitChild) {
|
||||||
|
node.active = YES;
|
||||||
|
return (node.responsible || (node != hitChild)) ? hitChild : self;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSString *)getDataURL
|
- (NSString *)getDataURL
|
||||||
{
|
{
|
||||||
UIGraphicsBeginImageContextWithOptions(_boundingBox.size, NO, 0);
|
UIGraphicsBeginImageContextWithOptions(_boundingBox.size, NO, 0);
|
||||||
[self clearChildCache];
|
[self clearChildCache];
|
||||||
[self drawRect:_boundingBox];
|
[self drawRect:_boundingBox];
|
||||||
[self clearChildCache];
|
[self clearChildCache];
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
NSData *imageData = UIImagePNGRepresentation(UIGraphicsGetImageFromCurrentImageContext());
|
NSData *imageData = UIImagePNGRepresentation(UIGraphicsGetImageFromCurrentImageContext());
|
||||||
NSString *base64 = [imageData base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength];
|
NSString *base64 = [imageData base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength];
|
||||||
UIGraphicsEndImageContext();
|
UIGraphicsEndImageContext();
|
||||||
return base64;
|
return base64;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSString *)getDataURLwithBounds:(CGRect)bounds
|
- (NSString *)getDataURLwithBounds:(CGRect)bounds
|
||||||
{
|
{
|
||||||
UIGraphicsBeginImageContextWithOptions(bounds.size, NO, 1);
|
UIGraphicsBeginImageContextWithOptions(bounds.size, NO, 1);
|
||||||
[self clearChildCache];
|
[self clearChildCache];
|
||||||
[self drawRect:bounds];
|
[self drawRect:bounds];
|
||||||
[self clearChildCache];
|
[self clearChildCache];
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
NSData *imageData = UIImagePNGRepresentation(UIGraphicsGetImageFromCurrentImageContext());
|
NSData *imageData = UIImagePNGRepresentation(UIGraphicsGetImageFromCurrentImageContext());
|
||||||
NSString *base64 = [imageData base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength];
|
NSString *base64 = [imageData base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength];
|
||||||
UIGraphicsEndImageContext();
|
UIGraphicsEndImageContext();
|
||||||
return base64;
|
return base64;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)reactSetInheritedBackgroundColor:(RNSVGColor *)inheritedBackgroundColor
|
- (void)reactSetInheritedBackgroundColor:(RNSVGColor *)inheritedBackgroundColor
|
||||||
{
|
{
|
||||||
self.backgroundColor = inheritedBackgroundColor;
|
self.backgroundColor = inheritedBackgroundColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)defineClipPath:(__kindof RNSVGNode *)clipPath clipPathName:(NSString *)clipPathName
|
- (void)defineClipPath:(__kindof RNSVGNode *)clipPath clipPathName:(NSString *)clipPathName
|
||||||
{
|
{
|
||||||
if (!_clipPaths) {
|
if (!_clipPaths) {
|
||||||
_clipPaths = [[NSMutableDictionary alloc] init];
|
_clipPaths = [[NSMutableDictionary alloc] init];
|
||||||
}
|
}
|
||||||
[_clipPaths setObject:clipPath forKey:clipPathName];
|
[_clipPaths setObject:clipPath forKey:clipPathName];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (RNSVGNode *)getDefinedClipPath:(NSString *)clipPathName
|
- (RNSVGNode *)getDefinedClipPath:(NSString *)clipPathName
|
||||||
{
|
{
|
||||||
return _clipPaths ? [_clipPaths objectForKey:clipPathName] : nil;
|
return _clipPaths ? [_clipPaths objectForKey:clipPathName] : nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)defineTemplate:(RNSVGNode *)definedTemplate templateName:(NSString *)templateName
|
- (void)defineTemplate:(RNSVGNode *)definedTemplate templateName:(NSString *)templateName
|
||||||
{
|
{
|
||||||
if (!_templates) {
|
if (!_templates) {
|
||||||
_templates = [[NSMutableDictionary alloc] init];
|
_templates = [[NSMutableDictionary alloc] init];
|
||||||
}
|
}
|
||||||
[_templates setObject:definedTemplate forKey:templateName];
|
[_templates setObject:definedTemplate forKey:templateName];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (RNSVGNode *)getDefinedTemplate:(NSString *)templateName
|
- (RNSVGNode *)getDefinedTemplate:(NSString *)templateName
|
||||||
{
|
{
|
||||||
return _templates ? [_templates objectForKey:templateName] : nil;
|
return _templates ? [_templates objectForKey:templateName] : nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (void)definePainter:(RNSVGPainter *)painter painterName:(NSString *)painterName
|
- (void)definePainter:(RNSVGPainter *)painter painterName:(NSString *)painterName
|
||||||
{
|
{
|
||||||
if (!_painters) {
|
if (!_painters) {
|
||||||
_painters = [[NSMutableDictionary alloc] init];
|
_painters = [[NSMutableDictionary alloc] init];
|
||||||
}
|
}
|
||||||
[_painters setObject:painter forKey:painterName];
|
[_painters setObject:painter forKey:painterName];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (RNSVGPainter *)getDefinedPainter:(NSString *)painterName;
|
- (RNSVGPainter *)getDefinedPainter:(NSString *)painterName;
|
||||||
{
|
{
|
||||||
return _painters ? [_painters objectForKey:painterName] : nil;
|
return _painters ? [_painters objectForKey:painterName] : nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)defineMarker:(RNSVGNode *)marker markerName:(NSString *)markerName
|
- (void)defineMarker:(RNSVGNode *)marker markerName:(NSString *)markerName
|
||||||
{
|
{
|
||||||
if (!_markers) {
|
if (!_markers) {
|
||||||
_markers = [[NSMutableDictionary alloc] init];
|
_markers = [[NSMutableDictionary alloc] init];
|
||||||
}
|
}
|
||||||
[_markers setObject:marker forKey:markerName];
|
[_markers setObject:marker forKey:markerName];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (RNSVGNode *)getDefinedMarker:(NSString *)markerName;
|
- (RNSVGNode *)getDefinedMarker:(NSString *)markerName;
|
||||||
{
|
{
|
||||||
return _markers ? [_markers objectForKey:markerName] : nil;
|
return _markers ? [_markers objectForKey:markerName] : nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)defineMask:(RNSVGNode *)mask maskName:(NSString *)maskName
|
- (void)defineMask:(RNSVGNode *)mask maskName:(NSString *)maskName
|
||||||
{
|
{
|
||||||
if (!_masks) {
|
if (!_masks) {
|
||||||
_masks = [[NSMutableDictionary alloc] init];
|
_masks = [[NSMutableDictionary alloc] init];
|
||||||
}
|
}
|
||||||
[_masks setObject:mask forKey:maskName];
|
[_masks setObject:mask forKey:maskName];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (RNSVGNode *)getDefinedMask:(NSString *)maskName;
|
- (RNSVGNode *)getDefinedMask:(NSString *)maskName;
|
||||||
{
|
{
|
||||||
return _masks ? [_masks objectForKey:maskName] : nil;
|
return _masks ? [_masks objectForKey:maskName] : nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CGRect)getContextBounds
|
- (CGRect)getContextBounds
|
||||||
{
|
{
|
||||||
return CGContextGetClipBoundingBox(UIGraphicsGetCurrentContext());
|
return CGContextGetClipBoundingBox(UIGraphicsGetCurrentContext());
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CGAffineTransform)getViewBoxTransform
|
- (CGAffineTransform)getViewBoxTransform
|
||||||
{
|
{
|
||||||
return _viewBoxTransform;
|
return _viewBoxTransform;
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -10,9 +10,9 @@
|
|||||||
|
|
||||||
#ifdef RN_FABRIC_ENABLED
|
#ifdef RN_FABRIC_ENABLED
|
||||||
#import <react/renderer/components/rnsvg/ComponentDescriptors.h>
|
#import <react/renderer/components/rnsvg/ComponentDescriptors.h>
|
||||||
#import "RCTFabricComponentsPlugins.h"
|
|
||||||
#import "RCTConversions.h"
|
|
||||||
#import <react/renderer/components/view/conversions.h>
|
#import <react/renderer/components/view/conversions.h>
|
||||||
|
#import "RCTConversions.h"
|
||||||
|
#import "RCTFabricComponentsPlugins.h"
|
||||||
#import "RNSVGFabricConversions.h"
|
#import "RNSVGFabricConversions.h"
|
||||||
#endif // RN_FABRIC_ENABLED
|
#endif // RN_FABRIC_ENABLED
|
||||||
|
|
||||||
@@ -39,110 +39,110 @@ using namespace facebook::react;
|
|||||||
|
|
||||||
- (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps
|
- (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps
|
||||||
{
|
{
|
||||||
const auto &newProps = *std::static_pointer_cast<const RNSVGSymbolProps>(props);
|
const auto &newProps = *std::static_pointer_cast<const RNSVGSymbolProps>(props);
|
||||||
|
|
||||||
self.minX = newProps.minX;
|
self.minX = newProps.minX;
|
||||||
self.minY = newProps.minY;
|
self.minY = newProps.minY;
|
||||||
self.vbWidth = newProps.vbWidth;
|
self.vbWidth = newProps.vbWidth;
|
||||||
self.vbHeight = newProps.vbHeight;
|
self.vbHeight = newProps.vbHeight;
|
||||||
self.align = RCTNSStringFromStringNilIfEmpty(newProps.align);
|
self.align = RCTNSStringFromStringNilIfEmpty(newProps.align);
|
||||||
self.meetOrSlice = intToRNSVGVBMOS(newProps.meetOrSlice);
|
self.meetOrSlice = intToRNSVGVBMOS(newProps.meetOrSlice);
|
||||||
|
|
||||||
setCommonGroupProps(newProps, self);
|
setCommonGroupProps(newProps, self);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)prepareForRecycle
|
- (void)prepareForRecycle
|
||||||
{
|
{
|
||||||
[super prepareForRecycle];
|
[super prepareForRecycle];
|
||||||
|
|
||||||
_minX = 0;
|
_minX = 0;
|
||||||
_minY = 0;
|
_minY = 0;
|
||||||
_vbWidth = 0;
|
_vbWidth = 0;
|
||||||
_vbHeight = 0;
|
_vbHeight = 0;
|
||||||
_align = nil;
|
_align = nil;
|
||||||
_meetOrSlice = kRNSVGVBMOSMeet;
|
_meetOrSlice = kRNSVGVBMOSMeet;
|
||||||
}
|
}
|
||||||
#endif // RN_FABRIC_ENABLED
|
#endif // RN_FABRIC_ENABLED
|
||||||
|
|
||||||
- (void)setMinX:(CGFloat)minX
|
- (void)setMinX:(CGFloat)minX
|
||||||
{
|
{
|
||||||
if (minX == _minX) {
|
if (minX == _minX) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
_minX = minX;
|
_minX = minX;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setMinY:(CGFloat)minY
|
- (void)setMinY:(CGFloat)minY
|
||||||
{
|
{
|
||||||
if (minY == _minY) {
|
if (minY == _minY) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
_minY = minY;
|
_minY = minY;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setVbWidth:(CGFloat)vbWidth
|
- (void)setVbWidth:(CGFloat)vbWidth
|
||||||
{
|
{
|
||||||
if (vbWidth == _vbWidth) {
|
if (vbWidth == _vbWidth) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
_vbWidth = vbWidth;
|
_vbWidth = vbWidth;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setVbHeight:(CGFloat)vbHeight
|
- (void)setVbHeight:(CGFloat)vbHeight
|
||||||
{
|
{
|
||||||
if (_vbHeight == vbHeight) {
|
if (_vbHeight == vbHeight) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
_vbHeight = vbHeight;
|
_vbHeight = vbHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setAlign:(NSString *)align
|
- (void)setAlign:(NSString *)align
|
||||||
{
|
{
|
||||||
if ([align isEqualToString:_align]) {
|
if ([align isEqualToString:_align]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
_align = align;
|
_align = align;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setMeetOrSlice:(RNSVGVBMOS)meetOrSlice
|
- (void)setMeetOrSlice:(RNSVGVBMOS)meetOrSlice
|
||||||
{
|
{
|
||||||
if (meetOrSlice == _meetOrSlice) {
|
if (meetOrSlice == _meetOrSlice) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
_meetOrSlice = meetOrSlice;
|
_meetOrSlice = meetOrSlice;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)renderTo:(CGContextRef)context rect:(CGRect)rect
|
- (void)renderTo:(CGContextRef)context rect:(CGRect)rect
|
||||||
{
|
{
|
||||||
self.dirty = false;
|
self.dirty = false;
|
||||||
// Do not render Symbol
|
// Do not render Symbol
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)renderSymbolTo:(CGContextRef)context width:(CGFloat)width height:(CGFloat)height
|
- (void)renderSymbolTo:(CGContextRef)context width:(CGFloat)width height:(CGFloat)height
|
||||||
{
|
{
|
||||||
CGRect eRect = CGRectMake(0, 0, width, height);
|
CGRect eRect = CGRectMake(0, 0, width, height);
|
||||||
if (self.align) {
|
if (self.align) {
|
||||||
|
CGAffineTransform viewBoxTransform =
|
||||||
|
[RNSVGViewBox getTransform:CGRectMake(self.minX, self.minY, self.vbWidth, self.vbHeight)
|
||||||
|
eRect:eRect
|
||||||
|
align:self.align
|
||||||
|
meetOrSlice:self.meetOrSlice];
|
||||||
|
|
||||||
CGAffineTransform viewBoxTransform = [RNSVGViewBox getTransform:CGRectMake(self.minX, self.minY, self.vbWidth, self.vbHeight)
|
CGContextConcatCTM(context, viewBoxTransform);
|
||||||
eRect:eRect
|
}
|
||||||
align:self.align
|
[self renderGroupTo:context rect:eRect];
|
||||||
meetOrSlice:self.meetOrSlice];
|
|
||||||
|
|
||||||
CGContextConcatCTM(context, viewBoxTransform);
|
|
||||||
}
|
|
||||||
[self renderGroupTo:context rect:eRect];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -6,8 +6,8 @@
|
|||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#import "RNSVGRenderable.h"
|
|
||||||
#import "RNSVGLength.h"
|
#import "RNSVGLength.h"
|
||||||
|
#import "RNSVGRenderable.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* RNSVG defination are implemented as abstract UIViews for all elements inside Defs.
|
* RNSVG defination are implemented as abstract UIViews for all elements inside Defs.
|
||||||
|
|||||||
@@ -6,14 +6,14 @@
|
|||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
#import "RNSVGUse.h"
|
#import "RNSVGUse.h"
|
||||||
#import "RNSVGSymbol.h"
|
|
||||||
#import <React/RCTLog.h>
|
#import <React/RCTLog.h>
|
||||||
|
#import "RNSVGSymbol.h"
|
||||||
|
|
||||||
#ifdef RN_FABRIC_ENABLED
|
#ifdef RN_FABRIC_ENABLED
|
||||||
#import <react/renderer/components/rnsvg/ComponentDescriptors.h>
|
#import <react/renderer/components/rnsvg/ComponentDescriptors.h>
|
||||||
#import "RCTFabricComponentsPlugins.h"
|
|
||||||
#import "RCTConversions.h"
|
|
||||||
#import <react/renderer/components/view/conversions.h>
|
#import <react/renderer/components/view/conversions.h>
|
||||||
|
#import "RCTConversions.h"
|
||||||
|
#import "RCTFabricComponentsPlugins.h"
|
||||||
#import "RNSVGFabricConversions.h"
|
#import "RNSVGFabricConversions.h"
|
||||||
#endif // RN_FABRIC_ENABLED
|
#endif // RN_FABRIC_ENABLED
|
||||||
|
|
||||||
@@ -40,166 +40,171 @@ using namespace facebook::react;
|
|||||||
|
|
||||||
- (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps
|
- (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps
|
||||||
{
|
{
|
||||||
const auto &newProps = *std::static_pointer_cast<const RNSVGUseProps>(props);
|
const auto &newProps = *std::static_pointer_cast<const RNSVGUseProps>(props);
|
||||||
|
|
||||||
self.x = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.x)];
|
self.x = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.x)];
|
||||||
self.y = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.y)];
|
self.y = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.y)];
|
||||||
if (RCTNSStringFromStringNilIfEmpty(newProps.useheight)) {
|
if (RCTNSStringFromStringNilIfEmpty(newProps.useheight)) {
|
||||||
self.useheight = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.useheight)];
|
self.useheight = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.useheight)];
|
||||||
}
|
}
|
||||||
if (RCTNSStringFromStringNilIfEmpty(newProps.usewidth)) {
|
if (RCTNSStringFromStringNilIfEmpty(newProps.usewidth)) {
|
||||||
self.usewidth = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.usewidth)];
|
self.usewidth = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.usewidth)];
|
||||||
}
|
}
|
||||||
if (RCTNSStringFromStringNilIfEmpty(newProps.height)) {
|
if (RCTNSStringFromStringNilIfEmpty(newProps.height)) {
|
||||||
self.useheight = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.height)];
|
self.useheight = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.height)];
|
||||||
}
|
}
|
||||||
if (RCTNSStringFromStringNilIfEmpty(newProps.width)) {
|
if (RCTNSStringFromStringNilIfEmpty(newProps.width)) {
|
||||||
self.usewidth = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.width)];
|
self.usewidth = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.width)];
|
||||||
}
|
}
|
||||||
self.href = RCTNSStringFromStringNilIfEmpty(newProps.href);
|
self.href = RCTNSStringFromStringNilIfEmpty(newProps.href);
|
||||||
|
|
||||||
setCommonRenderableProps(newProps, self);
|
setCommonRenderableProps(newProps, self);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)prepareForRecycle
|
- (void)prepareForRecycle
|
||||||
{
|
{
|
||||||
[super prepareForRecycle];
|
[super prepareForRecycle];
|
||||||
_x = nil;
|
_x = nil;
|
||||||
_y = nil;
|
_y = nil;
|
||||||
_useheight = nil;
|
_useheight = nil;
|
||||||
_usewidth = nil;
|
_usewidth = nil;
|
||||||
_href = nil;
|
_href = nil;
|
||||||
}
|
}
|
||||||
#endif // RN_FABRIC_ENABLED
|
#endif // RN_FABRIC_ENABLED
|
||||||
|
|
||||||
- (void)setHref:(NSString *)href
|
- (void)setHref:(NSString *)href
|
||||||
{
|
{
|
||||||
if ([href isEqualToString:_href]) {
|
if ([href isEqualToString:_href]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
_href = href;
|
_href = href;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setX:(RNSVGLength *)x
|
- (void)setX:(RNSVGLength *)x
|
||||||
{
|
{
|
||||||
if ([x isEqualTo:_x]) {
|
if ([x isEqualTo:_x]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
_x = x;
|
_x = x;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setY:(RNSVGLength *)y
|
- (void)setY:(RNSVGLength *)y
|
||||||
{
|
{
|
||||||
if ([y isEqualTo:_y]) {
|
if ([y isEqualTo:_y]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
_y = y;
|
_y = y;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (void)setUsewidth:(RNSVGLength *)usewidth
|
- (void)setUsewidth:(RNSVGLength *)usewidth
|
||||||
{
|
{
|
||||||
if ([usewidth isEqualTo:_usewidth]) {
|
if ([usewidth isEqualTo:_usewidth]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
_usewidth = usewidth;
|
_usewidth = usewidth;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setUseheight:(RNSVGLength *)useheight
|
- (void)setUseheight:(RNSVGLength *)useheight
|
||||||
{
|
{
|
||||||
if ([useheight isEqualTo:_useheight]) {
|
if ([useheight isEqualTo:_useheight]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
_useheight = useheight;
|
_useheight = useheight;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)renderLayerTo:(CGContextRef)context rect:(CGRect)rect
|
- (void)renderLayerTo:(CGContextRef)context rect:(CGRect)rect
|
||||||
{
|
{
|
||||||
CGContextTranslateCTM(context, [self relativeOnWidth:self.x], [self relativeOnHeight:self.y]);
|
CGContextTranslateCTM(context, [self relativeOnWidth:self.x], [self relativeOnHeight:self.y]);
|
||||||
RNSVGNode* definedTemplate = [self.svgView getDefinedTemplate:self.href];
|
RNSVGNode *definedTemplate = [self.svgView getDefinedTemplate:self.href];
|
||||||
if (definedTemplate) {
|
if (definedTemplate) {
|
||||||
[self beginTransparencyLayer:context];
|
[self beginTransparencyLayer:context];
|
||||||
[self clip:context];
|
[self clip:context];
|
||||||
|
|
||||||
if ([definedTemplate isKindOfClass:[RNSVGRenderable class]]) {
|
if ([definedTemplate isKindOfClass:[RNSVGRenderable class]]) {
|
||||||
[(RNSVGRenderable*)definedTemplate mergeProperties:self];
|
[(RNSVGRenderable *)definedTemplate mergeProperties:self];
|
||||||
}
|
}
|
||||||
|
|
||||||
if ([definedTemplate class] == [RNSVGSymbol class]) {
|
if ([definedTemplate class] == [RNSVGSymbol class]) {
|
||||||
RNSVGSymbol *symbol = (RNSVGSymbol*)definedTemplate;
|
RNSVGSymbol *symbol = (RNSVGSymbol *)definedTemplate;
|
||||||
[symbol renderSymbolTo:context width:[self relativeOnWidth:self.usewidth] height:[self relativeOnHeight:self.useheight]];
|
[symbol renderSymbolTo:context
|
||||||
} else {
|
width:[self relativeOnWidth:self.usewidth]
|
||||||
[definedTemplate renderTo:context rect:rect];
|
height:[self relativeOnHeight:self.useheight]];
|
||||||
}
|
|
||||||
|
|
||||||
if ([definedTemplate isKindOfClass:[RNSVGRenderable class]]) {
|
|
||||||
[(RNSVGRenderable*)definedTemplate resetProperties];
|
|
||||||
}
|
|
||||||
|
|
||||||
[self endTransparencyLayer:context];
|
|
||||||
} else if (self.href) {
|
|
||||||
// TODO: calling yellow box here
|
|
||||||
RCTLogWarn(@"`Use` element expected a pre-defined svg template as `href` prop, template named: %@ is not defined.", self.href);
|
|
||||||
return;
|
|
||||||
} else {
|
} else {
|
||||||
return;
|
[definedTemplate renderTo:context rect:rect];
|
||||||
}
|
}
|
||||||
CGRect bounds = definedTemplate.clientRect;
|
|
||||||
self.clientRect = bounds;
|
|
||||||
|
|
||||||
CGAffineTransform current = CGContextGetCTM(context);
|
if ([definedTemplate isKindOfClass:[RNSVGRenderable class]]) {
|
||||||
CGAffineTransform svgToClientTransform = CGAffineTransformConcat(current, self.svgView.invInitialCTM);
|
[(RNSVGRenderable *)definedTemplate resetProperties];
|
||||||
|
|
||||||
self.ctm = svgToClientTransform;
|
|
||||||
self.screenCTM = current;
|
|
||||||
|
|
||||||
CGAffineTransform transform = CGAffineTransformConcat(self.matrix, self.transforms);
|
|
||||||
CGPoint mid = CGPointMake(CGRectGetMidX(bounds), CGRectGetMidY(bounds));
|
|
||||||
CGPoint center = CGPointApplyAffineTransform(mid, transform);
|
|
||||||
|
|
||||||
self.bounds = bounds;
|
|
||||||
if (!isnan(center.x) && !isnan(center.y)) {
|
|
||||||
self.center = center;
|
|
||||||
}
|
}
|
||||||
self.frame = bounds;
|
|
||||||
|
[self endTransparencyLayer:context];
|
||||||
|
} else if (self.href) {
|
||||||
|
// TODO: calling yellow box here
|
||||||
|
RCTLogWarn(
|
||||||
|
@"`Use` element expected a pre-defined svg template as `href` prop, template named: %@ is not defined.",
|
||||||
|
self.href);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
CGRect bounds = definedTemplate.clientRect;
|
||||||
|
self.clientRect = bounds;
|
||||||
|
|
||||||
|
CGAffineTransform current = CGContextGetCTM(context);
|
||||||
|
CGAffineTransform svgToClientTransform = CGAffineTransformConcat(current, self.svgView.invInitialCTM);
|
||||||
|
|
||||||
|
self.ctm = svgToClientTransform;
|
||||||
|
self.screenCTM = current;
|
||||||
|
|
||||||
|
CGAffineTransform transform = CGAffineTransformConcat(self.matrix, self.transforms);
|
||||||
|
CGPoint mid = CGPointMake(CGRectGetMidX(bounds), CGRectGetMidY(bounds));
|
||||||
|
CGPoint center = CGPointApplyAffineTransform(mid, transform);
|
||||||
|
|
||||||
|
self.bounds = bounds;
|
||||||
|
if (!isnan(center.x) && !isnan(center.y)) {
|
||||||
|
self.center = center;
|
||||||
|
}
|
||||||
|
self.frame = bounds;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (RNSVGPlatformView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
|
- (RNSVGPlatformView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
|
||||||
CGPoint transformed = CGPointApplyAffineTransform(point, self.invmatrix);
|
|
||||||
transformed = CGPointApplyAffineTransform(transformed, self.invTransform);
|
|
||||||
RNSVGNode const* definedTemplate = [self.svgView getDefinedTemplate:self.href];
|
|
||||||
if (event) {
|
|
||||||
self.active = NO;
|
|
||||||
} else if (self.active) {
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
RNSVGPlatformView const* hitChild = [definedTemplate hitTest:transformed withEvent:event];
|
|
||||||
if (hitChild) {
|
|
||||||
self.active = YES;
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
return nil;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (CGPathRef)getPath: (CGContextRef)context
|
|
||||||
{
|
{
|
||||||
CGAffineTransform transform = CGAffineTransformMakeTranslation([self relativeOnWidth:self.x], [self relativeOnHeight:self.y]);
|
CGPoint transformed = CGPointApplyAffineTransform(point, self.invmatrix);
|
||||||
RNSVGNode const* definedTemplate = [self.svgView getDefinedTemplate:self.href];
|
transformed = CGPointApplyAffineTransform(transformed, self.invTransform);
|
||||||
if (!definedTemplate) {
|
RNSVGNode const *definedTemplate = [self.svgView getDefinedTemplate:self.href];
|
||||||
return nil;
|
if (event) {
|
||||||
}
|
self.active = NO;
|
||||||
CGPathRef path = [definedTemplate getPath:context];
|
} else if (self.active) {
|
||||||
return CGPathCreateCopyByTransformingPath(path, &transform);
|
return self;
|
||||||
|
}
|
||||||
|
RNSVGPlatformView const *hitChild = [definedTemplate hitTest:transformed withEvent:event];
|
||||||
|
if (hitChild) {
|
||||||
|
self.active = YES;
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CGPathRef)getPath:(CGContextRef)context
|
||||||
|
{
|
||||||
|
CGAffineTransform transform =
|
||||||
|
CGAffineTransformMakeTranslation([self relativeOnWidth:self.x], [self relativeOnHeight:self.y]);
|
||||||
|
RNSVGNode const *definedTemplate = [self.svgView getDefinedTemplate:self.href];
|
||||||
|
if (!definedTemplate) {
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
CGPathRef path = [definedTemplate getPath:context];
|
||||||
|
return CGPathCreateCopyByTransformingPath(path, &transform);
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -6,10 +6,11 @@
|
|||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#import "RNSVGSvgView.h"
|
|
||||||
#import <React/UIView+React.h>
|
|
||||||
#import <React/RCTPointerEvents.h>
|
|
||||||
#import "RNSVGCGFCRule.h"
|
#import "RNSVGCGFCRule.h"
|
||||||
|
#import "RNSVGSvgView.h"
|
||||||
|
|
||||||
|
#import <React/RCTPointerEvents.h>
|
||||||
|
#import <React/UIView+React.h>
|
||||||
|
|
||||||
#ifdef RN_FABRIC_ENABLED
|
#ifdef RN_FABRIC_ENABLED
|
||||||
#import <React/RCTViewComponentView.h>
|
#import <React/RCTViewComponentView.h>
|
||||||
@@ -24,9 +25,9 @@
|
|||||||
|
|
||||||
@interface RNSVGNode :
|
@interface RNSVGNode :
|
||||||
#ifdef RN_FABRIC_ENABLED
|
#ifdef RN_FABRIC_ENABLED
|
||||||
RCTViewComponentView
|
RCTViewComponentView
|
||||||
#else
|
#else
|
||||||
RNSVGView
|
RNSVGView
|
||||||
#endif // RN_FABRIC_ENABLED
|
#endif // RN_FABRIC_ENABLED
|
||||||
/*
|
/*
|
||||||
N[1/Sqrt[2], 36]
|
N[1/Sqrt[2], 36]
|
||||||
@@ -73,7 +74,6 @@ extern CGFloat const RNSVG_DEFAULT_FONT_SIZE;
|
|||||||
@property (nonatomic, assign) CGRect markerBounds;
|
@property (nonatomic, assign) CGRect markerBounds;
|
||||||
@property (nonatomic, copy) RCTDirectEventBlock onLayout;
|
@property (nonatomic, copy) RCTDirectEventBlock onLayout;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* RNSVGSvgView which ownes current RNSVGNode
|
* RNSVGSvgView which ownes current RNSVGNode
|
||||||
*/
|
*/
|
||||||
@@ -111,7 +111,7 @@ extern CGFloat const RNSVG_DEFAULT_FONT_SIZE;
|
|||||||
/**
|
/**
|
||||||
* getPath will return the path inside node as a ClipPath.
|
* getPath will return the path inside node as a ClipPath.
|
||||||
*/
|
*/
|
||||||
- (CGPathRef)getPath:(CGContextRef) context;
|
- (CGPathRef)getPath:(CGContextRef)context;
|
||||||
|
|
||||||
- (CGFloat)relativeOnWidthString:(NSString *)length;
|
- (CGFloat)relativeOnWidthString:(NSString *)length;
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -12,8 +12,8 @@
|
|||||||
|
|
||||||
#import "RNSVGBrush.h"
|
#import "RNSVGBrush.h"
|
||||||
#import "RNSVGCGFCRule.h"
|
#import "RNSVGCGFCRule.h"
|
||||||
#import "RNSVGNode.h"
|
|
||||||
#import "RNSVGLength.h"
|
#import "RNSVGLength.h"
|
||||||
|
#import "RNSVGNode.h"
|
||||||
#import "RNSVGVectorEffect.h"
|
#import "RNSVGVectorEffect.h"
|
||||||
|
|
||||||
@interface RNSVGRenderable : RNSVGNode
|
@interface RNSVGRenderable : RNSVGNode
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
|||||||
// Most (if not all) of this file could probably go away once react-native-macos's version of RCTUIKit.h makes its way upstream.
|
// Most (if not all) of this file could probably go away once react-native-macos's version of RCTUIKit.h makes its way
|
||||||
// https://github.com/microsoft/react-native-macos/issues/242
|
// upstream. https://github.com/microsoft/react-native-macos/issues/242
|
||||||
|
|
||||||
#if !TARGET_OS_OSX
|
#if !TARGET_OS_OSX
|
||||||
|
|
||||||
@@ -12,9 +12,9 @@
|
|||||||
|
|
||||||
#else // TARGET_OS_OSX [
|
#else // TARGET_OS_OSX [
|
||||||
|
|
||||||
// Due to name mangling, calling c-style functions from .mm files will fail, therefore we need to wrap them with extern "C"
|
// Due to name mangling, calling c-style functions from .mm files will fail, therefore we need to wrap them with extern
|
||||||
// so they are handled correctly. We also need to have imports positioned in a correct way,
|
// "C" so they are handled correctly. We also need to have imports positioned in a correct way, so that this extern "C"
|
||||||
// so that this extern "C" wrapper is used before the functions from RCTUIKit are used.
|
// wrapper is used before the functions from RCTUIKit are used.
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
@@ -37,7 +37,8 @@ extern "C" {
|
|||||||
@end
|
@end
|
||||||
|
|
||||||
// TODO: These could probably be a part of react-native-macos
|
// TODO: These could probably be a part of react-native-macos
|
||||||
// See https://github.com/microsoft/react-native-macos/issues/658 and https://github.com/microsoft/react-native-macos/issues/659
|
// See https://github.com/microsoft/react-native-macos/issues/658 and
|
||||||
|
// https://github.com/microsoft/react-native-macos/issues/659
|
||||||
@interface NSImage (RNSVGMacOSExtensions)
|
@interface NSImage (RNSVGMacOSExtensions)
|
||||||
@property (readonly) CGImageRef CGImage;
|
@property (readonly) CGImageRef CGImage;
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -1,86 +1,83 @@
|
|||||||
#import "RNSVGUIKit.h"
|
#import "RNSVGUIKit.h"
|
||||||
|
|
||||||
@implementation RNSVGView
|
@implementation RNSVGView {
|
||||||
{
|
NSColor *_tintColor;
|
||||||
NSColor *_tintColor;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CGPoint)center
|
- (CGPoint)center
|
||||||
{
|
{
|
||||||
NSRect frameRect = self.frame;
|
NSRect frameRect = self.frame;
|
||||||
CGFloat xCenter = frameRect.origin.x + frameRect.size.width / 2;
|
CGFloat xCenter = frameRect.origin.x + frameRect.size.width / 2;
|
||||||
CGFloat yCenter = frameRect.origin.y + frameRect.size.height / 2;
|
CGFloat yCenter = frameRect.origin.y + frameRect.size.height / 2;
|
||||||
return CGPointMake(xCenter, yCenter);
|
return CGPointMake(xCenter, yCenter);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setCenter:(CGPoint)point
|
- (void)setCenter:(CGPoint)point
|
||||||
{
|
{
|
||||||
NSRect frameRect = self.frame;
|
NSRect frameRect = self.frame;
|
||||||
CGFloat xOrigin = frameRect.origin.x - frameRect.size.width / 2;
|
CGFloat xOrigin = frameRect.origin.x - frameRect.size.width / 2;
|
||||||
CGFloat yOrigin = frameRect.origin.y - frameRect.size.height / 2;
|
CGFloat yOrigin = frameRect.origin.y - frameRect.size.height / 2;
|
||||||
self.frame = CGRectMake(xOrigin, yOrigin, frameRect.size.width, frameRect.size.height);
|
self.frame = CGRectMake(xOrigin, yOrigin, frameRect.size.width, frameRect.size.height);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSColor *)tintColor
|
- (NSColor *)tintColor
|
||||||
{
|
{
|
||||||
if (_tintColor != nil) {
|
if (_tintColor != nil) {
|
||||||
return _tintColor;
|
return _tintColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
// To mimic iOS's tintColor, we crawl up the view hierarchy until either:
|
// To mimic iOS's tintColor, we crawl up the view hierarchy until either:
|
||||||
// (a) we find a valid color
|
// (a) we find a valid color
|
||||||
// (b) we reach a view that isn't an RNSVGView
|
// (b) we reach a view that isn't an RNSVGView
|
||||||
NSView *parentView = [self superview];
|
NSView *parentView = [self superview];
|
||||||
if ([parentView isKindOfClass:[RNSVGView class]]) {
|
if ([parentView isKindOfClass:[RNSVGView class]]) {
|
||||||
return [(RNSVGView *)parentView tintColor];
|
return [(RNSVGView *)parentView tintColor];
|
||||||
} else {
|
} else {
|
||||||
return [NSColor controlAccentColor];
|
return [NSColor controlAccentColor];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setTintColor:(NSColor *)tintColor
|
- (void)setTintColor:(NSColor *)tintColor
|
||||||
{
|
{
|
||||||
_tintColor = tintColor;
|
_tintColor = tintColor;
|
||||||
[self setNeedsDisplay:YES];
|
[self setNeedsDisplay:YES];
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|
||||||
@implementation NSImage (RNSVGMacOSExtensions)
|
@implementation NSImage (RNSVGMacOSExtensions)
|
||||||
|
|
||||||
- (CGImageRef) CGImage
|
- (CGImageRef)CGImage
|
||||||
{
|
{
|
||||||
return [self CGImageForProposedRect:NULL context:NULL hints:NULL];
|
return [self CGImageForProposedRect:NULL context:NULL hints:NULL];
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|
||||||
@implementation NSValue (RNSVGMacOSExtensions)
|
@implementation NSValue (RNSVGMacOSExtensions)
|
||||||
|
|
||||||
+ (NSValue *)valueWithCGAffineTransform:(CGAffineTransform)transform
|
+ (NSValue *)valueWithCGAffineTransform:(CGAffineTransform)transform
|
||||||
{
|
{
|
||||||
return [NSValue valueWithBytes:&transform objCType:@encode(CGAffineTransform)];
|
return [NSValue valueWithBytes:&transform objCType:@encode(CGAffineTransform)];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (NSValue *)valueWithCGPoint:(CGPoint)point
|
+ (NSValue *)valueWithCGPoint:(CGPoint)point
|
||||||
{
|
{
|
||||||
return [NSValue valueWithBytes:&point objCType:@encode(CGPoint)];
|
return [NSValue valueWithBytes:&point objCType:@encode(CGPoint)];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CGAffineTransform)CGAffineTransformValue
|
- (CGAffineTransform)CGAffineTransformValue
|
||||||
{
|
{
|
||||||
CGAffineTransform value;
|
CGAffineTransform value;
|
||||||
[self getValue:&value];
|
[self getValue:&value];
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CGPoint)CGPointValue
|
- (CGPoint)CGPointValue
|
||||||
{
|
{
|
||||||
CGPoint value;
|
CGPoint value;
|
||||||
[self getValue:&value];
|
[self getValue:&value];
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -12,9 +12,8 @@
|
|||||||
|
|
||||||
@interface RNSVGCircle : RNSVGRenderable
|
@interface RNSVGCircle : RNSVGRenderable
|
||||||
|
|
||||||
@property (nonatomic, strong) RNSVGLength* cx;
|
@property (nonatomic, strong) RNSVGLength *cx;
|
||||||
@property (nonatomic, strong) RNSVGLength* cy;
|
@property (nonatomic, strong) RNSVGLength *cy;
|
||||||
@property (nonatomic, strong) RNSVGLength* r;
|
@property (nonatomic, strong) RNSVGLength *r;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|||||||
@@ -11,9 +11,9 @@
|
|||||||
|
|
||||||
#ifdef RN_FABRIC_ENABLED
|
#ifdef RN_FABRIC_ENABLED
|
||||||
#import <react/renderer/components/rnsvg/ComponentDescriptors.h>
|
#import <react/renderer/components/rnsvg/ComponentDescriptors.h>
|
||||||
#import "RCTFabricComponentsPlugins.h"
|
|
||||||
#import "RCTConversions.h"
|
|
||||||
#import <react/renderer/components/view/conversions.h>
|
#import <react/renderer/components/view/conversions.h>
|
||||||
|
#import "RCTConversions.h"
|
||||||
|
#import "RCTFabricComponentsPlugins.h"
|
||||||
#import "RNSVGFabricConversions.h"
|
#import "RNSVGFabricConversions.h"
|
||||||
#endif // RN_FABRIC_ENABLED
|
#endif // RN_FABRIC_ENABLED
|
||||||
|
|
||||||
@@ -40,59 +40,59 @@ using namespace facebook::react;
|
|||||||
|
|
||||||
- (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps
|
- (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps
|
||||||
{
|
{
|
||||||
const auto &newProps = *std::static_pointer_cast<const RNSVGCircleProps>(props);
|
const auto &newProps = *std::static_pointer_cast<const RNSVGCircleProps>(props);
|
||||||
|
|
||||||
self.cx = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.cx)];
|
self.cx = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.cx)];
|
||||||
self.cy = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.cy)];
|
self.cy = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.cy)];
|
||||||
self.r = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.r)];
|
self.r = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.r)];
|
||||||
|
|
||||||
setCommonRenderableProps(newProps, self);
|
setCommonRenderableProps(newProps, self);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)prepareForRecycle
|
- (void)prepareForRecycle
|
||||||
{
|
{
|
||||||
[super prepareForRecycle];
|
[super prepareForRecycle];
|
||||||
_cx = nil;
|
_cx = nil;
|
||||||
_cy = nil;
|
_cy = nil;
|
||||||
_r = nil;
|
_r = nil;
|
||||||
}
|
}
|
||||||
#endif // RN_FABRIC_ENABLED
|
#endif // RN_FABRIC_ENABLED
|
||||||
|
|
||||||
- (void)setCx:(RNSVGLength *)cx
|
- (void)setCx:(RNSVGLength *)cx
|
||||||
{
|
{
|
||||||
if ([cx isEqualTo:_cx]) {
|
if ([cx isEqualTo:_cx]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
_cx = cx;
|
_cx = cx;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setCy:(RNSVGLength *)cy
|
- (void)setCy:(RNSVGLength *)cy
|
||||||
{
|
{
|
||||||
if ([cy isEqualTo:_cy]) {
|
if ([cy isEqualTo:_cy]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
_cy = cy;
|
_cy = cy;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setR:(RNSVGLength *)r
|
- (void)setR:(RNSVGLength *)r
|
||||||
{
|
{
|
||||||
if ([r isEqualTo:_r]) {
|
if ([r isEqualTo:_r]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
_r = r;
|
_r = r;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CGPathRef)getPath:(CGContextRef)context
|
- (CGPathRef)getPath:(CGContextRef)context
|
||||||
{
|
{
|
||||||
CGMutablePathRef path = CGPathCreateMutable();
|
CGMutablePathRef path = CGPathCreateMutable();
|
||||||
CGFloat cx = [self relativeOnWidth:self.cx];
|
CGFloat cx = [self relativeOnWidth:self.cx];
|
||||||
CGFloat cy = [self relativeOnHeight:self.cy];
|
CGFloat cy = [self relativeOnHeight:self.cy];
|
||||||
CGFloat r = [self relativeOnOther:self.r];
|
CGFloat r = [self relativeOnOther:self.r];
|
||||||
CGPathAddArc(path, nil, cx, cy, r, 0, 2 * (CGFloat)M_PI, NO);
|
CGPathAddArc(path, nil, cx, cy, r, 0, 2 * (CGFloat)M_PI, NO);
|
||||||
return (CGPathRef)CFAutorelease(path);
|
return (CGPathRef)CFAutorelease(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -11,8 +11,8 @@
|
|||||||
#import "RNSVGPath.h"
|
#import "RNSVGPath.h"
|
||||||
|
|
||||||
@interface RNSVGEllipse : RNSVGRenderable
|
@interface RNSVGEllipse : RNSVGRenderable
|
||||||
@property (nonatomic, strong) RNSVGLength* cx;
|
@property (nonatomic, strong) RNSVGLength *cx;
|
||||||
@property (nonatomic, strong) RNSVGLength* cy;
|
@property (nonatomic, strong) RNSVGLength *cy;
|
||||||
@property (nonatomic, strong) RNSVGLength* rx;
|
@property (nonatomic, strong) RNSVGLength *rx;
|
||||||
@property (nonatomic, strong) RNSVGLength* ry;
|
@property (nonatomic, strong) RNSVGLength *ry;
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -11,9 +11,9 @@
|
|||||||
|
|
||||||
#ifdef RN_FABRIC_ENABLED
|
#ifdef RN_FABRIC_ENABLED
|
||||||
#import <react/renderer/components/rnsvg/ComponentDescriptors.h>
|
#import <react/renderer/components/rnsvg/ComponentDescriptors.h>
|
||||||
#import "RCTFabricComponentsPlugins.h"
|
|
||||||
#import "RCTConversions.h"
|
|
||||||
#import <react/renderer/components/view/conversions.h>
|
#import <react/renderer/components/view/conversions.h>
|
||||||
|
#import "RCTConversions.h"
|
||||||
|
#import "RCTFabricComponentsPlugins.h"
|
||||||
#import "RNSVGFabricConversions.h"
|
#import "RNSVGFabricConversions.h"
|
||||||
#endif // RN_FABRIC_ENABLED
|
#endif // RN_FABRIC_ENABLED
|
||||||
|
|
||||||
@@ -40,71 +40,71 @@ using namespace facebook::react;
|
|||||||
|
|
||||||
- (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps
|
- (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps
|
||||||
{
|
{
|
||||||
const auto &newProps = *std::static_pointer_cast<const RNSVGEllipseProps>(props);
|
const auto &newProps = *std::static_pointer_cast<const RNSVGEllipseProps>(props);
|
||||||
|
|
||||||
self.cx = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.cx)];
|
self.cx = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.cx)];
|
||||||
self.cy = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.cy)];
|
self.cy = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.cy)];
|
||||||
self.rx = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.rx)];
|
self.rx = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.rx)];
|
||||||
self.ry = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.ry)];
|
self.ry = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.ry)];
|
||||||
|
|
||||||
setCommonRenderableProps(newProps, self);
|
setCommonRenderableProps(newProps, self);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)prepareForRecycle
|
- (void)prepareForRecycle
|
||||||
{
|
{
|
||||||
[super prepareForRecycle];
|
[super prepareForRecycle];
|
||||||
_cx = nil;
|
_cx = nil;
|
||||||
_cy = nil;
|
_cy = nil;
|
||||||
_rx = nil;
|
_rx = nil;
|
||||||
_ry = nil;
|
_ry = nil;
|
||||||
}
|
}
|
||||||
#endif // RN_FABRIC_ENABLED
|
#endif // RN_FABRIC_ENABLED
|
||||||
|
|
||||||
- (void)setCx:(RNSVGLength *)cx
|
- (void)setCx:(RNSVGLength *)cx
|
||||||
{
|
{
|
||||||
if ([cx isEqualTo:_cx]) {
|
if ([cx isEqualTo:_cx]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
_cx = cx;
|
_cx = cx;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setCy:(RNSVGLength *)cy
|
- (void)setCy:(RNSVGLength *)cy
|
||||||
{
|
{
|
||||||
if ([cy isEqualTo:_cy]) {
|
if ([cy isEqualTo:_cy]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
_cy = cy;
|
_cy = cy;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setRx:(RNSVGLength *)rx
|
- (void)setRx:(RNSVGLength *)rx
|
||||||
{
|
{
|
||||||
if ([rx isEqualTo:_rx]) {
|
if ([rx isEqualTo:_rx]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
_rx = rx;
|
_rx = rx;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setRy:(RNSVGLength *)ry
|
- (void)setRy:(RNSVGLength *)ry
|
||||||
{
|
{
|
||||||
if ([ry isEqualTo:_ry]) {
|
if ([ry isEqualTo:_ry]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
_ry = ry;
|
_ry = ry;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CGPathRef)getPath:(CGContextRef)context
|
- (CGPathRef)getPath:(CGContextRef)context
|
||||||
{
|
{
|
||||||
CGMutablePathRef path = CGPathCreateMutable();
|
CGMutablePathRef path = CGPathCreateMutable();
|
||||||
CGFloat cx = [self relativeOnWidth:self.cx];
|
CGFloat cx = [self relativeOnWidth:self.cx];
|
||||||
CGFloat cy = [self relativeOnHeight:self.cy];
|
CGFloat cy = [self relativeOnHeight:self.cy];
|
||||||
CGFloat rx = [self relativeOnWidth:self.rx];
|
CGFloat rx = [self relativeOnWidth:self.rx];
|
||||||
CGFloat ry = [self relativeOnHeight:self.ry];
|
CGFloat ry = [self relativeOnHeight:self.ry];
|
||||||
CGPathAddEllipseInRect(path, nil, CGRectMake(cx - rx, cy - ry, rx * 2, ry * 2));
|
CGPathAddEllipseInRect(path, nil, CGRectMake(cx - rx, cy - ry, rx * 2, ry * 2));
|
||||||
return (CGPathRef)CFAutorelease(path);
|
return (CGPathRef)CFAutorelease(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -11,8 +11,8 @@
|
|||||||
#import "RNSVGPath.h"
|
#import "RNSVGPath.h"
|
||||||
|
|
||||||
@interface RNSVGLine : RNSVGRenderable
|
@interface RNSVGLine : RNSVGRenderable
|
||||||
@property (nonatomic, strong) RNSVGLength* x1;
|
@property (nonatomic, strong) RNSVGLength *x1;
|
||||||
@property (nonatomic, strong) RNSVGLength* y1;
|
@property (nonatomic, strong) RNSVGLength *y1;
|
||||||
@property (nonatomic, strong) RNSVGLength* x2;
|
@property (nonatomic, strong) RNSVGLength *x2;
|
||||||
@property (nonatomic, strong) RNSVGLength* y2;
|
@property (nonatomic, strong) RNSVGLength *y2;
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -11,9 +11,9 @@
|
|||||||
|
|
||||||
#ifdef RN_FABRIC_ENABLED
|
#ifdef RN_FABRIC_ENABLED
|
||||||
#import <react/renderer/components/rnsvg/ComponentDescriptors.h>
|
#import <react/renderer/components/rnsvg/ComponentDescriptors.h>
|
||||||
#import "RCTFabricComponentsPlugins.h"
|
|
||||||
#import "RCTConversions.h"
|
|
||||||
#import <react/renderer/components/view/conversions.h>
|
#import <react/renderer/components/view/conversions.h>
|
||||||
|
#import "RCTConversions.h"
|
||||||
|
#import "RCTFabricComponentsPlugins.h"
|
||||||
#import "RNSVGFabricConversions.h"
|
#import "RNSVGFabricConversions.h"
|
||||||
#endif // RN_FABRIC_ENABLED
|
#endif // RN_FABRIC_ENABLED
|
||||||
|
|
||||||
@@ -40,73 +40,73 @@ using namespace facebook::react;
|
|||||||
|
|
||||||
- (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps
|
- (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps
|
||||||
{
|
{
|
||||||
const auto &newProps = *std::static_pointer_cast<const RNSVGLineProps>(props);
|
const auto &newProps = *std::static_pointer_cast<const RNSVGLineProps>(props);
|
||||||
|
|
||||||
self.x1 = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.x1)];
|
self.x1 = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.x1)];
|
||||||
self.y1 = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.y1)];
|
self.y1 = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.y1)];
|
||||||
self.x2 = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.x2)];
|
self.x2 = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.x2)];
|
||||||
self.y2 = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.y2)];
|
self.y2 = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.y2)];
|
||||||
|
|
||||||
setCommonRenderableProps(newProps, self);
|
setCommonRenderableProps(newProps, self);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)prepareForRecycle
|
- (void)prepareForRecycle
|
||||||
{
|
{
|
||||||
[super prepareForRecycle];
|
[super prepareForRecycle];
|
||||||
_x1 = nil;
|
_x1 = nil;
|
||||||
_y1 = nil;
|
_y1 = nil;
|
||||||
_x2 = nil;
|
_x2 = nil;
|
||||||
_y2 = nil;
|
_y2 = nil;
|
||||||
}
|
}
|
||||||
#endif // RN_FABRIC_ENABLED
|
#endif // RN_FABRIC_ENABLED
|
||||||
|
|
||||||
- (void)setX1:(RNSVGLength *)x1
|
- (void)setX1:(RNSVGLength *)x1
|
||||||
{
|
{
|
||||||
if ([x1 isEqualTo:_x1]) {
|
if ([x1 isEqualTo:_x1]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
_x1 = x1;
|
_x1 = x1;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setY1:(RNSVGLength *)y1
|
- (void)setY1:(RNSVGLength *)y1
|
||||||
{
|
{
|
||||||
if ([y1 isEqualTo:_y1]) {
|
if ([y1 isEqualTo:_y1]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
_y1 = y1;
|
_y1 = y1;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setX2:(RNSVGLength *)x2
|
- (void)setX2:(RNSVGLength *)x2
|
||||||
{
|
{
|
||||||
if ([x2 isEqualTo:_x2]) {
|
if ([x2 isEqualTo:_x2]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
_x2 = x2;
|
_x2 = x2;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setY2:(RNSVGLength *)y2
|
- (void)setY2:(RNSVGLength *)y2
|
||||||
{
|
{
|
||||||
if ([y2 isEqualTo:_y2]) {
|
if ([y2 isEqualTo:_y2]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
_y2 = y2;
|
_y2 = y2;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CGPathRef)getPath:(CGContextRef)context
|
- (CGPathRef)getPath:(CGContextRef)context
|
||||||
{
|
{
|
||||||
CGMutablePathRef path = CGPathCreateMutable();
|
CGMutablePathRef path = CGPathCreateMutable();
|
||||||
CGFloat x1 = [self relativeOnWidth:self.x1];
|
CGFloat x1 = [self relativeOnWidth:self.x1];
|
||||||
CGFloat y1 = [self relativeOnHeight:self.y1];
|
CGFloat y1 = [self relativeOnHeight:self.y1];
|
||||||
CGFloat x2 = [self relativeOnWidth:self.x2];
|
CGFloat x2 = [self relativeOnWidth:self.x2];
|
||||||
CGFloat y2 = [self relativeOnHeight:self.y2];
|
CGFloat y2 = [self relativeOnHeight:self.y2];
|
||||||
CGPathMoveToPoint(path, nil, x1, y1);
|
CGPathMoveToPoint(path, nil, x1, y1);
|
||||||
CGPathAddLineToPoint(path, nil, x2, y2);
|
CGPathAddLineToPoint(path, nil, x2, y2);
|
||||||
|
|
||||||
return (CGPathRef)CFAutorelease(path);
|
return (CGPathRef)CFAutorelease(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -12,11 +12,11 @@
|
|||||||
|
|
||||||
@interface RNSVGRect : RNSVGRenderable
|
@interface RNSVGRect : RNSVGRenderable
|
||||||
|
|
||||||
@property (nonatomic, strong) RNSVGLength* x;
|
@property (nonatomic, strong) RNSVGLength *x;
|
||||||
@property (nonatomic, strong) RNSVGLength* y;
|
@property (nonatomic, strong) RNSVGLength *y;
|
||||||
@property (nonatomic, strong) RNSVGLength* rectwidth;
|
@property (nonatomic, strong) RNSVGLength *rectwidth;
|
||||||
@property (nonatomic, strong) RNSVGLength* rectheight;
|
@property (nonatomic, strong) RNSVGLength *rectheight;
|
||||||
@property (nonatomic, strong) RNSVGLength* rx;
|
@property (nonatomic, strong) RNSVGLength *rx;
|
||||||
@property (nonatomic, strong) RNSVGLength* ry;
|
@property (nonatomic, strong) RNSVGLength *ry;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -11,9 +11,9 @@
|
|||||||
|
|
||||||
#ifdef RN_FABRIC_ENABLED
|
#ifdef RN_FABRIC_ENABLED
|
||||||
#import <react/renderer/components/rnsvg/ComponentDescriptors.h>
|
#import <react/renderer/components/rnsvg/ComponentDescriptors.h>
|
||||||
#import "RCTFabricComponentsPlugins.h"
|
|
||||||
#import "RCTConversions.h"
|
|
||||||
#import <react/renderer/components/view/conversions.h>
|
#import <react/renderer/components/view/conversions.h>
|
||||||
|
#import "RCTConversions.h"
|
||||||
|
#import "RCTFabricComponentsPlugins.h"
|
||||||
#import "RNSVGFabricConversions.h"
|
#import "RNSVGFabricConversions.h"
|
||||||
#endif // RN_FABRIC_ENABLED
|
#endif // RN_FABRIC_ENABLED
|
||||||
|
|
||||||
@@ -40,132 +40,132 @@ using namespace facebook::react;
|
|||||||
|
|
||||||
- (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps
|
- (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps
|
||||||
{
|
{
|
||||||
const auto &newProps = *std::static_pointer_cast<const RNSVGRectProps>(props);
|
const auto &newProps = *std::static_pointer_cast<const RNSVGRectProps>(props);
|
||||||
|
|
||||||
self.x = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.x)];
|
self.x = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.x)];
|
||||||
self.y = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.y)];
|
self.y = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.y)];
|
||||||
if (RCTNSStringFromStringNilIfEmpty(newProps.rectheight)) {
|
if (RCTNSStringFromStringNilIfEmpty(newProps.rectheight)) {
|
||||||
self.rectheight = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.rectheight)];
|
self.rectheight = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.rectheight)];
|
||||||
}
|
}
|
||||||
if (RCTNSStringFromStringNilIfEmpty(newProps.rectwidth)) {
|
if (RCTNSStringFromStringNilIfEmpty(newProps.rectwidth)) {
|
||||||
self.rectwidth = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.rectwidth)];
|
self.rectwidth = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.rectwidth)];
|
||||||
}
|
}
|
||||||
if (RCTNSStringFromStringNilIfEmpty(newProps.height)) {
|
if (RCTNSStringFromStringNilIfEmpty(newProps.height)) {
|
||||||
self.rectheight = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.height)];
|
self.rectheight = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.height)];
|
||||||
}
|
}
|
||||||
if (RCTNSStringFromStringNilIfEmpty(newProps.width)) {
|
if (RCTNSStringFromStringNilIfEmpty(newProps.width)) {
|
||||||
self.rectwidth = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.width)];
|
self.rectwidth = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.width)];
|
||||||
}
|
}
|
||||||
self.rx = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.rx)];
|
self.rx = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.rx)];
|
||||||
self.ry = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.ry)];
|
self.ry = [RNSVGLength lengthWithString:RCTNSStringFromString(newProps.ry)];
|
||||||
|
|
||||||
setCommonRenderableProps(newProps, self);
|
setCommonRenderableProps(newProps, self);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)prepareForRecycle
|
- (void)prepareForRecycle
|
||||||
{
|
{
|
||||||
[super prepareForRecycle];
|
[super prepareForRecycle];
|
||||||
|
|
||||||
_x = nil;
|
_x = nil;
|
||||||
_y = nil;
|
_y = nil;
|
||||||
_rectwidth = nil;
|
_rectwidth = nil;
|
||||||
_rectheight = nil;
|
_rectheight = nil;
|
||||||
_rx = nil;
|
_rx = nil;
|
||||||
_ry = nil;
|
_ry = nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // RN_FABRIC_ENABLED
|
#endif // RN_FABRIC_ENABLED
|
||||||
|
|
||||||
- (void)setX:(RNSVGLength *)x
|
- (void)setX:(RNSVGLength *)x
|
||||||
{
|
{
|
||||||
if ([x isEqualTo:_x]) {
|
if ([x isEqualTo:_x]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
_x = x;
|
_x = x;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setY:(RNSVGLength *)y
|
- (void)setY:(RNSVGLength *)y
|
||||||
{
|
{
|
||||||
if ([y isEqualTo:_y]) {
|
if ([y isEqualTo:_y]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
_y = y;
|
_y = y;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setRectwidth:(RNSVGLength *)rectwidth
|
- (void)setRectwidth:(RNSVGLength *)rectwidth
|
||||||
{
|
{
|
||||||
if ([rectwidth isEqualTo:_rectwidth]) {
|
if ([rectwidth isEqualTo:_rectwidth]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
_rectwidth = rectwidth;
|
_rectwidth = rectwidth;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setRectheight:(RNSVGLength *)rectheight
|
- (void)setRectheight:(RNSVGLength *)rectheight
|
||||||
{
|
{
|
||||||
if ([rectheight isEqualTo:_rectheight]) {
|
if ([rectheight isEqualTo:_rectheight]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
_rectheight = rectheight;
|
_rectheight = rectheight;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setRx:(RNSVGLength *)rx
|
- (void)setRx:(RNSVGLength *)rx
|
||||||
{
|
{
|
||||||
if ([rx isEqualTo:_rx]) {
|
if ([rx isEqualTo:_rx]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
_rx = rx;
|
_rx = rx;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setRy:(RNSVGLength *)ry
|
- (void)setRy:(RNSVGLength *)ry
|
||||||
{
|
{
|
||||||
if ([ry isEqualTo:_ry]) {
|
if ([ry isEqualTo:_ry]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
[self invalidate];
|
[self invalidate];
|
||||||
_ry = ry;
|
_ry = ry;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CGPathRef)getPath:(CGContextRef)context
|
- (CGPathRef)getPath:(CGContextRef)context
|
||||||
{
|
{
|
||||||
CGMutablePathRef path = CGPathCreateMutable();
|
CGMutablePathRef path = CGPathCreateMutable();
|
||||||
CGFloat x = [self relativeOnWidth:self.x];
|
CGFloat x = [self relativeOnWidth:self.x];
|
||||||
CGFloat y = [self relativeOnHeight:self.y];
|
CGFloat y = [self relativeOnHeight:self.y];
|
||||||
CGFloat width = [self relativeOnWidth:self.rectwidth];
|
CGFloat width = [self relativeOnWidth:self.rectwidth];
|
||||||
CGFloat height = [self relativeOnHeight:self.rectheight];
|
CGFloat height = [self relativeOnHeight:self.rectheight];
|
||||||
|
|
||||||
if (self.rx != nil || self.ry != nil) {
|
if (self.rx != nil || self.ry != nil) {
|
||||||
CGFloat rx = 0;
|
CGFloat rx = 0;
|
||||||
CGFloat ry = 0;
|
CGFloat ry = 0;
|
||||||
if (self.rx == nil) {
|
if (self.rx == nil) {
|
||||||
ry = [self relativeOnHeight:self.ry];
|
ry = [self relativeOnHeight:self.ry];
|
||||||
rx = ry;
|
rx = ry;
|
||||||
} else if (self.ry == nil) {
|
} else if (self.ry == nil) {
|
||||||
rx = [self relativeOnWidth:self.rx];
|
rx = [self relativeOnWidth:self.rx];
|
||||||
ry = rx;
|
ry = rx;
|
||||||
} else {
|
|
||||||
rx = [self relativeOnWidth:self.rx];
|
|
||||||
ry = [self relativeOnHeight:self.ry];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rx > width / 2) {
|
|
||||||
rx = width / 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ry > height / 2) {
|
|
||||||
ry = height / 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
CGPathAddRoundedRect(path, nil, CGRectMake(x, y, width, height), rx, ry);
|
|
||||||
} else {
|
} else {
|
||||||
CGPathAddRect(path, nil, CGRectMake(x, y, width, height));
|
rx = [self relativeOnWidth:self.rx];
|
||||||
|
ry = [self relativeOnHeight:self.ry];
|
||||||
}
|
}
|
||||||
|
|
||||||
return (CGPathRef)CFAutorelease(path);
|
if (rx > width / 2) {
|
||||||
|
rx = width / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ry > height / 2) {
|
||||||
|
ry = height / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
CGPathAddRoundedRect(path, nil, CGRectMake(x, y, width, height), rx, ry);
|
||||||
|
} else {
|
||||||
|
CGPathAddRect(path, nil, CGRectMake(x, y, width, height));
|
||||||
|
}
|
||||||
|
|
||||||
|
return (CGPathRef)CFAutorelease(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -2,35 +2,33 @@
|
|||||||
|
|
||||||
#import "RNSVGUIKit.h"
|
#import "RNSVGUIKit.h"
|
||||||
|
|
||||||
#import "RNSVGTextProperties.h"
|
|
||||||
#import "RNSVGPropHelper.h"
|
#import "RNSVGPropHelper.h"
|
||||||
|
#import "RNSVGTextProperties.h"
|
||||||
|
|
||||||
@interface RNSVGFontData : NSObject {
|
@interface RNSVGFontData : NSObject {
|
||||||
@public
|
@public
|
||||||
CGFloat fontSize;
|
CGFloat fontSize;
|
||||||
NSString * fontSize_;
|
NSString *fontSize_;
|
||||||
NSString *fontFamily;
|
NSString *fontFamily;
|
||||||
enum RNSVGFontStyle fontStyle;
|
enum RNSVGFontStyle fontStyle;
|
||||||
NSDictionary * fontData;
|
NSDictionary *fontData;
|
||||||
enum RNSVGFontWeight fontWeight;
|
enum RNSVGFontWeight fontWeight;
|
||||||
int absoluteFontWeight;
|
int absoluteFontWeight;
|
||||||
NSString *fontFeatureSettings;
|
NSString *fontFeatureSettings;
|
||||||
enum RNSVGFontVariantLigatures fontVariantLigatures;
|
enum RNSVGFontVariantLigatures fontVariantLigatures;
|
||||||
enum RNSVGTextAnchor textAnchor;
|
enum RNSVGTextAnchor textAnchor;
|
||||||
enum RNSVGTextDecoration textDecoration;
|
enum RNSVGTextDecoration textDecoration;
|
||||||
CGFloat kerning;
|
CGFloat kerning;
|
||||||
CGFloat wordSpacing;
|
CGFloat wordSpacing;
|
||||||
CGFloat letterSpacing;
|
CGFloat letterSpacing;
|
||||||
bool manualKerning;
|
bool manualKerning;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (instancetype)Defaults;
|
+ (instancetype)Defaults;
|
||||||
|
|
||||||
+ (CGFloat)toAbsoluteWithNSString:(NSString *)string
|
+ (CGFloat)toAbsoluteWithNSString:(NSString *)string fontSize:(CGFloat)fontSize;
|
||||||
fontSize:(CGFloat)fontSize;
|
|
||||||
|
|
||||||
+ (instancetype)initWithNSDictionary:(NSDictionary *)font
|
+ (instancetype)initWithNSDictionary:(NSDictionary *)font parent:(RNSVGFontData *)parent;
|
||||||
parent:(RNSVGFontData *)parent;
|
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#import "RNSVGFontData.h"
|
#import "RNSVGFontData.h"
|
||||||
|
#import "RNSVGNode.h"
|
||||||
#import "RNSVGPropHelper.h"
|
#import "RNSVGPropHelper.h"
|
||||||
#import "RNSVGTextProperties.h"
|
#import "RNSVGTextProperties.h"
|
||||||
#import "RNSVGNode.h"
|
|
||||||
|
|
||||||
#define RNSVG_DEFAULT_KERNING 0.0
|
#define RNSVG_DEFAULT_KERNING 0.0
|
||||||
#define RNSVG_DEFAULT_WORD_SPACING 0.0
|
#define RNSVG_DEFAULT_WORD_SPACING 0.0
|
||||||
@@ -23,178 +23,174 @@ RNSVGFontData *RNSVGFontData_Defaults;
|
|||||||
|
|
||||||
@implementation RNSVGFontData
|
@implementation RNSVGFontData
|
||||||
|
|
||||||
+ (instancetype)Defaults {
|
+ (instancetype)Defaults
|
||||||
if (!RNSVGFontData_Defaults) {
|
{
|
||||||
RNSVGFontData *self = [RNSVGFontData alloc];
|
if (!RNSVGFontData_Defaults) {
|
||||||
self->fontData = nil;
|
RNSVGFontData *self = [RNSVGFontData alloc];
|
||||||
self->fontFamily = @"";
|
self->fontData = nil;
|
||||||
self->fontStyle = RNSVGFontStyleNormal;
|
self->fontFamily = @"";
|
||||||
self->fontWeight = RNSVGFontWeightNormal;
|
self->fontStyle = RNSVGFontStyleNormal;
|
||||||
self->absoluteFontWeight = 400;
|
self->fontWeight = RNSVGFontWeightNormal;
|
||||||
self->fontFeatureSettings = @"";
|
self->absoluteFontWeight = 400;
|
||||||
self->fontVariantLigatures = RNSVGFontVariantLigaturesNormal;
|
self->fontFeatureSettings = @"";
|
||||||
self->textAnchor = RNSVGTextAnchorStart;
|
self->fontVariantLigatures = RNSVGFontVariantLigaturesNormal;
|
||||||
self->textDecoration = RNSVGTextDecorationNone;
|
self->textAnchor = RNSVGTextAnchorStart;
|
||||||
self->manualKerning = false;
|
self->textDecoration = RNSVGTextDecorationNone;
|
||||||
self->kerning = RNSVG_DEFAULT_KERNING;
|
self->manualKerning = false;
|
||||||
self->fontSize = RNSVG_DEFAULT_FONT_SIZE;
|
self->kerning = RNSVG_DEFAULT_KERNING;
|
||||||
self->wordSpacing = RNSVG_DEFAULT_WORD_SPACING;
|
self->fontSize = RNSVG_DEFAULT_FONT_SIZE;
|
||||||
self->letterSpacing = RNSVG_DEFAULT_LETTER_SPACING;
|
self->wordSpacing = RNSVG_DEFAULT_WORD_SPACING;
|
||||||
RNSVGFontData_Defaults = self;
|
self->letterSpacing = RNSVG_DEFAULT_LETTER_SPACING;
|
||||||
}
|
RNSVGFontData_Defaults = self;
|
||||||
return RNSVGFontData_Defaults;
|
}
|
||||||
|
return RNSVGFontData_Defaults;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (CGFloat)toAbsoluteWithNSString:(NSString *)string
|
+ (CGFloat)toAbsoluteWithNSString:(NSString *)string fontSize:(CGFloat)fontSize
|
||||||
fontSize:(CGFloat)fontSize {
|
{
|
||||||
return [RNSVGPropHelper fromRelativeWithNSString:string
|
return [RNSVGPropHelper fromRelativeWithNSString:string relative:0 fontSize:fontSize];
|
||||||
relative:0
|
|
||||||
fontSize:fontSize];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setInheritedWeight:(RNSVGFontData*) parent {
|
- (void)setInheritedWeight:(RNSVGFontData *)parent
|
||||||
absoluteFontWeight = parent->absoluteFontWeight;
|
{
|
||||||
fontWeight = parent->fontWeight;
|
absoluteFontWeight = parent->absoluteFontWeight;
|
||||||
|
fontWeight = parent->fontWeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
RNSVGFontWeight nearestFontWeight(int absoluteFontWeight) {
|
RNSVGFontWeight nearestFontWeight(int absoluteFontWeight)
|
||||||
return RNSVGFontWeights[(int)round(absoluteFontWeight / 100.0)];
|
{
|
||||||
|
return RNSVGFontWeights[(int)round(absoluteFontWeight / 100.0)];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)handleNumericWeight:(RNSVGFontData*)parent weight:(double)weight {
|
- (void)handleNumericWeight:(RNSVGFontData *)parent weight:(double)weight
|
||||||
long roundWeight = round(weight);
|
{
|
||||||
if (roundWeight >= 1 && roundWeight <= 1000) {
|
long roundWeight = round(weight);
|
||||||
absoluteFontWeight = (int)roundWeight;
|
if (roundWeight >= 1 && roundWeight <= 1000) {
|
||||||
fontWeight = nearestFontWeight(absoluteFontWeight);
|
absoluteFontWeight = (int)roundWeight;
|
||||||
} else {
|
fontWeight = nearestFontWeight(absoluteFontWeight);
|
||||||
[self setInheritedWeight:parent];
|
} else {
|
||||||
}
|
[self setInheritedWeight:parent];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://drafts.csswg.org/css-fonts-4/#relative-weights
|
// https://drafts.csswg.org/css-fonts-4/#relative-weights
|
||||||
int AbsoluteFontWeight(RNSVGFontWeight fontWeight, RNSVGFontData* parent) {
|
int AbsoluteFontWeight(RNSVGFontWeight fontWeight, RNSVGFontData *parent)
|
||||||
if (fontWeight == RNSVGFontWeightBolder) {
|
{
|
||||||
return bolder(parent->absoluteFontWeight);
|
if (fontWeight == RNSVGFontWeightBolder) {
|
||||||
} else if (fontWeight == RNSVGFontWeightLighter) {
|
return bolder(parent->absoluteFontWeight);
|
||||||
return lighter(parent->absoluteFontWeight);
|
} else if (fontWeight == RNSVGFontWeightLighter) {
|
||||||
} else {
|
return lighter(parent->absoluteFontWeight);
|
||||||
return RNSVGAbsoluteFontWeights[fontWeight];
|
} else {
|
||||||
}
|
return RNSVGAbsoluteFontWeights[fontWeight];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int bolder(int inherited) {
|
int bolder(int inherited)
|
||||||
if (inherited < 350) {
|
{
|
||||||
return 400;
|
if (inherited < 350) {
|
||||||
} else if (inherited < 550) {
|
return 400;
|
||||||
return 700;
|
} else if (inherited < 550) {
|
||||||
} else if (inherited < 900) {
|
return 700;
|
||||||
return 900;
|
} else if (inherited < 900) {
|
||||||
} else {
|
return 900;
|
||||||
return inherited;
|
} else {
|
||||||
}
|
return inherited;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int lighter(int inherited) {
|
int lighter(int inherited)
|
||||||
if (inherited < 100) {
|
{
|
||||||
return inherited;
|
if (inherited < 100) {
|
||||||
} else if (inherited < 550) {
|
return inherited;
|
||||||
return 100;
|
} else if (inherited < 550) {
|
||||||
} else if (inherited < 750) {
|
return 100;
|
||||||
return 400;
|
} else if (inherited < 750) {
|
||||||
} else {
|
return 400;
|
||||||
return 700;
|
} else {
|
||||||
}
|
return 700;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (instancetype)initWithNSDictionary:(NSDictionary *)font
|
+ (instancetype)initWithNSDictionary:(NSDictionary *)font parent:(RNSVGFontData *)parent
|
||||||
parent:(RNSVGFontData *)parent {
|
{
|
||||||
RNSVGFontData *data = [RNSVGFontData alloc];
|
RNSVGFontData *data = [RNSVGFontData alloc];
|
||||||
CGFloat parentFontSize = parent->fontSize;
|
CGFloat parentFontSize = parent->fontSize;
|
||||||
if ([font objectForKey:FONT_SIZE]) {
|
if ([font objectForKey:FONT_SIZE]) {
|
||||||
id fontSize = [font objectForKey:FONT_SIZE];
|
id fontSize = [font objectForKey:FONT_SIZE];
|
||||||
if ([fontSize isKindOfClass:NSNumber.class]) {
|
if ([fontSize isKindOfClass:NSNumber.class]) {
|
||||||
NSNumber* fs = fontSize;
|
NSNumber *fs = fontSize;
|
||||||
data->fontSize = (CGFloat)[fs doubleValue];
|
data->fontSize = (CGFloat)[fs doubleValue];
|
||||||
} else {
|
|
||||||
data->fontSize = [RNSVGPropHelper fromRelativeWithNSString:fontSize
|
|
||||||
relative:parentFontSize
|
|
||||||
fontSize:parentFontSize];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
data->fontSize = parentFontSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ([font objectForKey:FONT_WEIGHT]) {
|
|
||||||
id fontWeight = [font objectForKey:FONT_WEIGHT];
|
|
||||||
if ([fontWeight isKindOfClass:NSNumber.class]) {
|
|
||||||
[data handleNumericWeight:parent weight:[fontWeight doubleValue]];
|
|
||||||
} else {
|
|
||||||
NSString* weight = fontWeight;
|
|
||||||
NSInteger fw = RNSVGFontWeightFromString(weight);
|
|
||||||
if (fw != -1) {
|
|
||||||
data->absoluteFontWeight = AbsoluteFontWeight((RNSVGFontWeight)fw, parent);
|
|
||||||
data->fontWeight = nearestFontWeight(data->absoluteFontWeight);
|
|
||||||
} else if ([weight length] != 0) {
|
|
||||||
[data handleNumericWeight:parent weight:[weight doubleValue]];
|
|
||||||
} else {
|
|
||||||
[data setInheritedWeight:parent];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
|
data->fontSize = [RNSVGPropHelper fromRelativeWithNSString:fontSize
|
||||||
|
relative:parentFontSize
|
||||||
|
fontSize:parentFontSize];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
data->fontSize = parentFontSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ([font objectForKey:FONT_WEIGHT]) {
|
||||||
|
id fontWeight = [font objectForKey:FONT_WEIGHT];
|
||||||
|
if ([fontWeight isKindOfClass:NSNumber.class]) {
|
||||||
|
[data handleNumericWeight:parent weight:[fontWeight doubleValue]];
|
||||||
|
} else {
|
||||||
|
NSString *weight = fontWeight;
|
||||||
|
NSInteger fw = RNSVGFontWeightFromString(weight);
|
||||||
|
if (fw != -1) {
|
||||||
|
data->absoluteFontWeight = AbsoluteFontWeight((RNSVGFontWeight)fw, parent);
|
||||||
|
data->fontWeight = nearestFontWeight(data->absoluteFontWeight);
|
||||||
|
} else if ([weight length] != 0) {
|
||||||
|
[data handleNumericWeight:parent weight:[weight doubleValue]];
|
||||||
|
} else {
|
||||||
[data setInheritedWeight:parent];
|
[data setInheritedWeight:parent];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
[data setInheritedWeight:parent];
|
||||||
|
}
|
||||||
|
|
||||||
data->fontData = [font objectForKey:FONT_DATA] ? [font objectForKey:FONT_DATA] : parent->fontData;
|
data->fontData = [font objectForKey:FONT_DATA] ? [font objectForKey:FONT_DATA] : parent->fontData;
|
||||||
data->fontFamily = [font objectForKey:FONT_FAMILY] ? [font objectForKey:FONT_FAMILY] : parent->fontFamily;
|
data->fontFamily = [font objectForKey:FONT_FAMILY] ? [font objectForKey:FONT_FAMILY] : parent->fontFamily;
|
||||||
NSString* style = [font objectForKey:FONT_STYLE];
|
NSString *style = [font objectForKey:FONT_STYLE];
|
||||||
data->fontStyle = style ? RNSVGFontStyleFromString(style) : parent->fontStyle;
|
data->fontStyle = style ? RNSVGFontStyleFromString(style) : parent->fontStyle;
|
||||||
NSString* feature = [font objectForKey:FONT_FEATURE_SETTINGS];
|
NSString *feature = [font objectForKey:FONT_FEATURE_SETTINGS];
|
||||||
data->fontFeatureSettings = feature ? [font objectForKey:FONT_FEATURE_SETTINGS] : parent->fontFeatureSettings;
|
data->fontFeatureSettings = feature ? [font objectForKey:FONT_FEATURE_SETTINGS] : parent->fontFeatureSettings;
|
||||||
NSString* variant = [font objectForKey:FONT_VARIANT_LIGATURES];
|
NSString *variant = [font objectForKey:FONT_VARIANT_LIGATURES];
|
||||||
data->fontVariantLigatures = variant ? RNSVGFontVariantLigaturesFromString(variant) : parent->fontVariantLigatures;
|
data->fontVariantLigatures = variant ? RNSVGFontVariantLigaturesFromString(variant) : parent->fontVariantLigatures;
|
||||||
NSString* anchor = [font objectForKey:TEXT_ANCHOR];
|
NSString *anchor = [font objectForKey:TEXT_ANCHOR];
|
||||||
data->textAnchor = anchor ? RNSVGTextAnchorFromString(anchor) : parent->textAnchor;
|
data->textAnchor = anchor ? RNSVGTextAnchorFromString(anchor) : parent->textAnchor;
|
||||||
NSString* decoration = [font objectForKey:TEXT_DECORATION];
|
NSString *decoration = [font objectForKey:TEXT_DECORATION];
|
||||||
data->textDecoration = decoration ? RNSVGTextDecorationFromString(decoration) : parent->textDecoration;
|
data->textDecoration = decoration ? RNSVGTextDecorationFromString(decoration) : parent->textDecoration;
|
||||||
|
|
||||||
CGFloat fontSize = data->fontSize;
|
CGFloat fontSize = data->fontSize;
|
||||||
id kerning = [font objectForKey:KERNING];
|
id kerning = [font objectForKey:KERNING];
|
||||||
data->manualKerning = (kerning || parent->manualKerning );
|
data->manualKerning = (kerning || parent->manualKerning);
|
||||||
if ([kerning isKindOfClass:NSNumber.class]) {
|
if ([kerning isKindOfClass:NSNumber.class]) {
|
||||||
NSNumber* kern = kerning;
|
NSNumber *kern = kerning;
|
||||||
data->kerning = (CGFloat)[kern doubleValue];
|
data->kerning = (CGFloat)[kern doubleValue];
|
||||||
} else {
|
} else {
|
||||||
data->kerning = kerning ?
|
data->kerning = kerning ? [RNSVGFontData toAbsoluteWithNSString:kerning fontSize:fontSize] : parent->kerning;
|
||||||
[RNSVGFontData toAbsoluteWithNSString:kerning
|
}
|
||||||
fontSize:fontSize]
|
|
||||||
: parent->kerning;
|
|
||||||
}
|
|
||||||
|
|
||||||
id wordSpacing = [font objectForKey:WORD_SPACING];
|
id wordSpacing = [font objectForKey:WORD_SPACING];
|
||||||
if ([wordSpacing isKindOfClass:NSNumber.class]) {
|
if ([wordSpacing isKindOfClass:NSNumber.class]) {
|
||||||
NSNumber* ws = wordSpacing;
|
NSNumber *ws = wordSpacing;
|
||||||
data->wordSpacing = (CGFloat)[ws doubleValue];
|
data->wordSpacing = (CGFloat)[ws doubleValue];
|
||||||
} else {
|
} else {
|
||||||
data->wordSpacing = wordSpacing ?
|
data->wordSpacing =
|
||||||
[RNSVGFontData toAbsoluteWithNSString:wordSpacing
|
wordSpacing ? [RNSVGFontData toAbsoluteWithNSString:wordSpacing fontSize:fontSize] : parent->wordSpacing;
|
||||||
fontSize:fontSize]
|
}
|
||||||
: parent->wordSpacing;
|
|
||||||
}
|
|
||||||
|
|
||||||
id letterSpacing = [font objectForKey:LETTER_SPACING];
|
id letterSpacing = [font objectForKey:LETTER_SPACING];
|
||||||
if ([letterSpacing isKindOfClass:NSNumber.class]) {
|
if ([letterSpacing isKindOfClass:NSNumber.class]) {
|
||||||
NSNumber* ls = letterSpacing;
|
NSNumber *ls = letterSpacing;
|
||||||
data->wordSpacing = (CGFloat)[ls doubleValue];
|
data->wordSpacing = (CGFloat)[ls doubleValue];
|
||||||
} else {
|
} else {
|
||||||
data->letterSpacing = letterSpacing ?
|
data->letterSpacing =
|
||||||
[RNSVGFontData toAbsoluteWithNSString:letterSpacing
|
letterSpacing ? [RNSVGFontData toAbsoluteWithNSString:letterSpacing fontSize:fontSize] : parent->letterSpacing;
|
||||||
fontSize:fontSize]
|
}
|
||||||
: parent->letterSpacing;
|
|
||||||
}
|
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#import <React/UIView+React.h>
|
|
||||||
#import <CoreText/CoreText.h>
|
#import <CoreText/CoreText.h>
|
||||||
|
#import <React/UIView+React.h>
|
||||||
#import "RNSVGFontData.h"
|
#import "RNSVGFontData.h"
|
||||||
|
|
||||||
@class RNSVGText;
|
@class RNSVGText;
|
||||||
@@ -10,8 +10,7 @@
|
|||||||
|
|
||||||
- (CTFontRef)getGlyphFont;
|
- (CTFontRef)getGlyphFont;
|
||||||
|
|
||||||
- (instancetype)initWithWidth:(CGFloat)width
|
- (instancetype)initWithWidth:(CGFloat)width height:(CGFloat)height;
|
||||||
height:(CGFloat)height;
|
|
||||||
|
|
||||||
- (RNSVGFontData *)getFont;
|
- (RNSVGFontData *)getFont;
|
||||||
|
|
||||||
@@ -33,17 +32,16 @@
|
|||||||
|
|
||||||
- (void)popContext;
|
- (void)popContext;
|
||||||
|
|
||||||
- (void)pushContext:(RNSVGText*)node
|
- (void)pushContext:(RNSVGText *)node
|
||||||
font:(NSDictionary*)font
|
font:(NSDictionary *)font
|
||||||
x:(NSArray<RNSVGLength*>*)x
|
x:(NSArray<RNSVGLength *> *)x
|
||||||
y:(NSArray<RNSVGLength*>*)y
|
y:(NSArray<RNSVGLength *> *)y
|
||||||
deltaX:(NSArray<RNSVGLength*>*)deltaX
|
deltaX:(NSArray<RNSVGLength *> *)deltaX
|
||||||
deltaY:(NSArray<RNSVGLength*>*)deltaY
|
deltaY:(NSArray<RNSVGLength *> *)deltaY
|
||||||
rotate:(NSArray<RNSVGLength*>*)rotate;
|
rotate:(NSArray<RNSVGLength *> *)rotate;
|
||||||
|
|
||||||
- (void)pushContext:(RNSVGGroup*)node
|
- (void)pushContext:(RNSVGGroup *)node font:(NSDictionary *)font;
|
||||||
font:(NSDictionary *)font;
|
|
||||||
|
|
||||||
- (NSArray*)getFontContext;
|
- (NSArray *)getFontContext;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -1,414 +1,414 @@
|
|||||||
#import "RNSVGGlyphContext.h"
|
#import "RNSVGGlyphContext.h"
|
||||||
#import <React/RCTFont.h>
|
#import <React/RCTFont.h>
|
||||||
|
#import "RNSVGFontData.h"
|
||||||
#import "RNSVGNode.h"
|
#import "RNSVGNode.h"
|
||||||
#import "RNSVGPropHelper.h"
|
#import "RNSVGPropHelper.h"
|
||||||
#import "RNSVGFontData.h"
|
|
||||||
#import "RNSVGText.h"
|
#import "RNSVGText.h"
|
||||||
|
|
||||||
// https://www.w3.org/TR/SVG/text.html#TSpanElement
|
// https://www.w3.org/TR/SVG/text.html#TSpanElement
|
||||||
@interface RNSVGGlyphContext () {
|
@interface RNSVGGlyphContext () {
|
||||||
@public
|
@public
|
||||||
// Current stack (one per node push/pop)
|
// Current stack (one per node push/pop)
|
||||||
NSMutableArray *mFontContext_;
|
NSMutableArray *mFontContext_;
|
||||||
|
|
||||||
// Unique input attribute lists (only added if node sets a value)
|
// Unique input attribute lists (only added if node sets a value)
|
||||||
NSMutableArray<NSArray<RNSVGLength*>*> *mXsContext_;
|
NSMutableArray<NSArray<RNSVGLength *> *> *mXsContext_;
|
||||||
NSMutableArray<NSArray<RNSVGLength*>*> *mYsContext_;
|
NSMutableArray<NSArray<RNSVGLength *> *> *mYsContext_;
|
||||||
NSMutableArray<NSArray<RNSVGLength*>*> *mDXsContext_;
|
NSMutableArray<NSArray<RNSVGLength *> *> *mDXsContext_;
|
||||||
NSMutableArray<NSArray<RNSVGLength*>*> *mDYsContext_;
|
NSMutableArray<NSArray<RNSVGLength *> *> *mDYsContext_;
|
||||||
NSMutableArray<NSArray<RNSVGLength*>*> *mRsContext_;
|
NSMutableArray<NSArray<RNSVGLength *> *> *mRsContext_;
|
||||||
|
|
||||||
// Unique index into attribute list (one per unique list)
|
// Unique index into attribute list (one per unique list)
|
||||||
NSMutableArray<NSNumber*> *mXIndices_;
|
NSMutableArray<NSNumber *> *mXIndices_;
|
||||||
NSMutableArray<NSNumber*> *mYIndices_;
|
NSMutableArray<NSNumber *> *mYIndices_;
|
||||||
NSMutableArray<NSNumber*> *mDXIndices_;
|
NSMutableArray<NSNumber *> *mDXIndices_;
|
||||||
NSMutableArray<NSNumber*> *mDYIndices_;
|
NSMutableArray<NSNumber *> *mDYIndices_;
|
||||||
NSMutableArray<NSNumber*> *mRIndices_;
|
NSMutableArray<NSNumber *> *mRIndices_;
|
||||||
|
|
||||||
// Index of unique context used (one per node push/pop)
|
// Index of unique context used (one per node push/pop)
|
||||||
NSMutableArray<NSNumber*> *mXsIndices_;
|
NSMutableArray<NSNumber *> *mXsIndices_;
|
||||||
NSMutableArray<NSNumber*> *mYsIndices_;
|
NSMutableArray<NSNumber *> *mYsIndices_;
|
||||||
NSMutableArray<NSNumber*> *mDXsIndices_;
|
NSMutableArray<NSNumber *> *mDXsIndices_;
|
||||||
NSMutableArray<NSNumber*> *mDYsIndices_;
|
NSMutableArray<NSNumber *> *mDYsIndices_;
|
||||||
NSMutableArray<NSNumber*> *mRsIndices_;
|
NSMutableArray<NSNumber *> *mRsIndices_;
|
||||||
|
|
||||||
// Calculated on push context, percentage and em length depends on parent font size
|
// Calculated on push context, percentage and em length depends on parent font size
|
||||||
CGFloat mFontSize_;
|
CGFloat mFontSize_;
|
||||||
RNSVGFontData *topFont_;
|
RNSVGFontData *topFont_;
|
||||||
|
|
||||||
// Current accumulated values
|
// Current accumulated values
|
||||||
// https://www.w3.org/TR/SVG/types.html#DataTypeCoordinate
|
// https://www.w3.org/TR/SVG/types.html#DataTypeCoordinate
|
||||||
// <coordinate> syntax is the same as that for <length>
|
// <coordinate> syntax is the same as that for <length>
|
||||||
CGFloat mX_;
|
CGFloat mX_;
|
||||||
CGFloat mY_;
|
CGFloat mY_;
|
||||||
|
|
||||||
// https://www.w3.org/TR/SVG/types.html#Length
|
// https://www.w3.org/TR/SVG/types.html#Length
|
||||||
CGFloat mDX_;
|
CGFloat mDX_;
|
||||||
CGFloat mDY_;
|
CGFloat mDY_;
|
||||||
|
|
||||||
// Current <list-of-coordinates> SVGLengthList
|
// Current <list-of-coordinates> SVGLengthList
|
||||||
// https://www.w3.org/TR/SVG/types.html#InterfaceSVGLengthList
|
// https://www.w3.org/TR/SVG/types.html#InterfaceSVGLengthList
|
||||||
// https://www.w3.org/TR/SVG/types.html#DataTypeCoordinates
|
// https://www.w3.org/TR/SVG/types.html#DataTypeCoordinates
|
||||||
|
|
||||||
// https://www.w3.org/TR/SVG/text.html#TSpanElementXAttribute
|
// https://www.w3.org/TR/SVG/text.html#TSpanElementXAttribute
|
||||||
NSArray<RNSVGLength*> *mXs_;
|
NSArray<RNSVGLength *> *mXs_;
|
||||||
|
|
||||||
// https://www.w3.org/TR/SVG/text.html#TSpanElementYAttribute
|
// https://www.w3.org/TR/SVG/text.html#TSpanElementYAttribute
|
||||||
NSArray<RNSVGLength*> *mYs_;
|
NSArray<RNSVGLength *> *mYs_;
|
||||||
|
|
||||||
// Current <list-of-lengths> SVGLengthList
|
// Current <list-of-lengths> SVGLengthList
|
||||||
// https://www.w3.org/TR/SVG/types.html#DataTypeLengths
|
// https://www.w3.org/TR/SVG/types.html#DataTypeLengths
|
||||||
|
|
||||||
// https://www.w3.org/TR/SVG/text.html#TSpanElementDXAttribute
|
// https://www.w3.org/TR/SVG/text.html#TSpanElementDXAttribute
|
||||||
NSArray<RNSVGLength*> *mDXs_;
|
NSArray<RNSVGLength *> *mDXs_;
|
||||||
|
|
||||||
// https://www.w3.org/TR/SVG/text.html#TSpanElementDYAttribute
|
// https://www.w3.org/TR/SVG/text.html#TSpanElementDYAttribute
|
||||||
NSArray<RNSVGLength*> *mDYs_;
|
NSArray<RNSVGLength *> *mDYs_;
|
||||||
|
|
||||||
// Current <list-of-numbers> SVGLengthList
|
// Current <list-of-numbers> SVGLengthList
|
||||||
// https://www.w3.org/TR/SVG/types.html#DataTypeNumbers
|
// https://www.w3.org/TR/SVG/types.html#DataTypeNumbers
|
||||||
|
|
||||||
// https://www.w3.org/TR/SVG/text.html#TSpanElementRotateAttribute
|
// https://www.w3.org/TR/SVG/text.html#TSpanElementRotateAttribute
|
||||||
NSArray<RNSVGLength*> *mRs_;
|
NSArray<RNSVGLength *> *mRs_;
|
||||||
|
|
||||||
// Current attribute list index
|
// Current attribute list index
|
||||||
long mXsIndex_;
|
long mXsIndex_;
|
||||||
long mYsIndex_;
|
long mYsIndex_;
|
||||||
long mDXsIndex_;
|
long mDXsIndex_;
|
||||||
long mDYsIndex_;
|
long mDYsIndex_;
|
||||||
long mRsIndex_;
|
long mRsIndex_;
|
||||||
|
|
||||||
// Current value index in current attribute list
|
// Current value index in current attribute list
|
||||||
long mXIndex_;
|
long mXIndex_;
|
||||||
long mYIndex_;
|
long mYIndex_;
|
||||||
long mDXIndex_;
|
long mDXIndex_;
|
||||||
long mDYIndex_;
|
long mDYIndex_;
|
||||||
long mRIndex_;
|
long mRIndex_;
|
||||||
|
|
||||||
// Top index of stack
|
// Top index of stack
|
||||||
long mTop_;
|
long mTop_;
|
||||||
|
|
||||||
// Constructor parameters
|
// Constructor parameters
|
||||||
CGFloat mWidth_;
|
CGFloat mWidth_;
|
||||||
CGFloat mHeight_;
|
CGFloat mHeight_;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)pushContext:(RNSVGText*)node
|
- (void)pushContext:(RNSVGText *)node
|
||||||
font:(NSDictionary*)font
|
font:(NSDictionary *)font
|
||||||
x:(NSArray<RNSVGLength*>*)x
|
x:(NSArray<RNSVGLength *> *)x
|
||||||
y:(NSArray<RNSVGLength*>*)y
|
y:(NSArray<RNSVGLength *> *)y
|
||||||
deltaX:(NSArray<RNSVGLength*>*)deltaX
|
deltaX:(NSArray<RNSVGLength *> *)deltaX
|
||||||
deltaY:(NSArray<RNSVGLength*>*)deltaY
|
deltaY:(NSArray<RNSVGLength *> *)deltaY
|
||||||
rotate:(NSArray<RNSVGLength*>*)rotate;
|
rotate:(NSArray<RNSVGLength *> *)rotate;
|
||||||
|
|
||||||
- (void)pushContext:(RNSVGGroup*)node
|
- (void)pushContext:(RNSVGGroup *)node font:(NSDictionary *)font;
|
||||||
font:(NSDictionary *)font;
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation RNSVGGlyphContext
|
@implementation RNSVGGlyphContext
|
||||||
|
|
||||||
- (NSArray*)getFontContext {
|
- (NSArray *)getFontContext
|
||||||
return mFontContext_;
|
{
|
||||||
|
return mFontContext_;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CTFontRef)getGlyphFont
|
- (CTFontRef)getGlyphFont
|
||||||
{
|
{
|
||||||
CGFloat size = topFont_->fontSize;
|
CGFloat size = topFont_->fontSize;
|
||||||
NSString *fontFamily = topFont_->fontFamily;
|
NSString *fontFamily = topFont_->fontFamily;
|
||||||
NSString *fontStyle = RNSVGFontStyleStrings[topFont_->fontStyle];
|
NSString *fontStyle = RNSVGFontStyleStrings[topFont_->fontStyle];
|
||||||
NSString *fontWeight = RNSVGFontWeightStrings[topFont_->fontWeight];
|
NSString *fontWeight = RNSVGFontWeightStrings[topFont_->fontWeight];
|
||||||
UIFont *font = [RCTFont updateFont:nil
|
UIFont *font = [RCTFont updateFont:nil
|
||||||
withFamily:[fontFamily isEqualToString:@""] ? nil : fontFamily
|
withFamily:[fontFamily isEqualToString:@""] ? nil : fontFamily
|
||||||
size:@(isnan(size) ? 0 : size)
|
size:@(isnan(size) ? 0 : size)
|
||||||
weight:fontWeight
|
weight:fontWeight
|
||||||
style:fontStyle
|
style:fontStyle
|
||||||
variant:nil
|
variant:nil
|
||||||
scaleMultiplier:1.0];
|
scaleMultiplier:1.0];
|
||||||
CTFontRef ref = (__bridge CTFontRef)font;
|
CTFontRef ref = (__bridge CTFontRef)font;
|
||||||
|
|
||||||
double weight = topFont_->absoluteFontWeight;
|
double weight = topFont_->absoluteFontWeight;
|
||||||
if (weight == 400) {
|
if (weight == 400) {
|
||||||
return ref;
|
return ref;
|
||||||
|
}
|
||||||
|
|
||||||
|
CFArrayRef cgAxes = CTFontCopyVariationAxes(ref);
|
||||||
|
if (cgAxes == 0) {
|
||||||
|
return ref;
|
||||||
|
}
|
||||||
|
CFIndex cgAxisCount = CFArrayGetCount(cgAxes);
|
||||||
|
CFNumberRef wght_id = 0;
|
||||||
|
|
||||||
|
for (CFIndex i = 0; i < cgAxisCount; ++i) {
|
||||||
|
CFTypeRef cgAxis = CFArrayGetValueAtIndex(cgAxes, i);
|
||||||
|
if (CFGetTypeID(cgAxis) != CFDictionaryGetTypeID()) {
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
CFArrayRef cgAxes = CTFontCopyVariationAxes(ref);
|
CFDictionaryRef cgAxisDict = (CFDictionaryRef)cgAxis;
|
||||||
if (cgAxes == 0) {
|
CFTypeRef axisName = CFDictionaryGetValue(cgAxisDict, kCTFontVariationAxisNameKey);
|
||||||
return ref;
|
|
||||||
|
if (!axisName || CFGetTypeID(axisName) != CFStringGetTypeID()) {
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
CFIndex cgAxisCount = CFArrayGetCount(cgAxes);
|
CFStringRef axisNameString = (CFStringRef)axisName;
|
||||||
CFNumberRef wght_id = 0;
|
NSString *axisNameNSString = (__bridge NSString *)(axisNameString);
|
||||||
|
if (![@"Weight" isEqualToString:axisNameNSString] && ![@"Size" isEqualToString:axisNameNSString]) {
|
||||||
for (CFIndex i = 0; i < cgAxisCount; ++i) {
|
continue;
|
||||||
CFTypeRef cgAxis = CFArrayGetValueAtIndex(cgAxes, i);
|
|
||||||
if (CFGetTypeID(cgAxis) != CFDictionaryGetTypeID()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
CFDictionaryRef cgAxisDict = (CFDictionaryRef)cgAxis;
|
|
||||||
CFTypeRef axisName = CFDictionaryGetValue(cgAxisDict, kCTFontVariationAxisNameKey);
|
|
||||||
|
|
||||||
if (!axisName || CFGetTypeID(axisName) != CFStringGetTypeID()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
CFStringRef axisNameString = (CFStringRef)axisName;
|
|
||||||
NSString *axisNameNSString = (__bridge NSString *)(axisNameString);
|
|
||||||
if (![@"Weight" isEqualToString:axisNameNSString] && ![@"Size" isEqualToString:axisNameNSString]) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
CFTypeRef axisMinValue = CFDictionaryGetValue(cgAxisDict, kCTFontVariationAxisMinimumValueKey);
|
|
||||||
if (axisMinValue && CFGetTypeID(axisMinValue) == CFNumberGetTypeID()) {
|
|
||||||
CFNumberRef axisMinValueNumber = (CFNumberRef)axisMinValue;
|
|
||||||
double axisMinValueDouble;
|
|
||||||
if (CFNumberGetValue(axisMinValueNumber, kCFNumberDoubleType, &axisMinValueDouble))
|
|
||||||
{
|
|
||||||
weight = fmax(axisMinValueDouble, weight);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CFTypeRef axisMaxValue = CFDictionaryGetValue(cgAxisDict, kCTFontVariationAxisMaximumValueKey);
|
|
||||||
if (axisMaxValue && CFGetTypeID(axisMaxValue) == CFNumberGetTypeID()) {
|
|
||||||
CFNumberRef axisMaxValueNumber = (CFNumberRef)axisMaxValue;
|
|
||||||
double axisMaxValueDouble;
|
|
||||||
if (CFNumberGetValue(axisMaxValueNumber, kCFNumberDoubleType, &axisMaxValueDouble))
|
|
||||||
{
|
|
||||||
weight = fmin(axisMaxValueDouble, weight);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CFTypeRef axisId = CFDictionaryGetValue(cgAxisDict, kCTFontVariationAxisIdentifierKey);
|
|
||||||
if (!axisId || CFGetTypeID(axisId) != CFNumberGetTypeID()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
wght_id = (CFNumberRef)axisId;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wght_id == 0) {
|
CFTypeRef axisMinValue = CFDictionaryGetValue(cgAxisDict, kCTFontVariationAxisMinimumValueKey);
|
||||||
return ref;
|
if (axisMinValue && CFGetTypeID(axisMinValue) == CFNumberGetTypeID()) {
|
||||||
|
CFNumberRef axisMinValueNumber = (CFNumberRef)axisMinValue;
|
||||||
|
double axisMinValueDouble;
|
||||||
|
if (CFNumberGetValue(axisMinValueNumber, kCFNumberDoubleType, &axisMinValueDouble)) {
|
||||||
|
weight = fmax(axisMinValueDouble, weight);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
UIFontDescriptor *uifd = font.fontDescriptor;
|
|
||||||
CTFontDescriptorRef ctfd = (__bridge CTFontDescriptorRef)(uifd);
|
|
||||||
CTFontDescriptorRef newfd = CTFontDescriptorCreateCopyWithVariation(ctfd, wght_id, (CGFloat)weight);
|
|
||||||
CTFontRef newfont = CTFontCreateCopyWithAttributes(ref, size, nil, newfd);
|
|
||||||
|
|
||||||
CFRelease(newfd);
|
CFTypeRef axisMaxValue = CFDictionaryGetValue(cgAxisDict, kCTFontVariationAxisMaximumValueKey);
|
||||||
|
if (axisMaxValue && CFGetTypeID(axisMaxValue) == CFNumberGetTypeID()) {
|
||||||
|
CFNumberRef axisMaxValueNumber = (CFNumberRef)axisMaxValue;
|
||||||
|
double axisMaxValueDouble;
|
||||||
|
if (CFNumberGetValue(axisMaxValueNumber, kCFNumberDoubleType, &axisMaxValueDouble)) {
|
||||||
|
weight = fmin(axisMaxValueDouble, weight);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (CTFontRef)CFAutorelease(newfont);
|
CFTypeRef axisId = CFDictionaryGetValue(cgAxisDict, kCTFontVariationAxisIdentifierKey);
|
||||||
|
if (!axisId || CFGetTypeID(axisId) != CFNumberGetTypeID()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
wght_id = (CFNumberRef)axisId;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wght_id == 0) {
|
||||||
|
return ref;
|
||||||
|
}
|
||||||
|
UIFontDescriptor *uifd = font.fontDescriptor;
|
||||||
|
CTFontDescriptorRef ctfd = (__bridge CTFontDescriptorRef)(uifd);
|
||||||
|
CTFontDescriptorRef newfd = CTFontDescriptorCreateCopyWithVariation(ctfd, wght_id, (CGFloat)weight);
|
||||||
|
CTFontRef newfont = CTFontCreateCopyWithAttributes(ref, size, nil, newfd);
|
||||||
|
|
||||||
|
CFRelease(newfd);
|
||||||
|
|
||||||
|
return (CTFontRef)CFAutorelease(newfont);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)pushIndices
|
- (void)pushIndices
|
||||||
{
|
{
|
||||||
[self->mXsIndices_ addObject:[NSNumber numberWithLong:self->mXsIndex_]];
|
[self->mXsIndices_ addObject:[NSNumber numberWithLong:self->mXsIndex_]];
|
||||||
[self->mYsIndices_ addObject:[NSNumber numberWithLong:self->mYsIndex_]];
|
[self->mYsIndices_ addObject:[NSNumber numberWithLong:self->mYsIndex_]];
|
||||||
[self->mDXsIndices_ addObject:[NSNumber numberWithLong:self->mDXsIndex_]];
|
[self->mDXsIndices_ addObject:[NSNumber numberWithLong:self->mDXsIndex_]];
|
||||||
[self->mDYsIndices_ addObject:[NSNumber numberWithLong:self->mDYsIndex_]];
|
[self->mDYsIndices_ addObject:[NSNumber numberWithLong:self->mDYsIndex_]];
|
||||||
[self->mRsIndices_ addObject:[NSNumber numberWithLong:self->mRsIndex_]];
|
[self->mRsIndices_ addObject:[NSNumber numberWithLong:self->mRsIndex_]];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (instancetype)initWithWidth:(CGFloat)width
|
- (instancetype)initWithWidth:(CGFloat)width height:(CGFloat)height
|
||||||
height:(CGFloat)height {
|
{
|
||||||
self = [super init];
|
self = [super init];
|
||||||
self->mFontContext_ = [[NSMutableArray alloc]init];
|
self->mFontContext_ = [[NSMutableArray alloc] init];
|
||||||
self->mXsContext_ = [[NSMutableArray alloc]init];
|
self->mXsContext_ = [[NSMutableArray alloc] init];
|
||||||
self->mYsContext_ = [[NSMutableArray alloc]init];
|
self->mYsContext_ = [[NSMutableArray alloc] init];
|
||||||
self->mDXsContext_ = [[NSMutableArray alloc]init];
|
self->mDXsContext_ = [[NSMutableArray alloc] init];
|
||||||
self->mDYsContext_ = [[NSMutableArray alloc]init];
|
self->mDYsContext_ = [[NSMutableArray alloc] init];
|
||||||
self->mRsContext_ = [[NSMutableArray alloc]init];
|
self->mRsContext_ = [[NSMutableArray alloc] init];
|
||||||
|
|
||||||
self->mXIndices_ = [[NSMutableArray alloc]init];
|
self->mXIndices_ = [[NSMutableArray alloc] init];
|
||||||
self->mYIndices_ = [[NSMutableArray alloc]init];
|
self->mYIndices_ = [[NSMutableArray alloc] init];
|
||||||
self->mDXIndices_ = [[NSMutableArray alloc]init];
|
self->mDXIndices_ = [[NSMutableArray alloc] init];
|
||||||
self->mDYIndices_ = [[NSMutableArray alloc]init];
|
self->mDYIndices_ = [[NSMutableArray alloc] init];
|
||||||
self->mRIndices_ = [[NSMutableArray alloc]init];
|
self->mRIndices_ = [[NSMutableArray alloc] init];
|
||||||
|
|
||||||
self->mXsIndices_ = [[NSMutableArray alloc]init];
|
self->mXsIndices_ = [[NSMutableArray alloc] init];
|
||||||
self->mYsIndices_ = [[NSMutableArray alloc]init];
|
self->mYsIndices_ = [[NSMutableArray alloc] init];
|
||||||
self->mDXsIndices_ = [[NSMutableArray alloc]init];
|
self->mDXsIndices_ = [[NSMutableArray alloc] init];
|
||||||
self->mDYsIndices_ = [[NSMutableArray alloc]init];
|
self->mDYsIndices_ = [[NSMutableArray alloc] init];
|
||||||
self->mRsIndices_ = [[NSMutableArray alloc]init];
|
self->mRsIndices_ = [[NSMutableArray alloc] init];
|
||||||
|
|
||||||
self->mFontSize_ = RNSVGFontData_DEFAULT_FONT_SIZE;
|
self->mFontSize_ = RNSVGFontData_DEFAULT_FONT_SIZE;
|
||||||
self->topFont_ = [RNSVGFontData Defaults];
|
self->topFont_ = [RNSVGFontData Defaults];
|
||||||
|
|
||||||
self->mXs_ = [[NSArray alloc]init];
|
self->mXs_ = [[NSArray alloc] init];
|
||||||
self->mYs_ = [[NSArray alloc]init];
|
self->mYs_ = [[NSArray alloc] init];
|
||||||
self->mDXs_ = [[NSArray alloc]init];
|
self->mDXs_ = [[NSArray alloc] init];
|
||||||
self->mDYs_ = [[NSArray alloc]init];
|
self->mDYs_ = [[NSArray alloc] init];
|
||||||
self->mRs_ = [[NSArray alloc]initWithObjects:[RNSVGLength lengthWithNumber:0], nil];
|
self->mRs_ = [[NSArray alloc] initWithObjects:[RNSVGLength lengthWithNumber:0], nil];
|
||||||
|
|
||||||
self->mXIndex_ = -1;
|
self->mXIndex_ = -1;
|
||||||
self->mYIndex_ = -1;
|
self->mYIndex_ = -1;
|
||||||
self->mDXIndex_ = -1;
|
self->mDXIndex_ = -1;
|
||||||
self->mDYIndex_ = -1;
|
self->mDYIndex_ = -1;
|
||||||
self->mRIndex_ = -1;
|
self->mRIndex_ = -1;
|
||||||
|
|
||||||
self->mWidth_ = width;
|
self->mWidth_ = width;
|
||||||
self->mHeight_ = height;
|
self->mHeight_ = height;
|
||||||
|
|
||||||
[self->mXsContext_ addObject:self->mXs_];
|
[self->mXsContext_ addObject:self->mXs_];
|
||||||
[self->mYsContext_ addObject:self->mYs_];
|
[self->mYsContext_ addObject:self->mYs_];
|
||||||
[self->mDXsContext_ addObject:self->mDXs_];
|
[self->mDXsContext_ addObject:self->mDXs_];
|
||||||
[self->mDYsContext_ addObject:self->mDYs_];
|
[self->mDYsContext_ addObject:self->mDYs_];
|
||||||
[self->mRsContext_ addObject:self->mRs_];
|
[self->mRsContext_ addObject:self->mRs_];
|
||||||
|
|
||||||
[self->mXIndices_ addObject:[NSNumber numberWithLong:self->mXIndex_]];
|
[self->mXIndices_ addObject:[NSNumber numberWithLong:self->mXIndex_]];
|
||||||
[self->mYIndices_ addObject:[NSNumber numberWithLong:self->mYIndex_]];
|
[self->mYIndices_ addObject:[NSNumber numberWithLong:self->mYIndex_]];
|
||||||
[self->mDXIndices_ addObject:[NSNumber numberWithLong:self->mDXIndex_]];
|
[self->mDXIndices_ addObject:[NSNumber numberWithLong:self->mDXIndex_]];
|
||||||
[self->mDYIndices_ addObject:[NSNumber numberWithLong:self->mDYIndex_]];
|
[self->mDYIndices_ addObject:[NSNumber numberWithLong:self->mDYIndex_]];
|
||||||
[self->mRIndices_ addObject:[NSNumber numberWithLong:self->mRIndex_]];
|
[self->mRIndices_ addObject:[NSNumber numberWithLong:self->mRIndex_]];
|
||||||
|
|
||||||
[self->mFontContext_ addObject:self->topFont_];
|
[self->mFontContext_ addObject:self->topFont_];
|
||||||
[self pushIndices];
|
[self pushIndices];
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (RNSVGFontData *)getFont {
|
- (RNSVGFontData *)getFont
|
||||||
return topFont_;
|
{
|
||||||
|
return topFont_;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (RNSVGFontData *)getTopOrParentFont:(RNSVGGroup *)child
|
- (RNSVGFontData *)getTopOrParentFont:(RNSVGGroup *)child
|
||||||
{
|
{
|
||||||
if (self->mTop_ > 0) {
|
if (self->mTop_ > 0) {
|
||||||
return self->topFont_;
|
return self->topFont_;
|
||||||
} else {
|
} else {
|
||||||
RNSVGGroup *parentRoot = [child getParentTextRoot];
|
RNSVGGroup *parentRoot = [child getParentTextRoot];
|
||||||
RNSVGFontData *Defaults = [RNSVGFontData Defaults];
|
RNSVGFontData *Defaults = [RNSVGFontData Defaults];
|
||||||
while (parentRoot != nil) {
|
while (parentRoot != nil) {
|
||||||
RNSVGFontData *map = [[parentRoot getGlyphContext] getFont];
|
RNSVGFontData *map = [[parentRoot getGlyphContext] getFont];
|
||||||
if (map != Defaults) {
|
if (map != Defaults) {
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
parentRoot = [parentRoot getParentTextRoot];
|
parentRoot = [parentRoot getParentTextRoot];
|
||||||
}
|
|
||||||
return Defaults;
|
|
||||||
}
|
}
|
||||||
|
return Defaults;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)pushNode:(RNSVGGroup *)node andFont:(NSDictionary *)font
|
- (void)pushNode:(RNSVGGroup *)node andFont:(NSDictionary *)font
|
||||||
{
|
{
|
||||||
RNSVGFontData *parent = [self getTopOrParentFont:node];
|
RNSVGFontData *parent = [self getTopOrParentFont:node];
|
||||||
self->mTop_++;
|
self->mTop_++;
|
||||||
if (font == nil) {
|
if (font == nil) {
|
||||||
[self->mFontContext_ addObject:parent];
|
[self->mFontContext_ addObject:parent];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
RNSVGFontData *data = [RNSVGFontData initWithNSDictionary:font
|
RNSVGFontData *data = [RNSVGFontData initWithNSDictionary:font parent:parent];
|
||||||
parent:parent];
|
self->mFontSize_ = data->fontSize;
|
||||||
self->mFontSize_ = data->fontSize;
|
[self->mFontContext_ addObject:data];
|
||||||
[self->mFontContext_ addObject:data];
|
self->topFont_ = data;
|
||||||
self->topFont_ = data;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)pushContext:(RNSVGGroup*)node
|
- (void)pushContext:(RNSVGGroup *)node font:(NSDictionary *)font
|
||||||
font:(NSDictionary*)font {
|
{
|
||||||
[self pushNode:node andFont:font];
|
[self pushNode:node andFont:font];
|
||||||
[self pushIndices];
|
[self pushIndices];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)pushContext:(RNSVGText*)node
|
- (void)pushContext:(RNSVGText *)node
|
||||||
font:(NSDictionary*)font
|
font:(NSDictionary *)font
|
||||||
x:(NSArray<RNSVGLength*>*)x
|
x:(NSArray<RNSVGLength *> *)x
|
||||||
y:(NSArray<RNSVGLength*>*)y
|
y:(NSArray<RNSVGLength *> *)y
|
||||||
deltaX:(NSArray<RNSVGLength*>*)deltaX
|
deltaX:(NSArray<RNSVGLength *> *)deltaX
|
||||||
deltaY:(NSArray<RNSVGLength*>*)deltaY
|
deltaY:(NSArray<RNSVGLength *> *)deltaY
|
||||||
rotate:(NSArray<RNSVGLength*>*)rotate {
|
rotate:(NSArray<RNSVGLength *> *)rotate
|
||||||
[self pushNode:(RNSVGGroup*)node andFont:font];
|
{
|
||||||
if (x != nil && [x count] != 0) {
|
[self pushNode:(RNSVGGroup *)node andFont:font];
|
||||||
mXsIndex_++;
|
if (x != nil && [x count] != 0) {
|
||||||
mXIndex_ = -1;
|
mXsIndex_++;
|
||||||
[mXIndices_ addObject:[NSNumber numberWithLong:mXIndex_]];
|
mXIndex_ = -1;
|
||||||
mXs_ = x;
|
[mXIndices_ addObject:[NSNumber numberWithLong:mXIndex_]];
|
||||||
[mXsContext_ addObject:mXs_];
|
mXs_ = x;
|
||||||
}
|
[mXsContext_ addObject:mXs_];
|
||||||
if (y != nil && [y count] != 0) {
|
}
|
||||||
mYsIndex_++;
|
if (y != nil && [y count] != 0) {
|
||||||
mYIndex_ = -1;
|
mYsIndex_++;
|
||||||
[mYIndices_ addObject:[NSNumber numberWithLong:mYIndex_]];
|
mYIndex_ = -1;
|
||||||
mYs_ = y;
|
[mYIndices_ addObject:[NSNumber numberWithLong:mYIndex_]];
|
||||||
[mYsContext_ addObject:mYs_];
|
mYs_ = y;
|
||||||
}
|
[mYsContext_ addObject:mYs_];
|
||||||
if (deltaX != nil && [deltaX count] != 0) {
|
}
|
||||||
mDXsIndex_++;
|
if (deltaX != nil && [deltaX count] != 0) {
|
||||||
mDXIndex_ = -1;
|
mDXsIndex_++;
|
||||||
[mDXIndices_ addObject:[NSNumber numberWithLong:mDXIndex_]];
|
mDXIndex_ = -1;
|
||||||
mDXs_ = deltaX;
|
[mDXIndices_ addObject:[NSNumber numberWithLong:mDXIndex_]];
|
||||||
[mDXsContext_ addObject:mDXs_];
|
mDXs_ = deltaX;
|
||||||
}
|
[mDXsContext_ addObject:mDXs_];
|
||||||
if (deltaY != nil && [deltaY count] != 0) {
|
}
|
||||||
mDYsIndex_++;
|
if (deltaY != nil && [deltaY count] != 0) {
|
||||||
mDYIndex_ = -1;
|
mDYsIndex_++;
|
||||||
[mDYIndices_ addObject:[NSNumber numberWithLong:mDYIndex_]];
|
mDYIndex_ = -1;
|
||||||
mDYs_ = deltaY;
|
[mDYIndices_ addObject:[NSNumber numberWithLong:mDYIndex_]];
|
||||||
[mDYsContext_ addObject:mDYs_];
|
mDYs_ = deltaY;
|
||||||
}
|
[mDYsContext_ addObject:mDYs_];
|
||||||
if (rotate != nil && [rotate count] != 0) {
|
}
|
||||||
mRsIndex_++;
|
if (rotate != nil && [rotate count] != 0) {
|
||||||
mRIndex_ = -1;
|
mRsIndex_++;
|
||||||
[mRIndices_ addObject:[NSNumber numberWithLong:mRIndex_]];
|
mRIndex_ = -1;
|
||||||
mRs_ = rotate;
|
[mRIndices_ addObject:[NSNumber numberWithLong:mRIndex_]];
|
||||||
[mRsContext_ addObject:mRs_];
|
mRs_ = rotate;
|
||||||
}
|
[mRsContext_ addObject:mRs_];
|
||||||
[self pushIndices];
|
}
|
||||||
|
[self pushIndices];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)popContext {
|
- (void)popContext
|
||||||
[mFontContext_ removeLastObject];
|
{
|
||||||
[mXsIndices_ removeLastObject];
|
[mFontContext_ removeLastObject];
|
||||||
[mYsIndices_ removeLastObject];
|
[mXsIndices_ removeLastObject];
|
||||||
[mDXsIndices_ removeLastObject];
|
[mYsIndices_ removeLastObject];
|
||||||
[mDYsIndices_ removeLastObject];
|
[mDXsIndices_ removeLastObject];
|
||||||
[mRsIndices_ removeLastObject];
|
[mDYsIndices_ removeLastObject];
|
||||||
|
[mRsIndices_ removeLastObject];
|
||||||
|
|
||||||
mTop_--;
|
mTop_--;
|
||||||
|
|
||||||
long x = mXsIndex_;
|
long x = mXsIndex_;
|
||||||
long y = mYsIndex_;
|
long y = mYsIndex_;
|
||||||
long dx = mDXsIndex_;
|
long dx = mDXsIndex_;
|
||||||
long dy = mDYsIndex_;
|
long dy = mDYsIndex_;
|
||||||
long r = mRsIndex_;
|
long r = mRsIndex_;
|
||||||
|
|
||||||
topFont_ = [mFontContext_ lastObject];
|
topFont_ = [mFontContext_ lastObject];
|
||||||
|
|
||||||
mXsIndex_ = [[mXsIndices_ lastObject] longValue];
|
mXsIndex_ = [[mXsIndices_ lastObject] longValue];
|
||||||
mYsIndex_ = [[mYsIndices_ lastObject] longValue];
|
mYsIndex_ = [[mYsIndices_ lastObject] longValue];
|
||||||
mDXsIndex_ = [[mDXsIndices_ lastObject] longValue];
|
mDXsIndex_ = [[mDXsIndices_ lastObject] longValue];
|
||||||
mDYsIndex_ = [[mDYsIndices_ lastObject] longValue];
|
mDYsIndex_ = [[mDYsIndices_ lastObject] longValue];
|
||||||
mRsIndex_ = [[mRsIndices_ lastObject] longValue];
|
mRsIndex_ = [[mRsIndices_ lastObject] longValue];
|
||||||
|
|
||||||
if (x != mXsIndex_) {
|
if (x != mXsIndex_) {
|
||||||
[mXsContext_ removeObjectAtIndex:x];
|
[mXsContext_ removeObjectAtIndex:x];
|
||||||
mXs_ = [mXsContext_ objectAtIndex:mXsIndex_];
|
mXs_ = [mXsContext_ objectAtIndex:mXsIndex_];
|
||||||
mXIndex_ = [[mXIndices_ objectAtIndex:mXsIndex_] longValue];
|
mXIndex_ = [[mXIndices_ objectAtIndex:mXsIndex_] longValue];
|
||||||
}
|
}
|
||||||
if (y != mYsIndex_) {
|
if (y != mYsIndex_) {
|
||||||
[mYsContext_ removeObjectAtIndex:y];
|
[mYsContext_ removeObjectAtIndex:y];
|
||||||
mYs_ = [mYsContext_ objectAtIndex:mYsIndex_];
|
mYs_ = [mYsContext_ objectAtIndex:mYsIndex_];
|
||||||
mYIndex_ = [[mYIndices_ objectAtIndex:mYsIndex_] longValue];
|
mYIndex_ = [[mYIndices_ objectAtIndex:mYsIndex_] longValue];
|
||||||
}
|
}
|
||||||
if (dx != mDXsIndex_) {
|
if (dx != mDXsIndex_) {
|
||||||
[mDXsContext_ removeObjectAtIndex:dx];
|
[mDXsContext_ removeObjectAtIndex:dx];
|
||||||
mDXs_ = [mDXsContext_ objectAtIndex:mDXsIndex_];
|
mDXs_ = [mDXsContext_ objectAtIndex:mDXsIndex_];
|
||||||
mDXIndex_ = [[mDXIndices_ objectAtIndex:mDXsIndex_] longValue];
|
mDXIndex_ = [[mDXIndices_ objectAtIndex:mDXsIndex_] longValue];
|
||||||
}
|
}
|
||||||
if (dy != mDYsIndex_) {
|
if (dy != mDYsIndex_) {
|
||||||
[mDYsContext_ removeObjectAtIndex:dy];
|
[mDYsContext_ removeObjectAtIndex:dy];
|
||||||
mDYs_ = [mDYsContext_ objectAtIndex:mDYsIndex_];
|
mDYs_ = [mDYsContext_ objectAtIndex:mDYsIndex_];
|
||||||
mDYIndex_ = [[mDYIndices_ objectAtIndex:mDYsIndex_] longValue];
|
mDYIndex_ = [[mDYIndices_ objectAtIndex:mDYsIndex_] longValue];
|
||||||
}
|
}
|
||||||
if (r != mRsIndex_) {
|
if (r != mRsIndex_) {
|
||||||
[mRsContext_ removeObjectAtIndex:r];
|
[mRsContext_ removeObjectAtIndex:r];
|
||||||
mRs_ = [mRsContext_ objectAtIndex:mRsIndex_];
|
mRs_ = [mRsContext_ objectAtIndex:mRsIndex_];
|
||||||
mRIndex_ = [[mRIndices_ objectAtIndex:mRsIndex_] longValue];
|
mRIndex_ = [[mRIndices_ objectAtIndex:mRsIndex_] longValue];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (void)incrementIndices:(NSMutableArray *)indices topIndex:(long)topIndex
|
+ (void)incrementIndices:(NSMutableArray *)indices topIndex:(long)topIndex
|
||||||
{
|
{
|
||||||
for (long index = topIndex; index >= 0; index--) {
|
for (long index = topIndex; index >= 0; index--) {
|
||||||
long xIndex = [[indices objectAtIndex:index] longValue];
|
long xIndex = [[indices objectAtIndex:index] longValue];
|
||||||
[indices setObject:[NSNumber numberWithLong:xIndex + 1] atIndexedSubscript:index];
|
[indices setObject:[NSNumber numberWithLong:xIndex + 1] atIndexedSubscript:index];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://www.w3.org/TR/SVG11/text.html#FontSizeProperty
|
// https://www.w3.org/TR/SVG11/text.html#FontSizeProperty
|
||||||
@@ -442,84 +442,84 @@
|
|||||||
* Except for any additional information provided in this specification,
|
* Except for any additional information provided in this specification,
|
||||||
* the normative definition of the property is in CSS2 ([CSS2], section 15.2.4).
|
* the normative definition of the property is in CSS2 ([CSS2], section 15.2.4).
|
||||||
*/
|
*/
|
||||||
- (CGFloat)getFontSize {
|
- (CGFloat)getFontSize
|
||||||
return mFontSize_;
|
{
|
||||||
|
return mFontSize_;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CGFloat)nextXWithDouble:(CGFloat)advance {
|
- (CGFloat)nextXWithDouble:(CGFloat)advance
|
||||||
[RNSVGGlyphContext incrementIndices:mXIndices_ topIndex:mXsIndex_];
|
{
|
||||||
long nextIndex = mXIndex_ + 1;
|
[RNSVGGlyphContext incrementIndices:mXIndices_ topIndex:mXsIndex_];
|
||||||
if (nextIndex < [mXs_ count]) {
|
long nextIndex = mXIndex_ + 1;
|
||||||
mDX_ = 0;
|
if (nextIndex < [mXs_ count]) {
|
||||||
mXIndex_ = nextIndex;
|
mDX_ = 0;
|
||||||
RNSVGLength *length = [mXs_ objectAtIndex:nextIndex];
|
mXIndex_ = nextIndex;
|
||||||
mX_ = [RNSVGPropHelper fromRelative:length
|
RNSVGLength *length = [mXs_ objectAtIndex:nextIndex];
|
||||||
relative:mWidth_
|
mX_ = [RNSVGPropHelper fromRelative:length relative:mWidth_ fontSize:mFontSize_];
|
||||||
fontSize:mFontSize_];
|
}
|
||||||
}
|
mX_ += advance;
|
||||||
mX_ += advance;
|
return mX_;
|
||||||
return mX_;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CGFloat)nextY {
|
- (CGFloat)nextY
|
||||||
[RNSVGGlyphContext incrementIndices:mYIndices_ topIndex:mYsIndex_];
|
{
|
||||||
long nextIndex = mYIndex_ + 1;
|
[RNSVGGlyphContext incrementIndices:mYIndices_ topIndex:mYsIndex_];
|
||||||
if (nextIndex < [mYs_ count]) {
|
long nextIndex = mYIndex_ + 1;
|
||||||
mDY_ = 0;
|
if (nextIndex < [mYs_ count]) {
|
||||||
mYIndex_ = nextIndex;
|
mDY_ = 0;
|
||||||
RNSVGLength *length = [mYs_ objectAtIndex:nextIndex];
|
mYIndex_ = nextIndex;
|
||||||
mY_ = [RNSVGPropHelper fromRelative:length
|
RNSVGLength *length = [mYs_ objectAtIndex:nextIndex];
|
||||||
relative:mHeight_
|
mY_ = [RNSVGPropHelper fromRelative:length relative:mHeight_ fontSize:mFontSize_];
|
||||||
fontSize:mFontSize_];
|
}
|
||||||
}
|
return mY_;
|
||||||
return mY_;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CGFloat)nextDeltaX {
|
- (CGFloat)nextDeltaX
|
||||||
[RNSVGGlyphContext incrementIndices:mDXIndices_ topIndex:mDXsIndex_];
|
{
|
||||||
long nextIndex = mDXIndex_ + 1;
|
[RNSVGGlyphContext incrementIndices:mDXIndices_ topIndex:mDXsIndex_];
|
||||||
if (nextIndex < [mDXs_ count]) {
|
long nextIndex = mDXIndex_ + 1;
|
||||||
mDXIndex_ = nextIndex;
|
if (nextIndex < [mDXs_ count]) {
|
||||||
RNSVGLength *length = [mDXs_ objectAtIndex:nextIndex];
|
mDXIndex_ = nextIndex;
|
||||||
CGFloat val = [RNSVGPropHelper fromRelative:length
|
RNSVGLength *length = [mDXs_ objectAtIndex:nextIndex];
|
||||||
relative:mWidth_
|
CGFloat val = [RNSVGPropHelper fromRelative:length relative:mWidth_ fontSize:mFontSize_];
|
||||||
fontSize:mFontSize_];
|
mDX_ += val;
|
||||||
mDX_ += val;
|
}
|
||||||
}
|
return mDX_;
|
||||||
return mDX_;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CGFloat)nextDeltaY {
|
- (CGFloat)nextDeltaY
|
||||||
[RNSVGGlyphContext incrementIndices:mDYIndices_ topIndex:mDYsIndex_];
|
{
|
||||||
long nextIndex = mDYIndex_ + 1;
|
[RNSVGGlyphContext incrementIndices:mDYIndices_ topIndex:mDYsIndex_];
|
||||||
if (nextIndex < [mDYs_ count]) {
|
long nextIndex = mDYIndex_ + 1;
|
||||||
mDYIndex_ = nextIndex;
|
if (nextIndex < [mDYs_ count]) {
|
||||||
RNSVGLength *length = [mDYs_ objectAtIndex:nextIndex];
|
mDYIndex_ = nextIndex;
|
||||||
CGFloat val = [RNSVGPropHelper fromRelative:length
|
RNSVGLength *length = [mDYs_ objectAtIndex:nextIndex];
|
||||||
relative:mHeight_
|
CGFloat val = [RNSVGPropHelper fromRelative:length relative:mHeight_ fontSize:mFontSize_];
|
||||||
fontSize:mFontSize_];
|
mDY_ += val;
|
||||||
mDY_ += val;
|
}
|
||||||
}
|
return mDY_;
|
||||||
return mDY_;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CGFloat)nextRotation {
|
- (CGFloat)nextRotation
|
||||||
[RNSVGGlyphContext incrementIndices:mRIndices_ topIndex:mRsIndex_];
|
{
|
||||||
long nextIndex = mRIndex_ + 1;
|
[RNSVGGlyphContext incrementIndices:mRIndices_ topIndex:mRsIndex_];
|
||||||
long count = [mRs_ count];
|
long nextIndex = mRIndex_ + 1;
|
||||||
if (nextIndex < count) {
|
long count = [mRs_ count];
|
||||||
mRIndex_ = nextIndex;
|
if (nextIndex < count) {
|
||||||
} else {
|
mRIndex_ = nextIndex;
|
||||||
mRIndex_ = count - 1;
|
} else {
|
||||||
}
|
mRIndex_ = count - 1;
|
||||||
return [mRs_[mRIndex_] value];
|
}
|
||||||
|
return [mRs_[mRIndex_] value];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CGFloat)getWidth {
|
- (CGFloat)getWidth
|
||||||
return mWidth_;
|
{
|
||||||
|
return mWidth_;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CGFloat)getHeight {
|
- (CGFloat)getHeight
|
||||||
return mHeight_;
|
{
|
||||||
|
return mHeight_;
|
||||||
}
|
}
|
||||||
@end
|
@end
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user