Home | History | Annotate | Download | only in hwui
      1 /*
      2  * Copyright (C) 2014 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 #ifndef RENDERNODEPROPERTIES_H
     17 #define RENDERNODEPROPERTIES_H
     18 
     19 #include <algorithm>
     20 #include <stddef.h>
     21 #include <vector>
     22 #include <cutils/compiler.h>
     23 #include <androidfw/ResourceTypes.h>
     24 #include <utils/Log.h>
     25 
     26 #include <SkCamera.h>
     27 #include <SkMatrix.h>
     28 #include <SkRegion.h>
     29 #include <SkXfermode.h>
     30 
     31 #include "Caches.h"
     32 #include "Rect.h"
     33 #include "RevealClip.h"
     34 #include "Outline.h"
     35 #include "utils/MathUtils.h"
     36 
     37 class SkBitmap;
     38 class SkColorFilter;
     39 class SkPaint;
     40 
     41 namespace android {
     42 namespace uirenderer {
     43 
     44 class Matrix4;
     45 class RenderNode;
     46 class RenderProperties;
     47 
     48 // The __VA_ARGS__ will be executed if a & b are not equal
     49 #define RP_SET(a, b, ...) (a != b ? (a = b, ##__VA_ARGS__, true) : false)
     50 #define RP_SET_AND_DIRTY(a, b) RP_SET(a, b, mPrimitiveFields.mMatrixOrPivotDirty = true)
     51 
     52 // Keep in sync with View.java:LAYER_TYPE_*
     53 enum class LayerType {
     54     None = 0,
     55     // Although we cannot build the software layer directly (must be done at
     56     // record time), this information is used when applying alpha.
     57     Software = 1,
     58     RenderLayer = 2,
     59     // TODO: LayerTypeSurfaceTexture? Maybe?
     60 };
     61 
     62 enum ClippingFlags {
     63     CLIP_TO_BOUNDS =      0x1 << 0,
     64     CLIP_TO_CLIP_BOUNDS = 0x1 << 1,
     65 };
     66 
     67 class ANDROID_API LayerProperties {
     68 public:
     69     bool setType(LayerType type) {
     70         if (RP_SET(mType, type)) {
     71             reset();
     72             return true;
     73         }
     74         return false;
     75     }
     76 
     77     bool setOpaque(bool opaque) {
     78         return RP_SET(mOpaque, opaque);
     79     }
     80 
     81     bool opaque() const {
     82         return mOpaque;
     83     }
     84 
     85     bool setAlpha(uint8_t alpha) {
     86         return RP_SET(mAlpha, alpha);
     87     }
     88 
     89     uint8_t alpha() const {
     90         return mAlpha;
     91     }
     92 
     93     bool setXferMode(SkXfermode::Mode mode) {
     94         return RP_SET(mMode, mode);
     95     }
     96 
     97     SkXfermode::Mode xferMode() const {
     98         return mMode;
     99     }
    100 
    101     bool setColorFilter(SkColorFilter* filter);
    102 
    103     SkColorFilter* colorFilter() const {
    104         return mColorFilter;
    105     }
    106 
    107     // Sets alpha, xfermode, and colorfilter from an SkPaint
    108     // paint may be NULL, in which case defaults will be set
    109     bool setFromPaint(const SkPaint* paint);
    110 
    111     bool needsBlending() const {
    112         return !opaque() || alpha() < 255;
    113     }
    114 
    115     LayerProperties& operator=(const LayerProperties& other);
    116 
    117 private:
    118     LayerProperties();
    119     ~LayerProperties();
    120     void reset();
    121 
    122     // Private since external users should go through properties().effectiveLayerType()
    123     LayerType type() const {
    124         return mType;
    125     }
    126 
    127     friend class RenderProperties;
    128 
    129     LayerType mType = LayerType::None;
    130     // Whether or not that Layer's content is opaque, doesn't include alpha
    131     bool mOpaque;
    132     uint8_t mAlpha;
    133     SkXfermode::Mode mMode;
    134     SkColorFilter* mColorFilter = nullptr;
    135 };
    136 
    137 /*
    138  * Data structure that holds the properties for a RenderNode
    139  */
    140 class ANDROID_API RenderProperties {
    141 public:
    142     RenderProperties();
    143     virtual ~RenderProperties();
    144 
    145     static bool setFlag(int flag, bool newValue, int* outFlags) {
    146         if (newValue) {
    147             if (!(flag & *outFlags)) {
    148                 *outFlags |= flag;
    149                 return true;
    150             }
    151             return false;
    152         } else {
    153             if (flag & *outFlags) {
    154                 *outFlags &= ~flag;
    155                 return true;
    156             }
    157             return false;
    158         }
    159     }
    160 
    161     /**
    162      * Set internal layer state based on whether this layer
    163      *
    164      * Additionally, returns true if child RenderNodes with functors will need to use a layer
    165      * to support clipping.
    166      */
    167     bool prepareForFunctorPresence(bool willHaveFunctor, bool ancestorDictatesFunctorsNeedLayer) {
    168         // parent may have already dictated that a descendant layer is needed
    169         bool functorsNeedLayer = ancestorDictatesFunctorsNeedLayer
    170 
    171                 // Round rect clipping forces layer for functors
    172                 || CC_UNLIKELY(getOutline().willRoundRectClip())
    173                 || CC_UNLIKELY(getRevealClip().willClip())
    174 
    175                 // Complex matrices forces layer, due to stencil clipping
    176                 || CC_UNLIKELY(getTransformMatrix() && !getTransformMatrix()->isScaleTranslate())
    177                 || CC_UNLIKELY(getAnimationMatrix() && !getAnimationMatrix()->isScaleTranslate())
    178                 || CC_UNLIKELY(getStaticMatrix() && !getStaticMatrix()->isScaleTranslate());
    179 
    180         mComputedFields.mNeedLayerForFunctors = (willHaveFunctor && functorsNeedLayer);
    181 
    182         // If on a layer, will have consumed the need for isolating functors from stencil.
    183         // Thus, it's safe to reset the flag until some descendent sets it.
    184         return CC_LIKELY(effectiveLayerType() == LayerType::None) && functorsNeedLayer;
    185     }
    186 
    187     RenderProperties& operator=(const RenderProperties& other);
    188 
    189     bool setClipToBounds(bool clipToBounds) {
    190         return setFlag(CLIP_TO_BOUNDS, clipToBounds, &mPrimitiveFields.mClippingFlags);
    191     }
    192 
    193     bool setClipBounds(const Rect& clipBounds) {
    194         bool ret = setFlag(CLIP_TO_CLIP_BOUNDS, true, &mPrimitiveFields.mClippingFlags);
    195         return RP_SET(mPrimitiveFields.mClipBounds, clipBounds) || ret;
    196     }
    197 
    198     bool setClipBoundsEmpty() {
    199         return setFlag(CLIP_TO_CLIP_BOUNDS, false, &mPrimitiveFields.mClippingFlags);
    200     }
    201 
    202     bool setProjectBackwards(bool shouldProject) {
    203         return RP_SET(mPrimitiveFields.mProjectBackwards, shouldProject);
    204     }
    205 
    206     bool setProjectionReceiver(bool shouldRecieve) {
    207         return RP_SET(mPrimitiveFields.mProjectionReceiver, shouldRecieve);
    208     }
    209 
    210     bool isProjectionReceiver() const {
    211         return mPrimitiveFields.mProjectionReceiver;
    212     }
    213 
    214     bool setStaticMatrix(const SkMatrix* matrix) {
    215         delete mStaticMatrix;
    216         if (matrix) {
    217             mStaticMatrix = new SkMatrix(*matrix);
    218         } else {
    219             mStaticMatrix = nullptr;
    220         }
    221         return true;
    222     }
    223 
    224     // Can return NULL
    225     const SkMatrix* getStaticMatrix() const {
    226         return mStaticMatrix;
    227     }
    228 
    229     bool setAnimationMatrix(const SkMatrix* matrix) {
    230         delete mAnimationMatrix;
    231         if (matrix) {
    232             mAnimationMatrix = new SkMatrix(*matrix);
    233         } else {
    234             mAnimationMatrix = nullptr;
    235         }
    236         return true;
    237     }
    238 
    239     bool setAlpha(float alpha) {
    240         alpha = MathUtils::clampAlpha(alpha);
    241         return RP_SET(mPrimitiveFields.mAlpha, alpha);
    242     }
    243 
    244     float getAlpha() const {
    245         return mPrimitiveFields.mAlpha;
    246     }
    247 
    248     bool setHasOverlappingRendering(bool hasOverlappingRendering) {
    249         return RP_SET(mPrimitiveFields.mHasOverlappingRendering, hasOverlappingRendering);
    250     }
    251 
    252     bool hasOverlappingRendering() const {
    253         return mPrimitiveFields.mHasOverlappingRendering;
    254     }
    255 
    256     bool setElevation(float elevation) {
    257         return RP_SET(mPrimitiveFields.mElevation, elevation);
    258         // Don't dirty matrix/pivot, since they don't respect Z
    259     }
    260 
    261     float getElevation() const {
    262         return mPrimitiveFields.mElevation;
    263     }
    264 
    265     bool setTranslationX(float translationX) {
    266         return RP_SET_AND_DIRTY(mPrimitiveFields.mTranslationX, translationX);
    267     }
    268 
    269     float getTranslationX() const {
    270         return mPrimitiveFields.mTranslationX;
    271     }
    272 
    273     bool setTranslationY(float translationY) {
    274         return RP_SET_AND_DIRTY(mPrimitiveFields.mTranslationY, translationY);
    275     }
    276 
    277     float getTranslationY() const {
    278         return mPrimitiveFields.mTranslationY;
    279     }
    280 
    281     bool setTranslationZ(float translationZ) {
    282         return RP_SET(mPrimitiveFields.mTranslationZ, translationZ);
    283         // mMatrixOrPivotDirty not set, since matrix doesn't respect Z
    284     }
    285 
    286     float getTranslationZ() const {
    287         return mPrimitiveFields.mTranslationZ;
    288     }
    289 
    290     // Animation helper
    291     bool setX(float value) {
    292         return setTranslationX(value - getLeft());
    293     }
    294 
    295     // Animation helper
    296     float getX() const {
    297         return getLeft() + getTranslationX();
    298     }
    299 
    300     // Animation helper
    301     bool setY(float value) {
    302         return setTranslationY(value - getTop());
    303     }
    304 
    305     // Animation helper
    306     float getY() const {
    307         return getTop() + getTranslationY();
    308     }
    309 
    310     // Animation helper
    311     bool setZ(float value) {
    312         return setTranslationZ(value - getElevation());
    313     }
    314 
    315     float getZ() const {
    316         return getElevation() + getTranslationZ();
    317     }
    318 
    319     bool setRotation(float rotation) {
    320         return RP_SET_AND_DIRTY(mPrimitiveFields.mRotation, rotation);
    321     }
    322 
    323     float getRotation() const {
    324         return mPrimitiveFields.mRotation;
    325     }
    326 
    327     bool setRotationX(float rotationX) {
    328         return RP_SET_AND_DIRTY(mPrimitiveFields.mRotationX, rotationX);
    329     }
    330 
    331     float getRotationX() const {
    332         return mPrimitiveFields.mRotationX;
    333     }
    334 
    335     bool setRotationY(float rotationY) {
    336         return RP_SET_AND_DIRTY(mPrimitiveFields.mRotationY, rotationY);
    337     }
    338 
    339     float getRotationY() const {
    340         return mPrimitiveFields.mRotationY;
    341     }
    342 
    343     bool setScaleX(float scaleX) {
    344         return RP_SET_AND_DIRTY(mPrimitiveFields.mScaleX, scaleX);
    345     }
    346 
    347     float getScaleX() const {
    348         return mPrimitiveFields.mScaleX;
    349     }
    350 
    351     bool setScaleY(float scaleY) {
    352         return RP_SET_AND_DIRTY(mPrimitiveFields.mScaleY, scaleY);
    353     }
    354 
    355     float getScaleY() const {
    356         return mPrimitiveFields.mScaleY;
    357     }
    358 
    359     bool setPivotX(float pivotX) {
    360         if (RP_SET(mPrimitiveFields.mPivotX, pivotX)
    361                 || !mPrimitiveFields.mPivotExplicitlySet) {
    362             mPrimitiveFields.mMatrixOrPivotDirty = true;
    363             mPrimitiveFields.mPivotExplicitlySet = true;
    364             return true;
    365         }
    366         return false;
    367     }
    368 
    369     /* Note that getPivotX and getPivotY are adjusted by updateMatrix(),
    370      * so the value returned may be stale if the RenderProperties has been
    371      * modified since the last call to updateMatrix()
    372      */
    373     float getPivotX() const {
    374         return mPrimitiveFields.mPivotX;
    375     }
    376 
    377     bool setPivotY(float pivotY) {
    378         if (RP_SET(mPrimitiveFields.mPivotY, pivotY)
    379                 || !mPrimitiveFields.mPivotExplicitlySet) {
    380             mPrimitiveFields.mMatrixOrPivotDirty = true;
    381             mPrimitiveFields.mPivotExplicitlySet = true;
    382             return true;
    383         }
    384         return false;
    385     }
    386 
    387     float getPivotY() const {
    388         return mPrimitiveFields.mPivotY;
    389     }
    390 
    391     bool isPivotExplicitlySet() const {
    392         return mPrimitiveFields.mPivotExplicitlySet;
    393     }
    394 
    395     bool setCameraDistance(float distance) {
    396         if (distance != getCameraDistance()) {
    397             mPrimitiveFields.mMatrixOrPivotDirty = true;
    398             mComputedFields.mTransformCamera.setCameraLocation(0, 0, distance);
    399             return true;
    400         }
    401         return false;
    402     }
    403 
    404     float getCameraDistance() const {
    405         // TODO: update getCameraLocationZ() to be const
    406         return const_cast<Sk3DView*>(&mComputedFields.mTransformCamera)->getCameraLocationZ();
    407     }
    408 
    409     bool setLeft(int left) {
    410         if (RP_SET(mPrimitiveFields.mLeft, left)) {
    411             mPrimitiveFields.mWidth = mPrimitiveFields.mRight - mPrimitiveFields.mLeft;
    412             if (!mPrimitiveFields.mPivotExplicitlySet) {
    413                 mPrimitiveFields.mMatrixOrPivotDirty = true;
    414             }
    415             return true;
    416         }
    417         return false;
    418     }
    419 
    420     float getLeft() const {
    421         return mPrimitiveFields.mLeft;
    422     }
    423 
    424     bool setTop(int top) {
    425         if (RP_SET(mPrimitiveFields.mTop, top)) {
    426             mPrimitiveFields.mHeight = mPrimitiveFields.mBottom - mPrimitiveFields.mTop;
    427             if (!mPrimitiveFields.mPivotExplicitlySet) {
    428                 mPrimitiveFields.mMatrixOrPivotDirty = true;
    429             }
    430             return true;
    431         }
    432         return false;
    433     }
    434 
    435     float getTop() const {
    436         return mPrimitiveFields.mTop;
    437     }
    438 
    439     bool setRight(int right) {
    440         if (RP_SET(mPrimitiveFields.mRight, right)) {
    441             mPrimitiveFields.mWidth = mPrimitiveFields.mRight - mPrimitiveFields.mLeft;
    442             if (!mPrimitiveFields.mPivotExplicitlySet) {
    443                 mPrimitiveFields.mMatrixOrPivotDirty = true;
    444             }
    445             return true;
    446         }
    447         return false;
    448     }
    449 
    450     float getRight() const {
    451         return mPrimitiveFields.mRight;
    452     }
    453 
    454     bool setBottom(int bottom) {
    455         if (RP_SET(mPrimitiveFields.mBottom, bottom)) {
    456             mPrimitiveFields.mHeight = mPrimitiveFields.mBottom - mPrimitiveFields.mTop;
    457             if (!mPrimitiveFields.mPivotExplicitlySet) {
    458                 mPrimitiveFields.mMatrixOrPivotDirty = true;
    459             }
    460             return true;
    461         }
    462         return false;
    463     }
    464 
    465     float getBottom() const {
    466         return mPrimitiveFields.mBottom;
    467     }
    468 
    469     bool setLeftTop(int left, int top) {
    470         bool leftResult = setLeft(left);
    471         bool topResult = setTop(top);
    472         return leftResult || topResult;
    473     }
    474 
    475     bool setLeftTopRightBottom(int left, int top, int right, int bottom) {
    476         if (left != mPrimitiveFields.mLeft || top != mPrimitiveFields.mTop
    477                 || right != mPrimitiveFields.mRight || bottom != mPrimitiveFields.mBottom) {
    478             mPrimitiveFields.mLeft = left;
    479             mPrimitiveFields.mTop = top;
    480             mPrimitiveFields.mRight = right;
    481             mPrimitiveFields.mBottom = bottom;
    482             mPrimitiveFields.mWidth = mPrimitiveFields.mRight - mPrimitiveFields.mLeft;
    483             mPrimitiveFields.mHeight = mPrimitiveFields.mBottom - mPrimitiveFields.mTop;
    484             if (!mPrimitiveFields.mPivotExplicitlySet) {
    485                 mPrimitiveFields.mMatrixOrPivotDirty = true;
    486             }
    487             return true;
    488         }
    489         return false;
    490     }
    491 
    492     bool offsetLeftRight(int offset) {
    493         if (offset != 0) {
    494             mPrimitiveFields.mLeft += offset;
    495             mPrimitiveFields.mRight += offset;
    496             return true;
    497         }
    498         return false;
    499     }
    500 
    501     bool offsetTopBottom(int offset) {
    502         if (offset != 0) {
    503             mPrimitiveFields.mTop += offset;
    504             mPrimitiveFields.mBottom += offset;
    505             return true;
    506         }
    507         return false;
    508     }
    509 
    510     int getWidth() const {
    511         return mPrimitiveFields.mWidth;
    512     }
    513 
    514     int getHeight() const {
    515         return mPrimitiveFields.mHeight;
    516     }
    517 
    518     const SkMatrix* getAnimationMatrix() const {
    519         return mAnimationMatrix;
    520     }
    521 
    522     bool hasTransformMatrix() const {
    523         return getTransformMatrix() && !getTransformMatrix()->isIdentity();
    524     }
    525 
    526     // May only call this if hasTransformMatrix() is true
    527     bool isTransformTranslateOnly() const {
    528         return getTransformMatrix()->getType() == SkMatrix::kTranslate_Mask;
    529     }
    530 
    531     const SkMatrix* getTransformMatrix() const {
    532         LOG_ALWAYS_FATAL_IF(mPrimitiveFields.mMatrixOrPivotDirty, "Cannot get a dirty matrix!");
    533         return mComputedFields.mTransformMatrix;
    534     }
    535 
    536     int getClippingFlags() const {
    537         return mPrimitiveFields.mClippingFlags;
    538     }
    539 
    540     bool getClipToBounds() const {
    541         return mPrimitiveFields.mClippingFlags & CLIP_TO_BOUNDS;
    542     }
    543 
    544     void getClippingRectForFlags(uint32_t flags, Rect* outRect) const {
    545         if (flags & CLIP_TO_BOUNDS) {
    546             outRect->set(0, 0, getWidth(), getHeight());
    547             if (flags & CLIP_TO_CLIP_BOUNDS) {
    548                 outRect->intersect(mPrimitiveFields.mClipBounds);
    549             }
    550         } else {
    551             outRect->set(mPrimitiveFields.mClipBounds);
    552         }
    553     }
    554 
    555     bool getHasOverlappingRendering() const {
    556         return mPrimitiveFields.mHasOverlappingRendering;
    557     }
    558 
    559     const Outline& getOutline() const {
    560         return mPrimitiveFields.mOutline;
    561     }
    562 
    563     const RevealClip& getRevealClip() const {
    564         return mPrimitiveFields.mRevealClip;
    565     }
    566 
    567     bool getProjectBackwards() const {
    568         return mPrimitiveFields.mProjectBackwards;
    569     }
    570 
    571     void debugOutputProperties(const int level) const;
    572 
    573     void updateMatrix();
    574 
    575     Outline& mutableOutline() {
    576         return mPrimitiveFields.mOutline;
    577     }
    578 
    579     RevealClip& mutableRevealClip() {
    580         return mPrimitiveFields.mRevealClip;
    581     }
    582 
    583     const LayerProperties& layerProperties() const {
    584         return mLayerProperties;
    585     }
    586 
    587     LayerProperties& mutateLayerProperties() {
    588         return mLayerProperties;
    589     }
    590 
    591     // Returns true if damage calculations should be clipped to bounds
    592     // TODO: Figure out something better for getZ(), as children should still be
    593     // clipped to this RP's bounds. But as we will damage -INT_MAX to INT_MAX
    594     // for this RP's getZ() anyway, this can be optimized when we have a
    595     // Z damage estimate instead of INT_MAX
    596     bool getClipDamageToBounds() const {
    597         return getClipToBounds() && (getZ() <= 0 || getOutline().isEmpty());
    598     }
    599 
    600     bool hasShadow() const {
    601         return getZ() > 0.0f
    602                 && getOutline().getPath() != nullptr
    603                 && getOutline().getAlpha() != 0.0f;
    604     }
    605 
    606     bool promotedToLayer() const {
    607         const int maxTextureSize = Caches::getInstance().maxTextureSize;
    608         return mLayerProperties.mType == LayerType::None
    609                 && mPrimitiveFields.mWidth <= maxTextureSize
    610                 && mPrimitiveFields.mHeight <= maxTextureSize
    611                 && (mComputedFields.mNeedLayerForFunctors
    612                         || (!MathUtils::isZero(mPrimitiveFields.mAlpha)
    613                                 && mPrimitiveFields.mAlpha < 1
    614                                 && mPrimitiveFields.mHasOverlappingRendering));
    615     }
    616 
    617     LayerType effectiveLayerType() const {
    618         return CC_UNLIKELY(promotedToLayer()) ? LayerType::RenderLayer : mLayerProperties.mType;
    619     }
    620 
    621 private:
    622     // Rendering properties
    623     struct PrimitiveFields {
    624         PrimitiveFields();
    625 
    626         Outline mOutline;
    627         RevealClip mRevealClip;
    628         int mClippingFlags;
    629         bool mProjectBackwards;
    630         bool mProjectionReceiver;
    631         float mAlpha;
    632         bool mHasOverlappingRendering;
    633         float mElevation;
    634         float mTranslationX, mTranslationY, mTranslationZ;
    635         float mRotation, mRotationX, mRotationY;
    636         float mScaleX, mScaleY;
    637         float mPivotX, mPivotY;
    638         int mLeft, mTop, mRight, mBottom;
    639         int mWidth, mHeight;
    640         bool mPivotExplicitlySet;
    641         bool mMatrixOrPivotDirty;
    642         Rect mClipBounds;
    643     } mPrimitiveFields;
    644 
    645     SkMatrix* mStaticMatrix;
    646     SkMatrix* mAnimationMatrix;
    647     LayerProperties mLayerProperties;
    648 
    649     /**
    650      * These fields are all generated from other properties and are not set directly.
    651      */
    652     struct ComputedFields {
    653         ComputedFields();
    654         ~ComputedFields();
    655 
    656         /**
    657          * Stores the total transformation of the DisplayList based upon its scalar
    658          * translate/rotate/scale properties.
    659          *
    660          * In the common translation-only case, the matrix isn't necessarily allocated,
    661          * and the mTranslation properties are used directly.
    662          */
    663         SkMatrix* mTransformMatrix;
    664 
    665         Sk3DView mTransformCamera;
    666 
    667         // Force layer on for functors to enable render features they don't yet support (clipping)
    668         bool mNeedLayerForFunctors = false;
    669     } mComputedFields;
    670 };
    671 
    672 } /* namespace uirenderer */
    673 } /* namespace android */
    674 
    675 #endif /* RENDERNODEPROPERTIES_H */
    676