Home | History | Annotate | Download | only in scenes
      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 
     22 class ListViewAnimation;
     23 
     24 static TestScene::Registrar _ListView(TestScene::Info{
     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     TestScene::simpleCreateScene<ListViewAnimation>
     29 });
     30 
     31 class ListViewAnimation : public TestScene {
     32 public:
     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(
     66                 listView->stagingProperties().getWidth(),
     67                 listView->stagingProperties().getHeight());
     68         for (size_t ci = 0; ci < cards.size(); ci++) {
     69             // update card position
     70             auto card = cards[(ci + cardIndexOffset) % cards.size()];
     71             int top = ((int)ci) * (cardSpacing + cardHeight) + pxOffset;
     72             card->mutateStagingProperties().setLeftTopRightBottom(
     73                     cardLeft, top, cardLeft + cardWidth, top + cardHeight);
     74             card->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
     75 
     76             // draw it to parent DisplayList
     77             canvas.drawRenderNode(cards[ci].get());
     78         }
     79         listView->setStagingDisplayList(canvas.finishRecording(), nullptr);
     80     }
     81 private:
     82     SkBitmap createRandomCharIcon() {
     83         int size = cardHeight - (dp(10) * 2);
     84         SkBitmap bitmap = TestUtils::createSkBitmap(size, size);
     85         SkCanvas canvas(bitmap);
     86         canvas.clear(0);
     87 
     88         SkPaint paint;
     89         paint.setAntiAlias(true);
     90         SkColor randomColor = BrightColors[rand() % BrightColorsCount];
     91         paint.setColor(randomColor);
     92         canvas.drawCircle(size / 2, size / 2, size / 2, paint);
     93 
     94         bool bgDark = SkColorGetR(randomColor) + SkColorGetG(randomColor) + SkColorGetB(randomColor)
     95                 < 128 * 3;
     96         paint.setColor(bgDark ? Color::White : Color::Grey_700);
     97         paint.setTextAlign(SkPaint::kCenter_Align);
     98         paint.setTextSize(size / 2);
     99         char charToShow = 'A' + (rand() % 26);
    100         canvas.drawText(&charToShow, 1, size / 2, /*approximate centering*/ size * 0.7, paint);
    101         return bitmap;
    102     }
    103 
    104     static SkBitmap createBoxBitmap(bool filled) {
    105         int size = dp(20);
    106         int stroke = dp(2);
    107         SkBitmap bitmap = TestUtils::createSkBitmap(size, size);
    108         SkCanvas canvas(bitmap);
    109         canvas.clear(Color::Transparent);
    110 
    111         SkPaint paint;
    112         paint.setAntiAlias(true);
    113         paint.setColor(filled ? Color::Yellow_500 : Color::Grey_700);
    114         paint.setStyle(filled ? SkPaint::kStrokeAndFill_Style : SkPaint::kStroke_Style);
    115         paint.setStrokeWidth(stroke);
    116         canvas.drawRect(SkRect::MakeLTRB(stroke, stroke, size - stroke, size - stroke), paint);
    117         return bitmap;
    118     }
    119 
    120     sp<RenderNode> createCard(int cardId, int top) {
    121         return TestUtils::createNode(cardLeft, top, cardLeft + cardWidth, top + cardHeight,
    122                 [this, cardId](RenderProperties& props, TestCanvas& canvas) {
    123             static SkBitmap filledBox = createBoxBitmap(true);
    124             static SkBitmap strokedBox = createBoxBitmap(false);
    125 
    126             // TODO: switch to using round rect clipping, once merging correctly handles that
    127             SkPaint roundRectPaint;
    128             roundRectPaint.setAntiAlias(true);
    129             roundRectPaint.setColor(Color::White);
    130             canvas.drawRoundRect(0, 0, cardWidth, cardHeight, dp(6), dp(6), roundRectPaint);
    131 
    132             SkPaint textPaint;
    133             textPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
    134             textPaint.setColor(rand() % 2 ? Color::Black : Color::Grey_500);
    135             textPaint.setTextSize(dp(20));
    136             textPaint.setAntiAlias(true);
    137             char buf[256];
    138             snprintf(buf, sizeof(buf), "This card is #%d", cardId);
    139             TestUtils::drawUtf8ToCanvas(&canvas, buf, textPaint, cardHeight, dp(25));
    140             textPaint.setTextSize(dp(15));
    141             TestUtils::drawUtf8ToCanvas(&canvas, "This is some more text on the card", textPaint,
    142                     cardHeight, dp(45));
    143 
    144             canvas.drawBitmap(createRandomCharIcon(), dp(10), dp(10), nullptr);
    145 
    146             const SkBitmap& boxBitmap = rand() % 2 ? filledBox : strokedBox;
    147             canvas.drawBitmap(boxBitmap, cardWidth - dp(10) - boxBitmap.width(), dp(10), nullptr);
    148         });
    149     }
    150 };
    151