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