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