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