privatebooleandrawSoftware(Surface surface, AttachInfo attachInfo, int xoff, int yoff, boolean scalingRequired, Rect dirty){
final Canvas canvas; try { finalint left = dirty.left; finalint top = dirty.top; finalint right = dirty.right; finalint bottom = dirty.bottom; //【1】锁定 canvas,并返回画布 Canvas; canvas = mSurface.lockCanvas(dirty);
// The dirty rectangle can be modified by Surface.lockCanvas() // noinspection ConstantConditions if (left != dirty.left || top != dirty.top || right != dirty.right || bottom != dirty.bottom) { attachInfo.mIgnoreDirtyState = true; }
// TODO: Do this in native canvas.setDensity(mDensity); } catch (Surface.OutOfResourcesException e) { handleOutOfResourcesException(e); returnfalse; } catch (IllegalArgumentException e) { Log.e(mTag, "Could not lock surface", e); // Don't assume this is due to out of memory, it could be // something else, and if it is something else then we could // kill stuff (or ourself) for no reason. mLayoutRequested = true; // ask wm for a new surface next time. returnfalse; }
drawAccessibilityFocusedDrawableIfNeeded(canvas); } finally { if (!attachInfo.mSetIgnoreDirtyState) { // Only clear the flag if it was not set during the mView.draw() call attachInfo.mIgnoreDirtyState = false; } } } finally { try { //【3】解锁 canvas surface.unlockCanvasAndPost(canvas); } catch (IllegalArgumentException e) { Log.e(mTag, "Could not unlock surface", e); mLayoutRequested = true; // ask wm for a new surface next time. //noinspection ReturnInsideFinallyBlock returnfalse; }
int left = mScrollX + paddingLeft; int right = left + mRight - mLeft - mPaddingRight - paddingLeft; int top = mScrollY + getFadeTop(offsetRequired); int bottom = top + getFadeHeight(offsetRequired);
if (offsetRequired) { right += getRightPaddingOffset(); bottom += getBottomPaddingOffset(); }
final ScrollabilityCache scrollabilityCache = mScrollCache; finalfloat fadeHeight = scrollabilityCache.fadingEdgeLength; int length = (int) fadeHeight;
// clip the fade length if top and bottom fades overlap // overlapping fades produce odd-looking artifacts if (verticalEdges && (top + length > bottom - length)) { length = (bottom - top) / 2; }
//【-->4.1.2】保存完 layer 后,我们先绘制当前 view 的内容; if (!dirtyOpaque) onDraw(canvas);
//【-->4.1.3】然后绘制 child 的内容; dispatchDraw(canvas);
//【11】绘制淡入淡出效果,并还原图层,淡入淡出实际上是在另外一个 layer 上绘制的; final Paint p = scrollabilityCache.paint; final Matrix matrix = scrollabilityCache.matrix; final Shader fade = scrollabilityCache.shader;
if (drawTop) { matrix.setScale(1, fadeHeight * topFadeStrength); matrix.postTranslate(left, top); fade.setLocalMatrix(matrix); p.setShader(fade); canvas.drawRect(left, top, right, top + length, p); }
int sx = 0; int sy = 0; if (!drawingWithRenderNode) { computeScroll(); sx = mScrollX; sy = mScrollY; } //【8】判断下是否使用缓存进行绘制(不是硬件绘制,可能是上面的 renderNode inValid 了,同时缓存不为 null) finalboolean drawingWithDrawingCache = cache != null && !drawingWithRenderNode; finalboolean offsetForScroll = cache == null && !drawingWithRenderNode;
int restoreTo = -1; if (!drawingWithRenderNode || transformToApply != null) { restoreTo = canvas.save(); } if (offsetForScroll) { canvas.translate(mLeft - sx, mTop - sy); } else { if (!drawingWithRenderNode) { canvas.translate(mLeft, mTop); } if (scalingRequired) { if (drawingWithRenderNode) { // TODO: Might not need this if we put everything inside the DL restoreTo = canvas.save(); } // mAttachInfo cannot be null, otherwise scalingRequired == false finalfloat scale = 1.0f / mAttachInfo.mApplicationScale; canvas.scale(scale, scale); } } //【9】处理 alpha 的变化; float alpha = drawingWithRenderNode ? 1 : (getAlpha() * getTransitionAlpha()); if (transformToApply != null || alpha < 1 || !hasIdentityMatrix() || (mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_ALPHA) != 0) { if (transformToApply != null || !childHasIdentityMatrix) { int transX = 0; int transY = 0;
if (offsetForScroll) { transX = -sx; transY = -sy; }
if (transformToApply != null) { if (concatMatrix) { if (drawingWithRenderNode) { renderNode.setAnimationMatrix(transformToApply.getMatrix()); } else { // Undo the scroll translation, apply the transformation matrix, // then redo the scroll translate to get the correct result. canvas.translate(-transX, -transY); canvas.concat(transformToApply.getMatrix()); canvas.translate(transX, transY); } parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION; }
//【11】如果不使用绘制缓存的话,会进行不同的处理; if (!drawingWithDrawingCache) { //【11.1】如果是硬件加速,这里会调用 DisplayListCanvas.drawRenderNode 方法,根据 // 收集到的 renderNode 树进行绘制; if (drawingWithRenderNode) { mPrivateFlags &= ~PFLAG_DIRTY_MASK; ((DisplayListCanvas) canvas).drawRenderNode(renderNode); } else { //【11.2】对于软件绘制,这里会判断下当前的 view 是否要跳过绘制; // 这里可能是硬件绘制被取消了,也可能就是软件绘制~~ if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { mPrivateFlags &= ~PFLAG_DIRTY_MASK; //【-->4.1.3】如果跳过绘制,那就会触发 dispatchDraw 方法; dispatchDraw(canvas); } else { //【-->4.1】如果需要绘制,就绘制自身,如果是 ViewGroup 的话,还会触发 dispatchDraw 方法; draw(canvas); } } } elseif (cache != null) { //【10.3】这里是使用绘制缓存,必须是软件绘制才行; mPrivateFlags &= ~PFLAG_DIRTY_MASK; if (layerType == LAYER_TYPE_NONE || mLayerPaint == null) { // no layer paint, use temporary paint to draw bitmap Paint cachePaint = parent.mCachePaint; if (cachePaint == null) { cachePaint = new Paint(); cachePaint.setDither(false); parent.mCachePaint = cachePaint; } cachePaint.setAlpha((int) (alpha * 255)); //【10.4】把存储 cpu 绘制缓存的 Bitmap 绘制到 canvas 上 ( skia 渲染引擎 ) // 下面也是一样的; canvas.drawBitmap(cache, 0.0f, 0.0f, cachePaint); } else { // use layer paint to draw the bitmap, merging the two alphas, but also restore int layerPaintAlpha = mLayerPaint.getAlpha(); if (alpha < 1) { mLayerPaint.setAlpha((int) (alpha * layerPaintAlpha)); } canvas.drawBitmap(cache, 0.0f, 0.0f, mLayerPaint); if (alpha < 1) { mLayerPaint.setAlpha(layerPaintAlpha); } } }
if (restoreTo >= 0) { canvas.restoreToCount(restoreTo); }
if (a != null && !more) { if (!hardwareAcceleratedCanvas && !a.getFillAfter()) { onSetAlpha(255); } parent.finishAnimatingView(this, a); }
if (more && hardwareAcceleratedCanvas) { if (a.hasAlpha() && (mPrivateFlags & PFLAG_ALPHA_SET) == PFLAG_ALPHA_SET) { // alpha animations should cause the child to recreate its display list invalidate(true); } }
finallong projectedBitmapSize = width * height * (opaque && !use32BitCache ? 2 : 4); finallong drawingCacheSize = ViewConfiguration.get(mContext).getScaledMaximumDrawingCacheSize(); //【3】这里比较了下要绘制的图案的内存大小是不是比允许缓存的最大值大,如果是的话,不允许缓存; if (width <= 0 || height <= 0 || projectedBitmapSize > drawingCacheSize) { if (width > 0 && height > 0) { Log.w(VIEW_LOG_TAG, getClass().getSimpleName() + " not displayed because it is" + " too large to fit into a software layer (or drawing cache), needs " + projectedBitmapSize + " bytes, only " + drawingCacheSize + " available"); } destroyDrawingCache(); mCachingFailed = true; return; }
boolean clear = true; //【4】选择哪一种缓存; Bitmap bitmap = autoScale ? mDrawingCache : mUnscaledDrawingCache; //【5】选择缓存对应的质量; if (bitmap == null || bitmap.getWidth() != width || bitmap.getHeight() != height) { Bitmap.Config quality; if (!opaque) { // Never pick ARGB_4444 because it looks awful // Keep the DRAWING_CACHE_QUALITY_LOW flag just in case switch (mViewFlags & DRAWING_CACHE_QUALITY_MASK) { case DRAWING_CACHE_QUALITY_AUTO: case DRAWING_CACHE_QUALITY_LOW: case DRAWING_CACHE_QUALITY_HIGH: default: quality = Bitmap.Config.ARGB_8888; break; } } else { // Optimization for translucent windows // If the window is translucent, use a 32 bits bitmap to benefit from memcpy() quality = use32BitCache ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565; }
Canvas canvas; //【7】这里的 attachInfo 来自于 ViewRootImpl。下面会对 canvas 做一下调整; if (attachInfo != null) { canvas = attachInfo.mCanvas; if (canvas == null) { canvas = new Canvas(); } //【7.1】canvas 的 Bitmap 设置为我们创建的缓存 Bitmap; canvas.setBitmap(bitmap); // Temporarily clobber the cached Canvas in case one of our children // is also using a drawing cache. Without this, the children would // steal the canvas by attaching their own bitmap to it and bad, bad // thing would happen (invisible views, corrupted drawings, etc.) attachInfo.mCanvas = null; } else { // 这是极端的情况,view 没有 attach 上; canvas = new Canvas(bitmap); }
if (clear) { bitmap.eraseColor(drawingCacheBackgroundColor); }
// register animating rendernodes which started animating prior to renderer // creation, which is typical for animators started prior to first draw if (attachInfo.mPendingAnimatingRenderNodes != null) { finalint count = attachInfo.mPendingAnimatingRenderNodes.size(); for (int i = 0; i < count; i++) { registerAnimatingRenderNode( attachInfo.mPendingAnimatingRenderNodes.get(i)); } attachInfo.mPendingAnimatingRenderNodes.clear(); // We don't need this anymore as subsequent calls to // ViewRootImpl#attachRenderNodeAnimator will go directly to us. attachInfo.mPendingAnimatingRenderNodes = null; }
finallong[] frameInfo = choreographer.mFrameInfo.mFrameInfo; //【2】同步帧数据,最终目的是将 OpenGL 指令写入 gpu; int syncResult = nSyncAndDrawFrame(mNativeProxy, frameInfo, frameInfo.length); if ((syncResult & SYNC_LOST_SURFACE_REWARD_IF_FOUND) != 0) { setEnabled(false); attachInfo.mViewRootImpl.mSurface.release(); // Invalidate since we failed to draw. This should fetch a Surface // if it is still needed or do nothing if we are no longer drawing attachInfo.mViewRootImpl.invalidate(); } if ((syncResult & SYNC_INVALIDATE_REQUIRED) != 0) { attachInfo.mViewRootImpl.invalidate(); } }