blob: 9e8182b16a9b0f21b642478f0e82a032f877f368 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001/*
2 * Copyright 2011 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
reed9a878a02015-12-27 12:47:25 -08007
reed@android.com8a1c16f2008-12-17 15:59:43 +00008#include "SkView.h"
9#include "SkCanvas.h"
10
reed9a878a02015-12-27 12:47:25 -080011static inline uint32_t SkSetClearShift(uint32_t bits, bool cond, unsigned shift) {
12 SkASSERT((int)cond == 0 || (int)cond == 1);
13 return (bits & ~(1 << shift)) | ((int)cond << shift);
14}
15
reed@android.com8a1c16f2008-12-17 15:59:43 +000016////////////////////////////////////////////////////////////////////////
17
reed9a878a02015-12-27 12:47:25 -080018SkView::SkView(uint32_t flags) : fFlags(SkToU8(flags)) {
robertphillips@google.coma22e2112012-08-16 14:58:06 +000019 fWidth = fHeight = 0;
20 fLoc.set(0, 0);
halcanary96fcdcc2015-08-27 07:41:13 -070021 fParent = fFirstChild = fNextSibling = fPrevSibling = nullptr;
reed@google.comf03bb562011-11-11 21:42:12 +000022 fMatrix.setIdentity();
robertphillips@google.coma22e2112012-08-16 14:58:06 +000023 fContainsFocus = 0;
reed@android.com8a1c16f2008-12-17 15:59:43 +000024}
25
reed9a878a02015-12-27 12:47:25 -080026SkView::~SkView() {
robertphillips@google.coma22e2112012-08-16 14:58:06 +000027 this->detachAllChildren();
reed@android.com8a1c16f2008-12-17 15:59:43 +000028}
29
reed9a878a02015-12-27 12:47:25 -080030void SkView::setFlags(uint32_t flags) {
robertphillips@google.coma22e2112012-08-16 14:58:06 +000031 SkASSERT((flags & ~kAllFlagMasks) == 0);
reed@android.com8a1c16f2008-12-17 15:59:43 +000032
robertphillips@google.coma22e2112012-08-16 14:58:06 +000033 uint32_t diff = fFlags ^ flags;
reed@android.com8a1c16f2008-12-17 15:59:43 +000034
robertphillips@google.coma22e2112012-08-16 14:58:06 +000035 if (diff & kVisible_Mask)
halcanary96fcdcc2015-08-27 07:41:13 -070036 this->inval(nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +000037
robertphillips@google.coma22e2112012-08-16 14:58:06 +000038 fFlags = SkToU8(flags);
reed@android.com8a1c16f2008-12-17 15:59:43 +000039
reed9a878a02015-12-27 12:47:25 -080040 if (diff & kVisible_Mask) {
halcanary96fcdcc2015-08-27 07:41:13 -070041 this->inval(nullptr);
robertphillips@google.coma22e2112012-08-16 14:58:06 +000042 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000043}
44
reed9a878a02015-12-27 12:47:25 -080045void SkView::setVisibleP(bool pred) {
robertphillips@google.coma22e2112012-08-16 14:58:06 +000046 this->setFlags(SkSetClearShift(fFlags, pred, kVisible_Shift));
reed@android.com8a1c16f2008-12-17 15:59:43 +000047}
48
reed9a878a02015-12-27 12:47:25 -080049void SkView::setEnabledP(bool pred) {
robertphillips@google.coma22e2112012-08-16 14:58:06 +000050 this->setFlags(SkSetClearShift(fFlags, pred, kEnabled_Shift));
reed@android.com8a1c16f2008-12-17 15:59:43 +000051}
52
reed9a878a02015-12-27 12:47:25 -080053void SkView::setFocusableP(bool pred) {
robertphillips@google.coma22e2112012-08-16 14:58:06 +000054 this->setFlags(SkSetClearShift(fFlags, pred, kFocusable_Shift));
reed@android.com8a1c16f2008-12-17 15:59:43 +000055}
56
reed@android.comf2b98d62010-12-20 18:26:13 +000057void SkView::setClipToBounds(bool pred) {
58 this->setFlags(SkSetClearShift(fFlags, !pred, kNoClip_Shift));
59}
60
reed9a878a02015-12-27 12:47:25 -080061void SkView::setSize(SkScalar width, SkScalar height) {
robertphillips@google.coma22e2112012-08-16 14:58:06 +000062 width = SkMaxScalar(0, width);
63 height = SkMaxScalar(0, height);
reed@android.com8a1c16f2008-12-17 15:59:43 +000064
robertphillips@google.coma22e2112012-08-16 14:58:06 +000065 if (fWidth != width || fHeight != height)
66 {
halcanary96fcdcc2015-08-27 07:41:13 -070067 this->inval(nullptr);
robertphillips@google.coma22e2112012-08-16 14:58:06 +000068 fWidth = width;
69 fHeight = height;
halcanary96fcdcc2015-08-27 07:41:13 -070070 this->inval(nullptr);
robertphillips@google.coma22e2112012-08-16 14:58:06 +000071 this->onSizeChange();
72 this->invokeLayout();
73 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000074}
75
reed9a878a02015-12-27 12:47:25 -080076void SkView::setLoc(SkScalar x, SkScalar y) {
77 if (fLoc.fX != x || fLoc.fY != y) {
halcanary96fcdcc2015-08-27 07:41:13 -070078 this->inval(nullptr);
robertphillips@google.coma22e2112012-08-16 14:58:06 +000079 fLoc.set(x, y);
halcanary96fcdcc2015-08-27 07:41:13 -070080 this->inval(nullptr);
robertphillips@google.coma22e2112012-08-16 14:58:06 +000081 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000082}
83
reed9a878a02015-12-27 12:47:25 -080084void SkView::offset(SkScalar dx, SkScalar dy) {
robertphillips@google.coma22e2112012-08-16 14:58:06 +000085 if (dx || dy)
86 this->setLoc(fLoc.fX + dx, fLoc.fY + dy);
reed@android.com8a1c16f2008-12-17 15:59:43 +000087}
88
reed9a878a02015-12-27 12:47:25 -080089void SkView::setLocalMatrix(const SkMatrix& matrix) {
halcanary96fcdcc2015-08-27 07:41:13 -070090 this->inval(nullptr);
reed@google.comf03bb562011-11-11 21:42:12 +000091 fMatrix = matrix;
halcanary96fcdcc2015-08-27 07:41:13 -070092 this->inval(nullptr);
reed@google.comf03bb562011-11-11 21:42:12 +000093}
94
reed9a878a02015-12-27 12:47:25 -080095void SkView::draw(SkCanvas* canvas) {
96 if (fWidth && fHeight && this->isVisible()) {
rmistry@google.comd6176b02012-08-23 18:14:13 +000097 SkRect r;
robertphillips@google.coma22e2112012-08-16 14:58:06 +000098 r.set(fLoc.fX, fLoc.fY, fLoc.fX + fWidth, fLoc.fY + fHeight);
reed9a878a02015-12-27 12:47:25 -080099 if (this->isClipToBounds() && canvas->quickReject(r)) {
100 return;
reed@android.comf2b98d62010-12-20 18:26:13 +0000101 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000102
rmistry@google.comd6176b02012-08-23 18:14:13 +0000103 SkAutoCanvasRestore as(canvas, true);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000104
reed@android.comf2b98d62010-12-20 18:26:13 +0000105 if (this->isClipToBounds()) {
106 canvas->clipRect(r);
107 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000108
109 canvas->translate(fLoc.fX, fLoc.fY);
reed@google.comf03bb562011-11-11 21:42:12 +0000110 canvas->concat(fMatrix);
rmistry@google.comd6176b02012-08-23 18:14:13 +0000111
reed@android.com6c5f6f22009-08-14 16:08:38 +0000112 if (fParent) {
113 fParent->beforeChild(this, canvas);
114 }
reed@android.com562ea922010-02-08 21:45:03 +0000115
116 int sc = canvas->save();
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000117 this->onDraw(canvas);
reed@android.com562ea922010-02-08 21:45:03 +0000118 canvas->restoreToCount(sc);
119
reed@android.com6c5f6f22009-08-14 16:08:38 +0000120 if (fParent) {
121 fParent->afterChild(this, canvas);
122 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000123
124 B2FIter iter(this);
125 SkView* child;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000126
127 SkCanvas* childCanvas = this->beforeChildren(canvas);
128
halcanary96fcdcc2015-08-27 07:41:13 -0700129 while ((child = iter.next()) != nullptr)
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000130 child->draw(childCanvas);
rmistry@google.comd6176b02012-08-23 18:14:13 +0000131
reed@android.com8a1c16f2008-12-17 15:59:43 +0000132 this->afterChildren(canvas);
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000133 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000134}
135
reed@android.comf2b98d62010-12-20 18:26:13 +0000136void SkView::inval(SkRect* rect) {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000137 SkView* view = this;
reed@android.comf2b98d62010-12-20 18:26:13 +0000138 SkRect storage;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000139
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000140 for (;;) {
reed@android.comf2b98d62010-12-20 18:26:13 +0000141 if (!view->isVisible()) {
142 return;
143 }
144 if (view->isClipToBounds()) {
145 SkRect bounds;
146 view->getLocalBounds(&bounds);
147 if (rect && !bounds.intersect(*rect)) {
148 return;
149 }
150 storage = bounds;
151 rect = &storage;
152 }
153 if (view->handleInval(rect)) {
154 return;
155 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000156
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000157 SkView* parent = view->fParent;
halcanary96fcdcc2015-08-27 07:41:13 -0700158 if (parent == nullptr) {
reed@android.comf2b98d62010-12-20 18:26:13 +0000159 return;
160 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000161
reed@android.comf2b98d62010-12-20 18:26:13 +0000162 if (rect) {
163 rect->offset(view->fLoc.fX, view->fLoc.fY);
164 }
165 view = parent;
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000166 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000167}
168
169////////////////////////////////////////////////////////////////////////////
170
reed9a878a02015-12-27 12:47:25 -0800171bool SkView::setFocusView(SkView* fv) {
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000172 SkView* view = this;
rmistry@google.comd6176b02012-08-23 18:14:13 +0000173
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000174 do {
reed9a878a02015-12-27 12:47:25 -0800175 if (view->onSetFocusView(fv)) {
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000176 return true;
reed9a878a02015-12-27 12:47:25 -0800177 }
halcanary96fcdcc2015-08-27 07:41:13 -0700178 } while ((view = view->fParent) != nullptr);
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000179 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000180}
181
reed9a878a02015-12-27 12:47:25 -0800182SkView* SkView::getFocusView() const {
183 SkView* focus = nullptr;
184 const SkView* view = this;
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000185 do {
reed9a878a02015-12-27 12:47:25 -0800186 if (view->onGetFocusView(&focus)) {
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000187 break;
reed9a878a02015-12-27 12:47:25 -0800188 }
halcanary96fcdcc2015-08-27 07:41:13 -0700189 } while ((view = view->fParent) != nullptr);
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000190 return focus;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000191}
192
reed9a878a02015-12-27 12:47:25 -0800193bool SkView::hasFocus() const {
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000194 return this == this->getFocusView();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000195}
196
reed9a878a02015-12-27 12:47:25 -0800197bool SkView::acceptFocus() {
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000198 return this->isFocusable() && this->setFocusView(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000199}
200
201/*
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000202 Try to give focus to this view, or its children
reed@android.com8a1c16f2008-12-17 15:59:43 +0000203*/
reed9a878a02015-12-27 12:47:25 -0800204SkView* SkView::acceptFocus(FocusDirection dir) {
205 if (dir == kNext_FocusDirection) {
206 if (this->acceptFocus()) {
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000207 return this;
reed9a878a02015-12-27 12:47:25 -0800208 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000209 B2FIter iter(this);
210 SkView* child, *focus;
reed9a878a02015-12-27 12:47:25 -0800211 while ((child = iter.next()) != nullptr) {
212 if ((focus = child->acceptFocus(dir)) != nullptr) {
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000213 return focus;
reed9a878a02015-12-27 12:47:25 -0800214 }
215 }
216 } else { // prev
rmistry@google.comd6176b02012-08-23 18:14:13 +0000217 F2BIter iter(this);
218 SkView* child, *focus;
reed9a878a02015-12-27 12:47:25 -0800219 while ((child = iter.next()) != nullptr) {
220 if ((focus = child->acceptFocus(dir)) != nullptr) {
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000221 return focus;
reed9a878a02015-12-27 12:47:25 -0800222 }
223 }
224 if (this->acceptFocus()) {
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000225 return this;
reed9a878a02015-12-27 12:47:25 -0800226 }
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000227 }
halcanary96fcdcc2015-08-27 07:41:13 -0700228 return nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000229}
230
reed9a878a02015-12-27 12:47:25 -0800231SkView* SkView::moveFocus(FocusDirection dir) {
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000232 SkView* focus = this->getFocusView();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000233
reed9a878a02015-12-27 12:47:25 -0800234 if (focus == nullptr) { // start with the root
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000235 focus = this;
reed9a878a02015-12-27 12:47:25 -0800236 while (focus->fParent) {
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000237 focus = focus->fParent;
reed9a878a02015-12-27 12:47:25 -0800238 }
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000239 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000240
reed9a878a02015-12-27 12:47:25 -0800241 SkView* child, *parent;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000242
reed9a878a02015-12-27 12:47:25 -0800243 if (dir == kNext_FocusDirection) {
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000244 parent = focus;
245 child = focus->fFirstChild;
246 if (child)
247 goto FIRST_CHILD;
248 else
249 goto NEXT_SIB;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000250
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000251 do {
reed9a878a02015-12-27 12:47:25 -0800252 while (child != parent->fFirstChild) {
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000253 FIRST_CHILD:
halcanary96fcdcc2015-08-27 07:41:13 -0700254 if ((focus = child->acceptFocus(dir)) != nullptr)
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000255 return focus;
256 child = child->fNextSibling;
257 }
258 NEXT_SIB:
259 child = parent->fNextSibling;
260 parent = parent->fParent;
halcanary96fcdcc2015-08-27 07:41:13 -0700261 } while (parent != nullptr);
reed9a878a02015-12-27 12:47:25 -0800262 } else { // prevfocus
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000263 parent = focus->fParent;
reed9a878a02015-12-27 12:47:25 -0800264 if (parent == nullptr) { // we're the root
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000265 return focus->acceptFocus(dir);
reed9a878a02015-12-27 12:47:25 -0800266 } else {
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000267 child = focus;
reed9a878a02015-12-27 12:47:25 -0800268 while (parent) {
269 while (child != parent->fFirstChild) {
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000270 child = child->fPrevSibling;
reed9a878a02015-12-27 12:47:25 -0800271 if ((focus = child->acceptFocus(dir)) != nullptr) {
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000272 return focus;
reed9a878a02015-12-27 12:47:25 -0800273 }
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000274 }
reed9a878a02015-12-27 12:47:25 -0800275 if (parent->acceptFocus()) {
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000276 return parent;
reed9a878a02015-12-27 12:47:25 -0800277 }
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000278 child = parent;
279 parent = parent->fParent;
280 }
281 }
282 }
halcanary96fcdcc2015-08-27 07:41:13 -0700283 return nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000284}
285
reed9a878a02015-12-27 12:47:25 -0800286void SkView::onFocusChange(bool gainFocusP) {
halcanary96fcdcc2015-08-27 07:41:13 -0700287 this->inval(nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000288}
289
290////////////////////////////////////////////////////////////////////////////
291
reed9a878a02015-12-27 12:47:25 -0800292SkView::Click::Click(SkView* target) {
Scroggod3aed392011-06-22 13:26:56 +0000293 SkASSERT(target);
294 fTargetID = target->getSinkID();
halcanary96fcdcc2015-08-27 07:41:13 -0700295 fType = nullptr;
Scroggod3aed392011-06-22 13:26:56 +0000296 fWeOwnTheType = false;
halcanary96fcdcc2015-08-27 07:41:13 -0700297 fOwner = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000298}
299
reed9a878a02015-12-27 12:47:25 -0800300SkView::Click::~Click() {
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000301 this->resetType();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000302}
303
reed9a878a02015-12-27 12:47:25 -0800304void SkView::Click::resetType() {
305 if (fWeOwnTheType) {
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000306 sk_free(fType);
307 fWeOwnTheType = false;
308 }
halcanary96fcdcc2015-08-27 07:41:13 -0700309 fType = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000310}
311
reed9a878a02015-12-27 12:47:25 -0800312bool SkView::Click::isType(const char type[]) const {
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000313 const char* t = fType;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000314
reed9a878a02015-12-27 12:47:25 -0800315 if (type == t) {
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000316 return true;
reed9a878a02015-12-27 12:47:25 -0800317 }
318 if (type == nullptr) {
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000319 type = "";
reed9a878a02015-12-27 12:47:25 -0800320 }
321 if (t == nullptr) {
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000322 t = "";
reed9a878a02015-12-27 12:47:25 -0800323 }
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000324 return !strcmp(t, type);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000325}
326
reed9a878a02015-12-27 12:47:25 -0800327void SkView::Click::setType(const char type[]) {
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000328 this->resetType();
329 fType = (char*)type;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000330}
331
reed9a878a02015-12-27 12:47:25 -0800332void SkView::Click::copyType(const char type[]) {
333 if (fType != type) {
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000334 this->resetType();
reed9a878a02015-12-27 12:47:25 -0800335 if (type) {
336 size_t len = strlen(type) + 1;
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000337 fType = (char*)sk_malloc_throw(len);
338 memcpy(fType, type, len);
339 fWeOwnTheType = true;
340 }
341 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000342}
343
reed@google.com4d5c26d2013-01-08 16:17:50 +0000344SkView::Click* SkView::findClickHandler(SkScalar x, SkScalar y, unsigned modi) {
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000345 if (x < 0 || y < 0 || x >= fWidth || y >= fHeight) {
halcanary96fcdcc2015-08-27 07:41:13 -0700346 return nullptr;
reed@android.come72fee52009-11-16 14:52:01 +0000347 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000348
reed@google.com4d5c26d2013-01-08 16:17:50 +0000349 if (this->onSendClickToChildren(x, y, modi)) {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000350 F2BIter iter(this);
351 SkView* child;
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000352
reed1a9caff2015-09-02 19:05:10 -0700353 while ((child = iter.next()) != nullptr) {
reed@google.comf03bb562011-11-11 21:42:12 +0000354 SkPoint p;
reed1a9caff2015-09-02 19:05:10 -0700355#if 0
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000356 if (!child->globalToLocal(x, y, &p)) {
357 continue;
358 }
reed1a9caff2015-09-02 19:05:10 -0700359#else
360 // the above seems broken, so just respecting fLoc for now <reed>
361 p.set(x - child->fLoc.x(), y - child->fLoc.y());
362#endif
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000363
reed@google.com4d5c26d2013-01-08 16:17:50 +0000364 Click* click = child->findClickHandler(p.fX, p.fY, modi);
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000365
reed@android.come72fee52009-11-16 14:52:01 +0000366 if (click) {
367 return click;
368 }
369 }
370 }
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000371
reed@google.com4d5c26d2013-01-08 16:17:50 +0000372 return this->onFindClickHandler(x, y, modi);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000373}
374
reed9a878a02015-12-27 12:47:25 -0800375void SkView::DoClickDown(Click* click, int x, int y, unsigned modi) {
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000376 SkASSERT(click);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000377
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000378 SkView* target = (SkView*)SkEventSink::FindSink(click->fTargetID);
halcanary96fcdcc2015-08-27 07:41:13 -0700379 if (nullptr == target) {
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000380 return;
381 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000382
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000383 click->fIOrig.set(x, y);
384 click->fICurr = click->fIPrev = click->fIOrig;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000385
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000386 click->fOrig.iset(x, y);
387 if (!target->globalToLocal(&click->fOrig)) {
388 // no history to let us recover from this failure
389 return;
390 }
391 click->fPrev = click->fCurr = click->fOrig;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000392
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000393 click->fState = Click::kDown_State;
reed@google.com4d5c26d2013-01-08 16:17:50 +0000394 click->fModifierKeys = modi;
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000395 target->onClick(click);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000396}
397
reed9a878a02015-12-27 12:47:25 -0800398void SkView::DoClickMoved(Click* click, int x, int y, unsigned modi) {
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000399 SkASSERT(click);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000400
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000401 SkView* target = (SkView*)SkEventSink::FindSink(click->fTargetID);
halcanary96fcdcc2015-08-27 07:41:13 -0700402 if (nullptr == target) {
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000403 return;
404 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000405
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000406 click->fIPrev = click->fICurr;
407 click->fICurr.set(x, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000408
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000409 click->fPrev = click->fCurr;
410 click->fCurr.iset(x, y);
411 if (!target->globalToLocal(&click->fCurr)) {
412 // on failure pretend the mouse didn't move
413 click->fCurr = click->fPrev;
414 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000415
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000416 click->fState = Click::kMoved_State;
reed@google.com4d5c26d2013-01-08 16:17:50 +0000417 click->fModifierKeys = modi;
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000418 target->onClick(click);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000419}
420
reed9a878a02015-12-27 12:47:25 -0800421void SkView::DoClickUp(Click* click, int x, int y, unsigned modi) {
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000422 SkASSERT(click);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000423
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000424 SkView* target = (SkView*)SkEventSink::FindSink(click->fTargetID);
halcanary96fcdcc2015-08-27 07:41:13 -0700425 if (nullptr == target) {
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000426 return;
427 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000428
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000429 click->fIPrev = click->fICurr;
430 click->fICurr.set(x, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000431
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000432 click->fPrev = click->fCurr;
433 click->fCurr.iset(x, y);
434 if (!target->globalToLocal(&click->fCurr)) {
435 // on failure pretend the mouse didn't move
436 click->fCurr = click->fPrev;
437 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000438
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000439 click->fState = Click::kUp_State;
reed@google.com4d5c26d2013-01-08 16:17:50 +0000440 click->fModifierKeys = modi;
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000441 target->onClick(click);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000442}
443
444//////////////////////////////////////////////////////////////////////
445
reed@android.come72fee52009-11-16 14:52:01 +0000446void SkView::invokeLayout() {
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000447 SkView::Layout* layout = this->getLayout();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000448
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000449 if (layout) {
450 layout->layoutChildren(this);
reed@android.come72fee52009-11-16 14:52:01 +0000451 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000452}
453
reed@android.come72fee52009-11-16 14:52:01 +0000454void SkView::onDraw(SkCanvas* canvas) {
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000455 Artist* artist = this->getArtist();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000456
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000457 if (artist) {
458 artist->draw(this, canvas);
reed@android.come72fee52009-11-16 14:52:01 +0000459 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000460}
461
reed@android.come72fee52009-11-16 14:52:01 +0000462void SkView::onSizeChange() {}
463
reed@google.com4d5c26d2013-01-08 16:17:50 +0000464bool SkView::onSendClickToChildren(SkScalar x, SkScalar y, unsigned modi) {
reed@android.come72fee52009-11-16 14:52:01 +0000465 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000466}
467
reed@google.com4d5c26d2013-01-08 16:17:50 +0000468SkView::Click* SkView::onFindClickHandler(SkScalar x, SkScalar y, unsigned modi) {
halcanary96fcdcc2015-08-27 07:41:13 -0700469 return nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000470}
471
reed@android.come72fee52009-11-16 14:52:01 +0000472bool SkView::onClick(Click*) {
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000473 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000474}
475
reed@android.comf2b98d62010-12-20 18:26:13 +0000476bool SkView::handleInval(const SkRect*) {
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000477 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000478}
479
480//////////////////////////////////////////////////////////////////////
481
reed@google.coma25c94e2013-06-13 20:20:17 +0000482void SkView::getLocalBounds(SkRect* bounds) const {
483 if (bounds) {
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000484 bounds->set(0, 0, fWidth, fHeight);
reed@google.coma25c94e2013-06-13 20:20:17 +0000485 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000486}
487
488//////////////////////////////////////////////////////////////////////
489//////////////////////////////////////////////////////////////////////
490
reed@google.coma25c94e2013-06-13 20:20:17 +0000491void SkView::detachFromParent_NoLayout() {
492 this->validate();
halcanary96fcdcc2015-08-27 07:41:13 -0700493 if (fParent == nullptr) {
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000494 return;
reed@google.coma25c94e2013-06-13 20:20:17 +0000495 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000496
reed@google.coma25c94e2013-06-13 20:20:17 +0000497 if (fContainsFocus) {
halcanary96fcdcc2015-08-27 07:41:13 -0700498 (void)this->setFocusView(nullptr);
reed@google.coma25c94e2013-06-13 20:20:17 +0000499 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000500
halcanary96fcdcc2015-08-27 07:41:13 -0700501 this->inval(nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000502
halcanary96fcdcc2015-08-27 07:41:13 -0700503 SkView* next = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000504
reed@google.coma25c94e2013-06-13 20:20:17 +0000505 if (fNextSibling != this) { // do we have any siblings
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000506 fNextSibling->fPrevSibling = fPrevSibling;
507 fPrevSibling->fNextSibling = fNextSibling;
508 next = fNextSibling;
509 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000510
reed@google.coma25c94e2013-06-13 20:20:17 +0000511 if (fParent->fFirstChild == this) {
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000512 fParent->fFirstChild = next;
reed@google.coma25c94e2013-06-13 20:20:17 +0000513 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000514
halcanary96fcdcc2015-08-27 07:41:13 -0700515 fParent = fNextSibling = fPrevSibling = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000516
reed@google.coma25c94e2013-06-13 20:20:17 +0000517 this->validate();
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000518 this->unref();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000519}
520
reed@google.coma25c94e2013-06-13 20:20:17 +0000521void SkView::detachFromParent() {
522 this->validate();
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000523 SkView* parent = fParent;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000524
reed@google.coma25c94e2013-06-13 20:20:17 +0000525 if (parent) {
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000526 this->detachFromParent_NoLayout();
527 parent->invokeLayout();
528 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000529}
530
reed@google.coma25c94e2013-06-13 20:20:17 +0000531SkView* SkView::attachChildToBack(SkView* child) {
532 this->validate();
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000533 SkASSERT(child != this);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000534
halcanary96fcdcc2015-08-27 07:41:13 -0700535 if (child == nullptr || fFirstChild == child)
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000536 goto DONE;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000537
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000538 child->ref();
539 child->detachFromParent_NoLayout();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000540
halcanary96fcdcc2015-08-27 07:41:13 -0700541 if (fFirstChild == nullptr) {
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000542 child->fNextSibling = child;
543 child->fPrevSibling = child;
reed@google.coma25c94e2013-06-13 20:20:17 +0000544 } else {
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000545 child->fNextSibling = fFirstChild;
546 child->fPrevSibling = fFirstChild->fPrevSibling;
547 fFirstChild->fPrevSibling->fNextSibling = child;
548 fFirstChild->fPrevSibling = child;
549 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000550
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000551 fFirstChild = child;
552 child->fParent = this;
halcanary96fcdcc2015-08-27 07:41:13 -0700553 child->inval(nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000554
reed@google.coma25c94e2013-06-13 20:20:17 +0000555 this->validate();
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000556 this->invokeLayout();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000557DONE:
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000558 return child;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000559}
560
reed@google.coma25c94e2013-06-13 20:20:17 +0000561SkView* SkView::attachChildToFront(SkView* child) {
562 this->validate();
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000563 SkASSERT(child != this);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000564
halcanary96fcdcc2015-08-27 07:41:13 -0700565 if (child == nullptr || (fFirstChild && fFirstChild->fPrevSibling == child))
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000566 goto DONE;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000567
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000568 child->ref();
569 child->detachFromParent_NoLayout();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000570
halcanary96fcdcc2015-08-27 07:41:13 -0700571 if (fFirstChild == nullptr) {
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000572 fFirstChild = child;
573 child->fNextSibling = child;
574 child->fPrevSibling = child;
reed@google.coma25c94e2013-06-13 20:20:17 +0000575 } else {
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000576 child->fNextSibling = fFirstChild;
577 child->fPrevSibling = fFirstChild->fPrevSibling;
578 fFirstChild->fPrevSibling->fNextSibling = child;
579 fFirstChild->fPrevSibling = child;
580 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000581
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000582 child->fParent = this;
halcanary96fcdcc2015-08-27 07:41:13 -0700583 child->inval(nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000584
reed@google.coma25c94e2013-06-13 20:20:17 +0000585 this->validate();
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000586 this->invokeLayout();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000587DONE:
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000588 return child;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000589}
590
reed@google.coma25c94e2013-06-13 20:20:17 +0000591void SkView::detachAllChildren() {
592 this->validate();
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000593 while (fFirstChild)
594 fFirstChild->detachFromParent_NoLayout();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000595}
596
reed@google.coma25c94e2013-06-13 20:20:17 +0000597void SkView::localToGlobal(SkMatrix* matrix) const {
reed@google.comf03bb562011-11-11 21:42:12 +0000598 if (matrix) {
599 matrix->reset();
600 const SkView* view = this;
601 while (view)
602 {
603 matrix->preConcat(view->getLocalMatrix());
604 matrix->preTranslate(-view->fLoc.fX, -view->fLoc.fY);
605 view = view->fParent;
606 }
607 }
608}
reed9a878a02015-12-27 12:47:25 -0800609
610bool SkView::globalToLocal(SkScalar x, SkScalar y, SkPoint* local) const {
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000611 SkASSERT(this);
612
bsalomon49f085d2014-09-05 13:34:00 -0700613 if (local) {
reed@google.comf03bb562011-11-11 21:42:12 +0000614 SkMatrix m;
615 this->localToGlobal(&m);
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000616 if (!m.invert(&m)) {
617 return false;
618 }
reed@google.comf03bb562011-11-11 21:42:12 +0000619 SkPoint p;
reed@google.comf03bb562011-11-11 21:42:12 +0000620 m.mapXY(x, y, &p);
robertphillips@google.com07ef9112012-06-04 13:22:14 +0000621 local->set(p.fX, p.fY);
622 }
623
624 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000625}
626
627//////////////////////////////////////////////////////////////////
628
rmistry@google.comd6176b02012-08-23 18:14:13 +0000629/* Even if the subclass overrides onInflate, they should always be
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000630 sure to call the inherited method, so that we get called.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000631*/
reed@google.coma25c94e2013-06-13 20:20:17 +0000632void SkView::onInflate(const SkDOM& dom, const SkDOM::Node* node) {
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000633 SkScalar x, y;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000634
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000635 x = this->locX();
636 y = this->locY();
637 (void)dom.findScalar(node, "x", &x);
638 (void)dom.findScalar(node, "y", &y);
639 this->setLoc(x, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000640
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000641 x = this->width();
642 y = this->height();
643 (void)dom.findScalar(node, "width", &x);
644 (void)dom.findScalar(node, "height", &y);
645 this->setSize(x, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000646
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000647 // inflate the flags
reed@android.com8a1c16f2008-12-17 15:59:43 +0000648
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000649 static const char* gFlagNames[] = {
650 "visible", "enabled", "focusable", "flexH", "flexV"
651 };
652 SkASSERT(SK_ARRAY_COUNT(gFlagNames) == kFlagShiftCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000653
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000654 bool b;
655 uint32_t flags = this->getFlags();
reed9a878a02015-12-27 12:47:25 -0800656 for (unsigned i = 0; i < SK_ARRAY_COUNT(gFlagNames); i++) {
657 if (dom.findBool(node, gFlagNames[i], &b)) {
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000658 flags = SkSetClearShift(flags, b, i);
reed9a878a02015-12-27 12:47:25 -0800659 }
660 }
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000661 this->setFlags(flags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000662}
663
reed@google.coma25c94e2013-06-13 20:20:17 +0000664void SkView::inflate(const SkDOM& dom, const SkDOM::Node* node) {
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000665 this->onInflate(dom, node);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000666}
667
reed@google.coma25c94e2013-06-13 20:20:17 +0000668void SkView::onPostInflate(const SkTDict<SkView*>&) {
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000669 // override in subclass as needed
reed@android.com8a1c16f2008-12-17 15:59:43 +0000670}
671
reed@google.coma25c94e2013-06-13 20:20:17 +0000672void SkView::postInflate(const SkTDict<SkView*>& dict) {
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000673 this->onPostInflate(dict);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000674
rmistry@google.comd6176b02012-08-23 18:14:13 +0000675 B2FIter iter(this);
676 SkView* child;
halcanary96fcdcc2015-08-27 07:41:13 -0700677 while ((child = iter.next()) != nullptr)
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000678 child->postInflate(dict);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000679}
680
681//////////////////////////////////////////////////////////////////
682
reed@google.coma25c94e2013-06-13 20:20:17 +0000683SkView* SkView::sendEventToParents(const SkEvent& evt) {
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000684 SkView* parent = fParent;
rmistry@google.comd6176b02012-08-23 18:14:13 +0000685
reed@google.coma25c94e2013-06-13 20:20:17 +0000686 while (parent) {
687 if (parent->doEvent(evt)) {
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000688 return parent;
reed@google.coma25c94e2013-06-13 20:20:17 +0000689 }
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000690 parent = parent->fParent;
691 }
halcanary96fcdcc2015-08-27 07:41:13 -0700692 return nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000693}
694
reed@android.com34245c72009-11-03 04:00:48 +0000695SkView* SkView::sendQueryToParents(SkEvent* evt) {
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000696 SkView* parent = fParent;
rmistry@google.comd6176b02012-08-23 18:14:13 +0000697
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000698 while (parent) {
699 if (parent->doQuery(evt)) {
700 return parent;
reed@android.com34245c72009-11-03 04:00:48 +0000701 }
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000702 parent = parent->fParent;
703 }
halcanary96fcdcc2015-08-27 07:41:13 -0700704 return nullptr;
reed@android.com34245c72009-11-03 04:00:48 +0000705}
706
reed@android.com8a1c16f2008-12-17 15:59:43 +0000707//////////////////////////////////////////////////////////////////
708//////////////////////////////////////////////////////////////////
709
reed@google.coma25c94e2013-06-13 20:20:17 +0000710SkView::F2BIter::F2BIter(const SkView* parent) {
halcanary96fcdcc2015-08-27 07:41:13 -0700711 fFirstChild = parent ? parent->fFirstChild : nullptr;
712 fChild = fFirstChild ? fFirstChild->fPrevSibling : nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000713}
714
reed@google.coma25c94e2013-06-13 20:20:17 +0000715SkView* SkView::F2BIter::next() {
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000716 SkView* curr = fChild;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000717
reed@google.coma25c94e2013-06-13 20:20:17 +0000718 if (fChild) {
719 if (fChild == fFirstChild) {
halcanary96fcdcc2015-08-27 07:41:13 -0700720 fChild = nullptr;
reed@google.coma25c94e2013-06-13 20:20:17 +0000721 } else {
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000722 fChild = fChild->fPrevSibling;
reed@google.coma25c94e2013-06-13 20:20:17 +0000723 }
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000724 }
725 return curr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000726}
727
reed@google.coma25c94e2013-06-13 20:20:17 +0000728SkView::B2FIter::B2FIter(const SkView* parent) {
halcanary96fcdcc2015-08-27 07:41:13 -0700729 fFirstChild = parent ? parent->fFirstChild : nullptr;
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000730 fChild = fFirstChild;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000731}
732
reed@google.coma25c94e2013-06-13 20:20:17 +0000733SkView* SkView::B2FIter::next() {
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000734 SkView* curr = fChild;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000735
reed@google.coma25c94e2013-06-13 20:20:17 +0000736 if (fChild) {
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000737 SkView* next = fChild->fNextSibling;
738 if (next == fFirstChild)
halcanary96fcdcc2015-08-27 07:41:13 -0700739 next = nullptr;
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000740 fChild = next;
741 }
742 return curr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000743}
744
745//////////////////////////////////////////////////////////////////
746//////////////////////////////////////////////////////////////////
747
748#ifdef SK_DEBUG
749
reed@google.coma25c94e2013-06-13 20:20:17 +0000750void SkView::validate() const {
reed@google.com079813e2013-06-14 17:46:07 +0000751// SkASSERT(this->getRefCnt() > 0 && this->getRefCnt() < 100);
reed@google.coma25c94e2013-06-13 20:20:17 +0000752 if (fParent) {
753 SkASSERT(fNextSibling);
754 SkASSERT(fPrevSibling);
755 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700756 bool nextNull = nullptr == fNextSibling;
757 bool prevNull = nullptr == fNextSibling;
reed@google.com732c5d52013-06-13 20:48:09 +0000758 SkASSERT(nextNull == prevNull);
reed@google.coma25c94e2013-06-13 20:20:17 +0000759 }
760}
761
reed9a878a02015-12-27 12:47:25 -0800762static inline void show_if_nonzero(const char name[], SkScalar value) {
763 if (value) {
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000764 SkDebugf("%s=\"%g\"", name, value/65536.);
reed9a878a02015-12-27 12:47:25 -0800765 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000766}
767
reed9a878a02015-12-27 12:47:25 -0800768static void tab(int level) {
769 for (int i = 0; i < level; i++) {
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000770 SkDebugf(" ");
reed9a878a02015-12-27 12:47:25 -0800771 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000772}
773
reed9a878a02015-12-27 12:47:25 -0800774static void dumpview(const SkView* view, int level, bool recurse) {
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000775 tab(level);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000776
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000777 SkDebugf("<view");
778 show_if_nonzero(" x", view->locX());
779 show_if_nonzero(" y", view->locY());
780 show_if_nonzero(" width", view->width());
781 show_if_nonzero(" height", view->height());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000782
reed9a878a02015-12-27 12:47:25 -0800783 if (recurse) {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000784 SkView::B2FIter iter(view);
785 SkView* child;
786 bool noChildren = true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000787
reed9a878a02015-12-27 12:47:25 -0800788 while ((child = iter.next()) != nullptr) {
789 if (noChildren) {
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000790 SkDebugf(">\n");
reed9a878a02015-12-27 12:47:25 -0800791 }
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000792 noChildren = false;
793 dumpview(child, level + 1, true);
794 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000795
reed9a878a02015-12-27 12:47:25 -0800796 if (!noChildren) {
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000797 tab(level);
798 SkDebugf("</view>\n");
reed9a878a02015-12-27 12:47:25 -0800799 } else {
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000800 goto ONELINER;
reed9a878a02015-12-27 12:47:25 -0800801 }
802 } else {
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000803 ONELINER:
804 SkDebugf(" />\n");
805 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000806}
807
reed9a878a02015-12-27 12:47:25 -0800808void SkView::dump(bool recurse) const {
robertphillips@google.coma22e2112012-08-16 14:58:06 +0000809 dumpview(this, 0, recurse);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000810}
811
812#endif