Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c94f742f authored by Raph Levien's avatar Raph Levien
Browse files

Calculate line breaks using Minikin

This patch moves the calculation of line breaks for StaticLayout into
the new LineBreaker class provided by Minikin. This specific patch
should preserve existing functionality, but perhaps performance is
better, and the movement opens the door to much more sophisticated
line-breaking.

Change-Id: Iafccb9da4e3559bbeaeb2c7c85f86ddfd8ae2fa1
parent 02bc1fe6
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -1153,7 +1153,10 @@ public abstract class Layout {
                return end - 1;
            }

            if (ch != ' ' && ch != '\t') {
            // Note: keep this in sync with Minikin LineBreaker::isLineEndSpace()
            if (!(ch == ' ' || ch == '\t' || ch == 0x1680 ||
                    (0x2000 <= ch && ch <= 0x200A && ch != 0x2007) ||
                    ch == 0x205F || ch == 0x3000)) {
                break;
            }

+30 −25
Original line number Diff line number Diff line
@@ -170,8 +170,9 @@ public class StaticLayout extends Layout {
         * Measurement and break iteration is done in native code. The protocol for using
         * the native code is as follows.
         *
         * For each paragraph, do a nSetText of the paragraph text. Then, for each run within the
         * paragraph:
         * For each paragraph, do a nSetText of the paragraph text. Also do nSetLineWidth.
         *
         * Then, for each run within the paragraph:
         *  - setLocale (this must be done at least for the first run, optional afterwards)
         *  - one of the following, depending on the type of run:
         *    + addStyleRun (a text run, to be measured in native code)
@@ -459,7 +460,26 @@ public class StaticLayout extends Layout {
            byte[] chdirs = measured.mLevels;
            int dir = measured.mDir;
            boolean easy = measured.mEasy;
            nSetText(b.mNativePtr, chs, paraEnd - paraStart);

            // tab stop locations
            int[] variableTabStops = null;
            if (spanned != null) {
                TabStopSpan[] spans = getParagraphSpans(spanned, paraStart,
                        paraEnd, TabStopSpan.class);
                if (spans.length > 0) {
                    int[] stops = new int[spans.length];
                    for (int i = 0; i < spans.length; i++) {
                        stops[i] = spans[i].getTabStop();
                    }
                    Arrays.sort(stops, 0, stops.length);
                    variableTabStops = stops;
                }
            }

            int breakStrategy = 0;  // 0 = kBreakStrategy_Greedy
            nSetupParagraph(b.mNativePtr, chs, paraEnd - paraStart,
                    firstWidth, firstWidthLineCount, restWidth,
                    variableTabStops, TAB_INCREMENT, breakStrategy);

            // measurement has to be done before performing line breaking
            // but we don't want to recompute fontmetrics or span ranges the
@@ -505,25 +525,9 @@ public class StaticLayout extends Layout {
                spanEndCacheCount++;
            }

            // tab stop locations
            int[] variableTabStops = null;
            if (spanned != null) {
                TabStopSpan[] spans = getParagraphSpans(spanned, paraStart,
                        paraEnd, TabStopSpan.class);
                if (spans.length > 0) {
                    int[] stops = new int[spans.length];
                    for (int i = 0; i < spans.length; i++) {
                        stops[i] = spans[i].getTabStop();
                    }
                    Arrays.sort(stops, 0, stops.length);
                    variableTabStops = stops;
                }
            }

            nGetWidths(b.mNativePtr, widths);
            int breakCount = nComputeLineBreaks(b.mNativePtr, paraEnd - paraStart, firstWidth,
                    firstWidthLineCount, restWidth, variableTabStops, TAB_INCREMENT, false, lineBreaks,
                    lineBreaks.breaks, lineBreaks.widths, lineBreaks.flags, lineBreaks.breaks.length);
            int breakCount = nComputeLineBreaks(b.mNativePtr, lineBreaks, lineBreaks.breaks,
                    lineBreaks.widths, lineBreaks.flags, lineBreaks.breaks.length);

            int[] breaks = lineBreaks.breaks;
            float[] lineWidths = lineBreaks.widths;
@@ -966,7 +970,10 @@ public class StaticLayout extends Layout {
    private static native void nFinishBuilder(long nativePtr);
    private static native void nSetLocale(long nativePtr, String locale);

    private static native void nSetText(long nativePtr, char[] text, int length);
    // Set up paragraph text and settings; done as one big method to minimize jni crossings
    private static native void nSetupParagraph(long nativePtr, char[] text, int length,
            float firstWidth, int firstWidthLineCount, float restWidth,
            int[] variableTabStops, int defaultTabStop, int breakStrategy);

    private static native float nAddStyleRun(long nativePtr, long nativePaint,
            long nativeTypeface, int start, int end, boolean isRtl);
@@ -983,9 +990,7 @@ public class StaticLayout extends Layout {
    // the arrays inside the LineBreaks objects are passed in as well
    // 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,
            int length, float firstWidth, int firstWidthLineCount, float restWidth,
            int[] variableTabStops, int defaultTabStop, boolean optimize, LineBreaks recycle,
    private static native int nComputeLineBreaks(long nativePtr, LineBreaks recycle,
            int[] recycleBreaks, float[] recycleWidths, boolean[] recycleFlags, int recycleLength);

    private int mLineCount;
+23 −12
Original line number Diff line number Diff line
@@ -26,10 +26,10 @@

namespace android {

void MinikinUtils::doLayout(Layout* layout, const Paint* paint, int bidiFlags, TypefaceImpl* typeface,
        const uint16_t* buf, size_t start, size_t count, size_t bufSize) {
    TypefaceImpl* resolvedFace = TypefaceImpl_resolveDefault(typeface);
    layout->setFontCollection(resolvedFace->fFontCollection);
FontStyle MinikinUtils::prepareMinikinPaint(MinikinPaint* minikinPaint, FontCollection** pFont,
        const Paint* paint, TypefaceImpl* typeface) {
    const TypefaceImpl* resolvedFace = TypefaceImpl_resolveDefault(typeface);
    *pFont = resolvedFace->fFontCollection;
    FontStyle resolved = resolvedFace->fStyle;

    /* Prepare minikin FontStyle */
@@ -40,15 +40,26 @@ void MinikinUtils::doLayout(Layout* layout, const Paint* paint, int bidiFlags, T
    FontStyle minikinStyle(minikinLang, minikinVariant, resolved.getWeight(), resolved.getItalic());

    /* Prepare minikin Paint */
    MinikinPaint minikinPaint;
    minikinPaint.size = (int)/*WHY?!*/paint->getTextSize();
    minikinPaint.scaleX = paint->getTextScaleX();
    minikinPaint.skewX = paint->getTextSkewX();
    minikinPaint.letterSpacing = paint->getLetterSpacing();
    minikinPaint.paintFlags = MinikinFontSkia::packPaintFlags(paint);
    minikinPaint.fontFeatureSettings = paint->getFontFeatureSettings();
    minikinPaint.hyphenEdit = HyphenEdit(paint->getHyphenEdit());
    // Note: it would be nice to handle fractional size values (it would improve smooth zoom
    // behavior), but historically size has been treated as an int.
    // TODO: explore whether to enable fractional sizes, possibly when linear text flag is set.
    minikinPaint->size = (int)paint->getTextSize();
    minikinPaint->scaleX = paint->getTextScaleX();
    minikinPaint->skewX = paint->getTextSkewX();
    minikinPaint->letterSpacing = paint->getLetterSpacing();
    minikinPaint->paintFlags = MinikinFontSkia::packPaintFlags(paint);
    minikinPaint->fontFeatureSettings = paint->getFontFeatureSettings();
    minikinPaint->hyphenEdit = HyphenEdit(paint->getHyphenEdit());
    return minikinStyle;
}

void MinikinUtils::doLayout(Layout* layout, const Paint* paint, int bidiFlags,
        TypefaceImpl* typeface, const uint16_t* buf, size_t start, size_t count,
        size_t bufSize) {
    FontCollection *font;
    MinikinPaint minikinPaint;
    FontStyle minikinStyle = prepareMinikinPaint(&minikinPaint, &font, paint, typeface);
    layout->setFontCollection(font);
    layout->doLayout(buf, start, count, bufSize, bidiFlags, minikinStyle, minikinPaint);
}

+6 −14
Original line number Diff line number Diff line
@@ -31,22 +31,14 @@

namespace android {

// TODO: these should be defined in Minikin's Layout.h
enum {
    kBidi_LTR = 0,
    kBidi_RTL = 1,
    kBidi_Default_LTR = 2,
    kBidi_Default_RTL = 3,
    kBidi_Force_LTR = 4,
    kBidi_Force_RTL = 5,

    kBidi_Mask = 0x7
};

class MinikinUtils {
public:
    static void doLayout(Layout* layout, const Paint* paint, int bidiFlags, TypefaceImpl* typeface,
            const uint16_t* buf, size_t start, size_t count, size_t bufSize);
    static FontStyle prepareMinikinPaint(MinikinPaint* minikinPaint, FontCollection** pFont,
            const Paint* paint, TypefaceImpl* typeface);

    static void doLayout(Layout* layout, const Paint* paint, int bidiFlags,
            TypefaceImpl* typeface, const uint16_t* buf, size_t start, size_t count,
            size_t bufSize);

    static float xOffsetForTextAlign(Paint* paint, const Layout& layout);

+50 −569

File changed.

Preview size limit exceeded, changes collapsed.

+1 −1

File changed.

Contains only whitespace changes.

Loading