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