Home | History | Annotate | Download | only in skia
      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 "ReorderBarrierDrawables.h"
     18 #include "RenderNode.h"
     19 #include "SkiaDisplayList.h"
     20 #include "SkiaPipeline.h"
     21 
     22 #include <SkBlurMask.h>
     23 #include <SkBlurMaskFilter.h>
     24 #include <SkGaussianEdgeShader.h>
     25 #include <SkPathOps.h>
     26 #include <SkRRectsGaussianEdgeMaskFilter.h>
     27 #include <SkShadowUtils.h>
     28 
     29 namespace android {
     30 namespace uirenderer {
     31 namespace skiapipeline {
     32 
     33 StartReorderBarrierDrawable::StartReorderBarrierDrawable(SkiaDisplayList* data)
     34         : mEndChildIndex(0)
     35         , mBeginChildIndex(data->mChildNodes.size())
     36         , mDisplayList(data) {
     37 }
     38 
     39 void StartReorderBarrierDrawable::onDraw(SkCanvas* canvas) {
     40     if (mChildren.empty()) {
     41         //mChildren is allocated and initialized only the first time onDraw is called and cached for
     42         //subsequent calls
     43         mChildren.reserve(mEndChildIndex - mBeginChildIndex + 1);
     44         for (int i = mBeginChildIndex; i <= mEndChildIndex; i++) {
     45             mChildren.push_back(const_cast<RenderNodeDrawable*>(&mDisplayList->mChildNodes[i]));
     46         }
     47     }
     48     std::stable_sort(mChildren.begin(), mChildren.end(),
     49         [](RenderNodeDrawable* a, RenderNodeDrawable* b) {
     50             const float aZValue = a->getNodeProperties().getZ();
     51             const float bZValue = b->getNodeProperties().getZ();
     52             return aZValue < bZValue;
     53         });
     54 
     55     SkASSERT(!mChildren.empty());
     56 
     57     size_t drawIndex = 0;
     58     const size_t endIndex = mChildren.size();
     59     while (drawIndex < endIndex) {
     60         RenderNodeDrawable* childNode = mChildren[drawIndex];
     61         SkASSERT(childNode);
     62         const float casterZ = childNode->getNodeProperties().getZ();
     63         if (casterZ >= -NON_ZERO_EPSILON) { //draw only children with negative Z
     64             return;
     65         }
     66         childNode->forceDraw(canvas);
     67         drawIndex++;
     68     }
     69 }
     70 
     71 EndReorderBarrierDrawable::EndReorderBarrierDrawable(StartReorderBarrierDrawable* startBarrier)
     72         : mStartBarrier(startBarrier) {
     73     mStartBarrier->mEndChildIndex = mStartBarrier->mDisplayList->mChildNodes.size() - 1;
     74 }
     75 
     76 #define SHADOW_DELTA 0.1f
     77 
     78 void EndReorderBarrierDrawable::onDraw(SkCanvas* canvas) {
     79     auto& zChildren = mStartBarrier->mChildren;
     80     SkASSERT(!zChildren.empty());
     81 
     82     /**
     83      * Draw shadows and (potential) casters mostly in order, but allow the shadows of casters
     84      * with very similar Z heights to draw together.
     85      *
     86      * This way, if Views A & B have the same Z height and are both casting shadows, the shadows are
     87      * underneath both, and neither's shadow is drawn on top of the other.
     88      */
     89     size_t drawIndex = 0;
     90 
     91     const size_t endIndex = zChildren.size();
     92     while (drawIndex < endIndex     //draw only children with positive Z
     93             && zChildren[drawIndex]->getNodeProperties().getZ() <= NON_ZERO_EPSILON) drawIndex++;
     94     size_t shadowIndex = drawIndex;
     95 
     96     float lastCasterZ = 0.0f;
     97     while (shadowIndex < endIndex || drawIndex < endIndex) {
     98         if (shadowIndex < endIndex) {
     99             const float casterZ = zChildren[shadowIndex]->getNodeProperties().getZ();
    100 
    101             // attempt to render the shadow if the caster about to be drawn is its caster,
    102             // OR if its caster's Z value is similar to the previous potential caster
    103             if (shadowIndex == drawIndex || casterZ - lastCasterZ < SHADOW_DELTA) {
    104                 this->drawShadow(canvas, zChildren[shadowIndex]);
    105                 lastCasterZ = casterZ; // must do this even if current caster not casting a shadow
    106                 shadowIndex++;
    107                 continue;
    108             }
    109         }
    110 
    111         RenderNodeDrawable* childNode = zChildren[drawIndex];
    112         SkASSERT(childNode);
    113         childNode->forceDraw(canvas);
    114 
    115         drawIndex++;
    116     }
    117 }
    118 
    119 // copied from FrameBuilder::deferShadow
    120 void EndReorderBarrierDrawable::drawShadow(SkCanvas* canvas, RenderNodeDrawable* caster) {
    121     const RenderProperties& casterProperties = caster->getNodeProperties();
    122 
    123     if (casterProperties.getAlpha() <= 0.0f
    124             || casterProperties.getOutline().getAlpha() <= 0.0f
    125             || !casterProperties.getOutline().getPath()
    126             || casterProperties.getScaleX() == 0
    127             || casterProperties.getScaleY() == 0) {
    128         // no shadow to draw
    129         return;
    130     }
    131 
    132     const SkScalar casterAlpha = casterProperties.getAlpha()
    133             * casterProperties.getOutline().getAlpha();
    134     if (casterAlpha <= 0.0f) {
    135         return;
    136     }
    137 
    138     float ambientAlpha = (SkiaPipeline::getAmbientShadowAlpha()/255.f)*casterAlpha;
    139     float spotAlpha = (SkiaPipeline::getSpotShadowAlpha()/255.f)*casterAlpha;
    140     const float casterZValue = casterProperties.getZ();
    141 
    142     const RevealClip& revealClip = casterProperties.getRevealClip();
    143     const SkPath* revealClipPath = revealClip.getPath();
    144     if (revealClipPath && revealClipPath->isEmpty()) {
    145         // An empty reveal clip means nothing is drawn
    146         return;
    147     }
    148 
    149     bool clippedToBounds = casterProperties.getClippingFlags() & CLIP_TO_CLIP_BOUNDS;
    150 
    151     SkRect casterClipRect = SkRect::MakeEmpty();
    152     if (clippedToBounds) {
    153         Rect clipBounds;
    154         casterProperties.getClippingRectForFlags(CLIP_TO_CLIP_BOUNDS, &clipBounds);
    155         casterClipRect = clipBounds.toSkRect();
    156         if (casterClipRect.isEmpty()) {
    157             // An empty clip rect means nothing is drawn
    158             return;
    159         }
    160     }
    161 
    162     SkAutoCanvasRestore acr(canvas, true);
    163 
    164     SkMatrix shadowMatrix;
    165     mat4 hwuiMatrix;
    166     // TODO we don't pass the optional boolean to treat it as a 4x4 matrix
    167     caster->getRenderNode()->applyViewPropertyTransforms(hwuiMatrix);
    168     hwuiMatrix.copyTo(shadowMatrix);
    169     canvas->concat(shadowMatrix);
    170 
    171     const SkPath* casterOutlinePath = casterProperties.getOutline().getPath();
    172     // holds temporary SkPath to store the result of intersections
    173     SkPath tmpPath;
    174     const SkPath* casterPath = casterOutlinePath;
    175 
    176     // TODO: In to following course of code that calculates the final shape, is there an optimal
    177     //       of doing the Op calculations?
    178     // intersect the shadow-casting path with the reveal, if present
    179     if (revealClipPath) {
    180         Op(*casterPath, *revealClipPath, kIntersect_SkPathOp, &tmpPath);
    181         casterPath = &tmpPath;
    182     }
    183 
    184     // intersect the shadow-casting path with the clipBounds, if present
    185     if (clippedToBounds) {
    186         SkPath clipBoundsPath;
    187         clipBoundsPath.addRect(casterClipRect);
    188         Op(*casterPath, clipBoundsPath, kIntersect_SkPathOp, &tmpPath);
    189         casterPath = &tmpPath;
    190     }
    191     const Vector3 lightPos = SkiaPipeline::getLightCenter();
    192     SkPoint3 skiaLightPos = SkPoint3::Make(lightPos.x, lightPos.y, lightPos.z);
    193     if (shadowMatrix.hasPerspective() || revealClipPath || clippedToBounds) {
    194         std::function<SkScalar(SkScalar, SkScalar)> casterHeightFunc;
    195         if (shadowMatrix.hasPerspective()) {
    196             // get the matrix with the full 3D transform
    197             mat4 zMatrix;
    198             caster->getRenderNode()->applyViewPropertyTransforms(zMatrix, true);
    199             SkScalar A = zMatrix[2];
    200             SkScalar B = zMatrix[6];
    201             SkScalar C = zMatrix[mat4::kTranslateZ];
    202             casterHeightFunc = [A, B, C](SkScalar x, SkScalar y) {
    203                 return A*x + B*y + C;  // casterZValue already baked into C
    204             };
    205         } else {
    206             casterHeightFunc = [casterZValue] (SkScalar, SkScalar) {
    207                 return casterZValue;
    208             };
    209         }
    210 
    211         SkShadowUtils::DrawUncachedShadow(canvas, *casterPath, casterHeightFunc, skiaLightPos,
    212             SkiaPipeline::getLightRadius(), ambientAlpha, spotAlpha, SK_ColorBLACK,
    213             casterAlpha < 1.0f ? SkShadowFlags::kTransparentOccluder_ShadowFlag : 0);
    214     } else {
    215         SkShadowUtils::DrawShadow(canvas, *casterPath, casterZValue, skiaLightPos,
    216             SkiaPipeline::getLightRadius(), ambientAlpha, spotAlpha, SK_ColorBLACK,
    217             casterAlpha < 1.0f ? SkShadowFlags::kTransparentOccluder_ShadowFlag : 0);
    218     }
    219 }
    220 
    221 }; // namespace skiapipeline
    222 }; // namespace uirenderer
    223 }; // namespace android
    224