Merge branch 'drhill-dev-v2_imagesubs' into dev-v2

This commit is contained in:
Oliver Woodman 2017-02-20 12:47:00 +00:00
commit 276788bc50
2 changed files with 117 additions and 35 deletions

View File

@ -16,6 +16,7 @@
package com.google.android.exoplayer2.text;
import android.graphics.Color;
import android.graphics.Bitmap;
import android.support.annotation.IntDef;
import android.text.Layout.Alignment;
import java.lang.annotation.Retention;
@ -78,7 +79,8 @@ public class Cue {
public static final int LINE_TYPE_NUMBER = 1;
/**
* The cue text. Note the {@link CharSequence} may be decorated with styling spans.
* The cue text, or null if this is an image cue. Note the {@link CharSequence} may be decorated
* with styling spans.
*/
public final CharSequence text;
@ -87,6 +89,11 @@ public class Cue {
*/
public final Alignment textAlignment;
/**
* The cue image, or null if this is a text cue.
*/
public final Bitmap bitmap;
/**
* The position of the {@link #lineAnchor} of the cue box within the viewport in the direction
* orthogonal to the writing direction, or {@link #DIMEN_UNSET}. When set, the interpretation of
@ -95,8 +102,8 @@ public class Cue {
* For horizontal text and {@link #lineType} equal to {@link #LINE_TYPE_FRACTION}, this is the
* fractional vertical position relative to the top of the viewport.
*/
public final float line;
/**
* The type of the {@link #line} value.
* <p>
@ -122,9 +129,8 @@ public class Cue {
* {@code (line == -2 && lineAnchor == ANCHOR_TYPE_START)} position a cue so that only its first
* line is visible at the bottom of the viewport.
*/
@LineType public final int lineType;
@LineType
public final int lineType;
/**
* The cue box anchor positioned by {@link #line}. One of {@link #ANCHOR_TYPE_START},
* {@link #ANCHOR_TYPE_MIDDLE}, {@link #ANCHOR_TYPE_END} and {@link #TYPE_UNSET}.
@ -133,9 +139,8 @@ public class Cue {
* and {@link #ANCHOR_TYPE_END} correspond to the top, middle and bottom of the cue box
* respectively.
*/
@AnchorType public final int lineAnchor;
@AnchorType
public final int lineAnchor;
/**
* The fractional position of the {@link #positionAnchor} of the cue box within the viewport in
* the direction orthogonal to {@link #line}, or {@link #DIMEN_UNSET}.
@ -154,8 +159,7 @@ public class Cue {
* and {@link #ANCHOR_TYPE_END} correspond to the left, middle and right of the cue box
* respectively.
*/
@AnchorType
public final int positionAnchor;
@AnchorType public final int positionAnchor;
/**
* The size of the cue box in the writing direction specified as a fraction of the viewport size
@ -174,7 +178,36 @@ public class Cue {
public final int windowColor;
/**
* Constructs a cue whose {@link #textAlignment} is null, whose type parameters are set to
* Constructs an image cue whose type parameters are set to {@link #TYPE_UNSET} and whose
* dimension parameters are set to {@link #DIMEN_UNSET}.
*
* @param bitmap See {@link #bitmap}.
*/
public Cue(Bitmap bitmap) {
this(bitmap, DIMEN_UNSET, TYPE_UNSET, DIMEN_UNSET, TYPE_UNSET, DIMEN_UNSET);
}
/**
* Creates an image cue.
*
* @param horizontalPosition The position of the horizontal anchor within the viewport, expressed
* as a fraction of the viewport width.
* @param horizontalPositionAnchor The horizontal anchor. One of {@link #ANCHOR_TYPE_START},
* {@link #ANCHOR_TYPE_MIDDLE}, {@link #ANCHOR_TYPE_END} and {@link #TYPE_UNSET}.
* @param verticalPosition The position of the vertical anchor within the viewport, expressed as a
* fraction of the viewport height.
* @param verticalPositionAnchor The vertical anchor. One of {@link #ANCHOR_TYPE_START},
* {@link #ANCHOR_TYPE_MIDDLE}, {@link #ANCHOR_TYPE_END} and {@link #TYPE_UNSET}.
* @param width The width of the cue, expressed as a fraction of the viewport width.
*/
public Cue(Bitmap bitmap, float horizontalPosition, @AnchorType int horizontalPositionAnchor,
float verticalPosition, @AnchorType int verticalPositionAnchor, float width) {
this(null, null, bitmap, verticalPosition, LINE_TYPE_FRACTION, verticalPositionAnchor,
horizontalPosition, horizontalPositionAnchor, width, false, Color.BLACK);
}
/**
* Constructs a text cue whose {@link #textAlignment} is null, whose type parameters are set to
* {@link #TYPE_UNSET} and whose dimension parameters are set to {@link #DIMEN_UNSET}.
*
* @param text See {@link #text}.
@ -184,6 +217,8 @@ public class Cue {
}
/**
* Creates a text cue.
*
* @param text See {@link #text}.
* @param textAlignment See {@link #textAlignment}.
* @param line See {@link #line}.
@ -200,6 +235,8 @@ public class Cue {
}
/**
* Creates a text cue.
*
* @param text See {@link #text}.
* @param textAlignment See {@link #textAlignment}.
* @param line See {@link #line}.
@ -214,8 +251,16 @@ public class Cue {
public Cue(CharSequence text, Alignment textAlignment, float line, @LineType int lineType,
@AnchorType int lineAnchor, float position, @AnchorType int positionAnchor, float size,
boolean windowColorSet, int windowColor) {
this(text, textAlignment, null, line, lineType, lineAnchor, position, positionAnchor, size,
windowColorSet, windowColor);
}
private Cue(CharSequence text, Alignment textAlignment, Bitmap bitmap, float line,
@LineType int lineType, @AnchorType int lineAnchor, float position,
@AnchorType int positionAnchor, float size, boolean windowColorSet, int windowColor) {
this.text = text;
this.textAlignment = textAlignment;
this.bitmap = bitmap;
this.line = line;
this.lineType = lineType;
this.lineAnchor = lineAnchor;

View File

@ -18,11 +18,13 @@ package com.google.android.exoplayer2.ui;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Join;
import android.graphics.Paint.Style;
import android.graphics.Rect;
import android.graphics.RectF;
import android.text.Layout.Alignment;
import android.text.StaticLayout;
@ -63,6 +65,7 @@ import com.google.android.exoplayer2.util.Util;
private final Paint paint;
// Previous input variables.
private Bitmap cueBitmap;
private CharSequence cueText;
private Alignment cueTextAlignment;
private float cueLine;
@ -93,6 +96,7 @@ import com.google.android.exoplayer2.util.Util;
private int textLeft;
private int textTop;
private int textPaddingX;
private Rect bitmapRect;
@SuppressWarnings("ResourceType")
public SubtitlePainter(Context context) {
@ -141,21 +145,25 @@ import com.google.android.exoplayer2.util.Util;
public void draw(Cue cue, boolean applyEmbeddedStyles, CaptionStyleCompat style, float textSizePx,
float bottomPaddingFraction, Canvas canvas, int cueBoxLeft, int cueBoxTop, int cueBoxRight,
int cueBoxBottom) {
CharSequence cueText = cue.text;
if (TextUtils.isEmpty(cueText)) {
// Nothing to draw.
return;
}
int windowColor = cue.windowColorSet ? cue.windowColor : style.windowColor;
if (!applyEmbeddedStyles) {
// Strip out any embedded styling.
cueText = cueText.toString();
windowColor = style.windowColor;
boolean isTextCue = cue.bitmap == null;
CharSequence cueText = null;
Bitmap cueBitmap = null;
if (isTextCue) {
cueText = cue.text;
if (TextUtils.isEmpty(cueText)) {
// Nothing to draw.
return;
}
if (!applyEmbeddedStyles) {
// Strip out any embedded styling.
cueText = cueText.toString();
}
} else {
cueBitmap = cue.bitmap;
}
if (areCharSequencesEqual(this.cueText, cueText)
&& Util.areEqual(this.cueTextAlignment, cue.textAlignment)
&& this.cueBitmap == cueBitmap
&& this.cueLine == cue.line
&& this.cueLineType == cue.lineType
&& Util.areEqual(this.cueLineAnchor, cue.lineAnchor)
@ -165,7 +173,7 @@ import com.google.android.exoplayer2.util.Util;
&& this.applyEmbeddedStyles == applyEmbeddedStyles
&& this.foregroundColor == style.foregroundColor
&& this.backgroundColor == style.backgroundColor
&& this.windowColor == windowColor
&& this.windowColor == style.windowColor
&& this.edgeType == style.edgeType
&& this.edgeColor == style.edgeColor
&& Util.areEqual(this.textPaint.getTypeface(), style.typeface)
@ -176,12 +184,13 @@ import com.google.android.exoplayer2.util.Util;
&& this.parentRight == cueBoxRight
&& this.parentBottom == cueBoxBottom) {
// We can use the cached layout.
drawLayout(canvas);
drawLayout(canvas, isTextCue);
return;
}
this.cueText = cueText;
this.cueTextAlignment = cue.textAlignment;
this.cueBitmap = cue.bitmap;
this.cueLine = cue.line;
this.cueLineType = cue.lineType;
this.cueLineAnchor = cue.lineAnchor;
@ -191,7 +200,7 @@ import com.google.android.exoplayer2.util.Util;
this.applyEmbeddedStyles = applyEmbeddedStyles;
this.foregroundColor = style.foregroundColor;
this.backgroundColor = style.backgroundColor;
this.windowColor = windowColor;
this.windowColor = style.windowColor;
this.edgeType = style.edgeType;
this.edgeColor = style.edgeColor;
this.textPaint.setTypeface(style.typeface);
@ -202,6 +211,15 @@ import com.google.android.exoplayer2.util.Util;
this.parentRight = cueBoxRight;
this.parentBottom = cueBoxBottom;
if (isTextCue) {
setupTextLayout();
} else {
setupBitmapLayout();
}
drawLayout(canvas, isTextCue);
}
private void setupTextLayout() {
int parentWidth = parentRight - parentLeft;
int parentHeight = parentBottom - parentTop;
@ -237,7 +255,7 @@ import com.google.android.exoplayer2.util.Util;
int anchorPosition = Math.round(parentWidth * cuePosition) + parentLeft;
textLeft = cuePositionAnchor == Cue.ANCHOR_TYPE_END ? anchorPosition - textWidth
: cuePositionAnchor == Cue.ANCHOR_TYPE_MIDDLE ? (anchorPosition * 2 - textWidth) / 2
: anchorPosition;
: anchorPosition;
textLeft = Math.max(textLeft, parentLeft);
textRight = Math.min(textLeft + textWidth, parentRight);
} else {
@ -256,12 +274,12 @@ import com.google.android.exoplayer2.util.Util;
if (cueLine >= 0) {
anchorPosition = Math.round(cueLine * firstLineHeight) + parentTop;
} else {
anchorPosition = Math.round((cueLine + 1) * firstLineHeight) + parentBottom;
anchorPosition = Math.round(cueLine * firstLineHeight) + parentBottom;
}
}
textTop = cueLineAnchor == Cue.ANCHOR_TYPE_END ? anchorPosition - textHeight
: cueLineAnchor == Cue.ANCHOR_TYPE_MIDDLE ? (anchorPosition * 2 - textHeight) / 2
: anchorPosition;
: anchorPosition;
if (textTop + textHeight > parentBottom) {
textTop = parentBottom - textHeight;
} else if (textTop < parentTop) {
@ -279,16 +297,31 @@ import com.google.android.exoplayer2.util.Util;
this.textLeft = textLeft;
this.textTop = textTop;
this.textPaddingX = textPaddingX;
drawLayout(canvas);
}
/**
* Draws {@link #textLayout} into the provided canvas.
*
* @param canvas The canvas into which to draw.
*/
private void drawLayout(Canvas canvas) {
private void setupBitmapLayout() {
int parentWidth = parentRight - parentLeft;
int parentHeight = parentBottom - parentTop;
float anchorX = parentLeft + (parentWidth * cuePosition);
float anchorY = parentTop + (parentHeight * cueLine);
int width = (int) (parentWidth * cueSize);
int height = (int) (width * ((float) cueBitmap.getHeight() / cueBitmap.getWidth()));
int x = (int) (cueLineAnchor == Cue.ANCHOR_TYPE_END ? (anchorX - width)
: cueLineAnchor == Cue.ANCHOR_TYPE_MIDDLE ? (anchorX - (width / 2)) : anchorX);
int y = (int) (cuePositionAnchor == Cue.ANCHOR_TYPE_END ? (anchorY - width)
: cuePositionAnchor == Cue.ANCHOR_TYPE_MIDDLE ? (anchorY - (width / 2)) : anchorY);
bitmapRect = new Rect(x, y, x + width, y + height);
}
private void drawLayout(Canvas canvas, boolean isTextCue) {
if (isTextCue) {
drawTextLayout(canvas);
} else {
drawBitmapLayout(canvas);
}
}
private void drawTextLayout(Canvas canvas) {
final StaticLayout layout = textLayout;
if (layout == null) {
// Nothing to draw.
@ -347,6 +380,10 @@ import com.google.android.exoplayer2.util.Util;
canvas.restoreToCount(saveCount);
}
private void drawBitmapLayout(Canvas canvas) {
canvas.drawBitmap(cueBitmap, null, bitmapRect, null);
}
/**
* This method is used instead of {@link TextUtils#equals(CharSequence, CharSequence)} because the
* latter only checks the text of each sequence, and does not check for equality of styling that