Skip to content

Commit

Permalink
Fix/doris 2540 subtitle padding (#29)
Browse files Browse the repository at this point in the history
* format code

* getLineLeft insteadof getLineStart

* fix x position issue

* fix padding in black bg color

* fix padding in black bg color

* remove log info

* revert code, not format

* fix subtitle padding issue.

* add test code for subtitle padding

* fix subtitle text left position issue.

* add PaddingLineBackgroundSpan to draw background and padding

* fix custom style padding not work

* optimize code, format code style, rename field name

* fix subtitle background is transparent issue.
  • Loading branch information
WeiLiuSH authored Nov 27, 2024
1 parent 39e0313 commit bb2ed56
Show file tree
Hide file tree
Showing 4 changed files with 222 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
private float textSize;
private CaptionStyleCompat style;
private float bottomPaddingFraction;
private int horizontalPadding = 0;

public CanvasSubtitleOutput(Context context) {
this(context, /* attrs= */ null);
Expand All @@ -56,6 +57,10 @@ public CanvasSubtitleOutput(Context context, @Nullable AttributeSet attrs) {
bottomPaddingFraction = DEFAULT_BOTTOM_PADDING_FRACTION;
}

public void setHorizontalPadding(int horizontalPadding) {
this.horizontalPadding = horizontalPadding;
}

@Override
public void update(
List<Cue> cues,
Expand All @@ -70,7 +75,7 @@ public void update(
this.bottomPaddingFraction = bottomPaddingFraction;
// Ensure we have sufficient painters.
while (painters.size() < cues.size()) {
painters.add(new SubtitlePainter(getContext()));
painters.add(new SubtitlePainter(getContext(), horizontalPadding));
}
// Invalidate to trigger drawing.
invalidate();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
package androidx.media3.ui;

import android.graphics.Canvas;
import android.graphics.Paint;
import android.text.style.LineBackgroundSpan;
import androidx.annotation.ColorInt;
import androidx.annotation.Nullable;
import androidx.annotation.Px;

public class PaddingLineBackgroundSpan implements LineBackgroundSpan {

private final int lineBackgroundColor;
private final int horizontalPadding;
private final float left;
private final float top;
private final float right;
private final float bottom;
private final float measureScale;
@Nullable
private final BackgroundSpanInfo[] spanInfos;

public PaddingLineBackgroundSpan(
@ColorInt int lineBackgroundColor,
int horizontalPadding,
float left,
float top,
float right,
float bottom,
float measureScale,
@Nullable BackgroundSpanInfo[] spanInfos) {
this.lineBackgroundColor = lineBackgroundColor;
this.horizontalPadding = horizontalPadding;
this.left = left;
this.top = top;
this.right = right;
this.bottom = bottom;
this.measureScale = measureScale;
this.spanInfos = spanInfos;
}

@Override
public void drawBackground(
Canvas canvas,
Paint paint,
@Px int left,
@Px int right,
@Px int top,
@Px int baseline,
@Px int bottom,
CharSequence text,
int start,
int end,
int lineNumber) {
drawBackgroundWithPadding(canvas, paint, text, start, end);
}

private void drawBackgroundWithPadding(
Canvas canvas,
Paint paint,
CharSequence text,
int start,
int end) {
final int originColor = paint.getColor();
if (spanInfos != null && spanInfos.length > 0) {
float left = this.left;
float right;
int textPos = start;
for (int index = 0; index < spanInfos.length; index++) {
BackgroundSpanInfo info = spanInfos[index];
if (info.start > end) {
continue;
}
// draw line background
if (info.start > textPos && info.start < end) {
paint.setColor(lineBackgroundColor);
// draw left padding
if (index == 0) {
canvas.drawRect(this.left - horizontalPadding, top, this.left, bottom, paint);
}

float textWidth = measureText(paint, text, textPos, info.start);
textPos = info.start;
right = left + textWidth;
canvas.drawRect(left, top, right, bottom, paint);
left = right;
}
// draw span background
if (info.end <= end) {
paint.setColor(info.color);
// draw left padding
if (info.start == start) {
canvas.drawRect(this.left - horizontalPadding, top, this.left, bottom, paint);
}

float textWidth = measureText(paint, text, textPos, info.end);
textPos = info.end;
right = left + textWidth;
canvas.drawRect(left, top, right, bottom, paint);
left = right;
}

BackgroundSpanInfo nextInfo = index < spanInfos.length - 1 ? spanInfos[index + 1] : null;
if (nextInfo == null) {
// draw line background and right padding
paint.setColor(info.end == end ? info.color : lineBackgroundColor);
right = this.right;
canvas.drawRect(left, top, right + horizontalPadding, bottom, paint);
left = right;
}
}
} else {
paint.setColor(lineBackgroundColor);
canvas.drawRect(left - horizontalPadding, top, right + horizontalPadding, bottom, paint);
}
paint.setColor(originColor);
}

private float measureText(Paint paint, CharSequence text, int start, int end) {
if (start < 0 || end < start || end > text.length()) {
return 0f;
}
return paint.measureText(text, start, end) * measureScale;
}

public static class BackgroundSpanInfo implements Comparable<BackgroundSpanInfo> {

public final int start;
public final int end;
public final int color;

public BackgroundSpanInfo(int start, int end, int color) {
this.start = start;
this.end = end;
this.color = color;
}

@Override
public int compareTo(BackgroundSpanInfo info) {
return start - info.start;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import android.graphics.Paint.Style;
import android.graphics.Rect;
import android.text.Layout.Alignment;
import android.text.Spannable;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.StaticLayout;
Expand All @@ -41,6 +42,9 @@
import androidx.media3.common.util.Assertions;
import androidx.media3.common.util.Log;
import androidx.media3.common.util.Util;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
import org.checkerframework.checker.nullness.qual.RequiresNonNull;

Expand Down Expand Up @@ -95,9 +99,10 @@
private int textTop;
private int textPaddingX;
private @MonotonicNonNull Rect bitmapRect;
private final int horizontalPadding;

@SuppressWarnings("ResourceType")
public SubtitlePainter(Context context) {
public SubtitlePainter(Context context, int horizontalPadding) {
int[] viewAttr = {android.R.attr.lineSpacingExtra, android.R.attr.lineSpacingMultiplier};
TypedArray styledAttributes = context.obtainStyledAttributes(null, viewAttr, 0, 0);
spacingAdd = styledAttributes.getDimensionPixelSize(0, 0);
Expand All @@ -122,6 +127,8 @@ public SubtitlePainter(Context context) {
bitmapPaint = new Paint();
bitmapPaint.setAntiAlias(true);
bitmapPaint.setFilterBitmap(true);

this.horizontalPadding = horizontalPadding;
}

/**
Expand Down Expand Up @@ -370,6 +377,9 @@ private void setupTextLayout() {
this.textLeft = textLeft;
this.textTop = textTop;
this.textPaddingX = textPaddingX;

// reset spannable text background span and draw padding area
setupPaddingSpan(backgroundColor, horizontalPadding);
}

@RequiresNonNull("cueBitmap")
Expand Down Expand Up @@ -470,6 +480,63 @@ private void drawTextLayout(Canvas canvas) {
canvas.restoreToCount(saveCount);
}

private void setupPaddingSpan(int backgroundColor, int horizontalPadding) {
if (horizontalPadding <= 0 || !(textLayout.getText() instanceof Spannable)) {
return;
}
List<PaddingLineBackgroundSpan.BackgroundSpanInfo> backgroundSpanInfos = new ArrayList<>();
int lineBackgroundColor = backgroundColor;
Spannable spannableText = (Spannable) textLayout.getText();
BackgroundColorSpan[] colorSpans = spannableText.getSpans(
0,
spannableText.length(),
BackgroundColorSpan.class);
if (colorSpans != null) {
for (BackgroundColorSpan span : colorSpans) {
int color = span.getBackgroundColor();
int spanStart = spannableText.getSpanStart(span);
int spanEnd = spannableText.getSpanEnd(span);
if (spanStart == 0 && spanEnd == spannableText.length()) {
lineBackgroundColor = color;
} else {
backgroundSpanInfos.add(
new PaddingLineBackgroundSpan.BackgroundSpanInfo(
spanStart,
spanEnd,
color));
}
// remove original background span, background will drawn by PaddingLineBackgroundSpan.
if (color != Color.TRANSPARENT) {
spannableText.removeSpan(span);
}
}
Collections.sort(backgroundSpanInfos); // sort by start position.
}

if (lineBackgroundColor != Color.TRANSPARENT) {
for (int line = 0; line < textLayout.getLineCount(); line++) {
final float lineWidth = textLayout.getLineMax(line);
int start = textLayout.getLineStart(line);
int end = textLayout.getLineVisibleEnd(line);
float measureScale = lineWidth / textPaint.measureText(spannableText, start, end);
spannableText.setSpan(
new PaddingLineBackgroundSpan(
lineBackgroundColor,
horizontalPadding,
textLayout.getLineLeft(line),
textLayout.getLineTop(line),
textLayout.getLineRight(line),
textLayout.getLineBottom(line),
measureScale,
backgroundSpanInfos.toArray(new PaddingLineBackgroundSpan.BackgroundSpanInfo[0])
),
start,
end,
Spanned.SPAN_PRIORITY);
}
}
}

@RequiresNonNull({"cueBitmap", "bitmapRect"})
private void drawBitmapLayout(Canvas canvas) {
canvas.drawBitmap(cueBitmap, /* src= */ null, bitmapRect, bitmapPaint);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,12 @@ public SubtitleView(Context context, @Nullable AttributeSet attrs) {
viewType = VIEW_TYPE_CANVAS;
}

public void setSubtitleHorizontalPadding(int horizontalPadding) {
if (innerSubtitleView instanceof CanvasSubtitleOutput) {
((CanvasSubtitleOutput) innerSubtitleView).setHorizontalPadding(horizontalPadding);
}
}

/**
* Sets the cues to be displayed by the view.
*
Expand Down

0 comments on commit bb2ed56

Please sign in to comment.