Home | History | Annotate | Download | only in views
      1 #include "SkImageView.h"
      2 #include "SkAnimator.h"
      3 #include "SkBitmap.h"
      4 #include "SkCanvas.h"
      5 #include "SkImageDecoder.h"
      6 #include "SkMatrix.h"
      7 #include "SkSystemEventTypes.h"
      8 #include "SkTime.h"
      9 
     10 SkImageView::SkImageView()
     11 {
     12 	fMatrix		= NULL;
     13 	fScaleType	= kMatrix_ScaleType;
     14 
     15 	fData.fAnim	= NULL;		// handles initializing the other union values
     16 	fDataIsAnim	= true;
     17 
     18 	fUriIsValid	= false;	// an empty string is not valid
     19 }
     20 
     21 SkImageView::~SkImageView()
     22 {
     23 	if (fMatrix)
     24 		sk_free(fMatrix);
     25 
     26 	this->freeData();
     27 }
     28 
     29 void SkImageView::getUri(SkString* uri) const
     30 {
     31 	if (uri)
     32 		*uri = fUri;
     33 }
     34 
     35 void SkImageView::setUri(const char uri[])
     36 {
     37 	if (!fUri.equals(uri))
     38 	{
     39 		fUri.set(uri);
     40 		this->onUriChange();
     41 	}
     42 }
     43 
     44 void SkImageView::setUri(const SkString& uri)
     45 {
     46 	if (fUri != uri)
     47 	{
     48 		fUri = uri;
     49 		this->onUriChange();
     50 	}
     51 }
     52 
     53 void SkImageView::setScaleType(ScaleType st)
     54 {
     55 	SkASSERT((unsigned)st <= kFitEnd_ScaleType);
     56 
     57 	if ((ScaleType)fScaleType != st)
     58 	{
     59 		fScaleType = SkToU8(st);
     60 		if (fUriIsValid)
     61 			this->inval(NULL);
     62 	}
     63 }
     64 
     65 bool SkImageView::getImageMatrix(SkMatrix* matrix) const
     66 {
     67 	if (fMatrix)
     68 	{
     69 		SkASSERT(!fMatrix->isIdentity());
     70 		if (matrix)
     71 			*matrix = *fMatrix;
     72 		return true;
     73 	}
     74 	else
     75 	{
     76 		if (matrix)
     77 			matrix->reset();
     78 		return false;
     79 	}
     80 }
     81 
     82 void SkImageView::setImageMatrix(const SkMatrix* matrix)
     83 {
     84 	bool changed = false;
     85 
     86 	if (matrix && !matrix->isIdentity())
     87 	{
     88 		if (fMatrix == NULL)
     89 			fMatrix = (SkMatrix*)sk_malloc_throw(sizeof(SkMatrix));
     90 		*fMatrix = *matrix;
     91 		changed = true;
     92 	}
     93 	else	// set us to identity
     94 	{
     95 		if (fMatrix)
     96 		{
     97 			SkASSERT(!fMatrix->isIdentity());
     98 			sk_free(fMatrix);
     99 			fMatrix = NULL;
    100 			changed = true;
    101 		}
    102 	}
    103 
    104 	// only redraw if we changed our matrix and we're not in scaleToFit mode
    105 	if (changed && this->getScaleType() == kMatrix_ScaleType && fUriIsValid)
    106 		this->inval(NULL);
    107 }
    108 
    109 ///////////////////////////////////////////////////////////////////////////////////////////////
    110 
    111 bool SkImageView::onEvent(const SkEvent& evt)
    112 {
    113 	if (evt.isType(SK_EventType_Inval))
    114 	{
    115 		if (fUriIsValid)
    116 			this->inval(NULL);
    117 		return true;
    118 	}
    119 	return this->INHERITED::onEvent(evt);
    120 }
    121 
    122 static inline SkMatrix::ScaleToFit scaleTypeToScaleToFit(SkImageView::ScaleType st)
    123 {
    124 	SkASSERT(st != SkImageView::kMatrix_ScaleType);
    125 	SkASSERT((unsigned)st <= SkImageView::kFitEnd_ScaleType);
    126 
    127 	SkASSERT(SkImageView::kFitXY_ScaleType - 1 == SkMatrix::kFill_ScaleToFit);
    128 	SkASSERT(SkImageView::kFitStart_ScaleType - 1 == SkMatrix::kStart_ScaleToFit);
    129 	SkASSERT(SkImageView::kFitCenter_ScaleType - 1 == SkMatrix::kCenter_ScaleToFit);
    130 	SkASSERT(SkImageView::kFitEnd_ScaleType - 1 == SkMatrix::kEnd_ScaleToFit);
    131 
    132 	return (SkMatrix::ScaleToFit)(st - 1);
    133 }
    134 
    135 void SkImageView::onDraw(SkCanvas* canvas)
    136 {
    137 	SkRect	src;
    138 	if (!this->getDataBounds(&src))
    139 	{
    140 		SkDEBUGCODE(canvas->drawColor(SK_ColorRED);)
    141 		return;		// nothing to draw
    142 	}
    143 
    144 	SkAutoCanvasRestore	restore(canvas, true);
    145 	SkMatrix			matrix;
    146 
    147 	if (this->getScaleType() == kMatrix_ScaleType)
    148 		(void)this->getImageMatrix(&matrix);
    149 	else
    150 	{
    151 		SkRect	dst;
    152 		dst.set(0, 0, this->width(), this->height());
    153 		matrix.setRectToRect(src, dst, scaleTypeToScaleToFit(this->getScaleType()));
    154 	}
    155 	canvas->concat(matrix);
    156 
    157 	SkPaint	paint;
    158 
    159 	paint.setAntiAlias(true);
    160 
    161 	if (fDataIsAnim)
    162 	{
    163 		SkMSec	now = SkTime::GetMSecs();
    164 
    165 		SkAnimator::DifferenceType diff = fData.fAnim->draw(canvas, &paint, now);
    166 
    167 SkDEBUGF(("SkImageView : now = %X[%12.3f], diff = %d\n", now, now/1000., diff));
    168 
    169 		if (diff == SkAnimator::kDifferent)
    170 			this->inval(NULL);
    171 		else if (diff == SkAnimator::kPartiallyDifferent)
    172 		{
    173 			SkRect	bounds;
    174 			fData.fAnim->getInvalBounds(&bounds);
    175 			matrix.mapRect(&bounds);	// get the bounds into view coordinates
    176 			this->inval(&bounds);
    177 		}
    178 	}
    179 	else
    180 		canvas->drawBitmap(*fData.fBitmap, 0, 0, &paint);
    181 }
    182 
    183 void SkImageView::onInflate(const SkDOM& dom, const SkDOMNode* node)
    184 {
    185 	this->INHERITED::onInflate(dom, node);
    186 
    187 	const char* src = dom.findAttr(node, "src");
    188 	if (src)
    189 		this->setUri(src);
    190 
    191 	int	index = dom.findList(node, "scaleType", "matrix,fitXY,fitStart,fitCenter,fitEnd");
    192 	if (index >= 0)
    193 		this->setScaleType((ScaleType)index);
    194 
    195 	// need inflate syntax/reader for matrix
    196 }
    197 
    198 /////////////////////////////////////////////////////////////////////////////////////
    199 
    200 void SkImageView::onUriChange()
    201 {
    202 	if (this->freeData())
    203 		this->inval(NULL);
    204 	fUriIsValid = true;		// give ensureUriIsLoaded() a shot at the new uri
    205 }
    206 
    207 bool SkImageView::freeData()
    208 {
    209 	if (fData.fAnim)	// test is valid for all union values
    210 	{
    211 		if (fDataIsAnim)
    212 			delete fData.fAnim;
    213 		else
    214 			delete fData.fBitmap;
    215 
    216 		fData.fAnim = NULL;	// valid for all union values
    217 		return true;
    218 	}
    219 	return false;
    220 }
    221 
    222 bool SkImageView::getDataBounds(SkRect* bounds)
    223 {
    224 	SkASSERT(bounds);
    225 
    226 	if (this->ensureUriIsLoaded())
    227 	{
    228 		SkScalar width, height;
    229 
    230 		if (fDataIsAnim)
    231 		{
    232 			if (SkScalarIsNaN(width = fData.fAnim->getScalar("dimensions", "x")) ||
    233 				SkScalarIsNaN(height = fData.fAnim->getScalar("dimensions", "y")))
    234 			{
    235 				// cons up fake bounds
    236 				width = this->width();
    237 				height = this->height();
    238 			}
    239 		}
    240 		else
    241 		{
    242 			width = SkIntToScalar(fData.fBitmap->width());
    243 			height = SkIntToScalar(fData.fBitmap->height());
    244 		}
    245 		bounds->set(0, 0, width, height);
    246 		return true;
    247 	}
    248 	return false;
    249 }
    250 
    251 bool SkImageView::ensureUriIsLoaded()
    252 {
    253 	if (fData.fAnim)	// test is valid for all union values
    254 	{
    255 		SkASSERT(fUriIsValid);
    256 		return true;
    257 	}
    258 	if (!fUriIsValid)
    259 		return false;
    260 
    261 	// try to load the url
    262 	if (fUri.endsWith(".xml"))	// assume it is screenplay
    263 	{
    264 		SkAnimator* anim = new SkAnimator;
    265 
    266 		if (!anim->decodeURI(fUri.c_str()))
    267 		{
    268 			delete anim;
    269 			fUriIsValid = false;
    270 			return false;
    271 		}
    272 		anim->setHostEventSink(this);
    273 
    274 		fData.fAnim = anim;
    275 		fDataIsAnim = true;
    276 	}
    277 	else	// assume it is an image format
    278 	{
    279     #if 0
    280 		SkBitmap* bitmap = new SkBitmap;
    281 
    282 		if (!SkImageDecoder::DecodeURL(fUri.c_str(), bitmap))
    283 		{
    284 			delete bitmap;
    285 			fUriIsValid = false;
    286 			return false;
    287 		}
    288 		fData.fBitmap = bitmap;
    289 		fDataIsAnim = false;
    290     #else
    291         return false;
    292     #endif
    293 	}
    294 	return true;
    295 }
    296 
    297