1
2/*
3 * Copyright 2011 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8#include "SampleCode.h"
9#include "SkCanvas.h"
10#include "SkPaint.h"
11#include "SkView.h"
12#include "SkLayer.h"
13
14#include "SkMatrix44.h"
15static void test_inv(const char label[], const SkMatrix44& mat) {
16    SkDebugf("%s\n", label);
17    mat.dump();
18
19    SkMatrix44 inv;
20    if (mat.invert(&inv)) {
21        inv.dump();
22    } else {
23        SkDebugf("--- invert failed\n");
24    }
25
26    SkMatrix44 a, b;
27    a.setConcat(mat, inv);
28    b.setConcat(inv, mat);
29    SkDebugf("concat mat with inverse pre=%d post=%d\n", a.isIdentity(), b.isIdentity());
30    if (!a.isIdentity()) {
31        a.dump();
32    }
33    if (!b.isIdentity()) {
34        b.dump();
35    }
36    SkDebugf("\n");
37}
38
39static void test_map(SkScalar x0, SkScalar y0, SkScalar z0,
40                     const SkMatrix44& mat,
41                     SkScalar x1, SkScalar y1, SkScalar z1) {
42    SkVector4 src, dst;
43    src.set(x0, y0, z0);
44    dst = mat * src;
45    SkDebugf("map: src: %g %g %g dst: %g %g %g (%g) expected: %g %g %g match: %d\n",
46             x0, y0, z0,
47             dst.fData[0], dst.fData[1], dst.fData[2], dst.fData[3],
48             x1, y1, z1,
49             dst.fData[0] == x1 && dst.fData[1] == y1 && dst.fData[2] == z1);
50}
51
52static void test_33(const SkMatrix44& mat,
53                    SkScalar x0, SkScalar x1, SkScalar x2,
54                    SkScalar y0, SkScalar y1, SkScalar y2) {
55    SkMatrix dst = mat;
56    if (dst[0] != x0 || dst[1] != x1 || dst[2] != x2 ||
57        dst[3] != y0 || dst[4] != y1 || dst[5] != y2) {
58        SkString str;
59        dst.toString(&str);
60        SkDebugf("3x3: expected 3x3 [%g %g %g] [%g %g %g] bug got %s\n",
61                 x0, x1, x2, y0, y1, y2, str.c_str());
62    }
63}
64
65static void test44() {
66    SkMatrix44 m0, m1, m2;
67
68    test_inv("identity", m0);
69    m0.setTranslate(2,3,4);
70    test_inv("translate", m0);
71    m0.setScale(2,3,4);
72    test_inv("scale", m0);
73    m0.postTranslate(5, 6, 7);
74    test_inv("postTranslate", m0);
75    m0.setScale(2,3,4);
76    m1.setTranslate(5, 6, 7);
77    m0.setConcat(m0, m1);
78    test_inv("postTranslate2", m0);
79    m0.setScale(2,3,4);
80    m0.preTranslate(5, 6, 7);
81    test_inv("preTranslate", m0);
82
83    m0.setScale(2, 4, 6);
84    m0.postScale(SkDoubleToMScalar(0.5));
85    test_inv("scale/postscale to 1,2,3", m0);
86
87    m0.reset();
88    test_map(1, 0, 0, m0, 1, 0, 0);
89    test_map(0, 1, 0, m0, 0, 1, 0);
90    test_map(0, 0, 1, m0, 0, 0, 1);
91    m0.setScale(2, 3, 4);
92    test_map(1, 0, 0, m0, 2, 0, 0);
93    test_map(0, 1, 0, m0, 0, 3, 0);
94    test_map(0, 0, 1, m0, 0, 0, 4);
95    m0.setTranslate(2, 3, 4);
96    test_map(0, 0, 0, m0, 2, 3, 4);
97    m0.preScale(5, 6, 7);
98    test_map(1, 0, 0, m0, 7, 3, 4);
99    test_map(0, 1, 0, m0, 2, 9, 4);
100    test_map(0, 0, 1, m0, 2, 3, 11);
101
102    SkMScalar deg = 45;
103    m0.setRotateDegreesAbout(0, 0, 1, deg);
104    test_map(1, 0, 0, m0, 0.707106769, -0.707106769, 0);
105
106    m0.reset();
107    test_33(m0, 1, 0, 0, 0, 1, 0);
108    m0.setTranslate(3, 4, 5);
109    test_33(m0, 1, 0, 3, 0, 1, 4);
110}
111
112///////////////////////////////////////////////////////////////////////////////
113
114static void dump_layers(const SkLayer* layer, int tab = 0) {
115    SkMatrix matrix;
116    SkString matrixStr;
117
118    layer->getLocalTransform(&matrix);
119    matrix.toString(&matrixStr);
120
121    for (int j = 0; j < tab; j++) {
122        SkDebugf(" ");
123    }
124    SkDebugf("layer=%p parent=%p size=[%g %g] transform=%s\n",
125             layer, layer->getParent(), layer->getWidth(), layer->getHeight(),
126             matrixStr.c_str());
127    for (int i = 0; i < layer->countChildren(); i++) {
128        dump_layers(layer->getChild(i), tab + 4);
129    }
130}
131
132class TestLayer : public SkLayer {
133public:
134    TestLayer(SkColor c) : fColor(c) {}
135
136protected:
137    virtual void onDraw(SkCanvas* canvas, SkScalar opacity) {
138        SkRect r;
139        r.set(0, 0, this->getWidth(), this->getHeight());
140
141        SkPaint paint;
142        paint.setColor(fColor);
143        paint.setAlpha(SkScalarRoundToInt(opacity * 255));
144
145        canvas->drawRect(r, paint);
146    }
147
148private:
149    SkColor fColor;
150};
151
152class SkLayerView : public SkView {
153private:
154    SkLayer* fRootLayer;
155    SkLayer* fLastChild;
156public:
157    SkLayerView() {
158        test44();
159        static const int W = 600;
160        static const int H = 440;
161        static const struct {
162            int fWidth;
163            int fHeight;
164            SkColor fColor;
165            int fPosX;
166            int fPosY;
167        } gData[] = {
168            { 120, 80, SK_ColorRED, 0, 0 },
169            { 120, 80, SK_ColorGREEN, W - 120, 0 },
170            { 120, 80, SK_ColorBLUE, 0, H - 80 },
171            { 120, 80, SK_ColorMAGENTA, W - 120, H - 80 },
172        };
173
174        fRootLayer = new TestLayer(0xFFDDDDDD);
175        fRootLayer->setSize(W, H);
176        for (size_t i = 0; i < SK_ARRAY_COUNT(gData); i++) {
177            SkLayer* child = new TestLayer(gData[i].fColor);
178            child->setSize(gData[i].fWidth, gData[i].fHeight);
179            child->setPosition(gData[i].fPosX, gData[i].fPosY);
180            fRootLayer->addChild(child)->unref();
181        }
182
183        SkLayer* child = new TestLayer(0xFFDD8844);
184        child->setSize(120, 80);
185        child->setPosition(fRootLayer->getWidth()/2 - child->getWidth()/2,
186                           fRootLayer->getHeight()/2 - child->getHeight()/2);
187        child->setAnchorPoint(SK_ScalarHalf, SK_ScalarHalf);
188        {
189            SkMatrix m;
190            m.setRotate(SkIntToScalar(30));
191            child->setMatrix(m);
192        }
193        fLastChild = child;
194        fRootLayer->addChild(child)->unref();
195
196        if (false) {
197            SkMatrix matrix;
198            matrix.setScale(0.5, 0.5);
199            fRootLayer->setMatrix(matrix);
200        }
201
202//        dump_layers(fRootLayer);
203    }
204
205    virtual ~SkLayerView() {
206        SkSafeUnref(fRootLayer);
207    }
208
209protected:
210    // overrides from SkEventSink
211    virtual bool onQuery(SkEvent* evt) {
212        if (SampleCode::TitleQ(*evt)) {
213            SampleCode::TitleR(evt, "SkLayer");
214            return true;
215        }
216        return this->INHERITED::onQuery(evt);
217    }
218
219    virtual void onDraw(SkCanvas* canvas) {
220        canvas->drawColor(SK_ColorWHITE);
221
222        canvas->translate(20, 20);
223        fRootLayer->draw(canvas);
224
225        // visual test of getLocalTransform
226        if (true) {
227            SkMatrix matrix;
228            fLastChild->localToGlobal(&matrix);
229            SkPaint paint;
230            paint.setStyle(SkPaint::kStroke_Style);
231            paint.setStrokeWidth(5);
232            paint.setColor(0x88FF0000);
233            canvas->concat(matrix);
234            canvas->drawRect(SkRect::MakeSize(fLastChild->getSize()), paint);
235        }
236    }
237
238private:
239    typedef SkView INHERITED;
240};
241
242///////////////////////////////////////////////////////////////////////////////
243
244static SkView* MyFactory() { return new SkLayerView; }
245static SkViewRegister reg(MyFactory);
246