Home | History | Annotate | Download | only in hwui
      1 /*
      2  * Copyright (C) 2012 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 #include "Snapshot.h"
     18 
     19 #include "hwui/Canvas.h"
     20 
     21 namespace android {
     22 namespace uirenderer {
     23 
     24 ///////////////////////////////////////////////////////////////////////////////
     25 // Constructors
     26 ///////////////////////////////////////////////////////////////////////////////
     27 
     28 Snapshot::Snapshot()
     29         : flags(0)
     30         , previous(nullptr)
     31         , layer(nullptr)
     32         , fbo(0)
     33         , alpha(1.0f)
     34         , roundRectClipState(nullptr)
     35         , projectionPathMask(nullptr)
     36         , mClipArea(&mClipAreaRoot) {
     37     transform = &mTransformRoot;
     38     mRelativeLightCenter.x = mRelativeLightCenter.y = mRelativeLightCenter.z = 0;
     39 }
     40 
     41 /**
     42  * Copies the specified snapshot/ The specified snapshot is stored as
     43  * the previous snapshot.
     44  */
     45 Snapshot::Snapshot(Snapshot* s, int saveFlags)
     46         : flags(0)
     47         , previous(s)
     48         , layer(s->layer)
     49         , fbo(s->fbo)
     50         , alpha(s->alpha)
     51         , roundRectClipState(s->roundRectClipState)
     52         , projectionPathMask(s->projectionPathMask)
     53         , mClipArea(nullptr)
     54         , mViewportData(s->mViewportData)
     55         , mRelativeLightCenter(s->mRelativeLightCenter) {
     56     if (saveFlags & SaveFlags::Matrix) {
     57         mTransformRoot = *s->transform;
     58         transform = &mTransformRoot;
     59     } else {
     60         transform = s->transform;
     61     }
     62 
     63     if (saveFlags & SaveFlags::Clip) {
     64         mClipAreaRoot = s->getClipArea();
     65         mClipArea = &mClipAreaRoot;
     66     } else {
     67         mClipArea = s->mClipArea;
     68     }
     69 }
     70 
     71 ///////////////////////////////////////////////////////////////////////////////
     72 // Clipping
     73 ///////////////////////////////////////////////////////////////////////////////
     74 
     75 void Snapshot::clip(const Rect& localClip, SkClipOp op) {
     76     flags |= Snapshot::kFlagClipSet;
     77     mClipArea->clipRectWithTransform(localClip, transform, static_cast<SkRegion::Op>(op));
     78 }
     79 
     80 void Snapshot::clipPath(const SkPath& path, SkClipOp op) {
     81     flags |= Snapshot::kFlagClipSet;
     82     mClipArea->clipPathWithTransform(path, transform, static_cast<SkRegion::Op>(op));
     83 }
     84 
     85 void Snapshot::setClip(float left, float top, float right, float bottom) {
     86     flags |= Snapshot::kFlagClipSet;
     87     mClipArea->setClip(left, top, right, bottom);
     88 }
     89 
     90 bool Snapshot::hasPerspectiveTransform() const {
     91     return transform->isPerspective();
     92 }
     93 
     94 const Rect& Snapshot::getLocalClip() {
     95     mat4 inverse;
     96     inverse.loadInverse(*transform);
     97 
     98     mLocalClip.set(mClipArea->getClipRect());
     99     inverse.mapRect(mLocalClip);
    100 
    101     return mLocalClip;
    102 }
    103 
    104 void Snapshot::resetClip(float left, float top, float right, float bottom) {
    105     // TODO: This is incorrect, when we start rendering into a new layer,
    106     // we may have to modify the previous snapshot's clip rect and clip
    107     // region if the previous restore() call did not restore the clip
    108     mClipArea = &mClipAreaRoot;
    109     setClip(left, top, right, bottom);
    110 }
    111 
    112 ///////////////////////////////////////////////////////////////////////////////
    113 // Clipping round rect
    114 ///////////////////////////////////////////////////////////////////////////////
    115 
    116 void Snapshot::setClippingRoundRect(LinearAllocator& allocator, const Rect& bounds, float radius,
    117                                     bool highPriority) {
    118     if (bounds.isEmpty()) {
    119         mClipArea->setEmpty();
    120         return;
    121     }
    122 
    123     if (roundRectClipState && roundRectClipState->highPriority) {
    124         // ignore, don't replace, already have a high priority clip
    125         return;
    126     }
    127 
    128     RoundRectClipState* state = new (allocator) RoundRectClipState;
    129 
    130     state->highPriority = highPriority;
    131 
    132     // store the inverse drawing matrix
    133     Matrix4 roundRectDrawingMatrix = getOrthoMatrix();
    134     roundRectDrawingMatrix.multiply(*transform);
    135     state->matrix.loadInverse(roundRectDrawingMatrix);
    136 
    137     // compute area under rounded corners - only draws overlapping these rects need to be clipped
    138     for (int i = 0; i < 4; i++) {
    139         state->dangerRects[i] = bounds;
    140     }
    141     state->dangerRects[0].bottom = state->dangerRects[1].bottom = bounds.top + radius;
    142     state->dangerRects[0].right = state->dangerRects[2].right = bounds.left + radius;
    143     state->dangerRects[1].left = state->dangerRects[3].left = bounds.right - radius;
    144     state->dangerRects[2].top = state->dangerRects[3].top = bounds.bottom - radius;
    145     for (int i = 0; i < 4; i++) {
    146         transform->mapRect(state->dangerRects[i]);
    147 
    148         // round danger rects out as though they are AA geometry (since they essentially are)
    149         state->dangerRects[i].snapGeometryToPixelBoundaries(true);
    150     }
    151 
    152     // store RR area
    153     state->innerRect = bounds;
    154     state->innerRect.inset(radius);
    155     state->radius = radius;
    156 
    157     // store as immutable so, for this frame, pointer uniquely identifies this bundle of shader info
    158     roundRectClipState = state;
    159 }
    160 
    161 void Snapshot::setProjectionPathMask(const SkPath* path) {
    162     projectionPathMask = path;
    163 }
    164 
    165 static Snapshot* getClipRoot(Snapshot* target) {
    166     while (target->previous && target->previous->previous) {
    167         target = target->previous;
    168     }
    169     return target;
    170 }
    171 
    172 const ClipBase* Snapshot::serializeIntersectedClip(LinearAllocator& allocator,
    173                                                    const ClipBase* recordedClip,
    174                                                    const Matrix4& recordedClipTransform) {
    175     auto target = this;
    176     if (CC_UNLIKELY(recordedClip && recordedClip->intersectWithRoot)) {
    177         // Clip must be intersected with root, instead of current clip.
    178         target = getClipRoot(this);
    179     }
    180 
    181     return target->mClipArea->serializeIntersectedClip(allocator, recordedClip,
    182                                                        recordedClipTransform);
    183 }
    184 
    185 void Snapshot::applyClip(const ClipBase* recordedClip, const Matrix4& transform) {
    186     if (CC_UNLIKELY(recordedClip && recordedClip->intersectWithRoot)) {
    187         // current clip is being replaced, but must intersect with clip root
    188         *mClipArea = *(getClipRoot(this)->mClipArea);
    189     }
    190     mClipArea->applyClip(recordedClip, transform);
    191 }
    192 
    193 ///////////////////////////////////////////////////////////////////////////////
    194 // Queries
    195 ///////////////////////////////////////////////////////////////////////////////
    196 
    197 void Snapshot::dump() const {
    198     ALOGD("Snapshot %p, flags %x, prev %p, height %d, hasComplexClip %d", this, flags, previous,
    199           getViewportHeight(), !mClipArea->isSimple());
    200     const Rect& clipRect(mClipArea->getClipRect());
    201     ALOGD("  ClipRect %.1f %.1f %.1f %.1f, clip simple %d", clipRect.left, clipRect.top,
    202           clipRect.right, clipRect.bottom, mClipArea->isSimple());
    203 
    204     ALOGD("  Transform (at %p):", transform);
    205     transform->dump();
    206 }
    207 
    208 };  // namespace uirenderer
    209 };  // namespace android
    210