• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
SkImageView()17 SkImageView::SkImageView()
18 {
19 	fMatrix		= NULL;
20 	fScaleType	= kMatrix_ScaleType;
21 
22 	fData.fAnim	= NULL;		// handles initializing the other union values
23 	fDataIsAnim	= true;
24 
25 	fUriIsValid	= false;	// an empty string is not valid
26 }
27 
~SkImageView()28 SkImageView::~SkImageView()
29 {
30 	if (fMatrix)
31 		sk_free(fMatrix);
32 
33 	this->freeData();
34 }
35 
getUri(SkString * uri) const36 void SkImageView::getUri(SkString* uri) const
37 {
38 	if (uri)
39 		*uri = fUri;
40 }
41 
setUri(const char uri[])42 void SkImageView::setUri(const char uri[])
43 {
44 	if (!fUri.equals(uri))
45 	{
46 		fUri.set(uri);
47 		this->onUriChange();
48 	}
49 }
50 
setUri(const SkString & uri)51 void SkImageView::setUri(const SkString& uri)
52 {
53 	if (fUri != uri)
54 	{
55 		fUri = uri;
56 		this->onUriChange();
57 	}
58 }
59 
setScaleType(ScaleType st)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(NULL);
69 	}
70 }
71 
getImageMatrix(SkMatrix * matrix) const72 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 
setImageMatrix(const SkMatrix * matrix)89 void SkImageView::setImageMatrix(const SkMatrix* matrix)
90 {
91 	bool changed = false;
92 
93 	if (matrix && !matrix->isIdentity())
94 	{
95 		if (fMatrix == NULL)
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 = NULL;
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(NULL);
114 }
115 
116 ///////////////////////////////////////////////////////////////////////////////////////////////
117 
onEvent(const SkEvent & evt)118 bool 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 
scaleTypeToScaleToFit(SkImageView::ScaleType st)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 
onDraw(SkCanvas * canvas)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(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 
onInflate(const SkDOM & dom,const SkDOMNode * node)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 
onUriChange()207 void SkImageView::onUriChange()
208 {
209 	if (this->freeData())
210 		this->inval(NULL);
211 	fUriIsValid = true;		// give ensureUriIsLoaded() a shot at the new uri
212 }
213 
freeData()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 = NULL;	// valid for all union values
224 		return true;
225 	}
226 	return false;
227 }
228 
getDataBounds(SkRect * bounds)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 
ensureUriIsLoaded()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 
304