RenderNodeDrawable.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 "RenderNodeDrawable.h" 18#include "RenderNode.h" 19#include "SkiaDisplayList.h" 20#include "SkiaPipeline.h" 21#include "utils/TraceUtils.h" 22 23namespace android { 24namespace uirenderer { 25namespace skiapipeline { 26 27void RenderNodeDrawable::drawBackwardsProjectedNodes(SkCanvas* canvas, const SkiaDisplayList& displayList, 28 int nestLevel) { 29 LOG_ALWAYS_FATAL_IF(0 == nestLevel && !displayList.mProjectionReceiver); 30 for (auto& child : displayList.mChildNodes) { 31 const RenderProperties& childProperties = child.getNodeProperties(); 32 33 //immediate children cannot be projected on their parent 34 if (childProperties.getProjectBackwards() && nestLevel > 0) { 35 SkAutoCanvasRestore acr2(canvas, true); 36 //Apply recorded matrix, which is a total matrix saved at recording time to avoid 37 //replaying all DL commands. 38 canvas->concat(child.getRecordedMatrix()); 39 child.drawContent(canvas); 40 } 41 42 //skip walking sub-nodes if current display list contains a receiver with exception of 43 //level 0, which is a known receiver 44 if (0 == nestLevel || !displayList.containsProjectionReceiver()) { 45 SkAutoCanvasRestore acr(canvas, true); 46 SkMatrix nodeMatrix; 47 mat4 hwuiMatrix(child.getRecordedMatrix()); 48 auto childNode = child.getRenderNode(); 49 childNode->applyViewPropertyTransforms(hwuiMatrix); 50 hwuiMatrix.copyTo(nodeMatrix); 51 canvas->concat(nodeMatrix); 52 SkiaDisplayList* childDisplayList = static_cast<SkiaDisplayList*>( 53 (const_cast<DisplayList*>(childNode->getDisplayList()))); 54 if (childDisplayList) { 55 drawBackwardsProjectedNodes(canvas, *childDisplayList, nestLevel+1); 56 } 57 } 58 } 59} 60 61static void clipOutline(const Outline& outline, SkCanvas* canvas, const SkRect* pendingClip) { 62 Rect possibleRect; 63 float radius; 64 LOG_ALWAYS_FATAL_IF(!outline.getAsRoundRect(&possibleRect, &radius), 65 "clipping outlines should be at most roundedRects"); 66 SkRect rect = possibleRect.toSkRect(); 67 if (radius != 0.0f) { 68 if (pendingClip && !pendingClip->contains(rect)) { 69 canvas->clipRect(*pendingClip); 70 } 71 canvas->clipRRect(SkRRect::MakeRectXY(rect, radius, radius), SkClipOp::kIntersect, true); 72 } else { 73 if (pendingClip) { 74 (void)rect.intersect(*pendingClip); 75 } 76 canvas->clipRect(rect); 77 } 78} 79 80const RenderProperties& RenderNodeDrawable::getNodeProperties() const { 81 return mRenderNode->properties(); 82} 83 84void RenderNodeDrawable::onDraw(SkCanvas* canvas) { 85 //negative and positive Z order are drawn out of order, if this render node drawable is in 86 //a reordering section 87 if ((!mInReorderingSection) || MathUtils::isZero(mRenderNode->properties().getZ())) { 88 this->forceDraw(canvas); 89 } 90} 91 92void RenderNodeDrawable::forceDraw(SkCanvas* canvas) { 93 RenderNode* renderNode = mRenderNode.get(); 94 if (SkiaPipeline::skpCaptureEnabled()) { 95 SkRect dimensions = SkRect::MakeWH(renderNode->getWidth(), renderNode->getHeight()); 96 canvas->drawAnnotation(dimensions, renderNode->getName(), nullptr); 97 } 98 99 // We only respect the nothingToDraw check when we are composing a layer. This 100 // ensures that we paint the layer even if it is not currently visible in the 101 // event that the properties change and it becomes visible. 102 if (!renderNode->isRenderable() || (renderNode->nothingToDraw() && mComposeLayer)) { 103 return; 104 } 105 106 SkASSERT(renderNode->getDisplayList()->isSkiaDL()); 107 SkiaDisplayList* displayList = (SkiaDisplayList*)renderNode->getDisplayList(); 108 109 SkAutoCanvasRestore acr(canvas, true); 110 const RenderProperties& properties = this->getNodeProperties(); 111 //pass this outline to the children that may clip backward projected nodes 112 displayList->mProjectedOutline = displayList->containsProjectionReceiver() 113 ? &properties.getOutline() : nullptr; 114 if (!properties.getProjectBackwards()) { 115 drawContent(canvas); 116 if (mProjectedDisplayList) { 117 acr.restore(); //draw projected children using parent matrix 118 LOG_ALWAYS_FATAL_IF(!mProjectedDisplayList->mProjectedOutline); 119 const bool shouldClip = mProjectedDisplayList->mProjectedOutline->getPath(); 120 SkAutoCanvasRestore acr2(canvas, shouldClip); 121 canvas->setMatrix(mProjectedDisplayList->mProjectedReceiverParentMatrix); 122 if (shouldClip) { 123 clipOutline(*mProjectedDisplayList->mProjectedOutline, canvas, nullptr); 124 } 125 drawBackwardsProjectedNodes(canvas, *mProjectedDisplayList); 126 } 127 } 128 displayList->mProjectedOutline = nullptr; 129} 130 131static bool layerNeedsPaint(const LayerProperties& properties, 132 float alphaMultiplier, SkPaint* paint) { 133 if (alphaMultiplier < 1.0f 134 || properties.alpha() < 255 135 || properties.xferMode() != SkBlendMode::kSrcOver 136 || properties.colorFilter() != nullptr) { 137 paint->setAlpha(properties.alpha() * alphaMultiplier); 138 paint->setBlendMode(properties.xferMode()); 139 paint->setColorFilter(sk_ref_sp(properties.colorFilter())); 140 return true; 141 } 142 return false; 143} 144 145void RenderNodeDrawable::drawContent(SkCanvas* canvas) const { 146 RenderNode* renderNode = mRenderNode.get(); 147 float alphaMultiplier = 1.0f; 148 const RenderProperties& properties = renderNode->properties(); 149 150 // If we are drawing the contents of layer, we don't want to apply any of 151 // the RenderNode's properties during this pass. Those will all be applied 152 // when the layer is composited. 153 if (mComposeLayer) { 154 setViewProperties(properties, canvas, &alphaMultiplier); 155 } 156 SkiaDisplayList* displayList = (SkiaDisplayList*)mRenderNode->getDisplayList(); 157 if (displayList->containsProjectionReceiver()) { 158 displayList->mProjectedReceiverParentMatrix = canvas->getTotalMatrix(); 159 } 160 161 //TODO should we let the bound of the drawable do this for us? 162 const SkRect bounds = SkRect::MakeWH(properties.getWidth(), properties.getHeight()); 163 bool quickRejected = properties.getClipToBounds() && canvas->quickReject(bounds); 164 if (!quickRejected) { 165 SkiaDisplayList* displayList = (SkiaDisplayList*)renderNode->getDisplayList(); 166 const LayerProperties& layerProperties = properties.layerProperties(); 167 // composing a hardware layer 168 if (renderNode->getLayerSurface() && mComposeLayer) { 169 SkASSERT(properties.effectiveLayerType() == LayerType::RenderLayer); 170 SkPaint* paint = nullptr; 171 SkPaint tmpPaint; 172 if (layerNeedsPaint(layerProperties, alphaMultiplier, &tmpPaint)) { 173 paint = &tmpPaint; 174 } 175 renderNode->getLayerSurface()->draw(canvas, 0, 0, paint); 176 177 if (!renderNode->getSkiaLayer()->hasRenderedSinceRepaint) { 178 renderNode->getSkiaLayer()->hasRenderedSinceRepaint = true; 179 if (CC_UNLIKELY(Properties::debugLayersUpdates)) { 180 SkPaint layerPaint; 181 layerPaint.setColor(0x7f00ff00); 182 canvas->drawRect(bounds, layerPaint); 183 } else if (CC_UNLIKELY(Properties::debugOverdraw)) { 184 // Render transparent rect to increment overdraw for repaint area. 185 // This can be "else if" because flashing green on layer updates 186 // will also increment the overdraw if it happens to be turned on. 187 SkPaint transparentPaint; 188 transparentPaint.setColor(SK_ColorTRANSPARENT); 189 canvas->drawRect(bounds, transparentPaint); 190 } 191 } 192 193 // composing a software layer with alpha 194 } else if (properties.effectiveLayerType() == LayerType::Software) { 195 SkPaint paint; 196 bool needsLayer = layerNeedsPaint(layerProperties, alphaMultiplier, &paint); 197 if (needsLayer) { 198 canvas->saveLayer(bounds, &paint); 199 } 200 displayList->draw(canvas); 201 if (needsLayer) { 202 canvas->restore(); 203 } 204 } else { 205 displayList->draw(canvas); 206 } 207 } 208} 209 210void RenderNodeDrawable::setViewProperties(const RenderProperties& properties, SkCanvas* canvas, 211 float* alphaMultiplier) { 212 if (properties.getLeft() != 0 || properties.getTop() != 0) { 213 canvas->translate(properties.getLeft(), properties.getTop()); 214 } 215 if (properties.getStaticMatrix()) { 216 canvas->concat(*properties.getStaticMatrix()); 217 } else if (properties.getAnimationMatrix()) { 218 canvas->concat(*properties.getAnimationMatrix()); 219 } 220 if (properties.hasTransformMatrix()) { 221 if (properties.isTransformTranslateOnly()) { 222 canvas->translate(properties.getTranslationX(), properties.getTranslationY()); 223 } else { 224 canvas->concat(*properties.getTransformMatrix()); 225 } 226 } 227 const bool isLayer = properties.effectiveLayerType() != LayerType::None; 228 int clipFlags = properties.getClippingFlags(); 229 if (properties.getAlpha() < 1) { 230 if (isLayer) { 231 clipFlags &= ~CLIP_TO_BOUNDS; // bounds clipping done by layer 232 } 233 if (CC_LIKELY(isLayer || !properties.getHasOverlappingRendering())) { 234 *alphaMultiplier = properties.getAlpha(); 235 } else { 236 // savelayer needed to create an offscreen buffer 237 Rect layerBounds(0, 0, properties.getWidth(), properties.getHeight()); 238 if (clipFlags) { 239 properties.getClippingRectForFlags(clipFlags, &layerBounds); 240 clipFlags = 0; // all clipping done by savelayer 241 } 242 SkRect bounds = SkRect::MakeLTRB(layerBounds.left, layerBounds.top, 243 layerBounds.right, layerBounds.bottom); 244 canvas->saveLayerAlpha(&bounds, (int) (properties.getAlpha() * 255)); 245 } 246 247 if (CC_UNLIKELY(ATRACE_ENABLED() && properties.promotedToLayer())) { 248 // pretend alpha always causes savelayer to warn about 249 // performance problem affecting old versions 250 ATRACE_FORMAT("alpha caused saveLayer %dx%d", properties.getWidth(), 251 properties.getHeight()); 252 } 253 } 254 255 const SkRect* pendingClip = nullptr; 256 SkRect clipRect; 257 258 if (clipFlags) { 259 Rect tmpRect; 260 properties.getClippingRectForFlags(clipFlags, &tmpRect); 261 clipRect = tmpRect.toSkRect(); 262 pendingClip = &clipRect; 263 } 264 265 if (properties.getRevealClip().willClip()) { 266 canvas->clipPath(*properties.getRevealClip().getPath(), SkClipOp::kIntersect, true); 267 } else if (properties.getOutline().willClip()) { 268 clipOutline(properties.getOutline(), canvas, pendingClip); 269 pendingClip = nullptr; 270 } 271 272 if (pendingClip) { 273 canvas->clipRect(*pendingClip); 274 } 275} 276 277}; // namespace skiapipeline 278}; // namespace uirenderer 279}; // namespace android 280