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