OLD | NEW |
| (Empty) |
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 val
ues | |
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_ScaleToF
it); | |
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,fitCen
ter,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 } | |
OLD | NEW |