154fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik/*
254fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik * Copyright (C) 2015 The Android Open Source Project
354fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik *
454fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik * Licensed under the Apache License, Version 2.0 (the "License");
554fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik * you may not use this file except in compliance with the License.
654fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik * You may obtain a copy of the License at
754fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik *
854fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik *      http://www.apache.org/licenses/LICENSE-2.0
954fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik *
1054fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik * Unless required by applicable law or agreed to in writing, software
1154fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik * distributed under the License is distributed on an "AS IS" BASIS,
1254fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1354fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik * See the License for the specific language governing permissions and
1454fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik * limitations under the License.
1554fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik */
1654fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik
1754fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik#include "TestSceneBase.h"
1854fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik#include "utils/Color.h"
1954fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik
2054fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik#include <cstdio>
2154fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik
2254fa17f667c285a5c9225e238c8132dfe830ef36Chris Craikclass ListViewAnimation;
2354fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik
2427e58b4f54d693ff1db7ab2edb5d47ca296c1278Chris Craikstatic TestScene::Registrar _ListView(TestScene::Info{
2554fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik    "listview",
2654fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik    "A mock ListView of scrolling content. Doesn't re-bind/re-record views as they are recycled, so"
2754fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik    "won't upload much content (either glyphs, or bitmaps).",
2827e58b4f54d693ff1db7ab2edb5d47ca296c1278Chris Craik    TestScene::simpleCreateScene<ListViewAnimation>
2954fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik});
3054fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik
3154fa17f667c285a5c9225e238c8132dfe830ef36Chris Craikclass ListViewAnimation : public TestScene {
3254fa17f667c285a5c9225e238c8132dfe830ef36Chris Craikpublic:
3354fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik    int cardHeight;
3454fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik    int cardSpacing;
3554fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik    int cardWidth;
3654fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik    int cardLeft;
3754fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik    sp<RenderNode> listView;
3854fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik    std::vector< sp<RenderNode> > cards;
3954fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik    void createContent(int width, int height, TestCanvas& canvas) override {
4054fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik        srand(0);
4154fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik        cardHeight = dp(60);
4254fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik        cardSpacing = dp(16);
4354fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik        cardWidth = std::min((height - cardSpacing * 2), (int)dp(300));
4454fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik        cardLeft = (width - cardWidth) / 2;
4554fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik
4654fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik        for (int y = 0; y < height + (cardHeight + cardSpacing - 1); y += (cardHeight + cardSpacing)) {
4754fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik            cards.push_back(createCard(cards.size(), y));
4854fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik        }
4954fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik        listView = TestUtils::createNode(0, 0, width, height,
5054fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik                [this](RenderProperties& props, TestCanvas& canvas) {
5154fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik            for (size_t ci = 0; ci < cards.size(); ci++) {
5254fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik                canvas.drawRenderNode(cards[ci].get());
5354fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik            }
5454fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik        });
5554fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik
5654fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik        canvas.drawColor(Color::Grey_500, SkXfermode::kSrcOver_Mode);
5754fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik        canvas.drawRenderNode(listView.get());
5854fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik    }
5954fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik
6054fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik    void doFrame(int frameNr) override {
6154fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik        int scrollPx = dp(frameNr) * 3;
6254fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik        int cardIndexOffset = scrollPx / (cardSpacing + cardHeight);
6354fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik        int pxOffset = -(scrollPx % (cardSpacing + cardHeight));
6454fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik
6515c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik        TestCanvas canvas(
6615c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik                listView->stagingProperties().getWidth(),
6715c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik                listView->stagingProperties().getHeight());
6854fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik        for (size_t ci = 0; ci < cards.size(); ci++) {
6954fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik            // update card position
7054fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik            auto card = cards[(ci + cardIndexOffset) % cards.size()];
7154fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik            int top = ((int)ci) * (cardSpacing + cardHeight) + pxOffset;
7254fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik            card->mutateStagingProperties().setLeftTopRightBottom(
7354fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik                    cardLeft, top, cardLeft + cardWidth, top + cardHeight);
7454fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik            card->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
7554fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik
7654fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik            // draw it to parent DisplayList
7754fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik            canvas.drawRenderNode(cards[ci].get());
7854fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik        }
7951f2d606dcbfba3cc5b03dfea37c1304b91c232fJohn Reck        listView->setStagingDisplayList(canvas.finishRecording(), nullptr);
8054fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik    }
8154fa17f667c285a5c9225e238c8132dfe830ef36Chris Craikprivate:
8254fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik    SkBitmap createRandomCharIcon() {
8354fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik        int size = cardHeight - (dp(10) * 2);
8454fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik        SkBitmap bitmap = TestUtils::createSkBitmap(size, size);
8554fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik        SkCanvas canvas(bitmap);
8654fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik        canvas.clear(0);
8754fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik
8854fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik        SkPaint paint;
8954fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik        paint.setAntiAlias(true);
9054fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik        SkColor randomColor = BrightColors[rand() % BrightColorsCount];
9154fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik        paint.setColor(randomColor);
9254fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik        canvas.drawCircle(size / 2, size / 2, size / 2, paint);
9354fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik
9454fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik        bool bgDark = SkColorGetR(randomColor) + SkColorGetG(randomColor) + SkColorGetB(randomColor)
9554fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik                < 128 * 3;
9654fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik        paint.setColor(bgDark ? Color::White : Color::Grey_700);
9754fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik        paint.setTextAlign(SkPaint::kCenter_Align);
9854fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik        paint.setTextSize(size / 2);
9954fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik        char charToShow = 'A' + (rand() % 26);
10054fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik        canvas.drawText(&charToShow, 1, size / 2, /*approximate centering*/ size * 0.7, paint);
10154fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik        return bitmap;
10254fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik    }
10354fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik
10454fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik    static SkBitmap createBoxBitmap(bool filled) {
10554fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik        int size = dp(20);
10654fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik        int stroke = dp(2);
10754fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik        SkBitmap bitmap = TestUtils::createSkBitmap(size, size);
10854fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik        SkCanvas canvas(bitmap);
10954fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik        canvas.clear(Color::Transparent);
11054fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik
11154fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik        SkPaint paint;
11254fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik        paint.setAntiAlias(true);
11354fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik        paint.setColor(filled ? Color::Yellow_500 : Color::Grey_700);
11454fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik        paint.setStyle(filled ? SkPaint::kStrokeAndFill_Style : SkPaint::kStroke_Style);
11554fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik        paint.setStrokeWidth(stroke);
11654fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik        canvas.drawRect(SkRect::MakeLTRB(stroke, stroke, size - stroke, size - stroke), paint);
11754fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik        return bitmap;
11854fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik    }
11954fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik
12054fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik    sp<RenderNode> createCard(int cardId, int top) {
12154fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik        return TestUtils::createNode(cardLeft, top, cardLeft + cardWidth, top + cardHeight,
12254fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik                [this, cardId](RenderProperties& props, TestCanvas& canvas) {
12354fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik            static SkBitmap filledBox = createBoxBitmap(true);
12454fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik            static SkBitmap strokedBox = createBoxBitmap(false);
12554fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik
12615c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik            // TODO: switch to using round rect clipping, once merging correctly handles that
12715c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik            SkPaint roundRectPaint;
12815c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik            roundRectPaint.setAntiAlias(true);
12915c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik            roundRectPaint.setColor(Color::White);
13015c3f19a445b8df575911a16e8a6dba755a084b5Chris Craik            canvas.drawRoundRect(0, 0, cardWidth, cardHeight, dp(6), dp(6), roundRectPaint);
13154fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik
13254fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik            SkPaint textPaint;
13354fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik            textPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
13454fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik            textPaint.setColor(rand() % 2 ? Color::Black : Color::Grey_500);
13554fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik            textPaint.setTextSize(dp(20));
13654fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik            textPaint.setAntiAlias(true);
13754fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik            char buf[256];
13854fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik            snprintf(buf, sizeof(buf), "This card is #%d", cardId);
139dccca44ffda4836b56a21da95a046c9708ffd49csergeyv            TestUtils::drawUtf8ToCanvas(&canvas, buf, textPaint, cardHeight, dp(25));
14054fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik            textPaint.setTextSize(dp(15));
141dccca44ffda4836b56a21da95a046c9708ffd49csergeyv            TestUtils::drawUtf8ToCanvas(&canvas, "This is some more text on the card", textPaint,
14254fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik                    cardHeight, dp(45));
14354fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik
14454fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik            canvas.drawBitmap(createRandomCharIcon(), dp(10), dp(10), nullptr);
14554fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik
14654fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik            const SkBitmap& boxBitmap = rand() % 2 ? filledBox : strokedBox;
14754fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik            canvas.drawBitmap(boxBitmap, cardWidth - dp(10) - boxBitmap.width(), dp(10), nullptr);
14854fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik        });
14954fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik    }
15054fa17f667c285a5c9225e238c8132dfe830ef36Chris Craik};
151