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