ListViewAnimation.cpp revision 54fa17f667c285a5c9225e238c8132dfe830ef36
1/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "TestSceneBase.h"
18#include "utils/Color.h"
19
20#include <cstdio>
21
22class ListViewAnimation;
23
24static Benchmark _ListView(BenchmarkInfo{
25    "listview",
26    "A mock ListView of scrolling content. Doesn't re-bind/re-record views as they are recycled, so"
27    "won't upload much content (either glyphs, or bitmaps).",
28    simpleCreateScene<ListViewAnimation>
29});
30
31class ListViewAnimation : public TestScene {
32public:
33    int cardHeight;
34    int cardSpacing;
35    int cardWidth;
36    int cardLeft;
37    sp<RenderNode> listView;
38    std::vector< sp<RenderNode> > cards;
39    void createContent(int width, int height, TestCanvas& canvas) override {
40        srand(0);
41        cardHeight = dp(60);
42        cardSpacing = dp(16);
43        cardWidth = std::min((height - cardSpacing * 2), (int)dp(300));
44        cardLeft = (width - cardWidth) / 2;
45
46        for (int y = 0; y < height + (cardHeight + cardSpacing - 1); y += (cardHeight + cardSpacing)) {
47            cards.push_back(createCard(cards.size(), y));
48        }
49        listView = TestUtils::createNode(0, 0, width, height,
50                [this](RenderProperties& props, TestCanvas& canvas) {
51            for (size_t ci = 0; ci < cards.size(); ci++) {
52                canvas.drawRenderNode(cards[ci].get());
53            }
54        });
55
56        canvas.drawColor(Color::Grey_500, SkXfermode::kSrcOver_Mode);
57        canvas.drawRenderNode(listView.get());
58    }
59
60    void doFrame(int frameNr) override {
61        int scrollPx = dp(frameNr) * 3;
62        int cardIndexOffset = scrollPx / (cardSpacing + cardHeight);
63        int pxOffset = -(scrollPx % (cardSpacing + cardHeight));
64
65        TestCanvas canvas(cardWidth, cardHeight);
66        for (size_t ci = 0; ci < cards.size(); ci++) {
67            // update card position
68            auto card = cards[(ci + cardIndexOffset) % cards.size()];
69            int top = ((int)ci) * (cardSpacing + cardHeight) + pxOffset;
70            card->mutateStagingProperties().setLeftTopRightBottom(
71                    cardLeft, top, cardLeft + cardWidth, top + cardHeight);
72            card->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
73
74            // draw it to parent DisplayList
75            canvas.drawRenderNode(cards[ci].get());
76        }
77        listView->setStagingDisplayList(canvas.finishRecording());
78    }
79private:
80    SkBitmap createRandomCharIcon() {
81        int size = cardHeight - (dp(10) * 2);
82        SkBitmap bitmap = TestUtils::createSkBitmap(size, size);
83        SkCanvas canvas(bitmap);
84        canvas.clear(0);
85
86        SkPaint paint;
87        paint.setAntiAlias(true);
88        SkColor randomColor = BrightColors[rand() % BrightColorsCount];
89        paint.setColor(randomColor);
90        canvas.drawCircle(size / 2, size / 2, size / 2, paint);
91
92        bool bgDark = SkColorGetR(randomColor) + SkColorGetG(randomColor) + SkColorGetB(randomColor)
93                < 128 * 3;
94        paint.setColor(bgDark ? Color::White : Color::Grey_700);
95        paint.setTextAlign(SkPaint::kCenter_Align);
96        paint.setTextSize(size / 2);
97        char charToShow = 'A' + (rand() % 26);
98        canvas.drawText(&charToShow, 1, size / 2, /*approximate centering*/ size * 0.7, paint);
99        return bitmap;
100    }
101
102    static SkBitmap createBoxBitmap(bool filled) {
103        int size = dp(20);
104        int stroke = dp(2);
105        SkBitmap bitmap = TestUtils::createSkBitmap(size, size);
106        SkCanvas canvas(bitmap);
107        canvas.clear(Color::Transparent);
108
109        SkPaint paint;
110        paint.setAntiAlias(true);
111        paint.setColor(filled ? Color::Yellow_500 : Color::Grey_700);
112        paint.setStyle(filled ? SkPaint::kStrokeAndFill_Style : SkPaint::kStroke_Style);
113        paint.setStrokeWidth(stroke);
114        canvas.drawRect(SkRect::MakeLTRB(stroke, stroke, size - stroke, size - stroke), paint);
115        return bitmap;
116    }
117
118    sp<RenderNode> createCard(int cardId, int top) {
119        return TestUtils::createNode(cardLeft, top, cardLeft + cardWidth, top + cardHeight,
120                [this, cardId](RenderProperties& props, TestCanvas& canvas) {
121            static SkBitmap filledBox = createBoxBitmap(true);
122            static SkBitmap strokedBox = createBoxBitmap(false);
123
124            props.mutableOutline().setRoundRect(0, 0, cardWidth, cardHeight, dp(6), 1);
125            props.mutableOutline().setShouldClip(true);
126            canvas.drawColor(Color::White, SkXfermode::kSrcOver_Mode);
127
128            SkPaint textPaint;
129            textPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
130            textPaint.setColor(rand() % 2 ? Color::Black : Color::Grey_500);
131            textPaint.setTextSize(dp(20));
132            textPaint.setAntiAlias(true);
133            char buf[256];
134            snprintf(buf, sizeof(buf), "This card is #%d", cardId);
135            TestUtils::drawTextToCanvas(&canvas, buf, textPaint, cardHeight, dp(25));
136            textPaint.setTextSize(dp(15));
137            TestUtils::drawTextToCanvas(&canvas, "This is some more text on the card", textPaint,
138                    cardHeight, dp(45));
139
140            canvas.drawBitmap(createRandomCharIcon(), dp(10), dp(10), nullptr);
141
142            const SkBitmap& boxBitmap = rand() % 2 ? filledBox : strokedBox;
143            canvas.drawBitmap(boxBitmap, cardWidth - dp(10) - boxBitmap.width(), dp(10), nullptr);
144        });
145    }
146};
147