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