• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 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 "SkBlendMode.h"
18 #include "TestSceneBase.h"
19 #include "tests/common/BitmapAllocationTestUtils.h"
20 #include "hwui/Paint.h"
21 
22 class TvApp;
23 class TvAppNoRoundedCorner;
24 class TvAppColorFilter;
25 class TvAppNoRoundedCornerColorFilter;
26 
27 static bool _TvApp(BitmapAllocationTestUtils::registerBitmapAllocationScene<TvApp>(
28         "tvapp",
29         "A dense grid of cards:"
30         "with rounded corner, using overlay RenderNode for dimming."));
31 
32 static bool _TvAppNoRoundedCorner(
33         BitmapAllocationTestUtils::registerBitmapAllocationScene<TvAppNoRoundedCorner>(
34                 "tvapp_norc",
35                 "A dense grid of cards:"
36                 "no rounded corner, using overlay RenderNode for dimming"));
37 
38 static bool _TvAppColorFilter(
39         BitmapAllocationTestUtils::registerBitmapAllocationScene<TvAppColorFilter>(
40                 "tvapp_cf",
41                 "A dense grid of cards:"
42                 "with rounded corner, using ColorFilter for dimming"));
43 
44 static bool _TvAppNoRoundedCornerColorFilter(
45         BitmapAllocationTestUtils::registerBitmapAllocationScene<TvAppNoRoundedCornerColorFilter>(
46                 "tvapp_norc_cf",
47                 "A dense grid of cards:"
48                 "no rounded corner, using ColorFilter for dimming"));
49 
50 class TvApp : public TestScene {
51 public:
TvApp(BitmapAllocationTestUtils::BitmapAllocator allocator)52     explicit TvApp(BitmapAllocationTestUtils::BitmapAllocator allocator)
53             : TestScene(), mAllocator(allocator) {}
54 
55     sp<RenderNode> mBg;
56     std::vector<sp<RenderNode>> mCards;
57     std::vector<sp<RenderNode>> mInfoAreas;
58     std::vector<sp<RenderNode>> mImages;
59     std::vector<sp<RenderNode>> mOverlays;
60     std::vector<sk_sp<Bitmap>> mCachedBitmaps;
61     BitmapAllocationTestUtils::BitmapAllocator mAllocator;
62     sk_sp<Bitmap> mSingleBitmap;
63     int mSeed = 0;
64     int mSeed2 = 0;
65 
createContent(int width,int height,Canvas & canvas)66     void createContent(int width, int height, Canvas& canvas) override {
67         mBg = createBitmapNode(canvas, 0xFF9C27B0, 0, 0, width, height);
68         canvas.drawRenderNode(mBg.get());
69 
70         canvas.enableZ(true);
71         mSingleBitmap = mAllocator(dp(160), dp(120), kRGBA_8888_SkColorType,
72                                    [](SkBitmap& skBitmap) { skBitmap.eraseColor(0xFF0000FF); });
73 
74         for (int y = dp(18) - dp(178); y < height - dp(18); y += dp(178)) {
75             bool isFirstCard = true;
76             for (int x = dp(18); x < width - dp(18); x += dp(178)) {
77                 sp<RenderNode> card = createCard(x, y, dp(160), dp(160), isFirstCard);
78                 isFirstCard = false;
79                 canvas.drawRenderNode(card.get());
80                 mCards.push_back(card);
81             }
82         }
83         canvas.enableZ(false);
84     }
85 
doFrame(int frameNr)86     void doFrame(int frameNr) override {
87         size_t numCards = mCards.size();
88         for (size_t ci = 0; ci < numCards; ci++) {
89             updateCard(ci, frameNr);
90         }
91     }
92 
93 private:
createBitmapNode(Canvas & canvas,SkColor color,int left,int top,int width,int height)94     sp<RenderNode> createBitmapNode(Canvas& canvas, SkColor color, int left, int top, int width,
95                                     int height) {
96         return TestUtils::createNode(
97                 left, top, left + width, top + height,
98                 [this, width, height, color](RenderProperties& props, Canvas& canvas) {
99                     sk_sp<Bitmap> bitmap =
100                             mAllocator(width, height, kRGBA_8888_SkColorType,
101                                        [color](SkBitmap& skBitmap) { skBitmap.eraseColor(color); });
102                     canvas.drawBitmap(*bitmap, 0, 0, nullptr);
103                 });
104     }
105 
createSharedBitmapNode(Canvas & canvas,int left,int top,int width,int height,sk_sp<Bitmap> bitmap)106     sp<RenderNode> createSharedBitmapNode(Canvas& canvas, int left, int top, int width, int height,
107                                           sk_sp<Bitmap> bitmap) {
108         return TestUtils::createNode(left, top, left + width, top + height,
109                                      [bitmap](RenderProperties& props, Canvas& canvas) {
110                                          canvas.drawBitmap(*bitmap, 0, 0, nullptr);
111                                      });
112     }
113 
createInfoNode(Canvas & canvas,int left,int top,int width,int height,const char * text,const char * text2)114     sp<RenderNode> createInfoNode(Canvas& canvas, int left, int top, int width, int height,
115                                   const char* text, const char* text2) {
116         return TestUtils::createNode(left, top, left + width, top + height,
117                                      [text, text2](RenderProperties& props, Canvas& canvas) {
118                                          canvas.drawColor(0xFFFFEEEE, SkBlendMode::kSrcOver);
119 
120                                          Paint paint;
121                                          paint.setAntiAlias(true);
122                                          paint.getSkFont().setSize(24);
123 
124                                          paint.setColor(Color::Black);
125                                          TestUtils::drawUtf8ToCanvas(&canvas, text, paint, 10, 30);
126                                          paint.getSkFont().setSize(20);
127                                          TestUtils::drawUtf8ToCanvas(&canvas, text2, paint, 10, 54);
128 
129                                      });
130     }
131 
createColorNode(Canvas & canvas,int left,int top,int width,int height,SkColor color)132     sp<RenderNode> createColorNode(Canvas& canvas, int left, int top, int width, int height,
133                                    SkColor color) {
134         return TestUtils::createNode(left, top, left + width, top + height,
135                                      [color](RenderProperties& props, Canvas& canvas) {
136                                          canvas.drawColor(color, SkBlendMode::kSrcOver);
137                                      });
138     }
139 
useSingleBitmap()140     virtual bool useSingleBitmap() { return false; }
141 
roundedCornerRadius()142     virtual float roundedCornerRadius() { return dp(2); }
143 
144     // when true, use overlay RenderNode for dimming, otherwise apply a ColorFilter to dim image
useOverlay()145     virtual bool useOverlay() { return true; }
146 
createCard(int x,int y,int width,int height,bool selected)147     sp<RenderNode> createCard(int x, int y, int width, int height, bool selected) {
148         return TestUtils::createNode(x, y, x + width, y + height, [width, height, selected, this](
149                                                                           RenderProperties& props,
150                                                                           Canvas& canvas) {
151             if (selected) {
152                 props.setElevation(dp(16));
153                 props.setScaleX(1.2);
154                 props.setScaleY(1.2);
155             }
156             props.mutableOutline().setRoundRect(0, 0, width, height, roundedCornerRadius(), 1);
157             props.mutableOutline().setShouldClip(true);
158 
159             sk_sp<Bitmap> bitmap =
160                     useSingleBitmap() ? mSingleBitmap
161                                       : mAllocator(width, dp(120), kRGBA_8888_SkColorType,
162                                                    [this](SkBitmap& skBitmap) {
163                                                        skBitmap.eraseColor(0xFF000000 |
164                                                                            ((mSeed << 3) & 0xFF));
165                                                    });
166             sp<RenderNode> cardImage = createSharedBitmapNode(canvas, 0, 0, width, dp(120), bitmap);
167             canvas.drawRenderNode(cardImage.get());
168             mCachedBitmaps.push_back(bitmap);
169             mImages.push_back(cardImage);
170 
171             char buffer[128];
172             sprintf(buffer, "Video %d-%d", mSeed, mSeed + 1);
173             mSeed++;
174             char buffer2[128];
175             sprintf(buffer2, "Studio %d", mSeed2++);
176             sp<RenderNode> infoArea =
177                     createInfoNode(canvas, 0, dp(120), width, height, buffer, buffer2);
178             canvas.drawRenderNode(infoArea.get());
179             mInfoAreas.push_back(infoArea);
180 
181             if (useOverlay()) {
182                 sp<RenderNode> overlayColor =
183                         createColorNode(canvas, 0, 0, width, height, 0x00000000);
184                 canvas.drawRenderNode(overlayColor.get());
185                 mOverlays.push_back(overlayColor);
186             }
187         });
188     }
189 
updateCard(int ci,int curFrame)190     void updateCard(int ci, int curFrame) {
191         // updating card's translation Y
192         sp<RenderNode> card = mCards[ci];
193         card->setPropertyFieldsDirty(RenderNode::Y);
194         card->mutateStagingProperties().setTranslationY(curFrame % 150);
195 
196         // re-recording card's canvas, not necessary but to add some burden to CPU
197         std::unique_ptr<Canvas> cardcanvas(Canvas::create_recording_canvas(
198                 card->stagingProperties().getWidth(), card->stagingProperties().getHeight(),
199                 card.get()));
200         sp<RenderNode> image = mImages[ci];
201         sp<RenderNode> infoArea = mInfoAreas[ci];
202         cardcanvas->drawRenderNode(infoArea.get());
203 
204         if (useOverlay()) {
205             cardcanvas->drawRenderNode(image.get());
206             // re-recording card overlay's canvas, animating overlay color alpha
207             sp<RenderNode> overlay = mOverlays[ci];
208             std::unique_ptr<Canvas> canvas(
209                     Canvas::create_recording_canvas(overlay->stagingProperties().getWidth(),
210                                                     overlay->stagingProperties().getHeight(),
211                                                     overlay.get()));
212             canvas->drawColor((curFrame % 150) << 24, SkBlendMode::kSrcOver);
213             canvas->finishRecording(overlay.get());
214             cardcanvas->drawRenderNode(overlay.get());
215         } else {
216             // re-recording image node's canvas, animating ColorFilter
217             std::unique_ptr<Canvas> canvas(Canvas::create_recording_canvas(
218                     image->stagingProperties().getWidth(), image->stagingProperties().getHeight(),
219                     image.get()));
220             Paint paint;
221             sk_sp<SkColorFilter> filter(
222                     SkColorFilters::Blend((curFrame % 150) << 24, SkBlendMode::kSrcATop));
223             paint.setColorFilter(filter);
224             sk_sp<Bitmap> bitmap = mCachedBitmaps[ci];
225             canvas->drawBitmap(*bitmap, 0, 0, &paint);
226             canvas->finishRecording(image.get());
227             cardcanvas->drawRenderNode(image.get());
228         }
229 
230         cardcanvas->finishRecording(card.get());
231     }
232 };
233 
234 class TvAppNoRoundedCorner : public TvApp {
235 public:
TvAppNoRoundedCorner(BitmapAllocationTestUtils::BitmapAllocator allocator)236     explicit TvAppNoRoundedCorner(BitmapAllocationTestUtils::BitmapAllocator allocator) : TvApp(allocator) {}
237 
238 private:
roundedCornerRadius()239     virtual float roundedCornerRadius() override { return dp(0); }
240 };
241 
242 class TvAppColorFilter : public TvApp {
243 public:
TvAppColorFilter(BitmapAllocationTestUtils::BitmapAllocator allocator)244     explicit TvAppColorFilter(BitmapAllocationTestUtils::BitmapAllocator allocator) : TvApp(allocator) {}
245 
246 private:
useOverlay()247     virtual bool useOverlay() override { return false; }
248 };
249 
250 class TvAppNoRoundedCornerColorFilter : public TvApp {
251 public:
TvAppNoRoundedCornerColorFilter(BitmapAllocationTestUtils::BitmapAllocator allocator)252     explicit TvAppNoRoundedCornerColorFilter(BitmapAllocationTestUtils::BitmapAllocator allocator)
253             : TvApp(allocator) {}
254 
255 private:
roundedCornerRadius()256     virtual float roundedCornerRadius() override { return dp(0); }
257 
useOverlay()258     virtual bool useOverlay() override { return false; }
259 };
260