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 <SkCanvas.h>
     20 
     21 namespace android {
     22 namespace uirenderer {
     23 
     24 ///////////////////////////////////////////////////////////////////////////////
     25 // Constructors
     26 ///////////////////////////////////////////////////////////////////////////////
     27 
     28 Snapshot::Snapshot(): flags(0), previous(NULL), layer(NULL), fbo(0),
     29         invisible(false), empty(false), alpha(1.0f) {
     30 
     31     transform = &mTransformRoot;
     32     clipRect = &mClipRectRoot;
     33     region = NULL;
     34     clipRegion = NULL;
     35 }
     36 
     37 /**
     38  * Copies the specified snapshot/ The specified snapshot is stored as
     39  * the previous snapshot.
     40  */
     41 Snapshot::Snapshot(const sp<Snapshot>& s, int saveFlags):
     42         flags(0), previous(s), layer(NULL), fbo(s->fbo),
     43         invisible(s->invisible), empty(false),
     44         viewport(s->viewport), height(s->height), alpha(s->alpha) {
     45 
     46     clipRegion = NULL;
     47 
     48     if (saveFlags & SkCanvas::kMatrix_SaveFlag) {
     49         mTransformRoot.load(*s->transform);
     50         transform = &mTransformRoot;
     51     } else {
     52         transform = s->transform;
     53     }
     54 
     55     if (saveFlags & SkCanvas::kClip_SaveFlag) {
     56         mClipRectRoot.set(*s->clipRect);
     57         clipRect = &mClipRectRoot;
     58 #if STENCIL_BUFFER_SIZE
     59         if (s->clipRegion) {
     60             mClipRegionRoot.merge(*s->clipRegion);
     61             clipRegion = &mClipRegionRoot;
     62         }
     63 #endif
     64     } else {
     65         clipRect = s->clipRect;
     66 #if STENCIL_BUFFER_SIZE
     67         clipRegion = s->clipRegion;
     68 #endif
     69     }
     70 
     71     if (s->flags & Snapshot::kFlagFboTarget) {
     72         flags |= Snapshot::kFlagFboTarget;
     73         region = s->region;
     74     } else {
     75         region = NULL;
     76     }
     77 }
     78 
     79 ///////////////////////////////////////////////////////////////////////////////
     80 // Clipping
     81 ///////////////////////////////////////////////////////////////////////////////
     82 
     83 void Snapshot::ensureClipRegion() {
     84 #if STENCIL_BUFFER_SIZE
     85     if (!clipRegion) {
     86         clipRegion = &mClipRegionRoot;
     87         android::Rect tmp(clipRect->left, clipRect->top, clipRect->right, clipRect->bottom);
     88         clipRegion->set(tmp);
     89     }
     90 #endif
     91 }
     92 
     93 void Snapshot::copyClipRectFromRegion() {
     94 #if STENCIL_BUFFER_SIZE
     95     if (!clipRegion->isEmpty()) {
     96         android::Rect bounds(clipRegion->bounds());
     97         clipRect->set(bounds.left, bounds.top, bounds.right, bounds.bottom);
     98 
     99         if (clipRegion->isRect()) {
    100             clipRegion->clear();
    101             clipRegion = NULL;
    102         }
    103     } else {
    104         clipRect->setEmpty();
    105         clipRegion = NULL;
    106     }
    107 #endif
    108 }
    109 
    110 bool Snapshot::clipRegionOr(float left, float top, float right, float bottom) {
    111 #if STENCIL_BUFFER_SIZE
    112     android::Rect tmp(left, top, right, bottom);
    113     clipRegion->orSelf(tmp);
    114     copyClipRectFromRegion();
    115     return true;
    116 #else
    117     return false;
    118 #endif
    119 }
    120 
    121 bool Snapshot::clipRegionXor(float left, float top, float right, float bottom) {
    122 #if STENCIL_BUFFER_SIZE
    123     android::Rect tmp(left, top, right, bottom);
    124     clipRegion->xorSelf(tmp);
    125     copyClipRectFromRegion();
    126     return true;
    127 #else
    128     return false;
    129 #endif
    130 }
    131 
    132 bool Snapshot::clipRegionAnd(float left, float top, float right, float bottom) {
    133 #if STENCIL_BUFFER_SIZE
    134     android::Rect tmp(left, top, right, bottom);
    135     clipRegion->andSelf(tmp);
    136     copyClipRectFromRegion();
    137     return true;
    138 #else
    139     return false;
    140 #endif
    141 }
    142 
    143 bool Snapshot::clipRegionNand(float left, float top, float right, float bottom) {
    144 #if STENCIL_BUFFER_SIZE
    145     android::Rect tmp(left, top, right, bottom);
    146     clipRegion->subtractSelf(tmp);
    147     copyClipRectFromRegion();
    148     return true;
    149 #else
    150     return false;
    151 #endif
    152 }
    153 
    154 bool Snapshot::clip(float left, float top, float right, float bottom, SkRegion::Op op) {
    155     Rect r(left, top, right, bottom);
    156     transform->mapRect(r);
    157     return clipTransformed(r, op);
    158 }
    159 
    160 bool Snapshot::clipTransformed(const Rect& r, SkRegion::Op op) {
    161     bool clipped = false;
    162 
    163     switch (op) {
    164         case SkRegion::kDifference_Op: {
    165             ensureClipRegion();
    166             clipped = clipRegionNand(r.left, r.top, r.right, r.bottom);
    167             break;
    168         }
    169         case SkRegion::kIntersect_Op: {
    170             if (CC_UNLIKELY(clipRegion)) {
    171                 clipped = clipRegionOr(r.left, r.top, r.right, r.bottom);
    172             } else {
    173                 clipped = clipRect->intersect(r);
    174                 if (!clipped) {
    175                     clipRect->setEmpty();
    176                     clipped = true;
    177                 }
    178             }
    179             break;
    180         }
    181         case SkRegion::kUnion_Op: {
    182             if (CC_UNLIKELY(clipRegion)) {
    183                 clipped = clipRegionAnd(r.left, r.top, r.right, r.bottom);
    184             } else {
    185                 clipped = clipRect->unionWith(r);
    186             }
    187             break;
    188         }
    189         case SkRegion::kXOR_Op: {
    190             ensureClipRegion();
    191             clipped = clipRegionXor(r.left, r.top, r.right, r.bottom);
    192             break;
    193         }
    194         case SkRegion::kReverseDifference_Op: {
    195             // TODO!!!!!!!
    196             break;
    197         }
    198         case SkRegion::kReplace_Op: {
    199             setClip(r.left, r.top, r.right, r.bottom);
    200             clipped = true;
    201             break;
    202         }
    203     }
    204 
    205     if (clipped) {
    206         flags |= Snapshot::kFlagClipSet;
    207     }
    208 
    209     return clipped;
    210 }
    211 
    212 void Snapshot::setClip(float left, float top, float right, float bottom) {
    213     clipRect->set(left, top, right, bottom);
    214 #if STENCIL_BUFFER_SIZE
    215     if (clipRegion) {
    216         clipRegion->clear();
    217         clipRegion = NULL;
    218     }
    219 #endif
    220     flags |= Snapshot::kFlagClipSet;
    221 }
    222 
    223 const Rect& Snapshot::getLocalClip() {
    224     mat4 inverse;
    225     inverse.loadInverse(*transform);
    226 
    227     mLocalClip.set(*clipRect);
    228     inverse.mapRect(mLocalClip);
    229 
    230     return mLocalClip;
    231 }
    232 
    233 void Snapshot::resetClip(float left, float top, float right, float bottom) {
    234     clipRect = &mClipRectRoot;
    235     setClip(left, top, right, bottom);
    236 }
    237 
    238 ///////////////////////////////////////////////////////////////////////////////
    239 // Transforms
    240 ///////////////////////////////////////////////////////////////////////////////
    241 
    242 void Snapshot::resetTransform(float x, float y, float z) {
    243     transform = &mTransformRoot;
    244     transform->loadTranslate(x, y, z);
    245 }
    246 
    247 ///////////////////////////////////////////////////////////////////////////////
    248 // Queries
    249 ///////////////////////////////////////////////////////////////////////////////
    250 
    251 bool Snapshot::isIgnored() const {
    252     return invisible || empty;
    253 }
    254 
    255 }; // namespace uirenderer
    256 }; // namespace android
    257