Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
SDK
/
exoplayer
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Settings
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
69394e6f
authored
May 26, 2021
by
Oliver Woodman
Browse files
Options
_('Browse Files')
Download
Email Patches
Plain Diff
Merge pull request #8943 from dlafayet:embeddedstyle2
PiperOrigin-RevId: 375484765
parent
55f50e24
Show whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
282 additions
and
34 deletions
RELEASENOTES.md
library/core/src/main/java/com/google/android/exoplayer2/text/span/HorizontalTextInVerticalContextSpan.java
library/core/src/main/java/com/google/android/exoplayer2/text/span/LanguageFeatureSpan.java
library/core/src/main/java/com/google/android/exoplayer2/text/span/RubySpan.java
library/core/src/main/java/com/google/android/exoplayer2/text/span/TextEmphasisSpan.java
library/ui/src/main/java/com/google/android/exoplayer2/ui/SubtitleView.java
library/ui/src/main/java/com/google/android/exoplayer2/ui/SubtitleViewUtils.java
library/ui/src/test/java/com/google/android/exoplayer2/ui/SubtitleViewUtilsTest.java
RELEASENOTES.md
View file @
69394e6f
...
@@ -15,6 +15,10 @@
...
@@ -15,6 +15,10 @@
*
DRM:
*
DRM:
*
Don't restore offline keys before releasing them. In OEMCrypto v16+ keys
*
Don't restore offline keys before releasing them. In OEMCrypto v16+ keys
must be released without restoring them first.
must be released without restoring them first.
*
UI:
*
Keep subtitle language features embedded (e.g. rubies & tate-chu-yoko)
in
`Cue.text`
even when
`SubtitleView#setApplyEmbeddedStyles()`
is
false.
### 2.14.0 (2021-05-13)
### 2.14.0 (2021-05-13)
...
...
library/core/src/main/java/com/google/android/exoplayer2/text/span/HorizontalTextInVerticalContextSpan.java
View file @
69394e6f
...
@@ -29,4 +29,4 @@ package com.google.android.exoplayer2.text.span;
...
@@ -29,4 +29,4 @@ package com.google.android.exoplayer2.text.span;
// NOTE: There's no Android layout support for this, so this span currently doesn't extend any
// NOTE: There's no Android layout support for this, so this span currently doesn't extend any
// styling superclasses (e.g. MetricAffectingSpan). The only way to render this styling is to
// styling superclasses (e.g. MetricAffectingSpan). The only way to render this styling is to
// extract the spans and do the layout manually.
// extract the spans and do the layout manually.
public
final
class
HorizontalTextInVerticalContextSpan
{}
public
final
class
HorizontalTextInVerticalContextSpan
implements
LanguageFeatureSpan
{}
library/core/src/main/java/com/google/android/exoplayer2/text/span/LanguageFeatureSpan.java
0 → 100644
View file @
69394e6f
/*
* Copyright 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
com
.
google
.
android
.
exoplayer2
.
text
.
span
;
/** Marker interface for span classes that carry language features rather than style information. */
public
interface
LanguageFeatureSpan
{}
library/core/src/main/java/com/google/android/exoplayer2/text/span/RubySpan.java
View file @
69394e6f
...
@@ -30,7 +30,7 @@ package com.google.android.exoplayer2.text.span;
...
@@ -30,7 +30,7 @@ package com.google.android.exoplayer2.text.span;
// extract the spans and do the layout manually.
// extract the spans and do the layout manually.
// TODO: Consider adding support for parenthetical text to be used when rendering doesn't support
// TODO: Consider adding support for parenthetical text to be used when rendering doesn't support
// rubies (e.g. HTML <rp> tag).
// rubies (e.g. HTML <rp> tag).
public
final
class
RubySpan
{
public
final
class
RubySpan
implements
LanguageFeatureSpan
{
/** The ruby text, i.e. the smaller explanatory characters. */
/** The ruby text, i.e. the smaller explanatory characters. */
public
final
String
rubyText
;
public
final
String
rubyText
;
...
...
library/core/src/main/java/com/google/android/exoplayer2/text/span/TextEmphasisSpan.java
View file @
69394e6f
...
@@ -32,7 +32,7 @@ import java.lang.annotation.Retention;
...
@@ -32,7 +32,7 @@ import java.lang.annotation.Retention;
// NOTE: There's no Android layout support for text emphasis, so this span currently doesn't extend
// NOTE: There's no Android layout support for text emphasis, so this span currently doesn't extend
// any styling superclasses (e.g. MetricAffectingSpan). The only way to render this emphasis is to
// any styling superclasses (e.g. MetricAffectingSpan). The only way to render this emphasis is to
// extract the spans and do the layout manually.
// extract the spans and do the layout manually.
public
final
class
TextEmphasisSpan
{
public
final
class
TextEmphasisSpan
implements
LanguageFeatureSpan
{
/**
/**
* The possible mark shapes that can be used.
* The possible mark shapes that can be used.
...
...
library/ui/src/main/java/com/google/android/exoplayer2/ui/SubtitleView.java
View file @
69394e6f
...
@@ -21,10 +21,6 @@ import static java.lang.annotation.RetentionPolicy.SOURCE;
...
@@ -21,10 +21,6 @@ import static java.lang.annotation.RetentionPolicy.SOURCE;
import
android.content.Context
;
import
android.content.Context
;
import
android.content.res.Resources
;
import
android.content.res.Resources
;
import
android.graphics.Canvas
;
import
android.graphics.Canvas
;
import
android.text.SpannableString
;
import
android.text.Spanned
;
import
android.text.style.AbsoluteSizeSpan
;
import
android.text.style.RelativeSizeSpan
;
import
android.util.AttributeSet
;
import
android.util.AttributeSet
;
import
android.util.TypedValue
;
import
android.util.TypedValue
;
import
android.view.View
;
import
android.view.View
;
...
@@ -380,37 +376,13 @@ public final class SubtitleView extends FrameLayout implements TextOutput {
...
@@ -380,37 +376,13 @@ public final class SubtitleView extends FrameLayout implements TextOutput {
}
}
private
Cue
removeEmbeddedStyling
(
Cue
cue
)
{
private
Cue
removeEmbeddedStyling
(
Cue
cue
)
{
@Nullable
CharSequence
cueText
=
cue
.
text
;
Cue
.
Builder
strippedCue
=
cue
.
buildUpon
()
;
if
(!
applyEmbeddedStyles
)
{
if
(!
applyEmbeddedStyles
)
{
Cue
.
Builder
strippedCue
=
SubtitleViewUtils
.
removeAllEmbeddedStyling
(
strippedCue
);
cue
.
buildUpon
().
setTextSize
(
Cue
.
DIMEN_UNSET
,
Cue
.
TYPE_UNSET
).
clearWindowColor
();
if
(
cueText
!=
null
)
{
// Remove all spans, regardless of type.
strippedCue
.
setText
(
cueText
.
toString
());
}
return
strippedCue
.
build
();
}
else
if
(!
applyEmbeddedFontSizes
)
{
}
else
if
(!
applyEmbeddedFontSizes
)
{
if
(
cueText
==
null
)
{
SubtitleViewUtils
.
removeEmbeddedFontSizes
(
strippedCue
);
return
cue
;
}
Cue
.
Builder
strippedCue
=
cue
.
buildUpon
().
setTextSize
(
Cue
.
DIMEN_UNSET
,
Cue
.
TYPE_UNSET
);
if
(
cueText
instanceof
Spanned
)
{
SpannableString
spannable
=
SpannableString
.
valueOf
(
cueText
);
AbsoluteSizeSpan
[]
absSpans
=
spannable
.
getSpans
(
0
,
spannable
.
length
(),
AbsoluteSizeSpan
.
class
);
for
(
AbsoluteSizeSpan
absSpan
:
absSpans
)
{
spannable
.
removeSpan
(
absSpan
);
}
RelativeSizeSpan
[]
relSpans
=
spannable
.
getSpans
(
0
,
spannable
.
length
(),
RelativeSizeSpan
.
class
);
for
(
RelativeSizeSpan
relSpan
:
relSpans
)
{
spannable
.
removeSpan
(
relSpan
);
}
strippedCue
.
setText
(
spannable
);
}
}
return
strippedCue
.
build
();
return
strippedCue
.
build
();
}
}
return
cue
;
}
}
}
library/ui/src/main/java/com/google/android/exoplayer2/ui/SubtitleViewUtils.java
View file @
69394e6f
...
@@ -16,7 +16,16 @@
...
@@ -16,7 +16,16 @@
*/
*/
package
com
.
google
.
android
.
exoplayer2
.
ui
;
package
com
.
google
.
android
.
exoplayer2
.
ui
;
import
static
com
.
google
.
android
.
exoplayer2
.
util
.
Assertions
.
checkNotNull
;
import
android.text.Spannable
;
import
android.text.SpannableString
;
import
android.text.Spanned
;
import
android.text.style.AbsoluteSizeSpan
;
import
android.text.style.RelativeSizeSpan
;
import
com.google.android.exoplayer2.text.Cue
;
import
com.google.android.exoplayer2.text.Cue
;
import
com.google.android.exoplayer2.text.span.LanguageFeatureSpan
;
import
com.google.common.base.Predicate
;
/** Utility class for subtitle layout logic. */
/** Utility class for subtitle layout logic. */
/* package */
final
class
SubtitleViewUtils
{
/* package */
final
class
SubtitleViewUtils
{
...
@@ -48,5 +57,50 @@ import com.google.android.exoplayer2.text.Cue;
...
@@ -48,5 +57,50 @@ import com.google.android.exoplayer2.text.Cue;
}
}
}
}
/** Removes all styling information from {@code cue}. */
public
static
void
removeAllEmbeddedStyling
(
Cue
.
Builder
cue
)
{
cue
.
clearWindowColor
();
if
(
cue
.
getText
()
instanceof
Spanned
)
{
if
(!(
cue
.
getText
()
instanceof
Spannable
))
{
cue
.
setText
(
SpannableString
.
valueOf
(
cue
.
getText
()));
}
removeSpansIf
(
(
Spannable
)
checkNotNull
(
cue
.
getText
()),
span
->
!(
span
instanceof
LanguageFeatureSpan
));
}
removeEmbeddedFontSizes
(
cue
);
}
/**
* Removes all font size information from {@code cue}.
*
* <p>This involves:
*
* <ul>
* <li>Clearing {@link Cue.Builder#setTextSize(float, int)}.
* <li>Removing all {@link AbsoluteSizeSpan} and {@link RelativeSizeSpan} spans from {@link
* Cue#text}.
* </ul>
*/
public
static
void
removeEmbeddedFontSizes
(
Cue
.
Builder
cue
)
{
cue
.
setTextSize
(
Cue
.
DIMEN_UNSET
,
Cue
.
TYPE_UNSET
);
if
(
cue
.
getText
()
instanceof
Spanned
)
{
if
(!(
cue
.
getText
()
instanceof
Spannable
))
{
cue
.
setText
(
SpannableString
.
valueOf
(
cue
.
getText
()));
}
removeSpansIf
(
(
Spannable
)
checkNotNull
(
cue
.
getText
()),
span
->
span
instanceof
AbsoluteSizeSpan
||
span
instanceof
RelativeSizeSpan
);
}
}
private
static
void
removeSpansIf
(
Spannable
spannable
,
Predicate
<
Object
>
removeFilter
)
{
Object
[]
spans
=
spannable
.
getSpans
(
0
,
spannable
.
length
(),
Object
.
class
);
for
(
Object
span
:
spans
)
{
if
(
removeFilter
.
apply
(
span
))
{
spannable
.
removeSpan
(
span
);
}
}
}
private
SubtitleViewUtils
()
{}
private
SubtitleViewUtils
()
{}
}
}
library/ui/src/test/java/com/google/android/exoplayer2/ui/SubtitleViewUtilsTest.java
0 → 100644
View file @
69394e6f
/*
* Copyright 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package
com
.
google
.
android
.
exoplayer2
.
ui
;
import
static
com
.
google
.
android
.
exoplayer2
.
testutil
.
truth
.
SpannedSubject
.
assertThat
;
import
static
com
.
google
.
common
.
truth
.
Truth
.
assertThat
;
import
android.graphics.Color
;
import
android.text.Layout
;
import
android.text.SpannableString
;
import
android.text.Spanned
;
import
android.text.style.AbsoluteSizeSpan
;
import
android.text.style.RelativeSizeSpan
;
import
android.text.style.UnderlineSpan
;
import
androidx.test.ext.junit.runners.AndroidJUnit4
;
import
com.google.android.exoplayer2.text.Cue
;
import
com.google.android.exoplayer2.text.span.HorizontalTextInVerticalContextSpan
;
import
com.google.android.exoplayer2.text.span.RubySpan
;
import
com.google.android.exoplayer2.text.span.TextAnnotation
;
import
com.google.android.exoplayer2.text.span.TextEmphasisSpan
;
import
org.junit.Test
;
import
org.junit.runner.RunWith
;
/** Tests for {@link SubtitleView}. */
@RunWith
(
AndroidJUnit4
.
class
)
public
class
SubtitleViewUtilsTest
{
private
static
final
Cue
CUE
=
buildCue
();
@Test
public
void
testRemoveAllEmbeddedStyling
()
{
Cue
.
Builder
cueBuilder
=
CUE
.
buildUpon
();
SubtitleViewUtils
.
removeAllEmbeddedStyling
(
cueBuilder
);
Cue
strippedCue
=
cueBuilder
.
build
();
Spanned
originalText
=
(
Spanned
)
CUE
.
text
;
Spanned
strippedText
=
(
Spanned
)
strippedCue
.
text
;
// Assert all non styling properties and spans are kept
assertThat
(
strippedCue
.
textAlignment
).
isEqualTo
(
CUE
.
textAlignment
);
assertThat
(
strippedCue
.
multiRowAlignment
).
isEqualTo
(
CUE
.
multiRowAlignment
);
assertThat
(
strippedCue
.
line
).
isEqualTo
(
CUE
.
line
);
assertThat
(
strippedCue
.
lineType
).
isEqualTo
(
CUE
.
lineType
);
assertThat
(
strippedCue
.
position
).
isEqualTo
(
CUE
.
position
);
assertThat
(
strippedCue
.
positionAnchor
).
isEqualTo
(
CUE
.
positionAnchor
);
assertThat
(
strippedCue
.
textSize
).
isEqualTo
(
Cue
.
DIMEN_UNSET
);
assertThat
(
strippedCue
.
textSizeType
).
isEqualTo
(
Cue
.
TYPE_UNSET
);
assertThat
(
strippedCue
.
size
).
isEqualTo
(
CUE
.
size
);
assertThat
(
strippedCue
.
verticalType
).
isEqualTo
(
CUE
.
verticalType
);
assertThat
(
strippedCue
.
shearDegrees
).
isEqualTo
(
CUE
.
shearDegrees
);
TextEmphasisSpan
expectedTextEmphasisSpan
=
originalText
.
getSpans
(
0
,
originalText
.
length
(),
TextEmphasisSpan
.
class
)[
0
];
assertThat
(
strippedText
)
.
hasTextEmphasisSpanBetween
(
originalText
.
getSpanStart
(
expectedTextEmphasisSpan
),
originalText
.
getSpanEnd
(
expectedTextEmphasisSpan
));
RubySpan
expectedRubySpan
=
originalText
.
getSpans
(
0
,
originalText
.
length
(),
RubySpan
.
class
)[
0
];
assertThat
(
strippedText
)
.
hasRubySpanBetween
(
originalText
.
getSpanStart
(
expectedRubySpan
),
originalText
.
getSpanEnd
(
expectedRubySpan
));
HorizontalTextInVerticalContextSpan
expectedHorizontalTextInVerticalContextSpan
=
originalText
.
getSpans
(
0
,
originalText
.
length
(),
HorizontalTextInVerticalContextSpan
.
class
)[
0
];
assertThat
(
strippedText
)
.
hasHorizontalTextInVerticalContextSpanBetween
(
originalText
.
getSpanStart
(
expectedHorizontalTextInVerticalContextSpan
),
originalText
.
getSpanEnd
(
expectedHorizontalTextInVerticalContextSpan
));
// Assert all styling properties and spans are removed
assertThat
(
strippedCue
.
windowColorSet
).
isFalse
();
assertThat
(
strippedText
).
hasNoUnderlineSpanBetween
(
0
,
strippedText
.
length
());
assertThat
(
strippedText
).
hasNoRelativeSizeSpanBetween
(
0
,
strippedText
.
length
());
assertThat
(
strippedText
).
hasNoAbsoluteSizeSpanBetween
(
0
,
strippedText
.
length
());
}
@Test
public
void
testRemoveEmbeddedFontSizes
()
{
Cue
.
Builder
cueBuilder
=
CUE
.
buildUpon
();
SubtitleViewUtils
.
removeEmbeddedFontSizes
(
cueBuilder
);
Cue
strippedCue
=
cueBuilder
.
build
();
Spanned
originalText
=
(
Spanned
)
CUE
.
text
;
Spanned
strippedText
=
(
Spanned
)
strippedCue
.
text
;
// Assert all non text-size properties and spans are kept
assertThat
(
strippedCue
.
textAlignment
).
isEqualTo
(
CUE
.
textAlignment
);
assertThat
(
strippedCue
.
multiRowAlignment
).
isEqualTo
(
CUE
.
multiRowAlignment
);
assertThat
(
strippedCue
.
line
).
isEqualTo
(
CUE
.
line
);
assertThat
(
strippedCue
.
lineType
).
isEqualTo
(
CUE
.
lineType
);
assertThat
(
strippedCue
.
position
).
isEqualTo
(
CUE
.
position
);
assertThat
(
strippedCue
.
positionAnchor
).
isEqualTo
(
CUE
.
positionAnchor
);
assertThat
(
strippedCue
.
size
).
isEqualTo
(
CUE
.
size
);
assertThat
(
strippedCue
.
windowColor
).
isEqualTo
(
CUE
.
windowColor
);
assertThat
(
strippedCue
.
windowColorSet
).
isEqualTo
(
CUE
.
windowColorSet
);
assertThat
(
strippedCue
.
verticalType
).
isEqualTo
(
CUE
.
verticalType
);
assertThat
(
strippedCue
.
shearDegrees
).
isEqualTo
(
CUE
.
shearDegrees
);
TextEmphasisSpan
expectedTextEmphasisSpan
=
originalText
.
getSpans
(
0
,
originalText
.
length
(),
TextEmphasisSpan
.
class
)[
0
];
assertThat
(
strippedText
)
.
hasTextEmphasisSpanBetween
(
originalText
.
getSpanStart
(
expectedTextEmphasisSpan
),
originalText
.
getSpanEnd
(
expectedTextEmphasisSpan
));
RubySpan
expectedRubySpan
=
originalText
.
getSpans
(
0
,
originalText
.
length
(),
RubySpan
.
class
)[
0
];
assertThat
(
strippedText
)
.
hasRubySpanBetween
(
originalText
.
getSpanStart
(
expectedRubySpan
),
originalText
.
getSpanEnd
(
expectedRubySpan
));
HorizontalTextInVerticalContextSpan
expectedHorizontalTextInVerticalContextSpan
=
originalText
.
getSpans
(
0
,
originalText
.
length
(),
HorizontalTextInVerticalContextSpan
.
class
)[
0
];
assertThat
(
strippedText
)
.
hasHorizontalTextInVerticalContextSpanBetween
(
originalText
.
getSpanStart
(
expectedHorizontalTextInVerticalContextSpan
),
originalText
.
getSpanEnd
(
expectedHorizontalTextInVerticalContextSpan
));
UnderlineSpan
expectedUnderlineSpan
=
originalText
.
getSpans
(
0
,
originalText
.
length
(),
UnderlineSpan
.
class
)[
0
];
assertThat
(
strippedText
)
.
hasUnderlineSpanBetween
(
originalText
.
getSpanStart
(
expectedUnderlineSpan
),
originalText
.
getSpanEnd
(
expectedUnderlineSpan
));
// Assert the text-size properties and spans are removed
assertThat
(
strippedCue
.
textSize
).
isEqualTo
(
Cue
.
DIMEN_UNSET
);
assertThat
(
strippedCue
.
textSizeType
).
isEqualTo
(
Cue
.
TYPE_UNSET
);
assertThat
(
strippedText
).
hasNoRelativeSizeSpanBetween
(
0
,
strippedText
.
length
());
assertThat
(
strippedText
).
hasNoAbsoluteSizeSpanBetween
(
0
,
strippedText
.
length
());
}
private
static
Cue
buildCue
()
{
SpannableString
spanned
=
new
SpannableString
(
"TextEmphasis おはよ Ruby ございます 123 Underline RelativeSize AbsoluteSize"
);
spanned
.
setSpan
(
new
TextEmphasisSpan
(
TextEmphasisSpan
.
MARK_SHAPE_CIRCLE
,
TextEmphasisSpan
.
MARK_FILL_FILLED
,
TextAnnotation
.
POSITION_BEFORE
),
"Text emphasis "
.
length
(),
"Text emphasis おはよ"
.
length
(),
Spanned
.
SPAN_EXCLUSIVE_EXCLUSIVE
);
spanned
.
setSpan
(
new
RubySpan
(
"おはよ"
,
TextAnnotation
.
POSITION_BEFORE
),
"TextEmphasis おはよ Ruby "
.
length
(),
"TextEmphasis おはよ Ruby ございます"
.
length
(),
Spanned
.
SPAN_EXCLUSIVE_EXCLUSIVE
);
spanned
.
setSpan
(
new
HorizontalTextInVerticalContextSpan
(),
"TextEmphasis おはよ Ruby ございます "
.
length
(),
"TextEmphasis おはよ Ruby ございます 123"
.
length
(),
Spanned
.
SPAN_EXCLUSIVE_EXCLUSIVE
);
spanned
.
setSpan
(
new
UnderlineSpan
(),
"TextEmphasis おはよ Ruby ございます 123 "
.
length
(),
"TextEmphasis おはよ Ruby ございます 123 Underline"
.
length
(),
Spanned
.
SPAN_EXCLUSIVE_EXCLUSIVE
);
spanned
.
setSpan
(
new
RelativeSizeSpan
(
1
f
),
"TextEmphasis おはよ Ruby ございます 123 Underline "
.
length
(),
"TextEmphasis おはよ Ruby ございます 123 Underline RelativeSize"
.
length
(),
Spanned
.
SPAN_EXCLUSIVE_EXCLUSIVE
);
spanned
.
setSpan
(
new
AbsoluteSizeSpan
(
10
),
"TextEmphasis おはよ Ruby ございます 123 Underline RelativeSize "
.
length
(),
"TextEmphasis おはよ Ruby ございます 123 Underline RelativeSize AbsoluteSize"
.
length
(),
Spanned
.
SPAN_EXCLUSIVE_EXCLUSIVE
);
return
new
Cue
.
Builder
()
.
setText
(
spanned
)
.
setTextAlignment
(
Layout
.
Alignment
.
ALIGN_CENTER
)
.
setMultiRowAlignment
(
Layout
.
Alignment
.
ALIGN_NORMAL
)
.
setLine
(
5
,
Cue
.
LINE_TYPE_NUMBER
)
.
setLineAnchor
(
Cue
.
ANCHOR_TYPE_END
)
.
setPosition
(
0.4f
)
.
setPositionAnchor
(
Cue
.
ANCHOR_TYPE_MIDDLE
)
.
setTextSize
(
0.2f
,
Cue
.
TEXT_SIZE_TYPE_FRACTIONAL
)
.
setSize
(
0.8f
)
.
setWindowColor
(
Color
.
CYAN
)
.
setVerticalType
(
Cue
.
VERTICAL_TYPE_RL
)
.
setShearDegrees
(-
15
f
)
.
build
();
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment