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