mirror of
https://github.com/zoriya/react-native-svg.git
synced 2025-12-20 14:05:09 +00:00
Implement rotate and textDecoration
This commit is contained in:
@@ -28,10 +28,13 @@ public class GlyphContext {
|
||||
private ArrayList<PointF> mDeltaContext;
|
||||
private ArrayList<ArrayList<Float>> mDeltaXContext;
|
||||
private ArrayList<ArrayList<Float>> mDeltaYContext;
|
||||
private ArrayList<ArrayList<Float>> mRotationContext;
|
||||
private ArrayList<Float> mGlyphRotationContext;
|
||||
private ArrayList<Float> mXContext;
|
||||
private ArrayList<Float> mYContext;
|
||||
private @Nonnull PointF mCurrentLocation;
|
||||
private @Nonnull PointF mCurrentDelta;
|
||||
private float mRotation = 0;
|
||||
private float mScale;
|
||||
private float mWidth;
|
||||
private float mHeight;
|
||||
@@ -51,6 +54,8 @@ public class GlyphContext {
|
||||
mDeltaContext = new ArrayList<>();
|
||||
mDeltaXContext = new ArrayList<>();
|
||||
mDeltaYContext = new ArrayList<>();
|
||||
mRotationContext = new ArrayList<>();
|
||||
mGlyphRotationContext = new ArrayList<>();
|
||||
mXContext = new ArrayList<>();
|
||||
mYContext = new ArrayList<>();
|
||||
}
|
||||
@@ -66,6 +71,8 @@ public class GlyphContext {
|
||||
mFontContext.add(font);
|
||||
mDeltaXContext.add(new ArrayList<Float>());
|
||||
mDeltaYContext.add(new ArrayList<Float>());
|
||||
mRotationContext.add(new ArrayList<Float>());
|
||||
mGlyphRotationContext.add(mRotation);
|
||||
mXContext.add(location.x);
|
||||
mYContext.add(location.y);
|
||||
|
||||
@@ -73,7 +80,7 @@ public class GlyphContext {
|
||||
mContextLength++;
|
||||
}
|
||||
|
||||
public void pushContext(@Nullable ReadableMap font, @Nullable ReadableArray deltaX, @Nullable ReadableArray deltaY, @Nullable String positionX, @Nullable String positionY) {
|
||||
public void pushContext(@Nullable ReadableMap font, @Nullable ReadableArray rotate, @Nullable ReadableArray deltaX, @Nullable ReadableArray deltaY, @Nullable String positionX, @Nullable String positionY) {
|
||||
PointF location = mCurrentLocation;
|
||||
|
||||
mDeltaContext.add(mCurrentDelta);
|
||||
@@ -94,6 +101,8 @@ public class GlyphContext {
|
||||
mFontContext.add(font);
|
||||
mDeltaXContext.add(getFloatArrayListFromReadableArray(deltaX));
|
||||
mDeltaYContext.add(getFloatArrayListFromReadableArray(deltaY));
|
||||
mRotationContext.add(getFloatArrayListFromReadableArray(rotate));
|
||||
mGlyphRotationContext.add(mRotation);
|
||||
mXContext.add(location.x);
|
||||
mYContext.add(location.y);
|
||||
|
||||
@@ -104,11 +113,14 @@ public class GlyphContext {
|
||||
public void popContext() {
|
||||
float x = mXContext.get(mContextLength - 1);
|
||||
float y = mYContext.get(mContextLength - 1);
|
||||
float r = mGlyphRotationContext.get(mContextLength - 1);
|
||||
mFontContext.remove(mContextLength - 1);
|
||||
mLocationContext.remove(mContextLength - 1);
|
||||
mDeltaContext.remove(mContextLength - 1);
|
||||
mDeltaXContext.remove(mContextLength - 1);
|
||||
mDeltaYContext.remove(mContextLength - 1);
|
||||
mRotationContext.remove(mContextLength - 1);
|
||||
mGlyphRotationContext.remove(mContextLength - 1);
|
||||
mXContext.remove(mContextLength - 1);
|
||||
mYContext.remove(mContextLength - 1);
|
||||
|
||||
@@ -117,12 +129,14 @@ public class GlyphContext {
|
||||
if (mContextLength != 0) {
|
||||
mXContext.set(mContextLength - 1, x);
|
||||
mYContext.set(mContextLength - 1, y);
|
||||
mGlyphRotationContext.set(mContextLength - 1, r);
|
||||
PointF lastLocation = mLocationContext.get(mContextLength - 1);
|
||||
PointF lastDelta = mDeltaContext.get(mContextLength - 1);
|
||||
mCurrentLocation = clonePointF(lastLocation);
|
||||
mCurrentDelta = clonePointF(lastDelta);
|
||||
mCurrentLocation.x = lastLocation.x = x;
|
||||
mCurrentLocation.y = lastLocation.y = y;
|
||||
mRotation = r;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,8 +148,8 @@ public class GlyphContext {
|
||||
}
|
||||
|
||||
public PointF getNextGlyphDelta() {
|
||||
float dx = mScale * getNextDelta(mDeltaXContext);
|
||||
float dy = mScale * getNextDelta(mDeltaYContext);
|
||||
float dx = mScale * getNextFloat(mDeltaXContext);
|
||||
float dy = mScale * getNextFloat(mDeltaYContext);
|
||||
|
||||
if (mContextLength > 0) {
|
||||
for (PointF point: mDeltaContext) {
|
||||
@@ -149,13 +163,50 @@ public class GlyphContext {
|
||||
return new PointF(dx, dy);
|
||||
}
|
||||
|
||||
private float getNextDelta(ArrayList<ArrayList<Float>> deltaContext) {
|
||||
float value = 0;
|
||||
public float getNextGlyphRotation() {
|
||||
if (hasNextFloat(mRotationContext)) {
|
||||
float r = getNextFloat(mRotationContext);
|
||||
|
||||
if (mContextLength > 0) {
|
||||
for (int i = 0; i < mContextLength; i++) {
|
||||
mGlyphRotationContext.set(i, r);
|
||||
}
|
||||
|
||||
return mGlyphRotationContext.get(mContextLength - 1);
|
||||
}
|
||||
|
||||
return r;
|
||||
} else if (mContextLength > 0) {
|
||||
return mGlyphRotationContext.get(mContextLength - 1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private float getNextFloat(ArrayList<ArrayList<Float>> context) {
|
||||
return getNextFloat(context, 0);
|
||||
}
|
||||
|
||||
private boolean hasNextFloat(ArrayList<ArrayList<Float>> context) {
|
||||
int index = mContextLength - 1;
|
||||
|
||||
for (; index >= 0; index--) {
|
||||
ArrayList<Float> delta = context.get(index);
|
||||
|
||||
if (delta.size() != 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private float getNextFloat(ArrayList<ArrayList<Float>> context, float value) {
|
||||
boolean valueSet = false;
|
||||
int index = mContextLength - 1;
|
||||
|
||||
for (; index >= 0; index--) {
|
||||
ArrayList<Float> delta = deltaContext.get(index);
|
||||
ArrayList<Float> delta = context.get(index);
|
||||
|
||||
if (delta.size() != 0) {
|
||||
if (!valueSet) {
|
||||
|
||||
@@ -101,6 +101,10 @@ public class GroupShadowNode extends RenderableShadowNode {
|
||||
return getTextRoot().getGlyphContext().getNextGlyphDelta();
|
||||
}
|
||||
|
||||
protected float getNextGlyphRotationFromContext() {
|
||||
return getTextRoot().getGlyphContext().getNextGlyphRotation();
|
||||
}
|
||||
|
||||
public void draw(final Canvas canvas, final Paint paint, final float opacity) {
|
||||
setupGlyphContext();
|
||||
if (opacity > MIN_OPACITY_FOR_DRAW) {
|
||||
|
||||
@@ -137,6 +137,7 @@ public class TSpanShadowNode extends TextShadowNode {
|
||||
String current;
|
||||
PointF glyphPoint;
|
||||
PointF glyphDelta;
|
||||
float glyphRotation;
|
||||
String previous = "";
|
||||
char[] chars = line.toCharArray();
|
||||
float[] widths = new float[length];
|
||||
@@ -166,6 +167,7 @@ public class TSpanShadowNode extends TextShadowNode {
|
||||
|
||||
glyphPoint = getGlyphPointFromContext(glyphPosition, width);
|
||||
glyphDelta = getGlyphDeltaFromContext();
|
||||
glyphRotation = getNextGlyphRotationFromContext();
|
||||
glyphPosition += width;
|
||||
matrix = new Matrix();
|
||||
|
||||
@@ -199,6 +201,8 @@ public class TSpanShadowNode extends TextShadowNode {
|
||||
);
|
||||
}
|
||||
|
||||
matrix.preRotate(glyphRotation);
|
||||
|
||||
paint.getTextPath(current, 0, 1, 0, 0, glyph);
|
||||
glyph.transform(matrix);
|
||||
path.addPath(glyph);
|
||||
@@ -220,6 +224,11 @@ public class TSpanShadowNode extends TextShadowNode {
|
||||
paint.setLetterSpacing(letterSpacing / fontSize); // setLetterSpacing is only available from LOLLIPOP and on
|
||||
}
|
||||
|
||||
int decoration = getTextDecoration();
|
||||
|
||||
paint.setUnderlineText(decoration == TEXT_DECORATION_UNDERLINE);
|
||||
paint.setStrikeThruText(decoration == TEXT_DECORATION_LINE_THROUGH);
|
||||
|
||||
boolean isBold = font.hasKey(PROP_FONT_WEIGHT) && "bold".equals(font.getString(PROP_FONT_WEIGHT));
|
||||
boolean isItalic = font.hasKey(PROP_FONT_STYLE) && "italic".equals(font.getString(PROP_FONT_STYLE));
|
||||
|
||||
|
||||
@@ -38,7 +38,15 @@ public class TextShadowNode extends GroupShadowNode {
|
||||
static final int TEXT_ANCHOR_MIDDLE = 2;
|
||||
static final int TEXT_ANCHOR_END = 3;
|
||||
|
||||
static final int TEXT_DECORATION_NONE = 0;
|
||||
static final int TEXT_DECORATION_UNDERLINE = 1;
|
||||
static final int TEXT_DECORATION_OVERLINE = 2;
|
||||
static final int TEXT_DECORATION_LINE_THROUGH = 3;
|
||||
static final int TEXT_DECORATION_BLINK = 4;
|
||||
|
||||
private int mTextAnchor = TEXT_ANCHOR_AUTO;
|
||||
private int mTextDecoration = TEXT_DECORATION_NONE;
|
||||
private @Nullable ReadableArray mRotate;
|
||||
private @Nullable ReadableArray mDeltaX;
|
||||
private @Nullable ReadableArray mDeltaY;
|
||||
private @Nullable String mPositionX;
|
||||
@@ -50,6 +58,18 @@ public class TextShadowNode extends GroupShadowNode {
|
||||
markUpdated();
|
||||
}
|
||||
|
||||
@ReactProp(name = "textDecoration", defaultInt = TEXT_DECORATION_NONE)
|
||||
public void setTextDecoration(int textDecoration) {
|
||||
mTextDecoration = textDecoration;
|
||||
markUpdated();
|
||||
}
|
||||
|
||||
@ReactProp(name = "rotate")
|
||||
public void setRotate(@Nullable ReadableArray rotate) {
|
||||
mRotate = rotate;
|
||||
markUpdated();
|
||||
}
|
||||
|
||||
@ReactProp(name = "deltaX")
|
||||
public void setDeltaX(@Nullable ReadableArray deltaX) {
|
||||
mDeltaX = deltaX;
|
||||
@@ -103,9 +123,33 @@ public class TextShadowNode extends GroupShadowNode {
|
||||
return mTextAnchor;
|
||||
}
|
||||
|
||||
int getTextDecoration() {
|
||||
int decoration = mTextDecoration;
|
||||
if (decoration != TEXT_DECORATION_NONE) {
|
||||
return decoration;
|
||||
}
|
||||
ReactShadowNode shadowNode = this.getParent();
|
||||
|
||||
while (shadowNode instanceof GroupShadowNode) {
|
||||
if (shadowNode instanceof TextShadowNode) {
|
||||
decoration = ((TextShadowNode) shadowNode).getTextDecoration();
|
||||
if (decoration != TEXT_DECORATION_NONE) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
shadowNode = shadowNode.getParent();
|
||||
}
|
||||
|
||||
return decoration;
|
||||
}
|
||||
|
||||
int getComputedTextAnchor() {
|
||||
int anchor = mTextAnchor;
|
||||
ReactShadowNode shadowNode = this;
|
||||
if (anchor != TEXT_ANCHOR_AUTO) {
|
||||
return anchor;
|
||||
}
|
||||
ReactShadowNode shadowNode = this.getParent();
|
||||
|
||||
while (shadowNode instanceof GroupShadowNode) {
|
||||
if (shadowNode instanceof TextShadowNode) {
|
||||
@@ -141,6 +185,6 @@ public class TextShadowNode extends GroupShadowNode {
|
||||
|
||||
@Override
|
||||
protected void pushGlyphContext() {
|
||||
getTextRoot().getGlyphContext().pushContext(mFont, mDeltaX, mDeltaY, mPositionX, mPositionY);
|
||||
getTextRoot().getGlyphContext().pushContext(mFont, mRotate, mDeltaX, mDeltaY, mPositionX, mPositionY);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,8 +107,10 @@ const TextAttributes = {
|
||||
diff: fontDiffer
|
||||
},
|
||||
textAnchor: true,
|
||||
textDecoration: true,
|
||||
deltaX: arrayDiffer,
|
||||
deltaY: arrayDiffer,
|
||||
rotate: arrayDiffer,
|
||||
positionX: true,
|
||||
positionY: true,
|
||||
...RenderableAttributes
|
||||
|
||||
@@ -15,6 +15,13 @@ const anchors = {
|
||||
end: 3
|
||||
};
|
||||
|
||||
const decorations = {
|
||||
none: 0,
|
||||
underline: 1,
|
||||
overline: 2,
|
||||
'line-through': 3,
|
||||
blink: 4
|
||||
};
|
||||
let cachedFontObjectsFromString = {};
|
||||
|
||||
function extractSingleFontFamily(fontFamilyString) {
|
||||
@@ -91,15 +98,18 @@ export default function(props, container) {
|
||||
y,
|
||||
dx,
|
||||
dy,
|
||||
rotate,
|
||||
method,
|
||||
spacing,
|
||||
textAnchor,
|
||||
startOffset
|
||||
startOffset,
|
||||
textDecoration
|
||||
} = props;
|
||||
|
||||
|
||||
const deltaX = parseDelta(dx);
|
||||
const deltaY = parseDelta(dy);
|
||||
const rotates = parseDelta(rotate);
|
||||
let { children } = props;
|
||||
let content = null;
|
||||
|
||||
@@ -123,12 +133,14 @@ export default function(props, container) {
|
||||
}
|
||||
|
||||
return {
|
||||
textDecoration: decorations[textDecoration] || 0,
|
||||
textAnchor: anchors[textAnchor] || 0,
|
||||
font: extractFont(props),
|
||||
children,
|
||||
content,
|
||||
deltaX,
|
||||
deltaY,
|
||||
rotate: rotates,
|
||||
method,
|
||||
spacing,
|
||||
startOffset: (startOffset || 0).toString(),
|
||||
|
||||
Reference in New Issue
Block a user