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