Home | History | Annotate | Download | only in animated
      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 "SkImageView.h"
      9 #include "SkAnimator.h"
     10 #include "SkBitmap.h"
     11 #include "SkCanvas.h"
     12 #include "SkImageDecoder.h"
     13 #include "SkMatrix.h"
     14 #include "SkSystemEventTypes.h"
     15 #include "SkTime.h"
     16 
     17 SkImageView::SkImageView()
     18 {
     19     fMatrix        = nullptr;
     20     fScaleType    = kMatrix_ScaleType;
     21 
     22     fData.fAnim    = nullptr;        // handles initializing the other union values
     23     fDataIsAnim    = true;
     24 
     25     fUriIsValid    = false;    // an empty string is not valid
     26 }
     27 
     28 SkImageView::~SkImageView()
     29 {
     30     if (fMatrix)
     31         sk_free(fMatrix);
     32 
     33     this->freeData();
     34 }
     35 
     36 void SkImageView::getUri(SkString* uri) const
     37 {
     38     if (uri)
     39         *uri = fUri;
     40 }
     41 
     42 void SkImageView::setUri(const char uri[])
     43 {
     44     if (!fUri.equals(uri))
     45     {
     46         fUri.set(uri);
     47         this->onUriChange();
     48     }
     49 }
     50 
     51 void SkImageView::setUri(const SkString& uri)
     52 {
     53     if (fUri != uri)
     54     {
     55         fUri = uri;
     56         this->onUriChange();
     57     }
     58 }
     59 
     60 void SkImageView::setScaleType(ScaleType st)
     61 {
     62     SkASSERT((unsigned)st <= kFitEnd_ScaleType);
     63 
     64     if ((ScaleType)fScaleType != st)
     65     {
     66         fScaleType = SkToU8(st);
     67         if (fUriIsValid)
     68             this->inval(nullptr);
     69     }
     70 }
     71 
     72 bool SkImageView::getImageMatrix(SkMatrix* matrix) const
     73 {
     74     if (fMatrix)
     75     {
     76         SkASSERT(!fMatrix->isIdentity());
     77         if (matrix)
     78             *matrix = *fMatrix;
     79         return true;
     80     }
     81     else
     82     {
     83         if (matrix)
     84             matrix->reset();
     85         return false;
     86     }
     87 }
     88 
     89 void SkImageView::setImageMatrix(const SkMatrix* matrix)
     90 {
     91     bool changed = false;
     92 
     93     if (matrix && !matrix->isIdentity())
     94     {
     95         if (fMatrix == nullptr)
     96             fMatrix = (SkMatrix*)sk_malloc_throw(sizeof(SkMatrix));
     97         *fMatrix = *matrix;
     98         changed = true;
     99     }
    100     else    // set us to identity
    101     {
    102         if (fMatrix)
    103         {
    104             SkASSERT(!fMatrix->isIdentity());
    105             sk_free(fMatrix);
    106             fMatrix = nullptr;
    107             changed = true;
    108         }
    109     }
    110 
    111     // only redraw if we changed our matrix and we're not in scaleToFit mode
    112     if (changed && this->getScaleType() == kMatrix_ScaleType && fUriIsValid)
    113         this->inval(nullptr);
    114 }
    115 
    116 ///////////////////////////////////////////////////////////////////////////////////////////////
    117 
    118 bool SkImageView::onEvent(const SkEvent& evt)
    119 {
    120     if (evt.isType(SK_EventType_Inval))
    121     {
    122         if (fUriIsValid)
    123             this->inval(nullptr);
    124         return true;
    125     }
    126     return this->INHERITED::onEvent(evt);
    127 }
    128 
    129 static 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 
    142 void 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 
    174 SkDEBUGF(("SkImageView : now = %X[%12.3f], diff = %d\n", now, now/1000., diff));
    175 
    176         if (diff == SkAnimator::kDifferent)
    177             this->inval(nullptr);
    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 
    190 void 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 
    207 void SkImageView::onUriChange()
    208 {
    209     if (this->freeData())
    210         this->inval(nullptr);
    211     fUriIsValid = true;        // give ensureUriIsLoaded() a shot at the new uri
    212 }
    213 
    214 bool 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 = nullptr;    // valid for all union values
    224         return true;
    225     }
    226     return false;
    227 }
    228 
    229 bool 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 
    258 bool 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