Support extra linespacing based on fallback fonts
* Increase the ascent and descent of individual lines in StaticLayout as needed, if any fallback fonts that end up getting used call for it. For backward compatibility, this is hidden behind a builder flag. * Document in Paint.java that the returned parameters are only for the default font, and a layout may need more space based on fallbacks used. Also update for changes in minikin API: * MinikinFont now requires a method for getting vertical extents (ascent, descent, and line gap). * minikin API now allows asking for vertical extents of laid out text. * minikin API's LineBreaker now returns ascents and descents for each line. Finally, added performances test for creating a StaticLayout. Follwing are the numbers on a marlin with a stable clock before and after this CL. For fixed text almost always hitting the cache: Before: mean=260684 median=260188 min=258532 standardDeviation=1897 After: mean=262432 median=261509 min=260429 standardDeviation=2185 For random text almost never hitting the cache: Before: mean=5971827 median=5991126 min=5886871 standardDeviation=83724 After: mean=6337093 median=6317010 min=6311222 standardDeviation=40213 Bug: 28963299 Bug: 29063863 Bug: 32057121 Bug: 37756858 Test: bit FrameworksCoreTests:android.text. Test: bit CtsTextTestCases:* Change-Id: I482a98ff8f472e8bab4f0ba9d1d7b368858038ff
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright (C) 2016 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 android.text;
|
||||
|
||||
import android.perftests.utils.BenchmarkState;
|
||||
import android.perftests.utils.PerfStatusReporter;
|
||||
|
||||
import android.support.test.filters.LargeTest;
|
||||
import android.support.test.runner.AndroidJUnit4;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.nio.CharBuffer;
|
||||
import java.util.Random;
|
||||
|
||||
@LargeTest
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class StaticLayoutPerfTest {
|
||||
|
||||
public StaticLayoutPerfTest() {
|
||||
}
|
||||
|
||||
@Rule
|
||||
public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
|
||||
|
||||
private static final String FIXED_TEXT = "Lorem ipsum dolor sit amet, consectetur adipiscing "
|
||||
+ "elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad "
|
||||
+ "minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea "
|
||||
+ "commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse "
|
||||
+ "cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non "
|
||||
+ "proident, sunt in culpa qui officia deserunt mollit anim id est laborum.";
|
||||
private static final int FIXED_TEXT_LENGTH = FIXED_TEXT.length();
|
||||
|
||||
private static TextPaint PAINT = new TextPaint();
|
||||
private static final int TEXT_WIDTH = 20 * (int) PAINT.getTextSize();
|
||||
|
||||
@Test
|
||||
public void testCreate() {
|
||||
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
|
||||
while (state.keepRunning()) {
|
||||
StaticLayout.Builder.obtain(FIXED_TEXT, 0, FIXED_TEXT_LENGTH, PAINT, TEXT_WIDTH)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
private static final String ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
||||
private static final int ALPHABET_LENGTH = ALPHABET.length();
|
||||
|
||||
private static final int PARA_LENGTH = 500;
|
||||
private final char[] mBuffer = new char[PARA_LENGTH];
|
||||
private final Random mRandom = new Random(31415926535L);
|
||||
|
||||
private CharSequence generateRandomParagraph(int wordLen) {
|
||||
for (int i = 0; i < PARA_LENGTH; i++) {
|
||||
if (i % (wordLen + 1) == wordLen) {
|
||||
mBuffer[i] = ' ';
|
||||
} else {
|
||||
mBuffer[i] = ALPHABET.charAt(mRandom.nextInt(ALPHABET_LENGTH));
|
||||
}
|
||||
}
|
||||
return CharBuffer.wrap(mBuffer);
|
||||
}
|
||||
|
||||
// This tries to simulate the case where the cache hit rate is low, and most of the text is
|
||||
// new text.
|
||||
@Test
|
||||
public void testCreateRandom() {
|
||||
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
|
||||
while (state.keepRunning()) {
|
||||
final CharSequence text = generateRandomParagraph(9);
|
||||
StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -41761,6 +41761,7 @@ package android.text {
|
||||
method public android.text.StaticLayout.Builder setMaxLines(int);
|
||||
method public android.text.StaticLayout.Builder setText(java.lang.CharSequence);
|
||||
method public android.text.StaticLayout.Builder setTextDirection(android.text.TextDirectionHeuristic);
|
||||
method public android.text.StaticLayout.Builder setUseLineSpacingFromFallbacks(boolean);
|
||||
}
|
||||
|
||||
public abstract interface TextDirectionHeuristic {
|
||||
|
||||
@@ -45362,6 +45362,7 @@ package android.text {
|
||||
method public android.text.StaticLayout.Builder setMaxLines(int);
|
||||
method public android.text.StaticLayout.Builder setText(java.lang.CharSequence);
|
||||
method public android.text.StaticLayout.Builder setTextDirection(android.text.TextDirectionHeuristic);
|
||||
method public android.text.StaticLayout.Builder setUseLineSpacingFromFallbacks(boolean);
|
||||
}
|
||||
|
||||
public abstract interface TextDirectionHeuristic {
|
||||
|
||||
@@ -42032,6 +42032,7 @@ package android.text {
|
||||
method public android.text.StaticLayout.Builder setMaxLines(int);
|
||||
method public android.text.StaticLayout.Builder setText(java.lang.CharSequence);
|
||||
method public android.text.StaticLayout.Builder setTextDirection(android.text.TextDirectionHeuristic);
|
||||
method public android.text.StaticLayout.Builder setUseLineSpacingFromFallbacks(boolean);
|
||||
}
|
||||
|
||||
public abstract interface TextDirectionHeuristic {
|
||||
|
||||
@@ -90,6 +90,7 @@ public class StaticLayout extends Layout {
|
||||
b.mSpacingMult = 1.0f;
|
||||
b.mSpacingAdd = 0.0f;
|
||||
b.mIncludePad = true;
|
||||
b.mFallbackLineSpacing = false;
|
||||
b.mEllipsizedWidth = width;
|
||||
b.mEllipsize = null;
|
||||
b.mMaxLines = Integer.MAX_VALUE;
|
||||
@@ -227,6 +228,24 @@ public class StaticLayout extends Layout {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether to respect the ascent and descent of the fallback fonts that are used in
|
||||
* displaying the text (which is needed to avoid text from consecutive lines running into
|
||||
* each other). If set, fallback fonts that end up getting used can increase the ascent
|
||||
* and descent of the lines that they are used on.
|
||||
*
|
||||
* <p>For backward compatibility reasons, the default is {@code false}, but setting this to
|
||||
* true is strongly recommended. It is required to be true if text could be in languages
|
||||
* like Burmese or Tibetan where text is typically much taller or deeper than Latin text.
|
||||
*
|
||||
* @param useLineSpacingFromFallbacks whether to expand linespacing based on fallback fonts
|
||||
* @return this builder, useful for chaining
|
||||
*/
|
||||
public Builder setUseLineSpacingFromFallbacks(boolean useLineSpacingFromFallbacks) {
|
||||
mFallbackLineSpacing = useLineSpacingFromFallbacks;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the width as used for ellipsizing purposes, if it differs from the
|
||||
* normal layout width. The default is the {@code width}
|
||||
@@ -432,6 +451,7 @@ public class StaticLayout extends Layout {
|
||||
float mSpacingMult;
|
||||
float mSpacingAdd;
|
||||
boolean mIncludePad;
|
||||
boolean mFallbackLineSpacing;
|
||||
int mEllipsizedWidth;
|
||||
TextUtils.TruncateAt mEllipsize;
|
||||
int mMaxLines;
|
||||
@@ -606,6 +626,7 @@ public class StaticLayout extends Layout {
|
||||
TextPaint paint = b.mPaint;
|
||||
int outerWidth = b.mWidth;
|
||||
TextDirectionHeuristic textDir = b.mTextDir;
|
||||
final boolean fallbackLineSpacing = b.mFallbackLineSpacing;
|
||||
float spacingmult = b.mSpacingMult;
|
||||
float spacingadd = b.mSpacingAdd;
|
||||
float ellipsizedWidth = b.mEllipsizedWidth;
|
||||
@@ -784,11 +805,14 @@ public class StaticLayout extends Layout {
|
||||
|
||||
nGetWidths(b.mNativePtr, widths);
|
||||
int breakCount = nComputeLineBreaks(b.mNativePtr, lineBreaks, lineBreaks.breaks,
|
||||
lineBreaks.widths, lineBreaks.flags, lineBreaks.breaks.length);
|
||||
lineBreaks.widths, lineBreaks.ascents, lineBreaks.descents, lineBreaks.flags,
|
||||
lineBreaks.breaks.length);
|
||||
|
||||
int[] breaks = lineBreaks.breaks;
|
||||
float[] lineWidths = lineBreaks.widths;
|
||||
int[] flags = lineBreaks.flags;
|
||||
final int[] breaks = lineBreaks.breaks;
|
||||
final float[] lineWidths = lineBreaks.widths;
|
||||
final float[] ascents = lineBreaks.ascents;
|
||||
final float[] descents = lineBreaks.descents;
|
||||
final int[] flags = lineBreaks.flags;
|
||||
|
||||
final int remainingLineCount = mMaximumVisibleLineCount - mLineCount;
|
||||
final boolean ellipsisMayBeApplied = ellipsize != null
|
||||
@@ -799,7 +823,7 @@ public class StaticLayout extends Layout {
|
||||
&& ellipsisMayBeApplied) {
|
||||
// Calculate width and flag.
|
||||
float width = 0;
|
||||
int flag = 0;
|
||||
int flag = 0; // XXX May need to also have starting hyphen edit
|
||||
for (int i = remainingLineCount - 1; i < breakCount; i++) {
|
||||
if (i == breakCount - 1) {
|
||||
width += lineWidths[i];
|
||||
@@ -808,7 +832,7 @@ public class StaticLayout extends Layout {
|
||||
width += widths[j];
|
||||
}
|
||||
}
|
||||
flag |= flags[i] & TAB_MASK; // XXX May need to also have starting hyphen edit
|
||||
flag |= flags[i] & TAB_MASK;
|
||||
}
|
||||
// Treat the last line and overflowed lines as a single line.
|
||||
breaks[remainingLineCount - 1] = breaks[breakCount - 1];
|
||||
@@ -859,8 +883,14 @@ public class StaticLayout extends Layout {
|
||||
|
||||
boolean moreChars = (endPos < bufEnd);
|
||||
|
||||
final int ascent = fallbackLineSpacing
|
||||
? Math.min(fmAscent, (int) Math.round(ascents[breakIndex]))
|
||||
: fmAscent;
|
||||
final int descent = fallbackLineSpacing
|
||||
? Math.max(fmDescent, (int) Math.round(descents[breakIndex]))
|
||||
: fmDescent;
|
||||
v = out(source, here, endPos,
|
||||
fmAscent, fmDescent, fmTop, fmBottom,
|
||||
ascent, descent, fmTop, fmBottom,
|
||||
v, spacingmult, spacingadd, chooseHt, chooseHtv, fm, flags[breakIndex],
|
||||
needMultiply, chdirs, dir, easy, bufEnd, includepad, trackpad,
|
||||
addLastLineSpacing, chs, widths, paraStart, ellipsize,
|
||||
@@ -891,8 +921,6 @@ public class StaticLayout extends Layout {
|
||||
|
||||
if ((bufEnd == bufStart || source.charAt(bufEnd - 1) == CHAR_NEW_LINE) &&
|
||||
mLineCount < mMaximumVisibleLineCount) {
|
||||
// Log.e("text", "output last " + bufEnd);
|
||||
|
||||
measured.setPara(source, bufEnd, bufEnd, textDir, b);
|
||||
|
||||
paint.getFontMetricsInt(fm);
|
||||
@@ -1470,7 +1498,8 @@ public class StaticLayout extends Layout {
|
||||
// to reduce the number of JNI calls in the common case where the
|
||||
// arrays do not have to be resized
|
||||
private static native int nComputeLineBreaks(long nativePtr, LineBreaks recycle,
|
||||
int[] recycleBreaks, float[] recycleWidths, int[] recycleFlags, int recycleLength);
|
||||
int[] recycleBreaks, float[] recycleWidths, float[] recycleAscents,
|
||||
float[] recycleDescents, int[] recycleFlags, int recycleLength);
|
||||
|
||||
private int mLineCount;
|
||||
private int mTopPadding, mBottomPadding;
|
||||
@@ -1529,6 +1558,8 @@ public class StaticLayout extends Layout {
|
||||
private static final int INITIAL_SIZE = 16;
|
||||
public int[] breaks = new int[INITIAL_SIZE];
|
||||
public float[] widths = new float[INITIAL_SIZE];
|
||||
public float[] ascents = new float[INITIAL_SIZE];
|
||||
public float[] descents = new float[INITIAL_SIZE];
|
||||
public int[] flags = new int[INITIAL_SIZE]; // hasTab
|
||||
// breaks, widths, and flags should all have the same length
|
||||
}
|
||||
|
||||
@@ -44,6 +44,8 @@ namespace android {
|
||||
struct JLineBreaksID {
|
||||
jfieldID breaks;
|
||||
jfieldID widths;
|
||||
jfieldID ascents;
|
||||
jfieldID descents;
|
||||
jfieldID flags;
|
||||
};
|
||||
|
||||
@@ -73,35 +75,45 @@ static void nSetupParagraph(JNIEnv* env, jclass, jlong nativePtr, jcharArray tex
|
||||
}
|
||||
|
||||
static void recycleCopy(JNIEnv* env, jobject recycle, jintArray recycleBreaks,
|
||||
jfloatArray recycleWidths, jintArray recycleFlags,
|
||||
jfloatArray recycleWidths, jfloatArray recycleAscents,
|
||||
jfloatArray recycleDescents, jintArray recycleFlags,
|
||||
jint recycleLength, size_t nBreaks, const jint* breaks,
|
||||
const jfloat* widths, const jint* flags) {
|
||||
const jfloat* widths, const jfloat* ascents, const jfloat* descents,
|
||||
const jint* flags) {
|
||||
if ((size_t)recycleLength < nBreaks) {
|
||||
// have to reallocate buffers
|
||||
recycleBreaks = env->NewIntArray(nBreaks);
|
||||
recycleWidths = env->NewFloatArray(nBreaks);
|
||||
recycleAscents = env->NewFloatArray(nBreaks);
|
||||
recycleDescents = env->NewFloatArray(nBreaks);
|
||||
recycleFlags = env->NewIntArray(nBreaks);
|
||||
|
||||
env->SetObjectField(recycle, gLineBreaks_fieldID.breaks, recycleBreaks);
|
||||
env->SetObjectField(recycle, gLineBreaks_fieldID.widths, recycleWidths);
|
||||
env->SetObjectField(recycle, gLineBreaks_fieldID.ascents, recycleAscents);
|
||||
env->SetObjectField(recycle, gLineBreaks_fieldID.descents, recycleDescents);
|
||||
env->SetObjectField(recycle, gLineBreaks_fieldID.flags, recycleFlags);
|
||||
}
|
||||
// copy data
|
||||
env->SetIntArrayRegion(recycleBreaks, 0, nBreaks, breaks);
|
||||
env->SetFloatArrayRegion(recycleWidths, 0, nBreaks, widths);
|
||||
env->SetFloatArrayRegion(recycleAscents, 0, nBreaks, ascents);
|
||||
env->SetFloatArrayRegion(recycleDescents, 0, nBreaks, descents);
|
||||
env->SetIntArrayRegion(recycleFlags, 0, nBreaks, flags);
|
||||
}
|
||||
|
||||
static jint nComputeLineBreaks(JNIEnv* env, jclass, jlong nativePtr,
|
||||
jobject recycle, jintArray recycleBreaks,
|
||||
jfloatArray recycleWidths, jintArray recycleFlags,
|
||||
jfloatArray recycleWidths, jfloatArray recycleAscents,
|
||||
jfloatArray recycleDescents, jintArray recycleFlags,
|
||||
jint recycleLength) {
|
||||
minikin::LineBreaker* b = reinterpret_cast<minikin::LineBreaker*>(nativePtr);
|
||||
|
||||
size_t nBreaks = b->computeBreaks();
|
||||
|
||||
recycleCopy(env, recycle, recycleBreaks, recycleWidths, recycleFlags, recycleLength,
|
||||
nBreaks, b->getBreaks(), b->getWidths(), b->getFlags());
|
||||
recycleCopy(env, recycle, recycleBreaks, recycleWidths, recycleAscents, recycleDescents,
|
||||
recycleFlags, recycleLength, nBreaks, b->getBreaks(), b->getWidths(), b->getAscents(),
|
||||
b->getDescents(), b->getFlags());
|
||||
|
||||
b->finish();
|
||||
|
||||
@@ -205,7 +217,7 @@ static const JNINativeMethod gMethods[] = {
|
||||
{"nAddMeasuredRun", "(JII[F)V", (void*) nAddMeasuredRun},
|
||||
{"nAddReplacementRun", "(JIIF)V", (void*) nAddReplacementRun},
|
||||
{"nGetWidths", "(J[F)V", (void*) nGetWidths},
|
||||
{"nComputeLineBreaks", "(JLandroid/text/StaticLayout$LineBreaks;[I[F[II)I",
|
||||
{"nComputeLineBreaks", "(JLandroid/text/StaticLayout$LineBreaks;[I[F[F[F[II)I",
|
||||
(void*) nComputeLineBreaks}
|
||||
};
|
||||
|
||||
@@ -216,6 +228,8 @@ int register_android_text_StaticLayout(JNIEnv* env)
|
||||
|
||||
gLineBreaks_fieldID.breaks = GetFieldIDOrDie(env, gLineBreaks_class, "breaks", "[I");
|
||||
gLineBreaks_fieldID.widths = GetFieldIDOrDie(env, gLineBreaks_class, "widths", "[F");
|
||||
gLineBreaks_fieldID.ascents = GetFieldIDOrDie(env, gLineBreaks_class, "ascents", "[F");
|
||||
gLineBreaks_fieldID.descents = GetFieldIDOrDie(env, gLineBreaks_class, "descents", "[F");
|
||||
gLineBreaks_fieldID.flags = GetFieldIDOrDie(env, gLineBreaks_class, "flags", "[I");
|
||||
|
||||
return RegisterMethodsOrDie(env, "android/text/StaticLayout", gMethods, NELEM(gMethods));
|
||||
|
||||
BIN
core/tests/coretests/assets/fonts/ascent1em-descent2em.ttf
Normal file
BIN
core/tests/coretests/assets/fonts/ascent1em-descent2em.ttf
Normal file
Binary file not shown.
181
core/tests/coretests/assets/fonts/ascent1em-descent2em.ttx
Normal file
181
core/tests/coretests/assets/fonts/ascent1em-descent2em.ttx
Normal file
@@ -0,0 +1,181 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Copyright (C) 2017 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.
|
||||
-->
|
||||
<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="3.0">
|
||||
|
||||
<GlyphOrder>
|
||||
<GlyphID id="0" name=".notdef"/>
|
||||
<GlyphID id="1" name="1em"/>
|
||||
</GlyphOrder>
|
||||
|
||||
<head>
|
||||
<tableVersion value="1.0"/>
|
||||
<fontRevision value="1.0"/>
|
||||
<checkSumAdjustment value="0x640cdb2f"/>
|
||||
<magicNumber value="0x5f0f3cf5"/>
|
||||
<flags value="00000000 00000011"/>
|
||||
<unitsPerEm value="1000"/>
|
||||
<created value="Fri Mar 17 07:26:00 2017"/>
|
||||
<macStyle value="00000000 00000000"/>
|
||||
<lowestRecPPEM value="7"/>
|
||||
<fontDirectionHint value="2"/>
|
||||
<glyphDataFormat value="0"/>
|
||||
</head>
|
||||
|
||||
<hhea>
|
||||
<tableVersion value="0x10000"/>
|
||||
<ascent value="1000"/>
|
||||
<descent value="-2000"/>
|
||||
<lineGap value="0"/>
|
||||
<caretSlopeRise value="1"/>
|
||||
<caretSlopeRun value="0"/>
|
||||
<caretOffset value="0"/>
|
||||
<reserved0 value="0"/>
|
||||
<reserved1 value="0"/>
|
||||
<reserved2 value="0"/>
|
||||
<reserved3 value="0"/>
|
||||
<metricDataFormat value="0"/>
|
||||
</hhea>
|
||||
|
||||
<maxp>
|
||||
<tableVersion value="0x10000"/>
|
||||
<maxZones value="0"/>
|
||||
<maxTwilightPoints value="0"/>
|
||||
<maxStorage value="0"/>
|
||||
<maxFunctionDefs value="0"/>
|
||||
<maxInstructionDefs value="0"/>
|
||||
<maxStackElements value="0"/>
|
||||
<maxSizeOfInstructions value="0"/>
|
||||
<maxComponentElements value="0"/>
|
||||
</maxp>
|
||||
|
||||
<OS_2>
|
||||
<!-- The fields 'usFirstCharIndex' and 'usLastCharIndex'
|
||||
will be recalculated by the compiler -->
|
||||
<version value="3"/>
|
||||
<xAvgCharWidth value="594"/>
|
||||
<usWeightClass value="400"/>
|
||||
<usWidthClass value="5"/>
|
||||
<fsType value="00000000 00001000"/>
|
||||
<ySubscriptXSize value="650"/>
|
||||
<ySubscriptYSize value="600"/>
|
||||
<ySubscriptXOffset value="0"/>
|
||||
<ySubscriptYOffset value="75"/>
|
||||
<ySuperscriptXSize value="650"/>
|
||||
<ySuperscriptYSize value="600"/>
|
||||
<ySuperscriptXOffset value="0"/>
|
||||
<ySuperscriptYOffset value="350"/>
|
||||
<yStrikeoutSize value="50"/>
|
||||
<yStrikeoutPosition value="300"/>
|
||||
<sFamilyClass value="0"/>
|
||||
<panose>
|
||||
<bFamilyType value="0"/>
|
||||
<bSerifStyle value="0"/>
|
||||
<bWeight value="5"/>
|
||||
<bProportion value="0"/>
|
||||
<bContrast value="0"/>
|
||||
<bStrokeVariation value="0"/>
|
||||
<bArmStyle value="0"/>
|
||||
<bLetterForm value="0"/>
|
||||
<bMidline value="0"/>
|
||||
<bXHeight value="0"/>
|
||||
</panose>
|
||||
<ulUnicodeRange1 value="00000000 00000000 00000000 00000001"/>
|
||||
<ulUnicodeRange2 value="00000000 00000000 00000000 00000000"/>
|
||||
<ulUnicodeRange3 value="00000000 00000000 00000000 00000000"/>
|
||||
<ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/>
|
||||
<achVendID value="UKWN"/>
|
||||
<fsSelection value="00000000 01000000"/>
|
||||
<usFirstCharIndex value="32"/>
|
||||
<usLastCharIndex value="122"/>
|
||||
<sTypoAscender value="800"/>
|
||||
<sTypoDescender value="-200"/>
|
||||
<sTypoLineGap value="200"/>
|
||||
<usWinAscent value="1000"/>
|
||||
<usWinDescent value="200"/>
|
||||
<ulCodePageRange1 value="00000000 00000000 00000000 00000001"/>
|
||||
<ulCodePageRange2 value="00000000 00000000 00000000 00000000"/>
|
||||
<sxHeight value="500"/>
|
||||
<sCapHeight value="700"/>
|
||||
<usDefaultChar value="0"/>
|
||||
<usBreakChar value="32"/>
|
||||
<usMaxContext value="0"/>
|
||||
</OS_2>
|
||||
|
||||
<hmtx>
|
||||
<mtx name=".notdef" width="1000" lsb="0"/>
|
||||
<mtx name="1em" width="1000" lsb="0"/>
|
||||
</hmtx>
|
||||
|
||||
<cmap>
|
||||
<tableVersion version="0"/>
|
||||
<cmap_format_4 platformID="3" platEncID="10" language="0">
|
||||
<map code="0x0020" name="1em" /> <!-- SPACE -->
|
||||
<map code="0x0061" name="1em" /> <!-- LATIN SMALL LETTER A -->
|
||||
</cmap_format_4>
|
||||
</cmap>
|
||||
|
||||
<loca>
|
||||
<!-- The 'loca' table will be calculated by the compiler -->
|
||||
</loca>
|
||||
|
||||
<glyf>
|
||||
<TTGlyph name=".notdef" xMin="0" yMin="0" xMax="0" yMax="0" />
|
||||
<TTGlyph name="1em" xMin="0" yMin="0" xMax="0" yMax="0" />
|
||||
</glyf>
|
||||
|
||||
<name>
|
||||
<namerecord nameID="0" platformID="3" platEncID="1" langID="0x409">
|
||||
Copyright (C) 2017 The Android Open Source Project
|
||||
</namerecord>
|
||||
<namerecord nameID="1" platformID="3" platEncID="1" langID="0x409">
|
||||
Sample Font
|
||||
</namerecord>
|
||||
<namerecord nameID="2" platformID="3" platEncID="1" langID="0x409">
|
||||
Regular
|
||||
</namerecord>
|
||||
<namerecord nameID="4" platformID="3" platEncID="1" langID="0x409">
|
||||
Sample Font
|
||||
</namerecord>
|
||||
<namerecord nameID="6" platformID="3" platEncID="1" langID="0x409">
|
||||
SampleFont-Regular
|
||||
</namerecord>
|
||||
<namerecord nameID="13" platformID="3" platEncID="1" langID="0x409">
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
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.
|
||||
</namerecord>
|
||||
<namerecord nameID="14" platformID="3" platEncID="1" langID="0x409">
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
</namerecord>
|
||||
</name>
|
||||
|
||||
<post>
|
||||
<formatType value="3.0"/>
|
||||
<italicAngle value="0.0"/>
|
||||
<underlinePosition value="-75"/>
|
||||
<underlineThickness value="50"/>
|
||||
<isFixedPitch value="0"/>
|
||||
<minMemType42 value="0"/>
|
||||
<maxMemType42 value="0"/>
|
||||
<minMemType1 value="0"/>
|
||||
<maxMemType1 value="0"/>
|
||||
</post>
|
||||
|
||||
</ttFont>
|
||||
BIN
core/tests/coretests/assets/fonts/ascent3em-descent4em.ttf
Normal file
BIN
core/tests/coretests/assets/fonts/ascent3em-descent4em.ttf
Normal file
Binary file not shown.
180
core/tests/coretests/assets/fonts/ascent3em-descent4em.ttx
Normal file
180
core/tests/coretests/assets/fonts/ascent3em-descent4em.ttx
Normal file
@@ -0,0 +1,180 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Copyright (C) 2017 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.
|
||||
-->
|
||||
<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="3.0">
|
||||
|
||||
<GlyphOrder>
|
||||
<GlyphID id="0" name=".notdef"/>
|
||||
<GlyphID id="1" name="1em"/>
|
||||
</GlyphOrder>
|
||||
|
||||
<head>
|
||||
<tableVersion value="1.0"/>
|
||||
<fontRevision value="1.0"/>
|
||||
<checkSumAdjustment value="0x640cdb2f"/>
|
||||
<magicNumber value="0x5f0f3cf5"/>
|
||||
<flags value="00000000 00000011"/>
|
||||
<unitsPerEm value="1000"/>
|
||||
<created value="Fri Mar 17 07:26:00 2017"/>
|
||||
<macStyle value="00000000 00000000"/>
|
||||
<lowestRecPPEM value="7"/>
|
||||
<fontDirectionHint value="2"/>
|
||||
<glyphDataFormat value="0"/>
|
||||
</head>
|
||||
|
||||
<hhea>
|
||||
<tableVersion value="0x10000"/>
|
||||
<ascent value="3000"/>
|
||||
<descent value="-4000"/>
|
||||
<lineGap value="0"/>
|
||||
<caretSlopeRise value="1"/>
|
||||
<caretSlopeRun value="0"/>
|
||||
<caretOffset value="0"/>
|
||||
<reserved0 value="0"/>
|
||||
<reserved1 value="0"/>
|
||||
<reserved2 value="0"/>
|
||||
<reserved3 value="0"/>
|
||||
<metricDataFormat value="0"/>
|
||||
</hhea>
|
||||
|
||||
<maxp>
|
||||
<tableVersion value="0x10000"/>
|
||||
<maxZones value="0"/>
|
||||
<maxTwilightPoints value="0"/>
|
||||
<maxStorage value="0"/>
|
||||
<maxFunctionDefs value="0"/>
|
||||
<maxInstructionDefs value="0"/>
|
||||
<maxStackElements value="0"/>
|
||||
<maxSizeOfInstructions value="0"/>
|
||||
<maxComponentElements value="0"/>
|
||||
</maxp>
|
||||
|
||||
<OS_2>
|
||||
<!-- The fields 'usFirstCharIndex' and 'usLastCharIndex'
|
||||
will be recalculated by the compiler -->
|
||||
<version value="3"/>
|
||||
<xAvgCharWidth value="594"/>
|
||||
<usWeightClass value="400"/>
|
||||
<usWidthClass value="5"/>
|
||||
<fsType value="00000000 00001000"/>
|
||||
<ySubscriptXSize value="650"/>
|
||||
<ySubscriptYSize value="600"/>
|
||||
<ySubscriptXOffset value="0"/>
|
||||
<ySubscriptYOffset value="75"/>
|
||||
<ySuperscriptXSize value="650"/>
|
||||
<ySuperscriptYSize value="600"/>
|
||||
<ySuperscriptXOffset value="0"/>
|
||||
<ySuperscriptYOffset value="350"/>
|
||||
<yStrikeoutSize value="50"/>
|
||||
<yStrikeoutPosition value="300"/>
|
||||
<sFamilyClass value="0"/>
|
||||
<panose>
|
||||
<bFamilyType value="0"/>
|
||||
<bSerifStyle value="0"/>
|
||||
<bWeight value="5"/>
|
||||
<bProportion value="0"/>
|
||||
<bContrast value="0"/>
|
||||
<bStrokeVariation value="0"/>
|
||||
<bArmStyle value="0"/>
|
||||
<bLetterForm value="0"/>
|
||||
<bMidline value="0"/>
|
||||
<bXHeight value="0"/>
|
||||
</panose>
|
||||
<ulUnicodeRange1 value="00000000 00000000 00000000 00000001"/>
|
||||
<ulUnicodeRange2 value="00000000 00000000 00000000 00000000"/>
|
||||
<ulUnicodeRange3 value="00000000 00000000 00000000 00000000"/>
|
||||
<ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/>
|
||||
<achVendID value="UKWN"/>
|
||||
<fsSelection value="00000000 01000000"/>
|
||||
<usFirstCharIndex value="32"/>
|
||||
<usLastCharIndex value="122"/>
|
||||
<sTypoAscender value="800"/>
|
||||
<sTypoDescender value="-200"/>
|
||||
<sTypoLineGap value="200"/>
|
||||
<usWinAscent value="1000"/>
|
||||
<usWinDescent value="200"/>
|
||||
<ulCodePageRange1 value="00000000 00000000 00000000 00000001"/>
|
||||
<ulCodePageRange2 value="00000000 00000000 00000000 00000000"/>
|
||||
<sxHeight value="500"/>
|
||||
<sCapHeight value="700"/>
|
||||
<usDefaultChar value="0"/>
|
||||
<usBreakChar value="32"/>
|
||||
<usMaxContext value="0"/>
|
||||
</OS_2>
|
||||
|
||||
<hmtx>
|
||||
<mtx name=".notdef" width="1000" lsb="0"/>
|
||||
<mtx name="1em" width="1000" lsb="0"/>
|
||||
</hmtx>
|
||||
|
||||
<cmap>
|
||||
<tableVersion version="0"/>
|
||||
<cmap_format_4 platformID="3" platEncID="10" language="0">
|
||||
<map code="0x0062" name="1em" /> <!-- LATIN SMALL LETTER B -->
|
||||
</cmap_format_4>
|
||||
</cmap>
|
||||
|
||||
<loca>
|
||||
<!-- The 'loca' table will be calculated by the compiler -->
|
||||
</loca>
|
||||
|
||||
<glyf>
|
||||
<TTGlyph name=".notdef" xMin="0" yMin="0" xMax="0" yMax="0" />
|
||||
<TTGlyph name="1em" xMin="0" yMin="0" xMax="0" yMax="0" />
|
||||
</glyf>
|
||||
|
||||
<name>
|
||||
<namerecord nameID="0" platformID="3" platEncID="1" langID="0x409">
|
||||
Copyright (C) 2017 The Android Open Source Project
|
||||
</namerecord>
|
||||
<namerecord nameID="1" platformID="3" platEncID="1" langID="0x409">
|
||||
Sample Font
|
||||
</namerecord>
|
||||
<namerecord nameID="2" platformID="3" platEncID="1" langID="0x409">
|
||||
Regular
|
||||
</namerecord>
|
||||
<namerecord nameID="4" platformID="3" platEncID="1" langID="0x409">
|
||||
Sample Font
|
||||
</namerecord>
|
||||
<namerecord nameID="6" platformID="3" platEncID="1" langID="0x409">
|
||||
SampleFont-Regular
|
||||
</namerecord>
|
||||
<namerecord nameID="13" platformID="3" platEncID="1" langID="0x409">
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
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.
|
||||
</namerecord>
|
||||
<namerecord nameID="14" platformID="3" platEncID="1" langID="0x409">
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
</namerecord>
|
||||
</name>
|
||||
|
||||
<post>
|
||||
<formatType value="3.0"/>
|
||||
<italicAngle value="0.0"/>
|
||||
<underlinePosition value="-75"/>
|
||||
<underlineThickness value="50"/>
|
||||
<isFixedPitch value="0"/>
|
||||
<minMemType42 value="0"/>
|
||||
<maxMemType42 value="0"/>
|
||||
<minMemType1 value="0"/>
|
||||
<maxMemType1 value="0"/>
|
||||
</post>
|
||||
|
||||
</ttFont>
|
||||
@@ -21,20 +21,33 @@ import static android.text.Layout.Alignment.ALIGN_NORMAL;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.AssetManager;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.FontFamily;
|
||||
import android.graphics.Paint.FontMetricsInt;
|
||||
import android.graphics.Typeface;
|
||||
import android.os.LocaleList;
|
||||
import android.support.test.InstrumentationRegistry;
|
||||
import android.support.test.filters.SmallTest;
|
||||
import android.support.test.runner.AndroidJUnit4;
|
||||
import android.text.Layout.Alignment;
|
||||
import android.text.method.EditorState;
|
||||
import android.text.style.LocaleSpan;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.Log;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.text.Normalizer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -799,4 +812,129 @@ public class StaticLayoutTest {
|
||||
layout.drawText(canvas, 0, 0);
|
||||
assertEquals(31, paint.getHyphenEdit());
|
||||
}
|
||||
|
||||
private String getTestFontsDir() {
|
||||
final Context targetCtx = InstrumentationRegistry.getInstrumentation().getTargetContext();
|
||||
final File cacheDir = new File(targetCtx.getCacheDir(), "StaticLayoutTest");
|
||||
if (!cacheDir.isDirectory()) {
|
||||
final boolean dirsCreated = cacheDir.mkdirs();
|
||||
if (!dirsCreated) {
|
||||
throw new RuntimeException("Creating test directories for fonts failed.");
|
||||
}
|
||||
}
|
||||
return cacheDir.getAbsolutePath() + "/";
|
||||
}
|
||||
|
||||
private TextPaint setupPaintForFallbackFonts(String[] fontFiles, String xml) {
|
||||
final String testFontsDir = getTestFontsDir();
|
||||
final String testFontsXml = new File(testFontsDir, "fonts.xml").getAbsolutePath();
|
||||
final AssetManager am =
|
||||
InstrumentationRegistry.getInstrumentation().getContext().getAssets();
|
||||
for (String fontFile : fontFiles) {
|
||||
final String sourceInAsset = "fonts/" + fontFile;
|
||||
final File outInCache = new File(testFontsDir, fontFile);
|
||||
try (InputStream is = am.open(sourceInAsset)) {
|
||||
Files.copy(is, outInCache.toPath(), StandardCopyOption.REPLACE_EXISTING);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
try (FileOutputStream fos = new FileOutputStream(testFontsXml)) {
|
||||
fos.write(xml.getBytes(Charset.forName("UTF-8")));
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
final ArrayMap<String, Typeface> fontMap = new ArrayMap<>();
|
||||
final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>();
|
||||
Typeface.buildSystemFallback(testFontsXml, testFontsDir, fontMap, fallbackMap);
|
||||
|
||||
final TextPaint paint = new TextPaint();
|
||||
final Typeface testTypeface = fontMap.get("sans-serif");
|
||||
paint.setTypeface(testTypeface);
|
||||
return paint;
|
||||
}
|
||||
|
||||
void destroyFallbackFonts(String[] fontFiles) {
|
||||
final String testFontsDir = getTestFontsDir();
|
||||
for (String fontFile : fontFiles) {
|
||||
final File outInCache = new File(testFontsDir, fontFile);
|
||||
outInCache.delete();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFallbackLineSpacing() {
|
||||
// All glyphs in the fonts are 1em wide.
|
||||
final String[] testFontFiles = {
|
||||
// ascent == 1em, descent == 2em, only supports 'a' and space
|
||||
"ascent1em-descent2em.ttf",
|
||||
// ascent == 3em, descent == 4em, only supports 'b'
|
||||
"ascent3em-descent4em.ttf"
|
||||
};
|
||||
final String xml = "<?xml version='1.0' encoding='UTF-8'?>"
|
||||
+ "<familyset>"
|
||||
+ " <family name='sans-serif'>"
|
||||
+ " <font weight='400' style='normal'>ascent1em-descent2em.ttf</font>"
|
||||
+ " </family>"
|
||||
+ " <family>"
|
||||
+ " <font weight='400' style='normal'>ascent3em-descent4em.ttf</font>"
|
||||
+ " </family>"
|
||||
+ "</familyset>";
|
||||
|
||||
try {
|
||||
final TextPaint paint = setupPaintForFallbackFonts(testFontFiles, xml);
|
||||
final int textSize = 100;
|
||||
paint.setTextSize(textSize);
|
||||
assertEquals(-textSize, paint.ascent(), 0.0f);
|
||||
assertEquals(2 * textSize, paint.descent(), 0.0f);
|
||||
|
||||
final int paraWidth = 5 * textSize;
|
||||
final String text = "aaaaa aabaa aaaaa"; // This should result in three lines.
|
||||
|
||||
// Old line spacing. All lines should get their ascent and descents from the first font.
|
||||
StaticLayout layout = StaticLayout.Builder
|
||||
.obtain(text, 0, text.length(), paint, paraWidth)
|
||||
.setIncludePad(false)
|
||||
.setUseLineSpacingFromFallbacks(false)
|
||||
.build();
|
||||
assertEquals(3, layout.getLineCount());
|
||||
assertEquals(-textSize, layout.getLineAscent(0));
|
||||
assertEquals(2 * textSize, layout.getLineDescent(0));
|
||||
assertEquals(-textSize, layout.getLineAscent(1));
|
||||
assertEquals(2 * textSize, layout.getLineDescent(1));
|
||||
assertEquals(-textSize, layout.getLineAscent(2));
|
||||
assertEquals(2 * textSize, layout.getLineDescent(2));
|
||||
|
||||
// New line spacing. The second line has a 'b', so it needs more ascent and descent.
|
||||
layout = StaticLayout.Builder
|
||||
.obtain(text, 0, text.length(), paint, paraWidth)
|
||||
.setIncludePad(false)
|
||||
.setUseLineSpacingFromFallbacks(true)
|
||||
.build();
|
||||
assertEquals(3, layout.getLineCount());
|
||||
assertEquals(-textSize, layout.getLineAscent(0));
|
||||
assertEquals(2 * textSize, layout.getLineDescent(0));
|
||||
assertEquals(-3 * textSize, layout.getLineAscent(1));
|
||||
assertEquals(4 * textSize, layout.getLineDescent(1));
|
||||
assertEquals(-textSize, layout.getLineAscent(2));
|
||||
assertEquals(2 * textSize, layout.getLineDescent(2));
|
||||
|
||||
// The default is the old line spacing, for backward compatibility.
|
||||
layout = StaticLayout.Builder
|
||||
.obtain(text, 0, text.length(), paint, paraWidth)
|
||||
.setIncludePad(false)
|
||||
.build();
|
||||
assertEquals(3, layout.getLineCount());
|
||||
assertEquals(-textSize, layout.getLineAscent(0));
|
||||
assertEquals(2 * textSize, layout.getLineDescent(0));
|
||||
assertEquals(-textSize, layout.getLineAscent(1));
|
||||
assertEquals(2 * textSize, layout.getLineDescent(1));
|
||||
assertEquals(-textSize, layout.getLineAscent(2));
|
||||
assertEquals(2 * textSize, layout.getLineDescent(2));
|
||||
} finally {
|
||||
destroyFallbackFonts(testFontFiles);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1729,6 +1729,9 @@ public class Paint {
|
||||
* Return the distance above (negative) the baseline (ascent) based on the
|
||||
* current typeface and text size.
|
||||
*
|
||||
* <p>Note that this is the ascent of the main typeface, and actual text rendered may need a
|
||||
* larger ascent because fallback fonts may get used in rendering the text.
|
||||
*
|
||||
* @return the distance above (negative) the baseline (ascent) based on the
|
||||
* current typeface and text size.
|
||||
*/
|
||||
@@ -1740,6 +1743,9 @@ public class Paint {
|
||||
* Return the distance below (positive) the baseline (descent) based on the
|
||||
* current typeface and text size.
|
||||
*
|
||||
* <p>Note that this is the descent of the main typeface, and actual text rendered may need a
|
||||
* larger descent because fallback fonts may get used in rendering the text.
|
||||
*
|
||||
* @return the distance below (positive) the baseline (descent) based on
|
||||
* the current typeface and text size.
|
||||
*/
|
||||
@@ -1783,6 +1789,9 @@ public class Paint {
|
||||
* settings for typeface, textSize, etc. If metrics is not null, return the
|
||||
* fontmetric values in it.
|
||||
*
|
||||
* <p>Note that these are the values for the main typeface, and actual text rendered may need a
|
||||
* larger set of values because fallback fonts may get used in rendering the text.
|
||||
*
|
||||
* @param metrics If this object is not null, its fields are filled with
|
||||
* the appropriate values given the paint's text attributes.
|
||||
* @return the font's recommended interline spacing.
|
||||
@@ -1844,6 +1853,9 @@ public class Paint {
|
||||
* and clipping. If you want more control over the rounding, call
|
||||
* getFontMetrics().
|
||||
*
|
||||
* <p>Note that these are the values for the main typeface, and actual text rendered may need a
|
||||
* larger set of values because fallback fonts may get used in rendering the text.
|
||||
*
|
||||
* @return the font's interline spacing.
|
||||
*/
|
||||
public int getFontMetricsInt(FontMetricsInt fmi) {
|
||||
@@ -1860,6 +1872,9 @@ public class Paint {
|
||||
* Return the recommend line spacing based on the current typeface and
|
||||
* text size.
|
||||
*
|
||||
* <p>Note that this is the value for the main typeface, and actual text rendered may need a
|
||||
* larger value because fallback fonts may get used in rendering the text.
|
||||
*
|
||||
* @return recommend line spacing based on the current typeface and
|
||||
* text size.
|
||||
*/
|
||||
|
||||
@@ -67,6 +67,17 @@ void MinikinFontSkia::GetBounds(minikin::MinikinRect* bounds, uint32_t glyph_id,
|
||||
bounds->mBottom = skBounds.fBottom;
|
||||
}
|
||||
|
||||
void MinikinFontSkia::GetFontExtent(minikin::MinikinExtent* extent,
|
||||
const minikin::MinikinPaint& paint) const {
|
||||
SkPaint skPaint;
|
||||
MinikinFontSkia_SetSkiaPaint(this, &skPaint, paint);
|
||||
SkPaint::FontMetrics metrics;
|
||||
skPaint.getFontMetrics(&metrics);
|
||||
extent->ascent = metrics.fAscent;
|
||||
extent->descent = metrics.fDescent;
|
||||
extent->line_gap = metrics.fLeading;
|
||||
}
|
||||
|
||||
SkTypeface *MinikinFontSkia::GetSkTypeface() const {
|
||||
return mTypeface.get();
|
||||
}
|
||||
|
||||
@@ -37,6 +37,9 @@ public:
|
||||
void GetBounds(minikin::MinikinRect* bounds, uint32_t glyph_id,
|
||||
const minikin::MinikinPaint &paint) const;
|
||||
|
||||
void GetFontExtent(minikin::MinikinExtent* extent,
|
||||
const minikin::MinikinPaint &paint) const;
|
||||
|
||||
SkTypeface* GetSkTypeface() const;
|
||||
sk_sp<SkTypeface> RefSkTypeface() const;
|
||||
|
||||
|
||||
@@ -68,7 +68,7 @@ float MinikinUtils::measureText(const Paint* paint, int bidiFlags, const Typefac
|
||||
minikin::FontStyle minikinStyle = prepareMinikinPaint(&minikinPaint, paint, typeface);
|
||||
const Typeface* resolvedTypeface = Typeface::resolveDefault(typeface);
|
||||
return minikin::Layout::measureText(buf, start, count, bufSize, bidiFlags, minikinStyle,
|
||||
minikinPaint, resolvedTypeface->fFontCollection, advances);
|
||||
minikinPaint, resolvedTypeface->fFontCollection, advances, nullptr /* extent */);
|
||||
}
|
||||
|
||||
bool MinikinUtils::hasVariationSelector(const Typeface* typeface, uint32_t codepoint, uint32_t vs) {
|
||||
|
||||
Reference in New Issue
Block a user