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