Home | History | Annotate | Download | only in unit
      1 /*
      2  * Copyright (C) 2015 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 "CanvasState.h"
     18 
     19 #include "Matrix.h"
     20 #include "Rect.h"
     21 #include "hwui/Canvas.h"
     22 #include "utils/LinearAllocator.h"
     23 
     24 #include <SkClipOp.h>
     25 #include <SkPath.h>
     26 #include <gtest/gtest.h>
     27 
     28 namespace android {
     29 namespace uirenderer {
     30 
     31 class NullClient : public CanvasStateClient {
     32     void onViewportInitialized() override {}
     33     void onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) {}
     34     GLuint getTargetFbo() const override { return 0; }
     35 };
     36 
     37 static NullClient sNullClient;
     38 
     39 static bool approxEqual(const Matrix4& a, const Matrix4& b) {
     40     for (int i = 0; i < 16; i++) {
     41         if (!MathUtils::areEqual(a[i], b[i])) {
     42             return false;
     43         }
     44     }
     45     return true;
     46 }
     47 
     48 TEST(CanvasState, gettersAndSetters) {
     49     CanvasState state(sNullClient);
     50     state.initializeSaveStack(200, 200, 0, 0, 200, 200, Vector3());
     51 
     52     ASSERT_EQ(state.getWidth(), 200);
     53     ASSERT_EQ(state.getHeight(), 200);
     54 
     55     Matrix4 simpleTranslate;
     56     simpleTranslate.loadTranslate(10, 20, 0);
     57     state.setMatrix(simpleTranslate);
     58 
     59     ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(200, 200));
     60     ASSERT_EQ(state.getLocalClipBounds(), Rect(-10, -20, 190, 180));
     61     EXPECT_TRUE(approxEqual(*state.currentTransform(), simpleTranslate));
     62     EXPECT_TRUE(state.clipIsSimple());
     63 }
     64 
     65 TEST(CanvasState, simpleClipping) {
     66     CanvasState state(sNullClient);
     67     state.initializeSaveStack(200, 200, 0, 0, 200, 200, Vector3());
     68 
     69     state.clipRect(0, 0, 100, 100, SkClipOp::kIntersect);
     70     ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(100, 100));
     71 
     72     state.clipRect(10, 10, 200, 200, SkClipOp::kIntersect);
     73     ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(10, 10, 100, 100));
     74 
     75     state.clipRect(50, 50, 150, 150, SkClipOp::kReplace_deprecated);
     76     ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(50, 50, 150, 150));
     77 }
     78 
     79 TEST(CanvasState, complexClipping) {
     80     CanvasState state(sNullClient);
     81     state.initializeSaveStack(200, 200, 0, 0, 200, 200, Vector3());
     82 
     83     state.save(SaveFlags::MatrixClip);
     84     {
     85         // rotated clip causes complex clip
     86         state.rotate(10);
     87         EXPECT_TRUE(state.clipIsSimple());
     88         state.clipRect(0, 0, 200, 200, SkClipOp::kIntersect);
     89         EXPECT_FALSE(state.clipIsSimple());
     90     }
     91     state.restore();
     92 
     93     state.save(SaveFlags::MatrixClip);
     94     {
     95         // subtracted clip causes complex clip
     96         EXPECT_TRUE(state.clipIsSimple());
     97         state.clipRect(50, 50, 150, 150, SkClipOp::kDifference);
     98         EXPECT_FALSE(state.clipIsSimple());
     99     }
    100     state.restore();
    101 
    102     state.save(SaveFlags::MatrixClip);
    103     {
    104         // complex path causes complex clip
    105         SkPath path;
    106         path.addOval(SkRect::MakeWH(200, 200));
    107         EXPECT_TRUE(state.clipIsSimple());
    108         state.clipPath(&path, SkClipOp::kDifference);
    109         EXPECT_FALSE(state.clipIsSimple());
    110     }
    111     state.restore();
    112 }
    113 
    114 TEST(CanvasState, saveAndRestore) {
    115     CanvasState state(sNullClient);
    116     state.initializeSaveStack(200, 200, 0, 0, 200, 200, Vector3());
    117 
    118     state.save(SaveFlags::Clip);
    119     {
    120         state.clipRect(0, 0, 10, 10, SkClipOp::kIntersect);
    121         ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(10, 10));
    122     }
    123     state.restore();
    124     ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(200, 200));  // verify restore
    125 
    126     Matrix4 simpleTranslate;
    127     simpleTranslate.loadTranslate(10, 10, 0);
    128     state.save(SaveFlags::Matrix);
    129     {
    130         state.translate(10, 10, 0);
    131         EXPECT_TRUE(approxEqual(*state.currentTransform(), simpleTranslate));
    132     }
    133     state.restore();
    134     EXPECT_FALSE(approxEqual(*state.currentTransform(), simpleTranslate));
    135 }
    136 
    137 TEST(CanvasState, saveAndRestoreButNotTooMuch) {
    138     CanvasState state(sNullClient);
    139     state.initializeSaveStack(200, 200, 0, 0, 200, 200, Vector3());
    140 
    141     state.save(SaveFlags::Matrix);  // NOTE: clip not saved
    142     {
    143         state.clipRect(0, 0, 10, 10, SkClipOp::kIntersect);
    144         ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(10, 10));
    145     }
    146     state.restore();
    147     ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(10, 10));  // verify not restored
    148 
    149     Matrix4 simpleTranslate;
    150     simpleTranslate.loadTranslate(10, 10, 0);
    151     state.save(SaveFlags::Clip);  // NOTE: matrix not saved
    152     {
    153         state.translate(10, 10, 0);
    154         EXPECT_TRUE(approxEqual(*state.currentTransform(), simpleTranslate));
    155     }
    156     state.restore();
    157     EXPECT_TRUE(approxEqual(*state.currentTransform(), simpleTranslate));  // verify not restored
    158 }
    159 }
    160 }
    161