summaryrefslogtreecommitdiff
path: root/views/animated/SkImageView.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'views/animated/SkImageView.cpp')
-rw-r--r--views/animated/SkImageView.cpp302
1 files changed, 302 insertions, 0 deletions
diff --git a/views/animated/SkImageView.cpp b/views/animated/SkImageView.cpp
new file mode 100644
index 00000000..2956729f
--- /dev/null
+++ b/views/animated/SkImageView.cpp
@@ -0,0 +1,302 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "SkImageView.h"
+#include "SkAnimator.h"
+#include "SkBitmap.h"
+#include "SkCanvas.h"
+#include "SkImageDecoder.h"
+#include "SkMatrix.h"
+#include "SkSystemEventTypes.h"
+#include "SkTime.h"
+
+SkImageView::SkImageView()
+{
+ fMatrix = NULL;
+ fScaleType = kMatrix_ScaleType;
+
+ fData.fAnim = NULL; // handles initializing the other union values
+ fDataIsAnim = true;
+
+ fUriIsValid = false; // an empty string is not valid
+}
+
+SkImageView::~SkImageView()
+{
+ if (fMatrix)
+ sk_free(fMatrix);
+
+ this->freeData();
+}
+
+void SkImageView::getUri(SkString* uri) const
+{
+ if (uri)
+ *uri = fUri;
+}
+
+void SkImageView::setUri(const char uri[])
+{
+ if (!fUri.equals(uri))
+ {
+ fUri.set(uri);
+ this->onUriChange();
+ }
+}
+
+void SkImageView::setUri(const SkString& uri)
+{
+ if (fUri != uri)
+ {
+ fUri = uri;
+ this->onUriChange();
+ }
+}
+
+void SkImageView::setScaleType(ScaleType st)
+{
+ SkASSERT((unsigned)st <= kFitEnd_ScaleType);
+
+ if ((ScaleType)fScaleType != st)
+ {
+ fScaleType = SkToU8(st);
+ if (fUriIsValid)
+ this->inval(NULL);
+ }
+}
+
+bool SkImageView::getImageMatrix(SkMatrix* matrix) const
+{
+ if (fMatrix)
+ {
+ SkASSERT(!fMatrix->isIdentity());
+ if (matrix)
+ *matrix = *fMatrix;
+ return true;
+ }
+ else
+ {
+ if (matrix)
+ matrix->reset();
+ return false;
+ }
+}
+
+void SkImageView::setImageMatrix(const SkMatrix* matrix)
+{
+ bool changed = false;
+
+ if (matrix && !matrix->isIdentity())
+ {
+ if (fMatrix == NULL)
+ fMatrix = (SkMatrix*)sk_malloc_throw(sizeof(SkMatrix));
+ *fMatrix = *matrix;
+ changed = true;
+ }
+ else // set us to identity
+ {
+ if (fMatrix)
+ {
+ SkASSERT(!fMatrix->isIdentity());
+ sk_free(fMatrix);
+ fMatrix = NULL;
+ changed = true;
+ }
+ }
+
+ // only redraw if we changed our matrix and we're not in scaleToFit mode
+ if (changed && this->getScaleType() == kMatrix_ScaleType && fUriIsValid)
+ this->inval(NULL);
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////
+
+bool SkImageView::onEvent(const SkEvent& evt)
+{
+ if (evt.isType(SK_EventType_Inval))
+ {
+ if (fUriIsValid)
+ this->inval(NULL);
+ return true;
+ }
+ return this->INHERITED::onEvent(evt);
+}
+
+static inline SkMatrix::ScaleToFit scaleTypeToScaleToFit(SkImageView::ScaleType st)
+{
+ SkASSERT(st != SkImageView::kMatrix_ScaleType);
+ SkASSERT((unsigned)st <= SkImageView::kFitEnd_ScaleType);
+
+ SkASSERT(SkImageView::kFitXY_ScaleType - 1 == SkMatrix::kFill_ScaleToFit);
+ SkASSERT(SkImageView::kFitStart_ScaleType - 1 == SkMatrix::kStart_ScaleToFit);
+ SkASSERT(SkImageView::kFitCenter_ScaleType - 1 == SkMatrix::kCenter_ScaleToFit);
+ SkASSERT(SkImageView::kFitEnd_ScaleType - 1 == SkMatrix::kEnd_ScaleToFit);
+
+ return (SkMatrix::ScaleToFit)(st - 1);
+}
+
+void SkImageView::onDraw(SkCanvas* canvas)
+{
+ SkRect src;
+ if (!this->getDataBounds(&src))
+ {
+ SkDEBUGCODE(canvas->drawColor(SK_ColorRED);)
+ return; // nothing to draw
+ }
+
+ SkAutoCanvasRestore restore(canvas, true);
+ SkMatrix matrix;
+
+ if (this->getScaleType() == kMatrix_ScaleType)
+ (void)this->getImageMatrix(&matrix);
+ else
+ {
+ SkRect dst;
+ dst.set(0, 0, this->width(), this->height());
+ matrix.setRectToRect(src, dst, scaleTypeToScaleToFit(this->getScaleType()));
+ }
+ canvas->concat(matrix);
+
+ SkPaint paint;
+
+ paint.setAntiAlias(true);
+
+ if (fDataIsAnim)
+ {
+ SkMSec now = SkTime::GetMSecs();
+
+ SkAnimator::DifferenceType diff = fData.fAnim->draw(canvas, &paint, now);
+
+SkDEBUGF(("SkImageView : now = %X[%12.3f], diff = %d\n", now, now/1000., diff));
+
+ if (diff == SkAnimator::kDifferent)
+ this->inval(NULL);
+ else if (diff == SkAnimator::kPartiallyDifferent)
+ {
+ SkRect bounds;
+ fData.fAnim->getInvalBounds(&bounds);
+ matrix.mapRect(&bounds); // get the bounds into view coordinates
+ this->inval(&bounds);
+ }
+ }
+ else
+ canvas->drawBitmap(*fData.fBitmap, 0, 0, &paint);
+}
+
+void SkImageView::onInflate(const SkDOM& dom, const SkDOMNode* node)
+{
+ this->INHERITED::onInflate(dom, node);
+
+ const char* src = dom.findAttr(node, "src");
+ if (src)
+ this->setUri(src);
+
+ int index = dom.findList(node, "scaleType", "matrix,fitXY,fitStart,fitCenter,fitEnd");
+ if (index >= 0)
+ this->setScaleType((ScaleType)index);
+
+ // need inflate syntax/reader for matrix
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+
+void SkImageView::onUriChange()
+{
+ if (this->freeData())
+ this->inval(NULL);
+ fUriIsValid = true; // give ensureUriIsLoaded() a shot at the new uri
+}
+
+bool SkImageView::freeData()
+{
+ if (fData.fAnim) // test is valid for all union values
+ {
+ if (fDataIsAnim)
+ delete fData.fAnim;
+ else
+ delete fData.fBitmap;
+
+ fData.fAnim = NULL; // valid for all union values
+ return true;
+ }
+ return false;
+}
+
+bool SkImageView::getDataBounds(SkRect* bounds)
+{
+ SkASSERT(bounds);
+
+ if (this->ensureUriIsLoaded())
+ {
+ SkScalar width, height;
+
+ if (fDataIsAnim)
+ {
+ if (SkScalarIsNaN(width = fData.fAnim->getScalar("dimensions", "x")) ||
+ SkScalarIsNaN(height = fData.fAnim->getScalar("dimensions", "y")))
+ {
+ // cons up fake bounds
+ width = this->width();
+ height = this->height();
+ }
+ }
+ else
+ {
+ width = SkIntToScalar(fData.fBitmap->width());
+ height = SkIntToScalar(fData.fBitmap->height());
+ }
+ bounds->set(0, 0, width, height);
+ return true;
+ }
+ return false;
+}
+
+bool SkImageView::ensureUriIsLoaded()
+{
+ if (fData.fAnim) // test is valid for all union values
+ {
+ SkASSERT(fUriIsValid);
+ return true;
+ }
+ if (!fUriIsValid)
+ return false;
+
+ // try to load the url
+ if (fUri.endsWith(".xml")) // assume it is screenplay
+ {
+ SkAnimator* anim = new SkAnimator;
+
+ if (!anim->decodeURI(fUri.c_str()))
+ {
+ delete anim;
+ fUriIsValid = false;
+ return false;
+ }
+ anim->setHostEventSink(this);
+
+ fData.fAnim = anim;
+ fDataIsAnim = true;
+ }
+ else // assume it is an image format
+ {
+ #if 0
+ SkBitmap* bitmap = new SkBitmap;
+
+ if (!SkImageDecoder::DecodeURL(fUri.c_str(), bitmap))
+ {
+ delete bitmap;
+ fUriIsValid = false;
+ return false;
+ }
+ fData.fBitmap = bitmap;
+ fDataIsAnim = false;
+ #else
+ return false;
+ #endif
+ }
+ return true;
+}