SkiaRecordingCanvas.cpp revision f5a370e097eb5bc29198dc53f956ba07f72842e5
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#include <SkImagePriv.h> 25 26namespace android { 27namespace uirenderer { 28namespace skiapipeline { 29 30// ---------------------------------------------------------------------------- 31// Recording Canvas Setup 32// ---------------------------------------------------------------------------- 33 34void SkiaRecordingCanvas::initDisplayList(uirenderer::RenderNode* renderNode, int width, 35 int height) { 36 mCurrentBarrier = nullptr; 37 SkASSERT(mDisplayList.get() == nullptr); 38 39 if (renderNode) { 40 mDisplayList = renderNode->detachAvailableList(); 41 } 42 if (!mDisplayList) { 43 mDisplayList.reset(new SkiaDisplayList()); 44 } 45 46 mDisplayList->attachRecorder(&mRecorder, SkIRect::MakeWH(width, height)); 47 SkiaCanvas::reset(&mRecorder); 48} 49 50uirenderer::DisplayList* SkiaRecordingCanvas::finishRecording() { 51 // close any existing chunks if necessary 52 insertReorderBarrier(false); 53 mRecorder.restoreToCount(1); 54 return mDisplayList.release(); 55} 56 57// ---------------------------------------------------------------------------- 58// Recording Canvas draw operations: View System 59// ---------------------------------------------------------------------------- 60 61void SkiaRecordingCanvas::drawRoundRect(uirenderer::CanvasPropertyPrimitive* left, 62 uirenderer::CanvasPropertyPrimitive* top, uirenderer::CanvasPropertyPrimitive* right, 63 uirenderer::CanvasPropertyPrimitive* bottom, uirenderer::CanvasPropertyPrimitive* rx, 64 uirenderer::CanvasPropertyPrimitive* ry, uirenderer::CanvasPropertyPaint* paint) { 65 // Destructor of drawables created with allocateDrawable, will be invoked by ~LinearAllocator. 66 drawDrawable(mDisplayList->allocateDrawable<AnimatedRoundRect>(left, top, right, bottom, 67 rx, ry, paint)); 68} 69 70void SkiaRecordingCanvas::drawCircle(uirenderer::CanvasPropertyPrimitive* x, 71 uirenderer::CanvasPropertyPrimitive* y, uirenderer::CanvasPropertyPrimitive* radius, 72 uirenderer::CanvasPropertyPaint* paint) { 73 drawDrawable(mDisplayList->allocateDrawable<AnimatedCircle>(x, y, radius, paint)); 74} 75 76void SkiaRecordingCanvas::insertReorderBarrier(bool enableReorder) { 77 if (nullptr != mCurrentBarrier) { 78 // finish off the existing chunk 79 SkDrawable* drawable = 80 mDisplayList->allocateDrawable<EndReorderBarrierDrawable>( 81 mCurrentBarrier); 82 mCurrentBarrier = nullptr; 83 drawDrawable(drawable); 84 } 85 if (enableReorder) { 86 mCurrentBarrier = (StartReorderBarrierDrawable*) 87 mDisplayList->allocateDrawable<StartReorderBarrierDrawable>( 88 mDisplayList.get()); 89 drawDrawable(mCurrentBarrier); 90 } 91} 92 93void SkiaRecordingCanvas::drawLayer(uirenderer::DeferredLayerUpdater* layerUpdater) { 94 if (layerUpdater != nullptr) { 95 // Create a ref-counted drawable, which is kept alive by sk_sp in SkLiteDL. 96 sk_sp<SkDrawable> drawable(new LayerDrawable(layerUpdater)); 97 drawDrawable(drawable.get()); 98 } 99} 100 101void SkiaRecordingCanvas::drawRenderNode(uirenderer::RenderNode* renderNode) { 102 // Record the child node. Drawable dtor will be invoked when mChildNodes deque is cleared. 103 mDisplayList->mChildNodes.emplace_back(renderNode, asSkCanvas(), true, mCurrentBarrier); 104 auto& renderNodeDrawable = mDisplayList->mChildNodes.back(); 105 drawDrawable(&renderNodeDrawable); 106 107 // use staging property, since recording on UI thread 108 if (renderNode->stagingProperties().isProjectionReceiver()) { 109 mDisplayList->mProjectionReceiver = &renderNodeDrawable; 110 // set projectionReceiveIndex so that RenderNode.hasProjectionReceiver returns true 111 mDisplayList->projectionReceiveIndex = mDisplayList->mChildNodes.size() - 1; 112 } 113} 114 115void SkiaRecordingCanvas::callDrawGLFunction(Functor* functor, 116 uirenderer::GlFunctorLifecycleListener* listener) { 117 // Drawable dtor will be invoked when mChildFunctors deque is cleared. 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 mRoot->draw(canvas); 132 } 133 134 private: 135 sp<VectorDrawableRoot> mRoot; 136}; 137 138void SkiaRecordingCanvas::drawVectorDrawable(VectorDrawableRoot* tree) { 139 drawDrawable(mDisplayList->allocateDrawable<VectorDrawable>(tree)); 140 mDisplayList->mVectorDrawables.push_back(tree); 141} 142 143// ---------------------------------------------------------------------------- 144// Recording Canvas draw operations: Bitmaps 145// ---------------------------------------------------------------------------- 146 147inline static const SkPaint* nonAAPaint(const SkPaint* origPaint, SkPaint* tmpPaint) { 148 if (origPaint && origPaint->isAntiAlias()) { 149 *tmpPaint = *origPaint; 150 tmpPaint->setAntiAlias(false); 151 return tmpPaint; 152 } else { 153 return origPaint; 154 } 155} 156 157void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, float left, float top, const SkPaint* paint) { 158 sk_sp<SkImage> image = bitmap.makeImage(); 159 SkPaint tmpPaint; 160 mRecorder.drawImage(image, left, top, nonAAPaint(paint, &tmpPaint)); 161 // if image->unique() is true, then mRecorder.drawImage failed for some reason. It also means 162 // it is not safe to store a raw SkImage pointer, because the image object will be destroyed 163 // when this function ends. 164 if (!bitmap.isImmutable() && image.get() && !image->unique()) { 165 mDisplayList->mMutableImages.push_back(image.get()); 166 } 167} 168 169void SkiaRecordingCanvas::drawBitmap(Bitmap& hwuiBitmap, const SkMatrix& matrix, 170 const SkPaint* paint) { 171 SkAutoCanvasRestore acr(&mRecorder, true); 172 concat(matrix); 173 sk_sp<SkImage> image = hwuiBitmap.makeImage(); 174 SkPaint tmpPaint; 175 mRecorder.drawImage(image, 0, 0, nonAAPaint(paint, &tmpPaint)); 176 if (!hwuiBitmap.isImmutable() && image.get() && !image->unique()) { 177 mDisplayList->mMutableImages.push_back(image.get()); 178 } 179} 180 181void SkiaRecordingCanvas::drawBitmap(Bitmap& hwuiBitmap, float srcLeft, float srcTop, 182 float srcRight, float srcBottom, float dstLeft, float dstTop, float dstRight, 183 float dstBottom, const SkPaint* paint) { 184 SkRect srcRect = SkRect::MakeLTRB(srcLeft, srcTop, srcRight, srcBottom); 185 SkRect dstRect = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom); 186 sk_sp<SkImage> image = hwuiBitmap.makeImage(); 187 SkPaint tmpPaint; 188 mRecorder.drawImageRect(image, srcRect, dstRect, nonAAPaint(paint, &tmpPaint)); 189 if (!hwuiBitmap.isImmutable() && image.get() && !image->unique() && !srcRect.isEmpty() 190 && !dstRect.isEmpty()) { 191 mDisplayList->mMutableImages.push_back(image.get()); 192 } 193} 194 195void SkiaRecordingCanvas::drawNinePatch(Bitmap& hwuiBitmap, const Res_png_9patch& chunk, 196 float dstLeft, float dstTop, float dstRight, float dstBottom, const SkPaint* paint) { 197 SkCanvas::Lattice lattice; 198 NinePatchUtils::SetLatticeDivs(&lattice, chunk, hwuiBitmap.width(), hwuiBitmap.height()); 199 200 lattice.fFlags = nullptr; 201 int numFlags = 0; 202 if (chunk.numColors > 0 && chunk.numColors == NinePatchUtils::NumDistinctRects(lattice)) { 203 // We can expect the framework to give us a color for every distinct rect. 204 // Skia requires placeholder flags for degenerate rects. 205 numFlags = (lattice.fXCount + 1) * (lattice.fYCount + 1); 206 } 207 208 SkAutoSTMalloc<25, SkCanvas::Lattice::Flags> flags(numFlags); 209 if (numFlags > 0) { 210 NinePatchUtils::SetLatticeFlags(&lattice, flags.get(), numFlags, chunk); 211 } 212 213 lattice.fBounds = nullptr; 214 SkRect dst = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom); 215 sk_sp<SkImage> image = hwuiBitmap.makeImage(); 216 217 SkPaint tmpPaint; 218 mRecorder.drawImageLattice(image.get(), lattice, dst, nonAAPaint(paint, &tmpPaint)); 219 if (!hwuiBitmap.isImmutable() && image.get() && !image->unique() && !dst.isEmpty()) { 220 mDisplayList->mMutableImages.push_back(image.get()); 221 } 222} 223 224}; // namespace skiapipeline 225}; // namespace uirenderer 226}; // namespace android 227