1197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch
2197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch/*
3197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch * Copyright 2011 Google Inc.
453e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) *
553e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) * Use of this source code is governed by a BSD-style license that can be
653e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) * found in the LICENSE file.
793ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles) */
893ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)#include "SkImageView.h"
953e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "SkAnimator.h"
10aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch#include "SkBitmap.h"
11aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch#include "SkCanvas.h"
12aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch#include "SkImageDecoder.h"
13aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch#include "SkMatrix.h"
14aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch#include "SkSystemEventTypes.h"
15aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch#include "SkTime.h"
16aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch
17aafa69cb17c9d6606c07663ade5f81388a2c5986Ben MurdochSkImageView::SkImageView()
1853e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles){
1953e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)    fMatrix        = NULL;
2053e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)    fScaleType    = kMatrix_ScaleType;
2153e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)
2253e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)    fData.fAnim    = NULL;        // handles initializing the other union values
2393ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)    fDataIsAnim    = true;
2493ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)
2593ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)    fUriIsValid    = false;    // an empty string is not valid
2693ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)}
2793ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)
2853e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)SkImageView::~SkImageView()
2993ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles){
3093ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)    if (fMatrix)
3193ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)        sk_free(fMatrix);
3293ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)
3353e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)    this->freeData();
3453e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)}
3553e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)
3693ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)void SkImageView::getUri(SkString* uri) const
3793ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles){
3853e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)    if (uri)
3953e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)        *uri = fUri;
4093ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)}
4193ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)
4293ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)void SkImageView::setUri(const char uri[])
4393ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles){
4493ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)    if (!fUri.equals(uri))
4593ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)    {
4693ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)        fUri.set(uri);
47aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch        this->onUriChange();
4893ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)    }
4993ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)}
5093ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)
5193ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)void SkImageView::setUri(const SkString& uri)
5293ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles){
5393ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)    if (fUri != uri)
5493ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)    {
5593ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)        fUri = uri;
5693ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)        this->onUriChange();
5793ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)    }
5893ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)}
5993ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)
6093ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)void SkImageView::setScaleType(ScaleType st)
6193ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles){
6293ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)    SkASSERT((unsigned)st <= kFitEnd_ScaleType);
6393ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)
6453e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)    if ((ScaleType)fScaleType != st)
6593ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)    {
6693ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)        fScaleType = SkToU8(st);
6793ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)        if (fUriIsValid)
6893ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)            this->inval(NULL);
6993ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)    }
7093ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)}
7193ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)
7293ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)bool SkImageView::getImageMatrix(SkMatrix* matrix) const
73aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch{
74aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch    if (fMatrix)
75aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch    {
7693ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)        SkASSERT(!fMatrix->isIdentity());
7793ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)        if (matrix)
7893ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)            *matrix = *fMatrix;
79aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch        return true;
80aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch    }
81aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdoch    else
8293ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)    {
8393ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)        if (matrix)
8493ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)            matrix->reset();
8593ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)        return false;
8693ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)    }
8793ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)}
8893ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)
8993ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)void SkImageView::setImageMatrix(const SkMatrix* matrix)
9093ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles){
9193ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)    bool changed = false;
9293ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)
9393ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)    if (matrix && !matrix->isIdentity())
9493ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)    {
9593ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)        if (fMatrix == NULL)
9693ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)            fMatrix = (SkMatrix*)sk_malloc_throw(sizeof(SkMatrix));
9793ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)        *fMatrix = *matrix;
9893ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)        changed = true;
9993ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)    }
10093ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)    else    // set us to identity
10193ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)    {
10293ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)        if (fMatrix)
10393ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)        {
10493ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)            SkASSERT(!fMatrix->isIdentity());
10593ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)            sk_free(fMatrix);
10693ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)            fMatrix = NULL;
10793ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)            changed = true;
10893ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)        }
10993ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)    }
11093ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)
11193ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)    // only redraw if we changed our matrix and we're not in scaleToFit mode
11293ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)    if (changed && this->getScaleType() == kMatrix_ScaleType && fUriIsValid)
11393ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)        this->inval(NULL);
11493ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)}
11593ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)
11693ac45cfc74041c8ae536ce58a9534d46db2024eTorne (Richard Coles)///////////////////////////////////////////////////////////////////////////////////////////////
11753e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)
118aafa69cb17c9d6606c07663ade5f81388a2c5986Ben Murdochbool SkImageView::onEvent(const SkEvent& evt)
119{
120    if (evt.isType(SK_EventType_Inval))
121    {
122        if (fUriIsValid)
123            this->inval(NULL);
124        return true;
125    }
126    return this->INHERITED::onEvent(evt);
127}
128
129static inline SkMatrix::ScaleToFit scaleTypeToScaleToFit(SkImageView::ScaleType st)
130{
131    SkASSERT(st != SkImageView::kMatrix_ScaleType);
132    SkASSERT((unsigned)st <= SkImageView::kFitEnd_ScaleType);
133
134    SkASSERT(SkImageView::kFitXY_ScaleType - 1 == SkMatrix::kFill_ScaleToFit);
135    SkASSERT(SkImageView::kFitStart_ScaleType - 1 == SkMatrix::kStart_ScaleToFit);
136    SkASSERT(SkImageView::kFitCenter_ScaleType - 1 == SkMatrix::kCenter_ScaleToFit);
137    SkASSERT(SkImageView::kFitEnd_ScaleType - 1 == SkMatrix::kEnd_ScaleToFit);
138
139    return (SkMatrix::ScaleToFit)(st - 1);
140}
141
142void SkImageView::onDraw(SkCanvas* canvas)
143{
144    SkRect    src;
145    if (!this->getDataBounds(&src))
146    {
147        SkDEBUGCODE(canvas->drawColor(SK_ColorRED);)
148        return;        // nothing to draw
149    }
150
151    SkAutoCanvasRestore    restore(canvas, true);
152    SkMatrix            matrix;
153
154    if (this->getScaleType() == kMatrix_ScaleType)
155        (void)this->getImageMatrix(&matrix);
156    else
157    {
158        SkRect    dst;
159        dst.set(0, 0, this->width(), this->height());
160        matrix.setRectToRect(src, dst, scaleTypeToScaleToFit(this->getScaleType()));
161    }
162    canvas->concat(matrix);
163
164    SkPaint    paint;
165
166    paint.setAntiAlias(true);
167
168    if (fDataIsAnim)
169    {
170        SkMSec    now = SkTime::GetMSecs();
171
172        SkAnimator::DifferenceType diff = fData.fAnim->draw(canvas, &paint, now);
173
174SkDEBUGF(("SkImageView : now = %X[%12.3f], diff = %d\n", now, now/1000., diff));
175
176        if (diff == SkAnimator::kDifferent)
177            this->inval(NULL);
178        else if (diff == SkAnimator::kPartiallyDifferent)
179        {
180            SkRect    bounds;
181            fData.fAnim->getInvalBounds(&bounds);
182            matrix.mapRect(&bounds);    // get the bounds into view coordinates
183            this->inval(&bounds);
184        }
185    }
186    else
187        canvas->drawBitmap(*fData.fBitmap, 0, 0, &paint);
188}
189
190void SkImageView::onInflate(const SkDOM& dom, const SkDOMNode* node)
191{
192    this->INHERITED::onInflate(dom, node);
193
194    const char* src = dom.findAttr(node, "src");
195    if (src)
196        this->setUri(src);
197
198    int    index = dom.findList(node, "scaleType", "matrix,fitXY,fitStart,fitCenter,fitEnd");
199    if (index >= 0)
200        this->setScaleType((ScaleType)index);
201
202    // need inflate syntax/reader for matrix
203}
204
205/////////////////////////////////////////////////////////////////////////////////////
206
207void SkImageView::onUriChange()
208{
209    if (this->freeData())
210        this->inval(NULL);
211    fUriIsValid = true;        // give ensureUriIsLoaded() a shot at the new uri
212}
213
214bool SkImageView::freeData()
215{
216    if (fData.fAnim)    // test is valid for all union values
217    {
218        if (fDataIsAnim)
219            delete fData.fAnim;
220        else
221            delete fData.fBitmap;
222
223        fData.fAnim = NULL;    // valid for all union values
224        return true;
225    }
226    return false;
227}
228
229bool SkImageView::getDataBounds(SkRect* bounds)
230{
231    SkASSERT(bounds);
232
233    if (this->ensureUriIsLoaded())
234    {
235        SkScalar width, height;
236
237        if (fDataIsAnim)
238        {
239            if (SkScalarIsNaN(width = fData.fAnim->getScalar("dimensions", "x")) ||
240                SkScalarIsNaN(height = fData.fAnim->getScalar("dimensions", "y")))
241            {
242                // cons up fake bounds
243                width = this->width();
244                height = this->height();
245            }
246        }
247        else
248        {
249            width = SkIntToScalar(fData.fBitmap->width());
250            height = SkIntToScalar(fData.fBitmap->height());
251        }
252        bounds->set(0, 0, width, height);
253        return true;
254    }
255    return false;
256}
257
258bool SkImageView::ensureUriIsLoaded()
259{
260    if (fData.fAnim)    // test is valid for all union values
261    {
262        SkASSERT(fUriIsValid);
263        return true;
264    }
265    if (!fUriIsValid)
266        return false;
267
268    // try to load the url
269    if (fUri.endsWith(".xml"))    // assume it is screenplay
270    {
271        SkAnimator* anim = new SkAnimator;
272
273        if (!anim->decodeURI(fUri.c_str()))
274        {
275            delete anim;
276            fUriIsValid = false;
277            return false;
278        }
279        anim->setHostEventSink(this);
280
281        fData.fAnim = anim;
282        fDataIsAnim = true;
283    }
284    else    // assume it is an image format
285    {
286    #if 0
287        SkBitmap* bitmap = new SkBitmap;
288
289        if (!SkImageDecoder::DecodeURL(fUri.c_str(), bitmap))
290        {
291            delete bitmap;
292            fUriIsValid = false;
293            return false;
294        }
295        fData.fBitmap = bitmap;
296        fDataIsAnim = false;
297    #else
298        return false;
299    #endif
300    }
301    return true;
302}
303