1af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir/*
2af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir * Copyright (C) 2017 The Android Open Source Project
3af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir *
4af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir * use this file except in compliance with the License. You may obtain a copy of
6af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir * the License at
7af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir *
8af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir * http://www.apache.org/licenses/LICENSE-2.0
9af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir *
10af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir * Unless required by applicable law or agreed to in writing, software
11af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir * License for the specific language governing permissions and limitations under
14af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir * the License.
15af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir */
16af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinirpackage android.text;
17af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir
18af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinirimport static android.text.Layout.Alignment.ALIGN_NORMAL;
19af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir
20af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinirimport android.graphics.Canvas;
21af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinirimport android.perftests.utils.BenchmarkState;
22af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinirimport android.perftests.utils.PerfStatusReporter;
23af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinirimport android.support.test.filters.LargeTest;
24af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinirimport android.text.NonEditableTextGenerator.TextType;
25af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinirimport android.view.DisplayListCanvas;
26af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinirimport android.view.RenderNode;
27af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir
28af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinirimport org.junit.Rule;
29af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinirimport org.junit.Test;
30af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinirimport org.junit.runner.RunWith;
31af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinirimport org.junit.runners.Parameterized;
32af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir
33af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinirimport java.util.ArrayList;
34af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinirimport java.util.Collection;
35af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinirimport java.util.List;
36af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinirimport java.util.Random;
37af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir
38af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir/**
39af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir * Performance test for multi line, single style {@link StaticLayout} creation/draw.
40af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir */
41af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir@LargeTest
42af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir@RunWith(Parameterized.class)
43af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinirpublic class StaticLayoutCreateDrawPerfTest {
44af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir
45af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir    private static final boolean[] BOOLEANS = new boolean[]{false, true};
46af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir
47af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir    private static final float SPACING_ADD = 10f;
48af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir    private static final float SPACING_MULT = 1.5f;
49af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir
50af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir    @Rule
51af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir    public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
52af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir
531f84ea9f2d9b5df63460e88216f618ae5d1a8e1bSiyamed Sinir    @Parameterized.Parameters(name = "cached={3},{1}chars,{0}")
54af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir    public static Collection cases() {
55af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir        final List<Object[]> params = new ArrayList<>();
56d0a5206dd8130611567acab92206eeecc222a65eSiyamed Sinir        for (int length : new int[]{128}) {
57af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir            for (boolean cached : BOOLEANS) {
58d0a5206dd8130611567acab92206eeecc222a65eSiyamed Sinir                for (TextType textType : new TextType[]{TextType.STRING,
59d0a5206dd8130611567acab92206eeecc222a65eSiyamed Sinir                        TextType.SPANNABLE_BUILDER}) {
60d0a5206dd8130611567acab92206eeecc222a65eSiyamed Sinir                    params.add(new Object[]{textType.name(), length, textType, cached});
61af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir                }
62af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir            }
63af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir        }
64af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir        return params;
65af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir    }
66af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir
67af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir    private final int mLineWidth;
68af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir    private final int mLength;
69af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir    private final TextType mTextType;
70af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir    private final boolean mCached;
71af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir    private final TextPaint mTextPaint;
72af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir
73af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir    public StaticLayoutCreateDrawPerfTest(String label, int length, TextType textType,
74d0a5206dd8130611567acab92206eeecc222a65eSiyamed Sinir            boolean cached) {
75af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir        mLength = length;
76af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir        mTextType = textType;
77af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir        mCached = cached;
78af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir        mTextPaint = new TextPaint();
79af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir        mTextPaint.setTextSize(10);
80d0a5206dd8130611567acab92206eeecc222a65eSiyamed Sinir        mLineWidth = Integer.MAX_VALUE;
81af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir    }
82af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir
83af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir    /**
84af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir     * Measures the creation time for a multi line {@link StaticLayout}.
85af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir     */
86af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir    @Test
87af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir    public void timeCreate() throws Exception {
88af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
89af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir
90af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir        state.pauseTiming();
91af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir        Canvas.freeTextLayoutCaches();
92af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir        final CharSequence text = createRandomText(mLength);
93af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir        createLayout(text);
94af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir        state.resumeTiming();
95af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir
96af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir        while (state.keepRunning()) {
97af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir            state.pauseTiming();
98af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir            if (!mCached) Canvas.freeTextLayoutCaches();
99af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir            state.resumeTiming();
100af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir
101af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir            createLayout(text);
102af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir        }
103af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir    }
104af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir
105af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir    /**
106af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir     * Measures the draw time for a multi line {@link StaticLayout}.
107af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir     */
108af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir    @Test
109af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir    public void timeDraw() throws Exception {
110af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
111af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir
112af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir        state.pauseTiming();
113af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir        Canvas.freeTextLayoutCaches();
114af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir        final RenderNode node = RenderNode.create("benchmark", null);
115af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir        final CharSequence text = createRandomText(mLength);
116af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir        final Layout layout = createLayout(text);
117af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir        state.resumeTiming();
118af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir
119af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir        while (state.keepRunning()) {
120af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir
121af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir            state.pauseTiming();
122af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir            final DisplayListCanvas canvas = node.start(1200, 200);
123af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir            int save = canvas.save();
124af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir            if (!mCached) Canvas.freeTextLayoutCaches();
125af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir            state.resumeTiming();
126af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir
127af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir            layout.draw(canvas);
128af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir
129af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir            state.pauseTiming();
130af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir            canvas.restoreToCount(save);
131af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir            node.end(canvas);
132af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir            state.resumeTiming();
133af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir        }
134af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir    }
135af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir
136af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir    private Layout createLayout(CharSequence text) {
137af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir        return StaticLayout.Builder.obtain(text, 0 /*start*/, text.length() /*end*/, mTextPaint,
138af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir                mLineWidth)
139af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir                .setAlignment(ALIGN_NORMAL)
140af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir                .setIncludePad(true)
141af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir                .setLineSpacing(SPACING_ADD, SPACING_MULT)
142af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir                .build();
143af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir    }
144af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir
145af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir    private CharSequence createRandomText(int length) {
146af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir        return new NonEditableTextGenerator(new Random(0))
147af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir                .setSequenceLength(length)
148af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir                .setTextType(mTextType)
149af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir                .build();
150af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir    }
151af479b8c9743a1536d46f0985294c8bc0823a338Siyamed Sinir}
152