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 12static 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 19SkView::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 27SkView::~SkView() { 28 this->detachAllChildren(); 29} 30 31void 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 46void SkView::setVisibleP(bool pred) { 47 this->setFlags(SkSetClearShift(fFlags, pred, kVisible_Shift)); 48} 49 50void SkView::setEnabledP(bool pred) { 51 this->setFlags(SkSetClearShift(fFlags, pred, kEnabled_Shift)); 52} 53 54void SkView::setFocusableP(bool pred) { 55 this->setFlags(SkSetClearShift(fFlags, pred, kFocusable_Shift)); 56} 57 58void SkView::setClipToBounds(bool pred) { 59 this->setFlags(SkSetClearShift(fFlags, !pred, kNoClip_Shift)); 60} 61 62void 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 77void 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 85void SkView::offset(SkScalar dx, SkScalar dy) { 86 if (dx || dy) 87 this->setLoc(fLoc.fX + dx, fLoc.fY + dy); 88} 89 90void SkView::setLocalMatrix(const SkMatrix& matrix) { 91 this->inval(nullptr); 92 fMatrix = matrix; 93 this->inval(nullptr); 94} 95 96void 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 137void 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 172bool 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 183SkView* 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 194bool SkView::hasFocus() const { 195 return this == this->getFocusView(); 196} 197 198bool SkView::acceptFocus() { 199 return this->isFocusable() && this->setFocusView(this); 200} 201 202/* 203 Try to give focus to this view, or its children 204*/ 205SkView* 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 232SkView* 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 287void SkView::onFocusChange(bool gainFocusP) { 288 this->inval(nullptr); 289} 290 291//////////////////////////////////////////////////////////////////////////// 292 293SkView::Click::Click(SkView* target) { 294 SkASSERT(target); 295 fTargetID = target->getSinkID(); 296 fType = nullptr; 297 fWeOwnTheType = false; 298 fOwner = nullptr; 299} 300 301SkView::Click::~Click() { 302 this->resetType(); 303} 304 305void SkView::Click::resetType() { 306 if (fWeOwnTheType) { 307 sk_free(fType); 308 fWeOwnTheType = false; 309 } 310 fType = nullptr; 311} 312 313bool 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 328void SkView::Click::setType(const char type[]) { 329 this->resetType(); 330 fType = (char*)type; 331} 332 333void 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 345SkView::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 376void 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 399void 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 422void 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 447void SkView::invokeLayout() { 448 SkView::Layout* layout = this->getLayout(); 449 450 if (layout) { 451 layout->layoutChildren(this); 452 } 453} 454 455void SkView::onDraw(SkCanvas* canvas) { 456 Artist* artist = this->getArtist(); 457 458 if (artist) { 459 artist->draw(this, canvas); 460 } 461} 462 463void SkView::onSizeChange() {} 464 465bool SkView::onSendClickToChildren(SkScalar x, SkScalar y, unsigned modi) { 466 return true; 467} 468 469SkView::Click* SkView::onFindClickHandler(SkScalar x, SkScalar y, unsigned modi) { 470 return nullptr; 471} 472 473bool SkView::onClick(Click*) { 474 return false; 475} 476 477bool SkView::handleInval(const SkRect*) { 478 return false; 479} 480 481////////////////////////////////////////////////////////////////////// 482 483void SkView::getLocalBounds(SkRect* bounds) const { 484 if (bounds) { 485 bounds->set(0, 0, fWidth, fHeight); 486 } 487} 488 489////////////////////////////////////////////////////////////////////// 490////////////////////////////////////////////////////////////////////// 491 492void 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 522void SkView::detachFromParent() { 523 this->validate(); 524 SkView* parent = fParent; 525 526 if (parent) { 527 this->detachFromParent_NoLayout(); 528 parent->invokeLayout(); 529 } 530} 531 532SkView* 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(); 558DONE: 559 return child; 560} 561 562SkView* 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(); 588DONE: 589 return child; 590} 591 592void SkView::detachAllChildren() { 593 this->validate(); 594 while (fFirstChild) 595 fFirstChild->detachFromParent_NoLayout(); 596} 597 598void 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 611bool 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*/ 631void 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 663void SkView::inflate(const SkDOM& dom, const SkDOM::Node* node) { 664 this->onInflate(dom, node); 665} 666 667////////////////////////////////////////////////////////////////// 668 669SkView* 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 681SkView* 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 696SkView::F2BIter::F2BIter(const SkView* parent) { 697 fFirstChild = parent ? parent->fFirstChild : nullptr; 698 fChild = fFirstChild ? fFirstChild->fPrevSibling : nullptr; 699} 700 701SkView* 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 714SkView::B2FIter::B2FIter(const SkView* parent) { 715 fFirstChild = parent ? parent->fFirstChild : nullptr; 716 fChild = fFirstChild; 717} 718 719SkView* 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 736void 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 748static inline void show_if_nonzero(const char name[], SkScalar value) { 749 if (value) { 750 SkDebugf("%s=\"%g\"", name, value/65536.); 751 } 752} 753 754static void tab(int level) { 755 for (int i = 0; i < level; i++) { 756 SkDebugf(" "); 757 } 758} 759 760static 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 794void SkView::dump(bool recurse) const { 795 dumpview(this, 0, recurse); 796} 797 798#endif 799