49f085dddf
R=reed@google.com Author: bsalomon@google.com Review URL: https://codereview.chromium.org/544233002
844 lines
19 KiB
C++
844 lines
19 KiB
C++
|
|
/*
|
|
* 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 "SkView.h"
|
|
#include "SkCanvas.h"
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
SkView::SkView(uint32_t flags) : fFlags(SkToU8(flags))
|
|
{
|
|
fWidth = fHeight = 0;
|
|
fLoc.set(0, 0);
|
|
fParent = fFirstChild = fNextSibling = fPrevSibling = NULL;
|
|
fMatrix.setIdentity();
|
|
fContainsFocus = 0;
|
|
}
|
|
|
|
SkView::~SkView()
|
|
{
|
|
this->detachAllChildren();
|
|
}
|
|
|
|
void SkView::setFlags(uint32_t flags)
|
|
{
|
|
SkASSERT((flags & ~kAllFlagMasks) == 0);
|
|
|
|
uint32_t diff = fFlags ^ flags;
|
|
|
|
if (diff & kVisible_Mask)
|
|
this->inval(NULL);
|
|
|
|
fFlags = SkToU8(flags);
|
|
|
|
if (diff & kVisible_Mask)
|
|
{
|
|
this->inval(NULL);
|
|
}
|
|
}
|
|
|
|
void SkView::setVisibleP(bool pred)
|
|
{
|
|
this->setFlags(SkSetClearShift(fFlags, pred, kVisible_Shift));
|
|
}
|
|
|
|
void SkView::setEnabledP(bool pred)
|
|
{
|
|
this->setFlags(SkSetClearShift(fFlags, pred, kEnabled_Shift));
|
|
}
|
|
|
|
void SkView::setFocusableP(bool pred)
|
|
{
|
|
this->setFlags(SkSetClearShift(fFlags, pred, kFocusable_Shift));
|
|
}
|
|
|
|
void SkView::setClipToBounds(bool pred) {
|
|
this->setFlags(SkSetClearShift(fFlags, !pred, kNoClip_Shift));
|
|
}
|
|
|
|
void SkView::setSize(SkScalar width, SkScalar height)
|
|
{
|
|
width = SkMaxScalar(0, width);
|
|
height = SkMaxScalar(0, height);
|
|
|
|
if (fWidth != width || fHeight != height)
|
|
{
|
|
this->inval(NULL);
|
|
fWidth = width;
|
|
fHeight = height;
|
|
this->inval(NULL);
|
|
this->onSizeChange();
|
|
this->invokeLayout();
|
|
}
|
|
}
|
|
|
|
void SkView::setLoc(SkScalar x, SkScalar y)
|
|
{
|
|
if (fLoc.fX != x || fLoc.fY != y)
|
|
{
|
|
this->inval(NULL);
|
|
fLoc.set(x, y);
|
|
this->inval(NULL);
|
|
}
|
|
}
|
|
|
|
void SkView::offset(SkScalar dx, SkScalar dy)
|
|
{
|
|
if (dx || dy)
|
|
this->setLoc(fLoc.fX + dx, fLoc.fY + dy);
|
|
}
|
|
|
|
void SkView::setLocalMatrix(const SkMatrix& matrix)
|
|
{
|
|
this->inval(NULL);
|
|
fMatrix = matrix;
|
|
this->inval(NULL);
|
|
}
|
|
|
|
void SkView::draw(SkCanvas* canvas)
|
|
{
|
|
if (fWidth && fHeight && this->isVisible())
|
|
{
|
|
SkRect r;
|
|
r.set(fLoc.fX, fLoc.fY, fLoc.fX + fWidth, fLoc.fY + fHeight);
|
|
if (this->isClipToBounds() &&
|
|
canvas->quickReject(r)) {
|
|
return;
|
|
}
|
|
|
|
SkAutoCanvasRestore as(canvas, true);
|
|
|
|
if (this->isClipToBounds()) {
|
|
canvas->clipRect(r);
|
|
}
|
|
|
|
canvas->translate(fLoc.fX, fLoc.fY);
|
|
canvas->concat(fMatrix);
|
|
|
|
if (fParent) {
|
|
fParent->beforeChild(this, canvas);
|
|
}
|
|
|
|
int sc = canvas->save();
|
|
this->onDraw(canvas);
|
|
canvas->restoreToCount(sc);
|
|
|
|
if (fParent) {
|
|
fParent->afterChild(this, canvas);
|
|
}
|
|
|
|
B2FIter iter(this);
|
|
SkView* child;
|
|
|
|
SkCanvas* childCanvas = this->beforeChildren(canvas);
|
|
|
|
while ((child = iter.next()) != NULL)
|
|
child->draw(childCanvas);
|
|
|
|
this->afterChildren(canvas);
|
|
}
|
|
}
|
|
|
|
void SkView::inval(SkRect* rect) {
|
|
SkView* view = this;
|
|
SkRect storage;
|
|
|
|
for (;;) {
|
|
if (!view->isVisible()) {
|
|
return;
|
|
}
|
|
if (view->isClipToBounds()) {
|
|
SkRect bounds;
|
|
view->getLocalBounds(&bounds);
|
|
if (rect && !bounds.intersect(*rect)) {
|
|
return;
|
|
}
|
|
storage = bounds;
|
|
rect = &storage;
|
|
}
|
|
if (view->handleInval(rect)) {
|
|
return;
|
|
}
|
|
|
|
SkView* parent = view->fParent;
|
|
if (parent == NULL) {
|
|
return;
|
|
}
|
|
|
|
if (rect) {
|
|
rect->offset(view->fLoc.fX, view->fLoc.fY);
|
|
}
|
|
view = parent;
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
bool SkView::setFocusView(SkView* fv)
|
|
{
|
|
SkView* view = this;
|
|
|
|
do {
|
|
if (view->onSetFocusView(fv))
|
|
return true;
|
|
} while ((view = view->fParent) != NULL);
|
|
return false;
|
|
}
|
|
|
|
SkView* SkView::getFocusView() const
|
|
{
|
|
SkView* focus = NULL;
|
|
const SkView* view = this;
|
|
do {
|
|
if (view->onGetFocusView(&focus))
|
|
break;
|
|
} while ((view = view->fParent) != NULL);
|
|
return focus;
|
|
}
|
|
|
|
bool SkView::hasFocus() const
|
|
{
|
|
return this == this->getFocusView();
|
|
}
|
|
|
|
bool SkView::acceptFocus()
|
|
{
|
|
return this->isFocusable() && this->setFocusView(this);
|
|
}
|
|
|
|
/*
|
|
Try to give focus to this view, or its children
|
|
*/
|
|
SkView* SkView::acceptFocus(FocusDirection dir)
|
|
{
|
|
if (dir == kNext_FocusDirection)
|
|
{
|
|
if (this->acceptFocus())
|
|
return this;
|
|
|
|
B2FIter iter(this);
|
|
SkView* child, *focus;
|
|
while ((child = iter.next()) != NULL)
|
|
if ((focus = child->acceptFocus(dir)) != NULL)
|
|
return focus;
|
|
}
|
|
else // prev
|
|
{
|
|
F2BIter iter(this);
|
|
SkView* child, *focus;
|
|
while ((child = iter.next()) != NULL)
|
|
if ((focus = child->acceptFocus(dir)) != NULL)
|
|
return focus;
|
|
|
|
if (this->acceptFocus())
|
|
return this;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
SkView* SkView::moveFocus(FocusDirection dir)
|
|
{
|
|
SkView* focus = this->getFocusView();
|
|
|
|
if (focus == NULL)
|
|
{ // start with the root
|
|
focus = this;
|
|
while (focus->fParent)
|
|
focus = focus->fParent;
|
|
}
|
|
|
|
SkView* child, *parent;
|
|
|
|
if (dir == kNext_FocusDirection)
|
|
{
|
|
parent = focus;
|
|
child = focus->fFirstChild;
|
|
if (child)
|
|
goto FIRST_CHILD;
|
|
else
|
|
goto NEXT_SIB;
|
|
|
|
do {
|
|
while (child != parent->fFirstChild)
|
|
{
|
|
FIRST_CHILD:
|
|
if ((focus = child->acceptFocus(dir)) != NULL)
|
|
return focus;
|
|
child = child->fNextSibling;
|
|
}
|
|
NEXT_SIB:
|
|
child = parent->fNextSibling;
|
|
parent = parent->fParent;
|
|
} while (parent != NULL);
|
|
}
|
|
else // prevfocus
|
|
{
|
|
parent = focus->fParent;
|
|
if (parent == NULL) // we're the root
|
|
return focus->acceptFocus(dir);
|
|
else
|
|
{
|
|
child = focus;
|
|
while (parent)
|
|
{
|
|
while (child != parent->fFirstChild)
|
|
{
|
|
child = child->fPrevSibling;
|
|
if ((focus = child->acceptFocus(dir)) != NULL)
|
|
return focus;
|
|
}
|
|
if (parent->acceptFocus())
|
|
return parent;
|
|
|
|
child = parent;
|
|
parent = parent->fParent;
|
|
}
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
void SkView::onFocusChange(bool gainFocusP)
|
|
{
|
|
this->inval(NULL);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
SkView::Click::Click(SkView* target)
|
|
{
|
|
SkASSERT(target);
|
|
fTargetID = target->getSinkID();
|
|
fType = NULL;
|
|
fWeOwnTheType = false;
|
|
fOwner = NULL;
|
|
}
|
|
|
|
SkView::Click::~Click()
|
|
{
|
|
this->resetType();
|
|
}
|
|
|
|
void SkView::Click::resetType()
|
|
{
|
|
if (fWeOwnTheType)
|
|
{
|
|
sk_free(fType);
|
|
fWeOwnTheType = false;
|
|
}
|
|
fType = NULL;
|
|
}
|
|
|
|
bool SkView::Click::isType(const char type[]) const
|
|
{
|
|
const char* t = fType;
|
|
|
|
if (type == t)
|
|
return true;
|
|
|
|
if (type == NULL)
|
|
type = "";
|
|
if (t == NULL)
|
|
t = "";
|
|
return !strcmp(t, type);
|
|
}
|
|
|
|
void SkView::Click::setType(const char type[])
|
|
{
|
|
this->resetType();
|
|
fType = (char*)type;
|
|
}
|
|
|
|
void SkView::Click::copyType(const char type[])
|
|
{
|
|
if (fType != type)
|
|
{
|
|
this->resetType();
|
|
if (type)
|
|
{
|
|
size_t len = strlen(type) + 1;
|
|
fType = (char*)sk_malloc_throw(len);
|
|
memcpy(fType, type, len);
|
|
fWeOwnTheType = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
SkView::Click* SkView::findClickHandler(SkScalar x, SkScalar y, unsigned modi) {
|
|
if (x < 0 || y < 0 || x >= fWidth || y >= fHeight) {
|
|
return NULL;
|
|
}
|
|
|
|
if (this->onSendClickToChildren(x, y, modi)) {
|
|
F2BIter iter(this);
|
|
SkView* child;
|
|
|
|
while ((child = iter.next()) != NULL)
|
|
{
|
|
SkPoint p;
|
|
if (!child->globalToLocal(x, y, &p)) {
|
|
continue;
|
|
}
|
|
|
|
Click* click = child->findClickHandler(p.fX, p.fY, modi);
|
|
|
|
if (click) {
|
|
return click;
|
|
}
|
|
}
|
|
}
|
|
|
|
return this->onFindClickHandler(x, y, modi);
|
|
}
|
|
|
|
void SkView::DoClickDown(Click* click, int x, int y, unsigned modi)
|
|
{
|
|
SkASSERT(click);
|
|
|
|
SkView* target = (SkView*)SkEventSink::FindSink(click->fTargetID);
|
|
if (NULL == target) {
|
|
return;
|
|
}
|
|
|
|
click->fIOrig.set(x, y);
|
|
click->fICurr = click->fIPrev = click->fIOrig;
|
|
|
|
click->fOrig.iset(x, y);
|
|
if (!target->globalToLocal(&click->fOrig)) {
|
|
// no history to let us recover from this failure
|
|
return;
|
|
}
|
|
click->fPrev = click->fCurr = click->fOrig;
|
|
|
|
click->fState = Click::kDown_State;
|
|
click->fModifierKeys = modi;
|
|
target->onClick(click);
|
|
}
|
|
|
|
void SkView::DoClickMoved(Click* click, int x, int y, unsigned modi)
|
|
{
|
|
SkASSERT(click);
|
|
|
|
SkView* target = (SkView*)SkEventSink::FindSink(click->fTargetID);
|
|
if (NULL == target) {
|
|
return;
|
|
}
|
|
|
|
click->fIPrev = click->fICurr;
|
|
click->fICurr.set(x, y);
|
|
|
|
click->fPrev = click->fCurr;
|
|
click->fCurr.iset(x, y);
|
|
if (!target->globalToLocal(&click->fCurr)) {
|
|
// on failure pretend the mouse didn't move
|
|
click->fCurr = click->fPrev;
|
|
}
|
|
|
|
click->fState = Click::kMoved_State;
|
|
click->fModifierKeys = modi;
|
|
target->onClick(click);
|
|
}
|
|
|
|
void SkView::DoClickUp(Click* click, int x, int y, unsigned modi)
|
|
{
|
|
SkASSERT(click);
|
|
|
|
SkView* target = (SkView*)SkEventSink::FindSink(click->fTargetID);
|
|
if (NULL == target) {
|
|
return;
|
|
}
|
|
|
|
click->fIPrev = click->fICurr;
|
|
click->fICurr.set(x, y);
|
|
|
|
click->fPrev = click->fCurr;
|
|
click->fCurr.iset(x, y);
|
|
if (!target->globalToLocal(&click->fCurr)) {
|
|
// on failure pretend the mouse didn't move
|
|
click->fCurr = click->fPrev;
|
|
}
|
|
|
|
click->fState = Click::kUp_State;
|
|
click->fModifierKeys = modi;
|
|
target->onClick(click);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
void SkView::invokeLayout() {
|
|
SkView::Layout* layout = this->getLayout();
|
|
|
|
if (layout) {
|
|
layout->layoutChildren(this);
|
|
}
|
|
}
|
|
|
|
void SkView::onDraw(SkCanvas* canvas) {
|
|
Artist* artist = this->getArtist();
|
|
|
|
if (artist) {
|
|
artist->draw(this, canvas);
|
|
}
|
|
}
|
|
|
|
void SkView::onSizeChange() {}
|
|
|
|
bool SkView::onSendClickToChildren(SkScalar x, SkScalar y, unsigned modi) {
|
|
return true;
|
|
}
|
|
|
|
SkView::Click* SkView::onFindClickHandler(SkScalar x, SkScalar y, unsigned modi) {
|
|
return NULL;
|
|
}
|
|
|
|
bool SkView::onClick(Click*) {
|
|
return false;
|
|
}
|
|
|
|
bool SkView::handleInval(const SkRect*) {
|
|
return false;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
void SkView::getLocalBounds(SkRect* bounds) const {
|
|
if (bounds) {
|
|
bounds->set(0, 0, fWidth, fHeight);
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
void SkView::detachFromParent_NoLayout() {
|
|
this->validate();
|
|
if (fParent == NULL) {
|
|
return;
|
|
}
|
|
|
|
if (fContainsFocus) {
|
|
(void)this->setFocusView(NULL);
|
|
}
|
|
|
|
this->inval(NULL);
|
|
|
|
SkView* next = NULL;
|
|
|
|
if (fNextSibling != this) { // do we have any siblings
|
|
fNextSibling->fPrevSibling = fPrevSibling;
|
|
fPrevSibling->fNextSibling = fNextSibling;
|
|
next = fNextSibling;
|
|
}
|
|
|
|
if (fParent->fFirstChild == this) {
|
|
fParent->fFirstChild = next;
|
|
}
|
|
|
|
fParent = fNextSibling = fPrevSibling = NULL;
|
|
|
|
this->validate();
|
|
this->unref();
|
|
}
|
|
|
|
void SkView::detachFromParent() {
|
|
this->validate();
|
|
SkView* parent = fParent;
|
|
|
|
if (parent) {
|
|
this->detachFromParent_NoLayout();
|
|
parent->invokeLayout();
|
|
}
|
|
}
|
|
|
|
SkView* SkView::attachChildToBack(SkView* child) {
|
|
this->validate();
|
|
SkASSERT(child != this);
|
|
|
|
if (child == NULL || fFirstChild == child)
|
|
goto DONE;
|
|
|
|
child->ref();
|
|
child->detachFromParent_NoLayout();
|
|
|
|
if (fFirstChild == NULL) {
|
|
child->fNextSibling = child;
|
|
child->fPrevSibling = child;
|
|
} else {
|
|
child->fNextSibling = fFirstChild;
|
|
child->fPrevSibling = fFirstChild->fPrevSibling;
|
|
fFirstChild->fPrevSibling->fNextSibling = child;
|
|
fFirstChild->fPrevSibling = child;
|
|
}
|
|
|
|
fFirstChild = child;
|
|
child->fParent = this;
|
|
child->inval(NULL);
|
|
|
|
this->validate();
|
|
this->invokeLayout();
|
|
DONE:
|
|
return child;
|
|
}
|
|
|
|
SkView* SkView::attachChildToFront(SkView* child) {
|
|
this->validate();
|
|
SkASSERT(child != this);
|
|
|
|
if (child == NULL || (fFirstChild && fFirstChild->fPrevSibling == child))
|
|
goto DONE;
|
|
|
|
child->ref();
|
|
child->detachFromParent_NoLayout();
|
|
|
|
if (fFirstChild == NULL) {
|
|
fFirstChild = child;
|
|
child->fNextSibling = child;
|
|
child->fPrevSibling = child;
|
|
} else {
|
|
child->fNextSibling = fFirstChild;
|
|
child->fPrevSibling = fFirstChild->fPrevSibling;
|
|
fFirstChild->fPrevSibling->fNextSibling = child;
|
|
fFirstChild->fPrevSibling = child;
|
|
}
|
|
|
|
child->fParent = this;
|
|
child->inval(NULL);
|
|
|
|
this->validate();
|
|
this->invokeLayout();
|
|
DONE:
|
|
return child;
|
|
}
|
|
|
|
void SkView::detachAllChildren() {
|
|
this->validate();
|
|
while (fFirstChild)
|
|
fFirstChild->detachFromParent_NoLayout();
|
|
}
|
|
|
|
void SkView::localToGlobal(SkMatrix* matrix) const {
|
|
if (matrix) {
|
|
matrix->reset();
|
|
const SkView* view = this;
|
|
while (view)
|
|
{
|
|
matrix->preConcat(view->getLocalMatrix());
|
|
matrix->preTranslate(-view->fLoc.fX, -view->fLoc.fY);
|
|
view = view->fParent;
|
|
}
|
|
}
|
|
}
|
|
bool SkView::globalToLocal(SkScalar x, SkScalar y, SkPoint* local) const
|
|
{
|
|
SkASSERT(this);
|
|
|
|
if (local) {
|
|
SkMatrix m;
|
|
this->localToGlobal(&m);
|
|
if (!m.invert(&m)) {
|
|
return false;
|
|
}
|
|
SkPoint p;
|
|
m.mapXY(x, y, &p);
|
|
local->set(p.fX, p.fY);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////
|
|
|
|
/* Even if the subclass overrides onInflate, they should always be
|
|
sure to call the inherited method, so that we get called.
|
|
*/
|
|
void SkView::onInflate(const SkDOM& dom, const SkDOM::Node* node) {
|
|
SkScalar x, y;
|
|
|
|
x = this->locX();
|
|
y = this->locY();
|
|
(void)dom.findScalar(node, "x", &x);
|
|
(void)dom.findScalar(node, "y", &y);
|
|
this->setLoc(x, y);
|
|
|
|
x = this->width();
|
|
y = this->height();
|
|
(void)dom.findScalar(node, "width", &x);
|
|
(void)dom.findScalar(node, "height", &y);
|
|
this->setSize(x, y);
|
|
|
|
// inflate the flags
|
|
|
|
static const char* gFlagNames[] = {
|
|
"visible", "enabled", "focusable", "flexH", "flexV"
|
|
};
|
|
SkASSERT(SK_ARRAY_COUNT(gFlagNames) == kFlagShiftCount);
|
|
|
|
bool b;
|
|
uint32_t flags = this->getFlags();
|
|
for (unsigned i = 0; i < SK_ARRAY_COUNT(gFlagNames); i++)
|
|
if (dom.findBool(node, gFlagNames[i], &b))
|
|
flags = SkSetClearShift(flags, b, i);
|
|
this->setFlags(flags);
|
|
}
|
|
|
|
void SkView::inflate(const SkDOM& dom, const SkDOM::Node* node) {
|
|
this->onInflate(dom, node);
|
|
}
|
|
|
|
void SkView::onPostInflate(const SkTDict<SkView*>&) {
|
|
// override in subclass as needed
|
|
}
|
|
|
|
void SkView::postInflate(const SkTDict<SkView*>& dict) {
|
|
this->onPostInflate(dict);
|
|
|
|
B2FIter iter(this);
|
|
SkView* child;
|
|
while ((child = iter.next()) != NULL)
|
|
child->postInflate(dict);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////
|
|
|
|
SkView* SkView::sendEventToParents(const SkEvent& evt) {
|
|
SkView* parent = fParent;
|
|
|
|
while (parent) {
|
|
if (parent->doEvent(evt)) {
|
|
return parent;
|
|
}
|
|
parent = parent->fParent;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
SkView* SkView::sendQueryToParents(SkEvent* evt) {
|
|
SkView* parent = fParent;
|
|
|
|
while (parent) {
|
|
if (parent->doQuery(evt)) {
|
|
return parent;
|
|
}
|
|
parent = parent->fParent;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////
|
|
//////////////////////////////////////////////////////////////////
|
|
|
|
SkView::F2BIter::F2BIter(const SkView* parent) {
|
|
fFirstChild = parent ? parent->fFirstChild : NULL;
|
|
fChild = fFirstChild ? fFirstChild->fPrevSibling : NULL;
|
|
}
|
|
|
|
SkView* SkView::F2BIter::next() {
|
|
SkView* curr = fChild;
|
|
|
|
if (fChild) {
|
|
if (fChild == fFirstChild) {
|
|
fChild = NULL;
|
|
} else {
|
|
fChild = fChild->fPrevSibling;
|
|
}
|
|
}
|
|
return curr;
|
|
}
|
|
|
|
SkView::B2FIter::B2FIter(const SkView* parent) {
|
|
fFirstChild = parent ? parent->fFirstChild : NULL;
|
|
fChild = fFirstChild;
|
|
}
|
|
|
|
SkView* SkView::B2FIter::next() {
|
|
SkView* curr = fChild;
|
|
|
|
if (fChild) {
|
|
SkView* next = fChild->fNextSibling;
|
|
if (next == fFirstChild)
|
|
next = NULL;
|
|
fChild = next;
|
|
}
|
|
return curr;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////
|
|
//////////////////////////////////////////////////////////////////
|
|
|
|
#ifdef SK_DEBUG
|
|
|
|
void SkView::validate() const {
|
|
// SkASSERT(this->getRefCnt() > 0 && this->getRefCnt() < 100);
|
|
if (fParent) {
|
|
SkASSERT(fNextSibling);
|
|
SkASSERT(fPrevSibling);
|
|
} else {
|
|
bool nextNull = NULL == fNextSibling;
|
|
bool prevNull = NULL == fNextSibling;
|
|
SkASSERT(nextNull == prevNull);
|
|
}
|
|
}
|
|
|
|
static inline void show_if_nonzero(const char name[], SkScalar value)
|
|
{
|
|
if (value)
|
|
SkDebugf("%s=\"%g\"", name, value/65536.);
|
|
}
|
|
|
|
static void tab(int level)
|
|
{
|
|
for (int i = 0; i < level; i++)
|
|
SkDebugf(" ");
|
|
}
|
|
|
|
static void dumpview(const SkView* view, int level, bool recurse)
|
|
{
|
|
tab(level);
|
|
|
|
SkDebugf("<view");
|
|
show_if_nonzero(" x", view->locX());
|
|
show_if_nonzero(" y", view->locY());
|
|
show_if_nonzero(" width", view->width());
|
|
show_if_nonzero(" height", view->height());
|
|
|
|
if (recurse)
|
|
{
|
|
SkView::B2FIter iter(view);
|
|
SkView* child;
|
|
bool noChildren = true;
|
|
|
|
while ((child = iter.next()) != NULL)
|
|
{
|
|
if (noChildren)
|
|
SkDebugf(">\n");
|
|
noChildren = false;
|
|
dumpview(child, level + 1, true);
|
|
}
|
|
|
|
if (!noChildren)
|
|
{
|
|
tab(level);
|
|
SkDebugf("</view>\n");
|
|
}
|
|
else
|
|
goto ONELINER;
|
|
}
|
|
else
|
|
{
|
|
ONELINER:
|
|
SkDebugf(" />\n");
|
|
}
|
|
}
|
|
|
|
void SkView::dump(bool recurse) const
|
|
{
|
|
dumpview(this, 0, recurse);
|
|
}
|
|
|
|
#endif
|