1 /*
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 */
7
8 #include "SkView.h"
9 #include "SkCanvas.h"
10
SkSetClearShift(uint32_t bits,bool cond,unsigned shift)11 static 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
16 ////////////////////////////////////////////////////////////////////////
17
SkView(uint32_t flags)18 SkView::SkView(uint32_t flags) : fFlags(SkToU8(flags)) {
19 fWidth = fHeight = 0;
20 fLoc.set(0, 0);
21 fParent = fFirstChild = fNextSibling = fPrevSibling = nullptr;
22 fMatrix.setIdentity();
23 fContainsFocus = 0;
24 }
25
~SkView()26 SkView::~SkView() {
27 this->detachAllChildren();
28 }
29
setFlags(uint32_t flags)30 void SkView::setFlags(uint32_t flags) {
31 SkASSERT((flags & ~kAllFlagMasks) == 0);
32
33 uint32_t diff = fFlags ^ flags;
34
35 if (diff & kVisible_Mask)
36 this->inval(nullptr);
37
38 fFlags = SkToU8(flags);
39
40 if (diff & kVisible_Mask) {
41 this->inval(nullptr);
42 }
43 }
44
setVisibleP(bool pred)45 void SkView::setVisibleP(bool pred) {
46 this->setFlags(SkSetClearShift(fFlags, pred, kVisible_Shift));
47 }
48
setEnabledP(bool pred)49 void SkView::setEnabledP(bool pred) {
50 this->setFlags(SkSetClearShift(fFlags, pred, kEnabled_Shift));
51 }
52
setFocusableP(bool pred)53 void SkView::setFocusableP(bool pred) {
54 this->setFlags(SkSetClearShift(fFlags, pred, kFocusable_Shift));
55 }
56
setClipToBounds(bool pred)57 void SkView::setClipToBounds(bool pred) {
58 this->setFlags(SkSetClearShift(fFlags, !pred, kNoClip_Shift));
59 }
60
setSize(SkScalar width,SkScalar height)61 void SkView::setSize(SkScalar width, SkScalar height) {
62 width = SkMaxScalar(0, width);
63 height = SkMaxScalar(0, height);
64
65 if (fWidth != width || fHeight != height)
66 {
67 this->inval(nullptr);
68 fWidth = width;
69 fHeight = height;
70 this->inval(nullptr);
71 this->onSizeChange();
72 this->invokeLayout();
73 }
74 }
75
setLoc(SkScalar x,SkScalar y)76 void SkView::setLoc(SkScalar x, SkScalar y) {
77 if (fLoc.fX != x || fLoc.fY != y) {
78 this->inval(nullptr);
79 fLoc.set(x, y);
80 this->inval(nullptr);
81 }
82 }
83
offset(SkScalar dx,SkScalar dy)84 void SkView::offset(SkScalar dx, SkScalar dy) {
85 if (dx || dy)
86 this->setLoc(fLoc.fX + dx, fLoc.fY + dy);
87 }
88
setLocalMatrix(const SkMatrix & matrix)89 void SkView::setLocalMatrix(const SkMatrix& matrix) {
90 this->inval(nullptr);
91 fMatrix = matrix;
92 this->inval(nullptr);
93 }
94
draw(SkCanvas * canvas)95 void SkView::draw(SkCanvas* canvas) {
96 if (fWidth && fHeight && this->isVisible()) {
97 SkRect r;
98 r.set(fLoc.fX, fLoc.fY, fLoc.fX + fWidth, fLoc.fY + fHeight);
99 if (this->isClipToBounds() && canvas->quickReject(r)) {
100 return;
101 }
102
103 SkAutoCanvasRestore as(canvas, true);
104
105 if (this->isClipToBounds()) {
106 canvas->clipRect(r);
107 }
108
109 canvas->translate(fLoc.fX, fLoc.fY);
110 canvas->concat(fMatrix);
111
112 if (fParent) {
113 fParent->beforeChild(this, canvas);
114 }
115
116 int sc = canvas->save();
117 this->onDraw(canvas);
118 canvas->restoreToCount(sc);
119
120 if (fParent) {
121 fParent->afterChild(this, canvas);
122 }
123
124 B2FIter iter(this);
125 SkView* child;
126
127 SkCanvas* childCanvas = this->beforeChildren(canvas);
128
129 while ((child = iter.next()) != nullptr)
130 child->draw(childCanvas);
131
132 this->afterChildren(canvas);
133 }
134 }
135
inval(SkRect * rect)136 void SkView::inval(SkRect* rect) {
137 SkView* view = this;
138 SkRect storage;
139
140 for (;;) {
141 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 }
156
157 SkView* parent = view->fParent;
158 if (parent == nullptr) {
159 return;
160 }
161
162 if (rect) {
163 rect->offset(view->fLoc.fX, view->fLoc.fY);
164 }
165 view = parent;
166 }
167 }
168
169 ////////////////////////////////////////////////////////////////////////////
170
setFocusView(SkView * fv)171 bool SkView::setFocusView(SkView* fv) {
172 SkView* view = this;
173
174 do {
175 if (view->onSetFocusView(fv)) {
176 return true;
177 }
178 } while ((view = view->fParent) != nullptr);
179 return false;
180 }
181
getFocusView() const182 SkView* SkView::getFocusView() const {
183 SkView* focus = nullptr;
184 const SkView* view = this;
185 do {
186 if (view->onGetFocusView(&focus)) {
187 break;
188 }
189 } while ((view = view->fParent) != nullptr);
190 return focus;
191 }
192
hasFocus() const193 bool SkView::hasFocus() const {
194 return this == this->getFocusView();
195 }
196
acceptFocus()197 bool SkView::acceptFocus() {
198 return this->isFocusable() && this->setFocusView(this);
199 }
200
201 /*
202 Try to give focus to this view, or its children
203 */
acceptFocus(FocusDirection dir)204 SkView* SkView::acceptFocus(FocusDirection dir) {
205 if (dir == kNext_FocusDirection) {
206 if (this->acceptFocus()) {
207 return this;
208 }
209 B2FIter iter(this);
210 SkView* child, *focus;
211 while ((child = iter.next()) != nullptr) {
212 if ((focus = child->acceptFocus(dir)) != nullptr) {
213 return focus;
214 }
215 }
216 } else { // prev
217 F2BIter iter(this);
218 SkView* child, *focus;
219 while ((child = iter.next()) != nullptr) {
220 if ((focus = child->acceptFocus(dir)) != nullptr) {
221 return focus;
222 }
223 }
224 if (this->acceptFocus()) {
225 return this;
226 }
227 }
228 return nullptr;
229 }
230
moveFocus(FocusDirection dir)231 SkView* SkView::moveFocus(FocusDirection dir) {
232 SkView* focus = this->getFocusView();
233
234 if (focus == nullptr) { // start with the root
235 focus = this;
236 while (focus->fParent) {
237 focus = focus->fParent;
238 }
239 }
240
241 SkView* child, *parent;
242
243 if (dir == kNext_FocusDirection) {
244 parent = focus;
245 child = focus->fFirstChild;
246 if (child)
247 goto FIRST_CHILD;
248 else
249 goto NEXT_SIB;
250
251 do {
252 while (child != parent->fFirstChild) {
253 FIRST_CHILD:
254 if ((focus = child->acceptFocus(dir)) != nullptr)
255 return focus;
256 child = child->fNextSibling;
257 }
258 NEXT_SIB:
259 child = parent->fNextSibling;
260 parent = parent->fParent;
261 } while (parent != nullptr);
262 } else { // prevfocus
263 parent = focus->fParent;
264 if (parent == nullptr) { // we're the root
265 return focus->acceptFocus(dir);
266 } else {
267 child = focus;
268 while (parent) {
269 while (child != parent->fFirstChild) {
270 child = child->fPrevSibling;
271 if ((focus = child->acceptFocus(dir)) != nullptr) {
272 return focus;
273 }
274 }
275 if (parent->acceptFocus()) {
276 return parent;
277 }
278 child = parent;
279 parent = parent->fParent;
280 }
281 }
282 }
283 return nullptr;
284 }
285
onFocusChange(bool gainFocusP)286 void SkView::onFocusChange(bool gainFocusP) {
287 this->inval(nullptr);
288 }
289
290 ////////////////////////////////////////////////////////////////////////////
291
Click(SkView * target)292 SkView::Click::Click(SkView* target) {
293 SkASSERT(target);
294 fTargetID = target->getSinkID();
295 fType = nullptr;
296 fWeOwnTheType = false;
297 fOwner = nullptr;
298 }
299
~Click()300 SkView::Click::~Click() {
301 this->resetType();
302 }
303
resetType()304 void SkView::Click::resetType() {
305 if (fWeOwnTheType) {
306 sk_free(fType);
307 fWeOwnTheType = false;
308 }
309 fType = nullptr;
310 }
311
isType(const char type[]) const312 bool SkView::Click::isType(const char type[]) const {
313 const char* t = fType;
314
315 if (type == t) {
316 return true;
317 }
318 if (type == nullptr) {
319 type = "";
320 }
321 if (t == nullptr) {
322 t = "";
323 }
324 return !strcmp(t, type);
325 }
326
setType(const char type[])327 void SkView::Click::setType(const char type[]) {
328 this->resetType();
329 fType = (char*)type;
330 }
331
copyType(const char type[])332 void SkView::Click::copyType(const char type[]) {
333 if (fType != type) {
334 this->resetType();
335 if (type) {
336 size_t len = strlen(type) + 1;
337 fType = (char*)sk_malloc_throw(len);
338 memcpy(fType, type, len);
339 fWeOwnTheType = true;
340 }
341 }
342 }
343
findClickHandler(SkScalar x,SkScalar y,unsigned modi)344 SkView::Click* SkView::findClickHandler(SkScalar x, SkScalar y, unsigned modi) {
345 if (x < 0 || y < 0 || x >= fWidth || y >= fHeight) {
346 return nullptr;
347 }
348
349 if (this->onSendClickToChildren(x, y, modi)) {
350 F2BIter iter(this);
351 SkView* child;
352
353 while ((child = iter.next()) != nullptr) {
354 SkPoint p;
355 #if 0
356 if (!child->globalToLocal(x, y, &p)) {
357 continue;
358 }
359 #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
363
364 Click* click = child->findClickHandler(p.fX, p.fY, modi);
365
366 if (click) {
367 return click;
368 }
369 }
370 }
371
372 return this->onFindClickHandler(x, y, modi);
373 }
374
DoClickDown(Click * click,int x,int y,unsigned modi)375 void SkView::DoClickDown(Click* click, int x, int y, unsigned modi) {
376 SkASSERT(click);
377
378 SkView* target = (SkView*)SkEventSink::FindSink(click->fTargetID);
379 if (nullptr == target) {
380 return;
381 }
382
383 click->fIOrig.set(x, y);
384 click->fICurr = click->fIPrev = click->fIOrig;
385
386 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;
392
393 click->fState = Click::kDown_State;
394 click->fModifierKeys = modi;
395 target->onClick(click);
396 }
397
DoClickMoved(Click * click,int x,int y,unsigned modi)398 void SkView::DoClickMoved(Click* click, int x, int y, unsigned modi) {
399 SkASSERT(click);
400
401 SkView* target = (SkView*)SkEventSink::FindSink(click->fTargetID);
402 if (nullptr == target) {
403 return;
404 }
405
406 click->fIPrev = click->fICurr;
407 click->fICurr.set(x, y);
408
409 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 }
415
416 click->fState = Click::kMoved_State;
417 click->fModifierKeys = modi;
418 target->onClick(click);
419 }
420
DoClickUp(Click * click,int x,int y,unsigned modi)421 void SkView::DoClickUp(Click* click, int x, int y, unsigned modi) {
422 SkASSERT(click);
423
424 SkView* target = (SkView*)SkEventSink::FindSink(click->fTargetID);
425 if (nullptr == target) {
426 return;
427 }
428
429 click->fIPrev = click->fICurr;
430 click->fICurr.set(x, y);
431
432 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 }
438
439 click->fState = Click::kUp_State;
440 click->fModifierKeys = modi;
441 target->onClick(click);
442 }
443
444 //////////////////////////////////////////////////////////////////////
445
invokeLayout()446 void SkView::invokeLayout() {
447 SkView::Layout* layout = this->getLayout();
448
449 if (layout) {
450 layout->layoutChildren(this);
451 }
452 }
453
onDraw(SkCanvas * canvas)454 void SkView::onDraw(SkCanvas* canvas) {
455 Artist* artist = this->getArtist();
456
457 if (artist) {
458 artist->draw(this, canvas);
459 }
460 }
461
onSizeChange()462 void SkView::onSizeChange() {}
463
onSendClickToChildren(SkScalar x,SkScalar y,unsigned modi)464 bool SkView::onSendClickToChildren(SkScalar x, SkScalar y, unsigned modi) {
465 return true;
466 }
467
onFindClickHandler(SkScalar x,SkScalar y,unsigned modi)468 SkView::Click* SkView::onFindClickHandler(SkScalar x, SkScalar y, unsigned modi) {
469 return nullptr;
470 }
471
onClick(Click *)472 bool SkView::onClick(Click*) {
473 return false;
474 }
475
handleInval(const SkRect *)476 bool SkView::handleInval(const SkRect*) {
477 return false;
478 }
479
480 //////////////////////////////////////////////////////////////////////
481
getLocalBounds(SkRect * bounds) const482 void SkView::getLocalBounds(SkRect* bounds) const {
483 if (bounds) {
484 bounds->set(0, 0, fWidth, fHeight);
485 }
486 }
487
488 //////////////////////////////////////////////////////////////////////
489 //////////////////////////////////////////////////////////////////////
490
detachFromParent_NoLayout()491 void SkView::detachFromParent_NoLayout() {
492 this->validate();
493 if (fParent == nullptr) {
494 return;
495 }
496
497 if (fContainsFocus) {
498 (void)this->setFocusView(nullptr);
499 }
500
501 this->inval(nullptr);
502
503 SkView* next = nullptr;
504
505 if (fNextSibling != this) { // do we have any siblings
506 fNextSibling->fPrevSibling = fPrevSibling;
507 fPrevSibling->fNextSibling = fNextSibling;
508 next = fNextSibling;
509 }
510
511 if (fParent->fFirstChild == this) {
512 fParent->fFirstChild = next;
513 }
514
515 fParent = fNextSibling = fPrevSibling = nullptr;
516
517 this->validate();
518 this->unref();
519 }
520
detachFromParent()521 void SkView::detachFromParent() {
522 this->validate();
523 SkView* parent = fParent;
524
525 if (parent) {
526 this->detachFromParent_NoLayout();
527 parent->invokeLayout();
528 }
529 }
530
attachChildToBack(SkView * child)531 SkView* SkView::attachChildToBack(SkView* child) {
532 this->validate();
533 SkASSERT(child != this);
534
535 if (child == nullptr || fFirstChild == child)
536 goto DONE;
537
538 child->ref();
539 child->detachFromParent_NoLayout();
540
541 if (fFirstChild == nullptr) {
542 child->fNextSibling = child;
543 child->fPrevSibling = child;
544 } else {
545 child->fNextSibling = fFirstChild;
546 child->fPrevSibling = fFirstChild->fPrevSibling;
547 fFirstChild->fPrevSibling->fNextSibling = child;
548 fFirstChild->fPrevSibling = child;
549 }
550
551 fFirstChild = child;
552 child->fParent = this;
553 child->inval(nullptr);
554
555 this->validate();
556 this->invokeLayout();
557 DONE:
558 return child;
559 }
560
attachChildToFront(SkView * child)561 SkView* SkView::attachChildToFront(SkView* child) {
562 this->validate();
563 SkASSERT(child != this);
564
565 if (child == nullptr || (fFirstChild && fFirstChild->fPrevSibling == child))
566 goto DONE;
567
568 child->ref();
569 child->detachFromParent_NoLayout();
570
571 if (fFirstChild == nullptr) {
572 fFirstChild = child;
573 child->fNextSibling = child;
574 child->fPrevSibling = child;
575 } else {
576 child->fNextSibling = fFirstChild;
577 child->fPrevSibling = fFirstChild->fPrevSibling;
578 fFirstChild->fPrevSibling->fNextSibling = child;
579 fFirstChild->fPrevSibling = child;
580 }
581
582 child->fParent = this;
583 child->inval(nullptr);
584
585 this->validate();
586 this->invokeLayout();
587 DONE:
588 return child;
589 }
590
detachAllChildren()591 void SkView::detachAllChildren() {
592 this->validate();
593 while (fFirstChild)
594 fFirstChild->detachFromParent_NoLayout();
595 }
596
localToGlobal(SkMatrix * matrix) const597 void SkView::localToGlobal(SkMatrix* matrix) const {
598 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 }
609
globalToLocal(SkScalar x,SkScalar y,SkPoint * local) const610 bool SkView::globalToLocal(SkScalar x, SkScalar y, SkPoint* local) const {
611 SkASSERT(this);
612
613 if (local) {
614 SkMatrix m;
615 this->localToGlobal(&m);
616 if (!m.invert(&m)) {
617 return false;
618 }
619 SkPoint p;
620 m.mapXY(x, y, &p);
621 local->set(p.fX, p.fY);
622 }
623
624 return true;
625 }
626
627 //////////////////////////////////////////////////////////////////
628
629 /* Even if the subclass overrides onInflate, they should always be
630 sure to call the inherited method, so that we get called.
631 */
onInflate(const SkDOM & dom,const SkDOM::Node * node)632 void SkView::onInflate(const SkDOM& dom, const SkDOM::Node* node) {
633 SkScalar x, y;
634
635 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);
640
641 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);
646
647 // inflate the flags
648
649 static const char* gFlagNames[] = {
650 "visible", "enabled", "focusable", "flexH", "flexV"
651 };
652 SkASSERT(SK_ARRAY_COUNT(gFlagNames) == kFlagShiftCount);
653
654 bool b;
655 uint32_t flags = this->getFlags();
656 for (unsigned i = 0; i < SK_ARRAY_COUNT(gFlagNames); i++) {
657 if (dom.findBool(node, gFlagNames[i], &b)) {
658 flags = SkSetClearShift(flags, b, i);
659 }
660 }
661 this->setFlags(flags);
662 }
663
inflate(const SkDOM & dom,const SkDOM::Node * node)664 void SkView::inflate(const SkDOM& dom, const SkDOM::Node* node) {
665 this->onInflate(dom, node);
666 }
667
onPostInflate(const SkTDict<SkView * > &)668 void SkView::onPostInflate(const SkTDict<SkView*>&) {
669 // override in subclass as needed
670 }
671
postInflate(const SkTDict<SkView * > & dict)672 void SkView::postInflate(const SkTDict<SkView*>& dict) {
673 this->onPostInflate(dict);
674
675 B2FIter iter(this);
676 SkView* child;
677 while ((child = iter.next()) != nullptr)
678 child->postInflate(dict);
679 }
680
681 //////////////////////////////////////////////////////////////////
682
sendEventToParents(const SkEvent & evt)683 SkView* SkView::sendEventToParents(const SkEvent& evt) {
684 SkView* parent = fParent;
685
686 while (parent) {
687 if (parent->doEvent(evt)) {
688 return parent;
689 }
690 parent = parent->fParent;
691 }
692 return nullptr;
693 }
694
sendQueryToParents(SkEvent * evt)695 SkView* SkView::sendQueryToParents(SkEvent* evt) {
696 SkView* parent = fParent;
697
698 while (parent) {
699 if (parent->doQuery(evt)) {
700 return parent;
701 }
702 parent = parent->fParent;
703 }
704 return nullptr;
705 }
706
707 //////////////////////////////////////////////////////////////////
708 //////////////////////////////////////////////////////////////////
709
F2BIter(const SkView * parent)710 SkView::F2BIter::F2BIter(const SkView* parent) {
711 fFirstChild = parent ? parent->fFirstChild : nullptr;
712 fChild = fFirstChild ? fFirstChild->fPrevSibling : nullptr;
713 }
714
next()715 SkView* SkView::F2BIter::next() {
716 SkView* curr = fChild;
717
718 if (fChild) {
719 if (fChild == fFirstChild) {
720 fChild = nullptr;
721 } else {
722 fChild = fChild->fPrevSibling;
723 }
724 }
725 return curr;
726 }
727
B2FIter(const SkView * parent)728 SkView::B2FIter::B2FIter(const SkView* parent) {
729 fFirstChild = parent ? parent->fFirstChild : nullptr;
730 fChild = fFirstChild;
731 }
732
next()733 SkView* SkView::B2FIter::next() {
734 SkView* curr = fChild;
735
736 if (fChild) {
737 SkView* next = fChild->fNextSibling;
738 if (next == fFirstChild)
739 next = nullptr;
740 fChild = next;
741 }
742 return curr;
743 }
744
745 //////////////////////////////////////////////////////////////////
746 //////////////////////////////////////////////////////////////////
747
748 #ifdef SK_DEBUG
749
validate() const750 void SkView::validate() const {
751 // SkASSERT(this->getRefCnt() > 0 && this->getRefCnt() < 100);
752 if (fParent) {
753 SkASSERT(fNextSibling);
754 SkASSERT(fPrevSibling);
755 } else {
756 bool nextNull = nullptr == fNextSibling;
757 bool prevNull = nullptr == fNextSibling;
758 SkASSERT(nextNull == prevNull);
759 }
760 }
761
show_if_nonzero(const char name[],SkScalar value)762 static inline void show_if_nonzero(const char name[], SkScalar value) {
763 if (value) {
764 SkDebugf("%s=\"%g\"", name, value/65536.);
765 }
766 }
767
tab(int level)768 static void tab(int level) {
769 for (int i = 0; i < level; i++) {
770 SkDebugf(" ");
771 }
772 }
773
dumpview(const SkView * view,int level,bool recurse)774 static void dumpview(const SkView* view, int level, bool recurse) {
775 tab(level);
776
777 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());
782
783 if (recurse) {
784 SkView::B2FIter iter(view);
785 SkView* child;
786 bool noChildren = true;
787
788 while ((child = iter.next()) != nullptr) {
789 if (noChildren) {
790 SkDebugf(">\n");
791 }
792 noChildren = false;
793 dumpview(child, level + 1, true);
794 }
795
796 if (!noChildren) {
797 tab(level);
798 SkDebugf("</view>\n");
799 } else {
800 goto ONELINER;
801 }
802 } else {
803 ONELINER:
804 SkDebugf(" />\n");
805 }
806 }
807
dump(bool recurse) const808 void SkView::dump(bool recurse) const {
809 dumpview(this, 0, recurse);
810 }
811
812 #endif
813