Implement rotate and textDecoration

This commit is contained in:
Mikael Sand
2017-07-16 01:50:59 +03:00
parent 61a17cb120
commit 2458a2f262
6 changed files with 131 additions and 9 deletions

View File

@@ -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) {

View File

@@ -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) {

View File

@@ -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));

View File

@@ -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);
}
}

View File

@@ -107,8 +107,10 @@ const TextAttributes = {
diff: fontDiffer
},
textAnchor: true,
textDecoration: true,
deltaX: arrayDiffer,
deltaY: arrayDiffer,
rotate: arrayDiffer,
positionX: true,
positionY: true,
...RenderableAttributes

View File

@@ -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(),