1 /* 2 * Copyright 2007, The Android Open Source Project 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * * Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * * Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 #include "CachedPrefix.h" 27 #include "CachedFrame.h" 28 #include "CachedNode.h" 29 #if DUMP_NAV_CACHE 30 #include "CachedRoot.h" 31 #endif 32 33 #include "CachedHistory.h" 34 35 namespace android { 36 37 CachedHistory::CachedHistory() { 38 memset(this, 0, sizeof(CachedHistory)); // this assume the class has no virtuals 39 mLastMove = CachedFrame::UNINITIALIZED; 40 mPriorMove = CachedFrame::UNINITIALIZED; 41 } 42 43 44 void CachedHistory::addToVisited(const CachedNode* node, CachedFrame::Direction direction) 45 { 46 memmove(&mVisited[1], &mVisited[0], sizeof(mVisited) - sizeof(mVisited[0])); 47 mVisited[0].mNode = node; 48 mVisited[0].mDirection = direction; 49 } 50 51 bool CachedHistory::checkVisited(const CachedNode* node, CachedFrame::Direction direction) const 52 { 53 // if the direction is unchanged and we've already visited this node, don't visit it again 54 int index = 0; 55 while (index < NAVIGATION_VISIT_DEPTH - 1) { 56 if (direction != mVisited[index].mDirection) 57 break; 58 index++; // compare with last direction, previous to last node (where the arrow took us from) 59 if (node == mVisited[index].mNode) 60 return false; 61 } 62 return true; 63 } 64 65 void CachedHistory::pinMaxMin(const WebCore::IntRect& viewBounds) 66 { 67 if (mMinWorkingHorizontal < viewBounds.y() || mMinWorkingHorizontal >= viewBounds.maxY()) 68 mMinWorkingHorizontal = viewBounds.y(); 69 if (mMaxWorkingHorizontal > viewBounds.maxY() || mMaxWorkingHorizontal <= viewBounds.y()) 70 mMaxWorkingHorizontal = viewBounds.maxY(); 71 if (mMinWorkingVertical < viewBounds.x() || mMinWorkingVertical >= viewBounds.maxX()) 72 mMinWorkingVertical = viewBounds.x(); 73 if (mMaxWorkingVertical > viewBounds.maxX() || mMaxWorkingVertical <= viewBounds.x()) 74 mMaxWorkingVertical = viewBounds.maxX(); 75 } 76 77 void CachedHistory::reset() 78 { 79 memset(mVisited, 0, sizeof(mVisited)); 80 // mLastScroll = 0; 81 mPriorBounds = WebCore::IntRect(0, 0, 0, 0); 82 mDirectionChange = false; 83 mDidFirstLayout = false; 84 mPriorMove = mLastMove = CachedFrame::UNINITIALIZED; 85 mMinWorkingHorizontal = mMinWorkingVertical = INT_MIN; 86 mMaxWorkingHorizontal = mMaxWorkingVertical = INT_MAX; 87 } 88 89 void CachedHistory::setWorking(CachedFrame::Direction newMove, 90 const CachedFrame* cursorFrame, const CachedNode* cursor, 91 const WebCore::IntRect& viewBounds) 92 { 93 CachedFrame::Direction lastAxis = (CachedFrame::Direction) (mLastMove & ~CachedFrame::RIGHT_DOWN); // up, left or uninitialized 94 CachedFrame::Direction newAxis = (CachedFrame::Direction) (newMove & ~CachedFrame::RIGHT_DOWN); 95 bool change = newAxis != lastAxis; 96 mDirectionChange = change && mLastMove != CachedFrame::UNINITIALIZED; 97 if (cursor != NULL || mLastMove != CachedFrame::UNINITIALIZED) { 98 mPriorMove = mLastMove; 99 mLastMove = newMove; 100 } 101 const WebCore::IntRect* navBounds = &mNavBounds; 102 if (cursor != NULL) { 103 WebCore::IntRect cursorBounds = cursor->bounds(cursorFrame); 104 if (cursorBounds.isEmpty() == false) 105 mNavBounds = cursorBounds; 106 } 107 if (change) { // uninitialized or change in direction 108 if (lastAxis != CachedFrame::LEFT && navBounds->height() > 0) { 109 mMinWorkingHorizontal = navBounds->y(); 110 mMaxWorkingHorizontal = navBounds->maxY(); 111 } 112 if (lastAxis != CachedFrame::UP && navBounds->width() > 0) { 113 mMinWorkingVertical = navBounds->x(); 114 mMaxWorkingVertical = navBounds->maxX(); 115 } 116 } 117 pinMaxMin(viewBounds); 118 } 119 120 #if DUMP_NAV_CACHE 121 122 #define DEBUG_PRINT_BOOL(field) \ 123 DUMP_NAV_LOGD("// bool " #field "=%s;\n", b->field ? "true" : "false") 124 125 #define DEBUG_PRINT_RECT(field) \ 126 { const WebCore::IntRect& r = b->field; \ 127 DUMP_NAV_LOGD("// IntRect " #field "={%d, %d, %d, %d};\n", \ 128 r.x(), r.y(), r.width(), r.height()); } 129 130 CachedHistory* CachedHistory::Debug::base() const { 131 CachedHistory* nav = (CachedHistory*) ((char*) this - OFFSETOF(CachedHistory, mDebug)); 132 return nav; 133 } 134 135 const char* CachedHistory::Debug::direction(CachedFrame::Direction d) const 136 { 137 switch (d) { 138 case CachedFrame::LEFT: return "LEFT"; break; 139 case CachedFrame::RIGHT: return "RIGHT"; break; 140 case CachedFrame::UP: return "UP"; break; 141 case CachedFrame::DOWN: return "DOWN"; break; 142 default: return "UNINITIALIZED"; 143 } 144 } 145 146 void CachedHistory::Debug::print(CachedRoot* root) const 147 { 148 CachedHistory* b = base(); 149 DUMP_NAV_LOGD("// Visited mVisited[]={\n"); 150 for (size_t i = 0; i < NAVIGATION_VISIT_DEPTH; i++) { 151 const Visited& visit = b->mVisited[i]; 152 const CachedNode* node = visit.mNode; 153 int index = root != NULL && root->CachedFrame::mDebug.validate(node) ? 154 node->index() : -1; 155 DUMP_NAV_LOGD(" // { 0x%p (%d), %s },\n", node, index, direction(visit.mDirection)); 156 } 157 DUMP_NAV_LOGD("// };\n"); 158 // DUMP_NAV_LOGD("// int mLastScroll=%d;\n", b->mLastScroll); 159 DEBUG_PRINT_RECT(mMouseBounds); 160 DEBUG_PRINT_RECT(mNavBounds); 161 DEBUG_PRINT_RECT(mPriorBounds); 162 DEBUG_PRINT_BOOL(mDirectionChange); 163 DEBUG_PRINT_BOOL(mDidFirstLayout); 164 DUMP_NAV_LOGD("// CachedFrame::Direction mLastMove=%s, mPriorMove=%s;\n", 165 direction(b->mLastMove), direction(b->mPriorMove)); 166 int max = b->mMaxWorkingHorizontal; 167 DUMP_NAV_LOGD("static int TEST_MAX_H = %d;\n", max); 168 int min = b->mMinWorkingHorizontal; 169 if (min == INT_MIN) 170 min++; 171 DUMP_NAV_LOGD("static int TEST_MIN_H = %d;\n", min); 172 max = b->mMaxWorkingVertical; 173 DUMP_NAV_LOGD("static int TEST_MAX_V = %d;\n", max); 174 min = b->mMinWorkingVertical; 175 if (min == INT_MIN) 176 min++; 177 DUMP_NAV_LOGD("static int TEST_MIN_V = %d;\n", min); 178 DUMP_NAV_LOGD("\n"); 179 } 180 181 #endif 182 183 } 184