Loading core/java/com/android/internal/widget/SubtitleView.java +48 −89 Original line number Diff line number Diff line Loading @@ -31,7 +31,6 @@ import android.graphics.Typeface; import android.text.Layout.Alignment; import android.text.StaticLayout; import android.text.TextPaint; import android.text.TextUtils; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.TypedValue; Loading @@ -52,14 +51,12 @@ public class SubtitleView extends View { /** Temporary rectangle used for computing line bounds. */ private final RectF mLineBounds = new RectF(); /** Temporary array used for computing line wrapping. */ private float[] mTextWidths; /** Reusable string builder used for holding text. */ private final StringBuilder mText = new StringBuilder(); private final StringBuilder mBreakText = new StringBuilder(); private TextPaint mPaint; private Alignment mAlignment; private TextPaint mTextPaint; private Paint mPaint; private int mForegroundColor; private int mBackgroundColor; Loading Loading @@ -122,11 +119,12 @@ public class SubtitleView extends View { mShadowOffsetX = res.getDimension(com.android.internal.R.dimen.subtitle_shadow_offset); mShadowOffsetY = mShadowOffsetX; final TextPaint paint = new TextPaint(); paint.setAntiAlias(true); paint.setSubpixelText(true); mTextPaint = new TextPaint(); mTextPaint.setAntiAlias(true); mTextPaint.setSubpixelText(true); mPaint = paint; mPaint = new Paint(); mPaint.setAntiAlias(true); setText(text); setTextSize(textSize); Loading Loading @@ -174,21 +172,30 @@ public class SubtitleView extends View { public void setTextSize(float size) { final DisplayMetrics metrics = getContext().getResources().getDisplayMetrics(); final float pixels = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, size, metrics); if (mPaint.getTextSize() != size) { mHasMeasurements = false; if (mTextPaint.getTextSize() != size) { mTextPaint.setTextSize(size); mInnerPaddingX = (int) (size * INNER_PADDING_RATIO + 0.5f); mPaint.setTextSize(size); requestLayout(); mHasMeasurements = false; forceLayout(); } } public void setTypeface(Typeface typeface) { if (mPaint.getTypeface() != typeface) { if (mTextPaint.getTypeface() != typeface) { mTextPaint.setTypeface(typeface); mHasMeasurements = false; mPaint.setTypeface(typeface); forceLayout(); } } requestLayout(); public void setAlignment(Alignment textAlignment) { if (mAlignment != textAlignment) { mAlignment = textAlignment; mHasMeasurements = false; forceLayout(); } } Loading Loading @@ -222,63 +229,19 @@ public class SubtitleView extends View { } // Account for padding. final int paddingX = mPaddingLeft + mPaddingRight + mInnerPaddingX; final int paddingX = mPaddingLeft + mPaddingRight + mInnerPaddingX * 2; maxWidth -= paddingX; if (maxWidth <= 0) { return false; } final TextPaint paint = mPaint; final CharSequence text = mText; final int textLength = text.length(); if (mTextWidths == null || mTextWidths.length < textLength) { mTextWidths = new float[textLength]; } final float[] textWidths = mTextWidths; paint.getTextWidths(text, 0, textLength, textWidths); // Compute total length. float runLength = 0; for (int i = 0; i < textLength; i++) { runLength += textWidths[i]; } final int lineCount = (int) (runLength / maxWidth) + 1; final int lineLength = (int) (runLength / lineCount); // Build line break buffer. final StringBuilder breakText = mBreakText; breakText.setLength(0); int line = 0; int lastBreak = 0; int maxRunLength = 0; runLength = 0; for (int i = 0; i < textLength; i++) { if (runLength > lineLength) { final CharSequence sequence = text.subSequence(lastBreak, i); final int trimmedLength = TextUtils.getTrimmedLength(sequence); breakText.append(sequence, 0, trimmedLength); breakText.append('\n'); lastBreak = i; runLength = 0; } runLength += textWidths[i]; if (runLength > maxRunLength) { maxRunLength = (int) Math.ceil(runLength); } } breakText.append(text.subSequence(lastBreak, textLength)); // TODO: Implement minimum-difference line wrapping. Adding the results // of Paint.getTextWidths() seems to return different values than // StaticLayout.getWidth(), so this is non-trivial. mHasMeasurements = true; mLastMeasuredWidth = maxWidth; mLayout = new StaticLayout(breakText, paint, maxRunLength, Alignment.ALIGN_LEFT, mSpacingMult, mSpacingAdd, true); mLayout = new StaticLayout( mText, mTextPaint, maxWidth, mAlignment, mSpacingMult, mSpacingAdd, true); return true; } Loading Loading @@ -316,54 +279,50 @@ public class SubtitleView extends View { final int innerPaddingX = mInnerPaddingX; c.translate(mPaddingLeft + innerPaddingX, mPaddingTop); final RectF bounds = mLineBounds; final int lineCount = layout.getLineCount(); final Paint paint = layout.getPaint(); paint.setShadowLayer(0, 0, 0, 0); final int backgroundColor = mBackgroundColor; if (Color.alpha(backgroundColor) > 0) { paint.setColor(backgroundColor); paint.setStyle(Style.FILL); final Paint textPaint = mTextPaint; final Paint paint = mPaint; final RectF bounds = mLineBounds; if (Color.alpha(mBackgroundColor) > 0) { final float cornerRadius = mCornerRadius; float previousBottom = layout.getLineTop(0); paint.setColor(mBackgroundColor); paint.setStyle(Style.FILL); for (int i = 0; i < lineCount; i++) { bounds.left = layout.getLineLeft(i) -innerPaddingX; bounds.right = layout.getLineRight(i) + innerPaddingX; bounds.top = previousBottom; bounds.bottom = layout.getLineBottom(i); previousBottom = bounds.bottom; c.drawRoundRect(bounds, cornerRadius, cornerRadius, paint); } } final int edgeType = mEdgeType; if (edgeType == CaptionStyle.EDGE_TYPE_OUTLINE) { paint.setColor(mEdgeColor); paint.setStyle(Style.FILL_AND_STROKE); paint.setStrokeJoin(Join.ROUND); paint.setStrokeWidth(mOutlineWidth); if (mEdgeType == CaptionStyle.EDGE_TYPE_OUTLINE) { textPaint.setStrokeJoin(Join.ROUND); textPaint.setStrokeWidth(mOutlineWidth); textPaint.setColor(mEdgeColor); textPaint.setStyle(Style.FILL_AND_STROKE); for (int i = 0; i < lineCount; i++) { layout.drawText(c, i, i); } } else if (mEdgeType == CaptionStyle.EDGE_TYPE_DROP_SHADOW) { textPaint.setShadowLayer(mShadowRadius, mShadowOffsetX, mShadowOffsetY, mEdgeColor); } if (edgeType == CaptionStyle.EDGE_TYPE_DROP_SHADOW) { paint.setShadowLayer(mShadowRadius, mShadowOffsetX, mShadowOffsetY, mEdgeColor); } paint.setColor(mForegroundColor); paint.setStyle(Style.FILL); textPaint.setColor(mForegroundColor); textPaint.setStyle(Style.FILL); for (int i = 0; i < lineCount; i++) { layout.drawText(c, i, i); } textPaint.setShadowLayer(0, 0, 0, 0); c.restoreToCount(saveCount); } } media/java/android/media/WebVttRenderer.java +17 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package android.media; import android.content.Context; import android.text.Layout.Alignment; import android.text.SpannableStringBuilder; import android.util.ArrayMap; import android.util.AttributeSet; Loading Loading @@ -1583,6 +1584,7 @@ class WebVttRenderingWidget extends ViewGroup implements SubtitleTrack.Rendering } final CueLayout cueBox = new CueLayout(getContext(), cue, mCaptionStyle, mFontSize); mRegionCueBoxes.add(cueBox); addView(cueBox, LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); if (getChildCount() > mRegion.mLines) { Loading Loading @@ -1696,12 +1698,27 @@ class WebVttRenderingWidget extends ViewGroup implements SubtitleTrack.Rendering removeAllViews(); final int cueAlignment = resolveCueAlignment(getLayoutDirection(), mCue.mAlignment); final Alignment alignment; switch (cueAlignment) { case TextTrackCue.ALIGNMENT_LEFT: alignment = Alignment.ALIGN_LEFT; break; case TextTrackCue.ALIGNMENT_RIGHT: alignment = Alignment.ALIGN_RIGHT; break; case TextTrackCue.ALIGNMENT_MIDDLE: default: alignment = Alignment.ALIGN_CENTER; } final CaptionStyle captionStyle = mCaptionStyle; final float fontSize = mFontSize; final TextTrackCueSpan[][] lines = mCue.mLines; final int lineCount = lines.length; for (int i = 0; i < lineCount; i++) { final SpanLayout lineBox = new SpanLayout(getContext(), lines[i]); lineBox.setAlignment(alignment); lineBox.setCaptionStyle(captionStyle, fontSize); addView(lineBox, LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); Loading Loading
core/java/com/android/internal/widget/SubtitleView.java +48 −89 Original line number Diff line number Diff line Loading @@ -31,7 +31,6 @@ import android.graphics.Typeface; import android.text.Layout.Alignment; import android.text.StaticLayout; import android.text.TextPaint; import android.text.TextUtils; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.TypedValue; Loading @@ -52,14 +51,12 @@ public class SubtitleView extends View { /** Temporary rectangle used for computing line bounds. */ private final RectF mLineBounds = new RectF(); /** Temporary array used for computing line wrapping. */ private float[] mTextWidths; /** Reusable string builder used for holding text. */ private final StringBuilder mText = new StringBuilder(); private final StringBuilder mBreakText = new StringBuilder(); private TextPaint mPaint; private Alignment mAlignment; private TextPaint mTextPaint; private Paint mPaint; private int mForegroundColor; private int mBackgroundColor; Loading Loading @@ -122,11 +119,12 @@ public class SubtitleView extends View { mShadowOffsetX = res.getDimension(com.android.internal.R.dimen.subtitle_shadow_offset); mShadowOffsetY = mShadowOffsetX; final TextPaint paint = new TextPaint(); paint.setAntiAlias(true); paint.setSubpixelText(true); mTextPaint = new TextPaint(); mTextPaint.setAntiAlias(true); mTextPaint.setSubpixelText(true); mPaint = paint; mPaint = new Paint(); mPaint.setAntiAlias(true); setText(text); setTextSize(textSize); Loading Loading @@ -174,21 +172,30 @@ public class SubtitleView extends View { public void setTextSize(float size) { final DisplayMetrics metrics = getContext().getResources().getDisplayMetrics(); final float pixels = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, size, metrics); if (mPaint.getTextSize() != size) { mHasMeasurements = false; if (mTextPaint.getTextSize() != size) { mTextPaint.setTextSize(size); mInnerPaddingX = (int) (size * INNER_PADDING_RATIO + 0.5f); mPaint.setTextSize(size); requestLayout(); mHasMeasurements = false; forceLayout(); } } public void setTypeface(Typeface typeface) { if (mPaint.getTypeface() != typeface) { if (mTextPaint.getTypeface() != typeface) { mTextPaint.setTypeface(typeface); mHasMeasurements = false; mPaint.setTypeface(typeface); forceLayout(); } } requestLayout(); public void setAlignment(Alignment textAlignment) { if (mAlignment != textAlignment) { mAlignment = textAlignment; mHasMeasurements = false; forceLayout(); } } Loading Loading @@ -222,63 +229,19 @@ public class SubtitleView extends View { } // Account for padding. final int paddingX = mPaddingLeft + mPaddingRight + mInnerPaddingX; final int paddingX = mPaddingLeft + mPaddingRight + mInnerPaddingX * 2; maxWidth -= paddingX; if (maxWidth <= 0) { return false; } final TextPaint paint = mPaint; final CharSequence text = mText; final int textLength = text.length(); if (mTextWidths == null || mTextWidths.length < textLength) { mTextWidths = new float[textLength]; } final float[] textWidths = mTextWidths; paint.getTextWidths(text, 0, textLength, textWidths); // Compute total length. float runLength = 0; for (int i = 0; i < textLength; i++) { runLength += textWidths[i]; } final int lineCount = (int) (runLength / maxWidth) + 1; final int lineLength = (int) (runLength / lineCount); // Build line break buffer. final StringBuilder breakText = mBreakText; breakText.setLength(0); int line = 0; int lastBreak = 0; int maxRunLength = 0; runLength = 0; for (int i = 0; i < textLength; i++) { if (runLength > lineLength) { final CharSequence sequence = text.subSequence(lastBreak, i); final int trimmedLength = TextUtils.getTrimmedLength(sequence); breakText.append(sequence, 0, trimmedLength); breakText.append('\n'); lastBreak = i; runLength = 0; } runLength += textWidths[i]; if (runLength > maxRunLength) { maxRunLength = (int) Math.ceil(runLength); } } breakText.append(text.subSequence(lastBreak, textLength)); // TODO: Implement minimum-difference line wrapping. Adding the results // of Paint.getTextWidths() seems to return different values than // StaticLayout.getWidth(), so this is non-trivial. mHasMeasurements = true; mLastMeasuredWidth = maxWidth; mLayout = new StaticLayout(breakText, paint, maxRunLength, Alignment.ALIGN_LEFT, mSpacingMult, mSpacingAdd, true); mLayout = new StaticLayout( mText, mTextPaint, maxWidth, mAlignment, mSpacingMult, mSpacingAdd, true); return true; } Loading Loading @@ -316,54 +279,50 @@ public class SubtitleView extends View { final int innerPaddingX = mInnerPaddingX; c.translate(mPaddingLeft + innerPaddingX, mPaddingTop); final RectF bounds = mLineBounds; final int lineCount = layout.getLineCount(); final Paint paint = layout.getPaint(); paint.setShadowLayer(0, 0, 0, 0); final int backgroundColor = mBackgroundColor; if (Color.alpha(backgroundColor) > 0) { paint.setColor(backgroundColor); paint.setStyle(Style.FILL); final Paint textPaint = mTextPaint; final Paint paint = mPaint; final RectF bounds = mLineBounds; if (Color.alpha(mBackgroundColor) > 0) { final float cornerRadius = mCornerRadius; float previousBottom = layout.getLineTop(0); paint.setColor(mBackgroundColor); paint.setStyle(Style.FILL); for (int i = 0; i < lineCount; i++) { bounds.left = layout.getLineLeft(i) -innerPaddingX; bounds.right = layout.getLineRight(i) + innerPaddingX; bounds.top = previousBottom; bounds.bottom = layout.getLineBottom(i); previousBottom = bounds.bottom; c.drawRoundRect(bounds, cornerRadius, cornerRadius, paint); } } final int edgeType = mEdgeType; if (edgeType == CaptionStyle.EDGE_TYPE_OUTLINE) { paint.setColor(mEdgeColor); paint.setStyle(Style.FILL_AND_STROKE); paint.setStrokeJoin(Join.ROUND); paint.setStrokeWidth(mOutlineWidth); if (mEdgeType == CaptionStyle.EDGE_TYPE_OUTLINE) { textPaint.setStrokeJoin(Join.ROUND); textPaint.setStrokeWidth(mOutlineWidth); textPaint.setColor(mEdgeColor); textPaint.setStyle(Style.FILL_AND_STROKE); for (int i = 0; i < lineCount; i++) { layout.drawText(c, i, i); } } else if (mEdgeType == CaptionStyle.EDGE_TYPE_DROP_SHADOW) { textPaint.setShadowLayer(mShadowRadius, mShadowOffsetX, mShadowOffsetY, mEdgeColor); } if (edgeType == CaptionStyle.EDGE_TYPE_DROP_SHADOW) { paint.setShadowLayer(mShadowRadius, mShadowOffsetX, mShadowOffsetY, mEdgeColor); } paint.setColor(mForegroundColor); paint.setStyle(Style.FILL); textPaint.setColor(mForegroundColor); textPaint.setStyle(Style.FILL); for (int i = 0; i < lineCount; i++) { layout.drawText(c, i, i); } textPaint.setShadowLayer(0, 0, 0, 0); c.restoreToCount(saveCount); } }
media/java/android/media/WebVttRenderer.java +17 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package android.media; import android.content.Context; import android.text.Layout.Alignment; import android.text.SpannableStringBuilder; import android.util.ArrayMap; import android.util.AttributeSet; Loading Loading @@ -1583,6 +1584,7 @@ class WebVttRenderingWidget extends ViewGroup implements SubtitleTrack.Rendering } final CueLayout cueBox = new CueLayout(getContext(), cue, mCaptionStyle, mFontSize); mRegionCueBoxes.add(cueBox); addView(cueBox, LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); if (getChildCount() > mRegion.mLines) { Loading Loading @@ -1696,12 +1698,27 @@ class WebVttRenderingWidget extends ViewGroup implements SubtitleTrack.Rendering removeAllViews(); final int cueAlignment = resolveCueAlignment(getLayoutDirection(), mCue.mAlignment); final Alignment alignment; switch (cueAlignment) { case TextTrackCue.ALIGNMENT_LEFT: alignment = Alignment.ALIGN_LEFT; break; case TextTrackCue.ALIGNMENT_RIGHT: alignment = Alignment.ALIGN_RIGHT; break; case TextTrackCue.ALIGNMENT_MIDDLE: default: alignment = Alignment.ALIGN_CENTER; } final CaptionStyle captionStyle = mCaptionStyle; final float fontSize = mFontSize; final TextTrackCueSpan[][] lines = mCue.mLines; final int lineCount = lines.length; for (int i = 0; i < lineCount; i++) { final SpanLayout lineBox = new SpanLayout(getContext(), lines[i]); lineBox.setAlignment(alignment); lineBox.setCaptionStyle(captionStyle, fontSize); addView(lineBox, LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); Loading