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