SkiaRecordingCanvas.cpp revision 88e0891f6657573a5ad918c2d76d6c02bb8ceba3
1/* 2 * Copyright (C) 2016 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 "SkiaRecordingCanvas.h" 18 19#include "Layer.h" 20#include "RenderNode.h" 21#include "LayerDrawable.h" 22#include "NinePatchUtils.h" 23#include "pipeline/skia/AnimatedDrawables.h" 24 25namespace android { 26namespace uirenderer { 27namespace skiapipeline { 28 29// ---------------------------------------------------------------------------- 30// Recording Canvas Setup 31// ---------------------------------------------------------------------------- 32 33void SkiaRecordingCanvas::initDisplayList(uirenderer::RenderNode* renderNode, int width, 34 int height) { 35 mCurrentBarrier = nullptr; 36 SkASSERT(mDisplayList.get() == nullptr); 37 38 if (renderNode) { 39 mDisplayList = renderNode->detachAvailableList(); 40 } 41 SkRect bounds = SkRect::MakeWH(width, height); 42 if (mDisplayList) { 43 mDisplayList->reset(bounds); 44 } else { 45 mDisplayList.reset(new SkiaDisplayList(bounds)); 46 } 47 48 mRecorder.reset(mDisplayList->mDrawable.get()); 49 SkiaCanvas::reset(&mRecorder); 50} 51 52uirenderer::DisplayList* SkiaRecordingCanvas::finishRecording() { 53 // close any existing chunks if necessary 54 insertReorderBarrier(false); 55 mRecorder.restoreToCount(1); 56 return mDisplayList.release(); 57} 58 59// ---------------------------------------------------------------------------- 60// Recording Canvas draw operations: View System 61// ---------------------------------------------------------------------------- 62 63void SkiaRecordingCanvas::drawRoundRect(uirenderer::CanvasPropertyPrimitive* left, 64 uirenderer::CanvasPropertyPrimitive* top, uirenderer::CanvasPropertyPrimitive* right, 65 uirenderer::CanvasPropertyPrimitive* bottom, uirenderer::CanvasPropertyPrimitive* rx, 66 uirenderer::CanvasPropertyPrimitive* ry, uirenderer::CanvasPropertyPaint* paint) { 67 drawDrawable(mDisplayList->allocateDrawable<AnimatedRoundRect>(left, top, right, bottom, 68 rx, ry, paint)); 69} 70 71void SkiaRecordingCanvas::drawCircle(uirenderer::CanvasPropertyPrimitive* x, 72 uirenderer::CanvasPropertyPrimitive* y, uirenderer::CanvasPropertyPrimitive* radius, 73 uirenderer::CanvasPropertyPaint* paint) { 74 drawDrawable(mDisplayList->allocateDrawable<AnimatedCircle>(x, y, radius, paint)); 75} 76 77void SkiaRecordingCanvas::insertReorderBarrier(bool enableReorder) { 78 if (nullptr != mCurrentBarrier) { 79 // finish off the existing chunk 80 SkDrawable* drawable = 81 mDisplayList->allocateDrawable<EndReorderBarrierDrawable>( 82 mCurrentBarrier); 83 mCurrentBarrier = nullptr; 84 drawDrawable(drawable); 85 } 86 if (enableReorder) { 87 mCurrentBarrier = (StartReorderBarrierDrawable*) 88 mDisplayList->allocateDrawable<StartReorderBarrierDrawable>( 89 mDisplayList.get()); 90 drawDrawable(mCurrentBarrier); 91 } 92} 93 94void SkiaRecordingCanvas::drawLayer(uirenderer::DeferredLayerUpdater* layerUpdater) { 95 if (layerUpdater != nullptr && layerUpdater->backingLayer() != nullptr) { 96 uirenderer::Layer* layer = layerUpdater->backingLayer(); 97 sk_sp<SkDrawable> drawable(new LayerDrawable(layer)); 98 drawDrawable(drawable.get()); 99 } 100} 101 102void SkiaRecordingCanvas::drawRenderNode(uirenderer::RenderNode* renderNode) { 103 // record the child node 104 mDisplayList->mChildNodes.emplace_back(renderNode, asSkCanvas(), true, mCurrentBarrier); 105 auto& renderNodeDrawable = mDisplayList->mChildNodes.back(); 106 drawDrawable(&renderNodeDrawable); 107 108 // use staging property, since recording on UI thread 109 if (renderNode->stagingProperties().isProjectionReceiver()) { 110 mDisplayList->mProjectionReceiver = &renderNodeDrawable; 111 // set projectionReceiveIndex so that RenderNode.hasProjectionReceiver returns true 112 mDisplayList->projectionReceiveIndex = mDisplayList->mChildNodes.size() - 1; 113 } 114} 115 116void SkiaRecordingCanvas::callDrawGLFunction(Functor* functor, 117 uirenderer::GlFunctorLifecycleListener* listener) { 118 mDisplayList->mChildFunctors.emplace_back(functor, listener, asSkCanvas()); 119 drawDrawable(&mDisplayList->mChildFunctors.back()); 120} 121 122class VectorDrawable : public SkDrawable { 123 public: 124 VectorDrawable(VectorDrawableRoot* tree) : mRoot(tree) {} 125 126 protected: 127 virtual SkRect onGetBounds() override { 128 return SkRect::MakeLargest(); 129 } 130 virtual void onDraw(SkCanvas* canvas) override { 131 Bitmap& hwuiBitmap = mRoot->getBitmapUpdateIfDirty(); 132 SkBitmap bitmap; 133 hwuiBitmap.getSkBitmap(&bitmap); 134 SkPaint* paint = mRoot->getPaint(); 135 canvas->drawBitmapRect(bitmap, mRoot->mutateProperties()->getBounds(), paint); 136 /* 137 * TODO we can draw this directly but need to address the following... 138 * 139 * 1) Add drawDirect(SkCanvas*) to VectorDrawableRoot 140 * 2) fix VectorDrawable.cpp's Path::draw to not make a temporary path 141 * so that we don't break caching 142 * 3) figure out how to set path's as volatile during animation 143 * 4) if mRoot->getPaint() != null either promote to layer (during 144 * animation) or cache in SkSurface (for static content) 145 * 146 */ 147 } 148 149 private: 150 sp<VectorDrawableRoot> mRoot; 151}; 152 153void SkiaRecordingCanvas::drawVectorDrawable(VectorDrawableRoot* tree) { 154 drawDrawable(mDisplayList->allocateDrawable<VectorDrawable>(tree)); 155 mDisplayList->mVectorDrawables.push_back(tree); 156} 157 158// ---------------------------------------------------------------------------- 159// Recording Canvas draw operations: Bitmaps 160// ---------------------------------------------------------------------------- 161 162inline static const SkPaint* nonAAPaint(const SkPaint* origPaint, SkPaint* tmpPaint) { 163 if (origPaint && origPaint->isAntiAlias()) { 164 *tmpPaint = *origPaint; 165 tmpPaint->setAntiAlias(false); 166 return tmpPaint; 167 } else { 168 return origPaint; 169 } 170} 171 172void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, float left, float top, const SkPaint* paint) { 173 SkBitmap skBitmap; 174 bitmap.getSkBitmap(&skBitmap); 175 176 sk_sp<SkImage> image = SkMakeImageFromRasterBitmap(skBitmap, kNever_SkCopyPixelsMode); 177 if (!skBitmap.isImmutable()) { 178 mDisplayList->mMutableImages.push_back(image.get()); 179 } 180 SkPaint tmpPaint; 181 mRecorder.drawImage(image, left, top, nonAAPaint(paint, &tmpPaint)); 182} 183 184void SkiaRecordingCanvas::drawBitmap(Bitmap& hwuiBitmap, const SkMatrix& matrix, 185 const SkPaint* paint) { 186 SkBitmap bitmap; 187 hwuiBitmap.getSkBitmap(&bitmap); 188 SkAutoCanvasRestore acr(&mRecorder, true); 189 concat(matrix); 190 sk_sp<SkImage> image = SkMakeImageFromRasterBitmap(bitmap, kNever_SkCopyPixelsMode); 191 if (!bitmap.isImmutable()) { 192 mDisplayList->mMutableImages.push_back(image.get()); 193 } 194 SkPaint tmpPaint; 195 mRecorder.drawImage(image, 0, 0, nonAAPaint(paint, &tmpPaint)); 196} 197 198void SkiaRecordingCanvas::drawBitmap(Bitmap& hwuiBitmap, float srcLeft, float srcTop, 199 float srcRight, float srcBottom, float dstLeft, float dstTop, float dstRight, 200 float dstBottom, const SkPaint* paint) { 201 SkBitmap bitmap; 202 hwuiBitmap.getSkBitmap(&bitmap); 203 SkRect srcRect = SkRect::MakeLTRB(srcLeft, srcTop, srcRight, srcBottom); 204 SkRect dstRect = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom); 205 sk_sp<SkImage> image = SkMakeImageFromRasterBitmap(bitmap, kNever_SkCopyPixelsMode); 206 if (!bitmap.isImmutable()) { 207 mDisplayList->mMutableImages.push_back(image.get()); 208 } 209 SkPaint tmpPaint; 210 mRecorder.drawImageRect(image, srcRect, dstRect, nonAAPaint(paint, &tmpPaint)); 211} 212 213void SkiaRecordingCanvas::drawNinePatch(Bitmap& hwuiBitmap, const Res_png_9patch& chunk, 214 float dstLeft, float dstTop, float dstRight, float dstBottom, const SkPaint* paint) { 215 SkBitmap bitmap; 216 hwuiBitmap.getSkBitmap(&bitmap); 217 218 SkCanvas::Lattice lattice; 219 NinePatchUtils::SetLatticeDivs(&lattice, chunk, bitmap.width(), bitmap.height()); 220 221 lattice.fFlags = nullptr; 222 int numFlags = 0; 223 if (chunk.numColors > 0 && chunk.numColors == NinePatchUtils::NumDistinctRects(lattice)) { 224 // We can expect the framework to give us a color for every distinct rect. 225 // Skia requires placeholder flags for degenerate rects. 226 numFlags = (lattice.fXCount + 1) * (lattice.fYCount + 1); 227 } 228 229 SkAutoSTMalloc<25, SkCanvas::Lattice::Flags> flags(numFlags); 230 if (numFlags > 0) { 231 NinePatchUtils::SetLatticeFlags(&lattice, flags.get(), numFlags, chunk); 232 } 233 234 lattice.fBounds = nullptr; 235 SkRect dst = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom); 236 sk_sp<SkImage> image = SkMakeImageFromRasterBitmap(bitmap, kNever_SkCopyPixelsMode); 237 if (!bitmap.isImmutable()) { 238 mDisplayList->mMutableImages.push_back(image.get()); 239 } 240 241 SkPaint tmpPaint; 242 mRecorder.drawImageLattice(image.get(), lattice, dst, nonAAPaint(paint, &tmpPaint)); 243} 244 245}; // namespace skiapipeline 246}; // namespace uirenderer 247}; // namespace android 248